Fix CSS styles lost during SPA navigation

The text/sx AJAX response path (handle-sx-response) never called
hoist-head-elements, so <style> elements stayed in #sx-content instead
of moving to <head>. Additionally, CSS rules collected during client-side
island hydration were never flushed to the DOM.

- Add hoist-head-elements call to handle-sx-response (matching
  handle-html-response which already had it)
- Add flush-collected-styles helper that drains collected CSS rules
  into a <style data-sx-css> element in <head>
- Call flush after island hydration in post-swap, boot-init, and
  run-post-render-hooks to catch reactive re-renders
- Unify on data-sx-css attribute (existing convention) in ~tw/flush
  and shell template, removing the ad-hoc data-cssx attribute

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 09:37:58 +00:00
parent 90a2eaaf7a
commit 7651260fc7
16 changed files with 691 additions and 84 deletions

View File

@@ -256,6 +256,22 @@
"sx:afterSwap"
(dict "target" target-el "swap" swap-style)))))))
(define
flush-collected-styles
:effects (mutation io)
(fn
()
(let
((rules (collected "cssx")))
(when
(not (empty? rules))
(clear-collected! "cssx")
(let
((el (dom-create-element "style" nil)))
(dom-set-attr el "data-sx-css" "true")
(dom-set-prop el "textContent" (join "" rules))
(dom-append-to-head el))))))
(define
handle-sx-response
:effects (mutation io)
@@ -287,6 +303,7 @@
(if (= s "innerHTML") (children-to-fragment oob) oob)
s)
(post-swap t)))
(hoist-head-elements container)
(let
((select-sel (dom-get-attr el "sx-select")))
(let
@@ -428,7 +445,7 @@
(observe-intersection
el
(fn () (execute-request el nil nil))
false
true
(get mods "delay"))
(= kind "load")
(set-timeout
@@ -438,7 +455,7 @@
(observe-intersection
el
(fn () (execute-request el nil nil))
true
false
(get mods "delay"))
(= kind "event")
(bind-event el (get trigger "event") mods verbInfo))))
@@ -540,6 +557,7 @@
(sx-hydrate root)
(sx-hydrate-islands root)
(run-post-render-hooks)
(flush-collected-styles)
(process-elements root)))
(define
@@ -1484,8 +1502,8 @@
(el)
(when
(not (is-processed? el "verb"))
(mark-processed! el "verb")
(process-one el)))
(process-one el)
(mark-processed! el "verb")))
els))
(process-boosted root)
(process-sse root)