Fix stepper: lake SSR preservation + stack rebuild after stepping
Three fixes: 1. Framework: render-dom-lake preserves SSR elements during hydration. When client-side render-to-dom encounters a lake with an existing DOM element (from SSR), it reuses that element instead of creating a new one. This prevents the SSR HTML from being replaced with unresolvable raw SX expressions (~tw calls). 2. Stepper: skip rebuild-preview on initial hydration. Uses a non- reactive dict flag (not a signal) to avoid triggering the effect twice. On first run, just initializes the DOM stack from the existing SSR content by computing open-element depth from step types and walking lastElementChild. 3. Stepper: rebuild-preview computes correct DOM stack after re-render. Same depth computation + DOM walk approach. This fixes the bug where do-step after do-back would append elements to the wrong parent (e.g. "sx" span outside h1). Also: increased code view font-size from 0.5rem to 0.85rem. Playwright tests: - lake never shows raw SX during hydration (mutation observer) - back 6 + forward 6 keeps all 4 spans inside h1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
(step-idx (if store (get store "step-idx") (signal 16)))
|
||||
(dom-stack-sig (signal (list)))
|
||||
(code-tokens (signal (list)))
|
||||
(initial-render (signal true)))
|
||||
(initial-render (dict "v" true)))
|
||||
(letrec
|
||||
((split-tag (fn (expr result) (cond (not (list? expr)) (append! result {:expr expr :type "leaf"}) (empty? expr) nil (not (= (type-of (first expr)) "symbol")) (append! result {:expr expr :type "leaf"}) (is-html-tag? (symbol-name (first expr))) (let ((ctag (symbol-name (first expr))) (cargs (rest expr)) (cch (list)) (cat (list)) (spreads (list)) (ckw false)) (for-each (fn (a) (cond (= (type-of a) "keyword") (do (set! ckw true) (append! cat a)) ckw (do (set! ckw false) (append! cat a)) (and (list? a) (not (empty? a)) (= (type-of (first a)) "symbol") (starts-with? (symbol-name (first a)) "~")) (do (set! ckw false) (append! spreads a)) :else (do (set! ckw false) (append! cch a)))) cargs) (append! result {:spreads spreads :tag ctag :type "open" :attrs cat}) (for-each (fn (c) (split-tag c result)) cch) (append! result {:open-attrs cat :open-spreads spreads :tag ctag :type "close"})) :else (append! result {:expr expr :type "expr"}))))
|
||||
(build-code-tokens
|
||||
@@ -334,14 +334,14 @@
|
||||
(build-code-tokens (first parsed) tokens step-ref 0)
|
||||
(reset! code-tokens tokens)))))
|
||||
(let
|
||||
((_eff (effect (fn () (schedule-idle (fn () (build-code-dom) (if (deref initial-render) (do (reset! initial-render false) (set-stack (let ((p (get-preview))) (if p (list p) (list))))) (rebuild-preview (deref step-idx))) (update-code-highlight) (run-post-render-hooks)))))))
|
||||
((_eff (effect (fn () (schedule-idle (fn () (build-code-dom) (if (get initial-render "v") (do (dict-set! initial-render "v" false) (let ((container (get-preview)) (depth 0) (all (deref steps)) (target (deref step-idx))) (let loop ((i 0)) (when (< i target) (let ((stype (get (nth all i) "type"))) (cond (= stype "open") (set! depth (+ depth 1)) (= stype "close") (set! depth (- depth 1)))) (loop (+ i 1)))) (let ((stack (if container (list container) (list))) (node container)) (let walk ((d 0)) (when (and (< d depth) node) (let ((child (host-get node "lastElementChild"))) (when child (append! stack child) (set! node child))) (walk (+ d 1)))) (set-stack stack)))) (rebuild-preview (deref step-idx))) (update-code-highlight) (run-post-render-hooks)))))))
|
||||
(div
|
||||
(~tw :tokens "space-y-4 text-center")
|
||||
(div
|
||||
:data-code-view true
|
||||
(~tw
|
||||
:tokens "font-mono bg-stone-50 rounded p-2 overflow-x-auto leading-relaxed whitespace-pre-wrap")
|
||||
:style "font-size:0.5rem"
|
||||
:style "font-size:0.85rem"
|
||||
(map
|
||||
(fn
|
||||
(tok)
|
||||
|
||||
Reference in New Issue
Block a user