Refactor spread to use provide/emit! internally
Spreads now emit their attrs into the nearest element's provide scope instead of requiring per-child spread? checks at every intermediate layer. emit! is tolerant (no-op when no provider), so spreads in non-element contexts silently vanish. - adapter-html: element/lake/marsh wrap children in provide, collect emitted; removed 14 spread filters from fragment, forms, components - adapter-sx: aser wraps result to catch spread values from fn calls; aser-call uses provide with attr-parts/child-parts ordering - adapter-async: same pattern for both render and aser paths - adapter-dom: added emit! in spread dispatch + provide in element rendering; kept spread? checks for reactive/island and DOM safety - platform: emit! returns NIL when no provider instead of erroring - 3 new aser tests: stored spread, nested element, silent drop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -44,8 +44,8 @@
|
||||
;; Pre-rendered DOM node → pass through
|
||||
"dom-node" expr
|
||||
|
||||
;; Spread → pass through (parent element handles it)
|
||||
"spread" expr
|
||||
;; Spread → emit attrs to nearest element provider, pass through for reactive-spread
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) expr)
|
||||
|
||||
;; Dict → empty
|
||||
"dict" (create-fragment)
|
||||
@@ -180,6 +180,9 @@
|
||||
:else ns))
|
||||
(el (dom-create-element tag new-ns)))
|
||||
|
||||
;; Provide scope for spread emit! — deeply nested spreads emit here
|
||||
(provide-push! "element-attrs" nil)
|
||||
|
||||
;; Process args: keywords → attrs, others → children
|
||||
(reduce
|
||||
(fn (state arg)
|
||||
@@ -236,28 +239,8 @@
|
||||
;; 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)
|
||||
val)))
|
||||
(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)))
|
||||
;; Static spread: already emitted via provide, skip
|
||||
(spread? child) nil
|
||||
;; Normal child: append to element
|
||||
:else
|
||||
(dom-append el child))))
|
||||
@@ -265,6 +248,29 @@
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
|
||||
;; Collect emitted spread attrs and merge onto DOM element
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn ((key :as string))
|
||||
(let ((val (dict-get spread-dict key)))
|
||||
(if (= key "class")
|
||||
(let ((existing (dom-get-attr el "class")))
|
||||
(dom-set-attr el "class"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing " " val)
|
||||
val)))
|
||||
(if (= key "style")
|
||||
(let ((existing (dom-get-attr el "style")))
|
||||
(dom-set-attr el "style"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing ";" val)
|
||||
val)))
|
||||
(dom-set-attr el key (str val))))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
|
||||
el)))
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user