Reactive forms pass spreads through instead of wrapping in fragments
adapter-dom.sx: if/when/cond reactive paths now check whether initial-result is a spread. If so, return it directly — spreads aren't DOM nodes and can't be appended to fragments. This lets any spread-returning component (like ~cssx/tw) work inside islands without the spread being silently dropped. cssx.sx: revert make-spread workaround — the root cause is now fixed in the adapter. ~cssx/tw can use a natural top-level if. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||||
var SX_VERSION = "2026-03-13T04:16:14Z";
|
var SX_VERSION = "2026-03-13T04:50:39Z";
|
||||||
|
|
||||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||||
@@ -2019,7 +2019,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
|||||||
})();
|
})();
|
||||||
return (isSxTruthy(domParent(marker)) ? (forEach(function(n) { return domRemove(n); }, currentNodes), (currentNodes = (isSxTruthy(domIsFragment(result)) ? domChildNodes(result) : [result])), domInsertAfter(marker, result)) : (initialResult = result));
|
return (isSxTruthy(domParent(marker)) ? (forEach(function(n) { return domRemove(n); }, currentNodes), (currentNodes = (isSxTruthy(domIsFragment(result)) ? domChildNodes(result) : [result])), domInsertAfter(marker, result)) : (initialResult = result));
|
||||||
})(); });
|
})(); });
|
||||||
return (function() {
|
return (isSxTruthy(isSpread(initialResult)) ? initialResult : (function() {
|
||||||
var frag = createFragment();
|
var frag = createFragment();
|
||||||
domAppend(frag, marker);
|
domAppend(frag, marker);
|
||||||
if (isSxTruthy(initialResult)) {
|
if (isSxTruthy(initialResult)) {
|
||||||
@@ -2027,7 +2027,7 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
|||||||
domAppend(frag, initialResult);
|
domAppend(frag, initialResult);
|
||||||
}
|
}
|
||||||
return frag;
|
return frag;
|
||||||
})();
|
})());
|
||||||
})() : (function() {
|
})() : (function() {
|
||||||
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
||||||
return (isSxTruthy(condVal) ? renderToDom(nth(expr, 2), env, ns) : (isSxTruthy((len(expr) > 3)) ? renderToDom(nth(expr, 3), env, ns) : createFragment()));
|
return (isSxTruthy(condVal) ? renderToDom(nth(expr, 2), env, ns) : (isSxTruthy((len(expr) > 3)) ? renderToDom(nth(expr, 3), env, ns) : createFragment()));
|
||||||
@@ -2046,14 +2046,14 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
|||||||
currentNodes = domChildNodes(frag);
|
currentNodes = domChildNodes(frag);
|
||||||
return (initialResult = frag);
|
return (initialResult = frag);
|
||||||
})() : NIL)); });
|
})() : NIL)); });
|
||||||
return (function() {
|
return (isSxTruthy(isSpread(initialResult)) ? initialResult : (function() {
|
||||||
var frag = createFragment();
|
var frag = createFragment();
|
||||||
domAppend(frag, marker);
|
domAppend(frag, marker);
|
||||||
if (isSxTruthy(initialResult)) {
|
if (isSxTruthy(initialResult)) {
|
||||||
domAppend(frag, initialResult);
|
domAppend(frag, initialResult);
|
||||||
}
|
}
|
||||||
return frag;
|
return frag;
|
||||||
})();
|
})());
|
||||||
})() : (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? createFragment() : (function() {
|
})() : (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? createFragment() : (function() {
|
||||||
var frag = createFragment();
|
var frag = createFragment();
|
||||||
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||||||
@@ -2074,14 +2074,14 @@ return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragme
|
|||||||
return (initialResult = result);
|
return (initialResult = result);
|
||||||
})() : NIL));
|
})() : NIL));
|
||||||
})(); });
|
})(); });
|
||||||
return (function() {
|
return (isSxTruthy(isSpread(initialResult)) ? initialResult : (function() {
|
||||||
var frag = createFragment();
|
var frag = createFragment();
|
||||||
domAppend(frag, marker);
|
domAppend(frag, marker);
|
||||||
if (isSxTruthy(initialResult)) {
|
if (isSxTruthy(initialResult)) {
|
||||||
domAppend(frag, initialResult);
|
domAppend(frag, initialResult);
|
||||||
}
|
}
|
||||||
return frag;
|
return frag;
|
||||||
})();
|
})());
|
||||||
})() : (function() {
|
})() : (function() {
|
||||||
var branch = evalCond(rest(expr), env);
|
var branch = evalCond(rest(expr), env);
|
||||||
return (isSxTruthy(branch) ? renderToDom(branch, env, ns) : createFragment());
|
return (isSxTruthy(branch) ? renderToDom(branch, env, ns) : createFragment());
|
||||||
|
|||||||
@@ -406,16 +406,19 @@
|
|||||||
(dom-insert-after marker result))
|
(dom-insert-after marker result))
|
||||||
;; Marker not yet in DOM (first run) — just save result
|
;; Marker not yet in DOM (first run) — just save result
|
||||||
(set! initial-result result)))))
|
(set! initial-result result)))))
|
||||||
;; Return fragment: marker + initial render result
|
;; Spread pass-through: spreads aren't DOM nodes, can't live
|
||||||
(let ((frag (create-fragment)))
|
;; in fragments. Return directly so parent element merges attrs.
|
||||||
(dom-append frag marker)
|
(if (spread? initial-result)
|
||||||
(when initial-result
|
initial-result
|
||||||
(set! current-nodes
|
(let ((frag (create-fragment)))
|
||||||
(if (dom-is-fragment? initial-result)
|
(dom-append frag marker)
|
||||||
(dom-child-nodes initial-result)
|
(when initial-result
|
||||||
(list initial-result)))
|
(set! current-nodes
|
||||||
(dom-append frag initial-result))
|
(if (dom-is-fragment? initial-result)
|
||||||
frag))
|
(dom-child-nodes initial-result)
|
||||||
|
(list initial-result)))
|
||||||
|
(dom-append frag initial-result))
|
||||||
|
frag)))
|
||||||
;; Static if
|
;; Static if
|
||||||
(let ((cond-val (trampoline (eval-expr (nth expr 1) env))))
|
(let ((cond-val (trampoline (eval-expr (nth expr 1) env))))
|
||||||
(if cond-val
|
(if cond-val
|
||||||
@@ -453,10 +456,13 @@
|
|||||||
(range 2 (len expr)))
|
(range 2 (len expr)))
|
||||||
(set! current-nodes (dom-child-nodes frag))
|
(set! current-nodes (dom-child-nodes frag))
|
||||||
(set! initial-result frag))))))
|
(set! initial-result frag))))))
|
||||||
(let ((frag (create-fragment)))
|
;; Spread pass-through
|
||||||
(dom-append frag marker)
|
(if (spread? initial-result)
|
||||||
(when initial-result (dom-append frag initial-result))
|
initial-result
|
||||||
frag))
|
(let ((frag (create-fragment)))
|
||||||
|
(dom-append frag marker)
|
||||||
|
(when initial-result (dom-append frag initial-result))
|
||||||
|
frag)))
|
||||||
;; Static when
|
;; Static when
|
||||||
(if (not (trampoline (eval-expr (nth expr 1) env)))
|
(if (not (trampoline (eval-expr (nth expr 1) env)))
|
||||||
(create-fragment)
|
(create-fragment)
|
||||||
@@ -495,10 +501,13 @@
|
|||||||
(dom-child-nodes result)
|
(dom-child-nodes result)
|
||||||
(list result)))
|
(list result)))
|
||||||
(set! initial-result result)))))))
|
(set! initial-result result)))))))
|
||||||
(let ((frag (create-fragment)))
|
;; Spread pass-through
|
||||||
(dom-append frag marker)
|
(if (spread? initial-result)
|
||||||
(when initial-result (dom-append frag initial-result))
|
initial-result
|
||||||
frag))
|
(let ((frag (create-fragment)))
|
||||||
|
(dom-append frag marker)
|
||||||
|
(when initial-result (dom-append frag initial-result))
|
||||||
|
frag)))
|
||||||
;; Static cond
|
;; Static cond
|
||||||
(let ((branch (eval-cond (rest expr) env)))
|
(let ((branch (eval-cond (rest expr) env)))
|
||||||
(if branch
|
(if branch
|
||||||
|
|||||||
@@ -476,12 +476,10 @@
|
|||||||
(classes (map (fn (r) (get r "cls")) valid))
|
(classes (map (fn (r) (get r "cls")) valid))
|
||||||
(rules (map (fn (r) (get r "rule")) valid))
|
(rules (map (fn (r) (get r "rule")) valid))
|
||||||
(_ (for-each (fn (rule) (collect! "cssx" rule)) rules)))
|
(_ (for-each (fn (rule) (collect! "cssx" rule)) rules)))
|
||||||
;; Return spread: injects class + data-tw onto parent element.
|
;; Return spread: injects class + data-tw onto parent element
|
||||||
;; The if is inside make-spread's arg so it goes through eval-expr
|
(if (empty? classes)
|
||||||
;; (not render-to-dom), avoiding reactive-if wrapping in islands.
|
nil
|
||||||
(make-spread (if (empty? classes)
|
(make-spread {"class" (join " " classes)
|
||||||
{}
|
|
||||||
{"class" (join " " classes)
|
|
||||||
"data-tw" (or tokens "")}))))
|
"data-tw" (or tokens "")}))))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user