Web extension module for def-forms + modifier-key clicks + CSSX SSR fix
Move defhandler/defquery/defaction/defpage/defrelation from hardcoded evaluator dispatch to web/web-forms.sx extension module, registered via register-special-form!. Adapters updated to use definition-form? and dynamically extended form-name lists. Fix modifier-key clicks (ctrl-click → new tab) in three click handlers: bindBoostLink, bindClientRouteClick, and orchestration.sx bind-event. Add event-modifier-key? primitive (eventModifierKey_p for transpiler). Fix CSSX SSR: ~cssx/flush no longer drains the collected bucket on the server, so the shell template correctly emits CSSX rules in <head>. Add missing server-side DOM stubs (create-text-node, dom-append, etc.) and SSR passthrough for portal/error-boundary/promise-delayed. Passive event listeners for touch/wheel/scroll to fix touchpad scrolling. 97/97 Playwright demo tests + 4/4 isomorphic SSR tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -420,10 +420,11 @@ class OcamlBridge:
|
||||
# All directories loaded into the Python env
|
||||
all_dirs = list(set(_watched_dirs) | _dirs_from_cache)
|
||||
|
||||
# Isomorphic libraries: signals, rendering, freeze scopes
|
||||
# Isomorphic libraries: signals, rendering, freeze scopes, web forms
|
||||
web_dir = os.path.join(os.path.dirname(__file__), "../../web")
|
||||
if os.path.isdir(web_dir):
|
||||
for web_file in ["signals.sx", "adapter-html.sx", "adapter-sx.sx"]:
|
||||
for web_file in ["signals.sx", "adapter-html.sx", "adapter-sx.sx",
|
||||
"web-forms.sx"]:
|
||||
path = os.path.normpath(os.path.join(web_dir, web_file))
|
||||
if os.path.isfile(path):
|
||||
all_files.append(path)
|
||||
|
||||
@@ -494,16 +494,13 @@
|
||||
;; =========================================================================
|
||||
|
||||
(defcomp ~cssx/flush () :affinity :client
|
||||
(let ((rules (collected "cssx")))
|
||||
(clear-collected! "cssx")
|
||||
(when (not (empty? rules))
|
||||
;; Append to the persistent <style id="sx-css"> in <head> if available.
|
||||
;; This survives #main-panel morphs during SPA navigation.
|
||||
;; Falls back to inline <style> if no head stylesheet exists.
|
||||
(let ((head-style (dom-query "#sx-css")))
|
||||
(if head-style
|
||||
(do
|
||||
(dom-set-prop head-style "textContent"
|
||||
(str (dom-get-prop head-style "textContent") (join "" rules)))
|
||||
nil)
|
||||
(raw! (str "<style data-cssx>" (join "" rules) "</style>")))))))
|
||||
(let ((rules (collected "cssx"))
|
||||
(head-style (dom-query "#sx-css")))
|
||||
;; On client: append rules to <style id="sx-css"> in <head>.
|
||||
;; On server: head-style is nil (no DOM). Don't clear the bucket —
|
||||
;; the shell's <head> template reads collected("cssx") and emits them.
|
||||
(when head-style
|
||||
(clear-collected! "cssx")
|
||||
(when (not (empty? rules))
|
||||
(dom-set-prop head-style "textContent"
|
||||
(str (dom-get-prop head-style "textContent") (join "" rules)))))))
|
||||
|
||||
Reference in New Issue
Block a user