Fix island reactivity: trampoline callLambda result in dom-on handlers
dom-on wraps Lambda event handlers in JS functions that call callLambda. callLambda returns a Thunk (TCO), but the wrapper never trampolined it, so the handler body (swap!, set!, etc.) never executed. Buttons rendered but clicks had no effect. Fix: wrap callLambda result in trampoline() so thunks resolve and side effects (signal mutations, DOM updates) execute. Also use call-lambda instead of direct invocation for Lambda objects (Lambda is a plain JS object, not callable as a function). All 100 Playwright tests pass: - 6 isomorphic SSR - 5 reactive navigation (cross-demo) - 61 geography page loads - 7 handler response rendering - 21 demo interaction + health checks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,24 @@
|
||||
(define MATH_NS "http://www.w3.org/1998/Math/MathML")
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; dom-on — dom-listen with post-render hooks
|
||||
;;
|
||||
;; Wraps dom-listen so that run-post-render-hooks fires after every SX
|
||||
;; event handler invocation. This is the SX-level hook integration;
|
||||
;; the native dom-listen primitive is a clean addEventListener wrapper.
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
(define dom-on :effects [io]
|
||||
(fn (el name handler)
|
||||
(dom-listen el name
|
||||
(if (lambda? handler)
|
||||
(if (= 0 (len (lambda-params handler)))
|
||||
(fn () (trampoline (call-lambda handler (list))) (run-post-render-hooks))
|
||||
(fn (e) (trampoline (call-lambda handler (list e))) (run-post-render-hooks)))
|
||||
handler))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; render-to-dom — main entry point
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -199,7 +217,7 @@
|
||||
(starts-with? attr-name "on-")
|
||||
(let ((attr-val (trampoline (eval-expr attr-expr env))))
|
||||
(when (callable? attr-val)
|
||||
(dom-listen el (slice attr-name 3) attr-val)))
|
||||
(dom-on el (slice attr-name 3) attr-val)))
|
||||
;; Two-way input binding: :bind signal
|
||||
(= attr-name "bind")
|
||||
(let ((attr-val (trampoline (eval-expr attr-expr env))))
|
||||
@@ -1100,7 +1118,7 @@
|
||||
(when (!= (dom-get-prop el "value") v)
|
||||
(dom-set-prop el "value" v))))))
|
||||
;; Element → signal (event listener)
|
||||
(dom-listen el (if is-checkbox "change" "input")
|
||||
(dom-on el (if is-checkbox "change" "input")
|
||||
(fn (e)
|
||||
(if is-checkbox
|
||||
(reset! sig (dom-get-prop el "checked"))
|
||||
|
||||
Reference in New Issue
Block a user