Fix island reactivity lost on client-side navigation; add Playwright tests

When morphing DOM after server fetch, the morph engine reuses elements
with the same tag. If old element was island A and new is island B,
syncAttrs updates data-sx-island but the JS property _sxBoundisland-hydrated
persists on the reused element. sx-hydrate-islands then skips it.

Fix: in morphNode, when data-sx-island attribute changes between old and
new elements, dispose the old island's signals and clear the hydration
flag so the new island gets properly hydrated.

New Playwright tests:
- counter → temperature navigation: temperature signals work
- temperature → counter navigation: counter signals work
- Direct load verification for both islands
- No JS errors during navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 17:36:51 +00:00
parent 3df8c41ca1
commit 732d733eac
3 changed files with 153 additions and 2 deletions

View File

@@ -368,6 +368,15 @@
;; Element nodes → sync attributes, then recurse children
(= (dom-node-type old-node) 1)
(do
;; If the island name changed, clear hydration flag so the new
;; island gets re-hydrated after morph. The DOM element is reused
;; (same tag) but the island content is completely different.
(when (and (dom-has-attr? old-node "data-sx-island")
(dom-has-attr? new-node "data-sx-island")
(not (= (dom-get-attr old-node "data-sx-island")
(dom-get-attr new-node "data-sx-island"))))
(dispose-islands-in old-node)
(clear-processed! old-node "island-hydrated"))
(sync-attrs old-node new-node)
;; Skip morphing focused input to preserve user's in-progress edits
(when (not (and (dom-is-active-element? old-node)