Merge branch 'worktree-api-urls' into macros

This commit is contained in:
2026-03-13 05:31:40 +00:00
6 changed files with 374 additions and 24 deletions

View File

@@ -232,30 +232,35 @@
(do
(when (not (contains? VOID_ELEMENTS tag))
(let ((child (render-to-dom arg env new-ns)))
(if (spread? child)
;; Spread: merge attrs onto parent element
(for-each
(fn ((key :as string))
(let ((val (dict-get (spread-attrs child) key)))
(if (= key "class")
;; Class: append to existing
(let ((existing (dom-get-attr el "class")))
(dom-set-attr el "class"
(if (and existing (not (= existing "")))
(str existing " " val)
val)))
(if (= key "style")
;; Style: append with semicolon
(let ((existing (dom-get-attr el "style")))
(dom-set-attr el "style"
(cond
;; Reactive spread: track signal deps, update attrs on change
(and (spread? child) *island-scope*)
(reactive-spread el (fn () (render-to-dom arg env new-ns)))
;; Static spread: one-shot merge attrs onto parent element
(spread? child)
(for-each
(fn ((key :as string))
(let ((val (dict-get (spread-attrs child) key)))
(if (= key "class")
;; Class: append to existing
(let ((existing (dom-get-attr el "class")))
(dom-set-attr el "class"
(if (and existing (not (= existing "")))
(str existing ";" val)
(str existing " " val)
val)))
;; Other attrs: overwrite
(dom-set-attr el key (str val))))))
(keys (spread-attrs child)))
(if (= key "style")
;; Style: append with semicolon
(let ((existing (dom-get-attr el "style")))
(dom-set-attr el "style"
(if (and existing (not (= existing "")))
(str existing ";" val)
val)))
;; Other attrs: overwrite
(dom-set-attr el key (str val))))))
(keys (spread-attrs child)))
;; Normal child: append to element
(dom-append el child))))
:else
(dom-append el child))))
(assoc state "i" (inc (get state "i"))))))))
(dict "i" 0 "skip" false)
args)
@@ -867,6 +872,64 @@
:else
(dom-set-attr el attr-name (str val)))))))))
;; reactive-spread — reactively bind spread attrs to parent element.
;; Used when a child of an element produces a spread inside an island.
;; Tracks signal deps in the spread expression. When signals change:
;; old classes are removed, new ones applied. Non-class attrs (data-tw etc.)
;; are overwritten. Flushes newly collected CSS rules to live stylesheet.
;;
;; Multiple reactive spreads on the same element are safe — each tracks
;; its own class contribution and only removes/adds its own tokens.
(define reactive-spread :effects [render mutation]
(fn (el (render-fn :as lambda))
(let ((prev-classes (list))
(prev-extra-keys (list)))
;; Mark for morph protection
(let ((existing (or (dom-get-attr el "data-sx-reactive-attrs") "")))
(dom-set-attr el "data-sx-reactive-attrs"
(if (empty? existing) "_spread" (str existing ",_spread"))))
(effect (fn ()
;; 1. Remove previously applied classes from element's class list
(when (not (empty? prev-classes))
(let ((current (or (dom-get-attr el "class") ""))
(tokens (filter (fn (c) (not (= c ""))) (split current " ")))
(kept (filter (fn (c)
(not (some (fn (pc) (= pc c)) prev-classes)))
tokens)))
(if (empty? kept)
(dom-remove-attr el "class")
(dom-set-attr el "class" (join " " kept)))))
;; 2. Remove previously applied extra attrs
(for-each (fn (k) (dom-remove-attr el k)) prev-extra-keys)
;; 3. Re-evaluate the spread expression (tracks signal deps)
(let ((result (render-fn)))
(if (spread? result)
(let ((attrs (spread-attrs result))
(cls-str (or (dict-get attrs "class") ""))
(new-classes (filter (fn (c) (not (= c "")))
(split cls-str " ")))
(extra-keys (filter (fn (k) (not (= k "class")))
(keys attrs))))
(set! prev-classes new-classes)
(set! prev-extra-keys extra-keys)
;; Append new classes to element
(when (not (empty? new-classes))
(let ((current (or (dom-get-attr el "class") "")))
(dom-set-attr el "class"
(if (and current (not (= current "")))
(str current " " cls-str)
cls-str))))
;; Set extra attrs (data-tw, etc.) — simple overwrite
(for-each (fn (k)
(dom-set-attr el k (str (dict-get attrs k))))
extra-keys)
;; Flush any newly collected CSS rules to live stylesheet
(flush-cssx-to-dom))
;; No longer a spread — clear tracked state
(do
(set! prev-classes (list))
(set! prev-extra-keys (list))))))))))
;; reactive-fragment — conditionally render a fragment based on a signal
;; Used for (when (deref sig) ...) or (if (deref sig) ...) inside an island.
(define reactive-fragment :effects [render mutation]