diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js
index 221b289..80f1fca 100644
--- a/shared/static/scripts/sx-browser.js
+++ b/shared/static/scripts/sx-browser.js
@@ -103,6 +103,7 @@
if (x._macro) return "macro";
if (x._raw) return "raw-html";
if (x._styleValue) return "style-value";
+ if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
if (Array.isArray(x)) return "list";
if (typeof x === "object") return "dict";
return "unknown";
@@ -178,6 +179,29 @@
function dictSet(d, k, v) { d[k] = v; }
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
+ // Render-expression detection — lets the evaluator delegate to the active adapter.
+ // Matches HTML tags, SVG tags, <>, raw!, ~components, html: prefix, custom elements.
+ function isRenderExpr(expr) {
+ if (!Array.isArray(expr) || !expr.length) return false;
+ var h = expr[0];
+ if (!h || !h._sym) return false;
+ var n = h.name;
+ return !!(n === "<>" || n === "raw!" ||
+ n.charAt(0) === "~" || n.indexOf("html:") === 0 ||
+ (typeof HTML_TAGS !== "undefined" && HTML_TAGS.indexOf(n) >= 0) ||
+ (typeof SVG_TAGS !== "undefined" && SVG_TAGS.indexOf(n) >= 0) ||
+ (n.indexOf("-") > 0 && expr.length > 1 && expr[1] && expr[1]._kw));
+ }
+
+ // Render dispatch — call the active adapter's render function.
+ // Set by each adapter when loaded; defaults to identity (no rendering).
+ var _renderExprFn = null;
+ function renderExpr(expr, env) {
+ if (_renderExprFn) return _renderExprFn(expr, env);
+ // No adapter loaded — just return the expression as-is
+ return expr;
+ }
+
function stripPrefix(s, prefix) {
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
}
@@ -507,7 +531,7 @@
return (isSxTruthy((name == "if")) ? sfIf(args, env) : (isSxTruthy((name == "when")) ? sfWhen(args, env) : (isSxTruthy((name == "cond")) ? sfCond(args, env) : (isSxTruthy((name == "case")) ? sfCase(args, env) : (isSxTruthy((name == "and")) ? sfAnd(args, env) : (isSxTruthy((name == "or")) ? sfOr(args, env) : (isSxTruthy((name == "let")) ? sfLet(args, env) : (isSxTruthy((name == "let*")) ? sfLet(args, env) : (isSxTruthy((name == "lambda")) ? sfLambda(args, env) : (isSxTruthy((name == "fn")) ? sfLambda(args, env) : (isSxTruthy((name == "define")) ? sfDefine(args, env) : (isSxTruthy((name == "defcomp")) ? sfDefcomp(args, env) : (isSxTruthy((name == "defmacro")) ? sfDefmacro(args, env) : (isSxTruthy((name == "defstyle")) ? sfDefstyle(args, env) : (isSxTruthy((name == "defkeyframes")) ? sfDefkeyframes(args, env) : (isSxTruthy((name == "defhandler")) ? sfDefine(args, env) : (isSxTruthy((name == "begin")) ? sfBegin(args, env) : (isSxTruthy((name == "do")) ? sfBegin(args, env) : (isSxTruthy((name == "quote")) ? sfQuote(args, env) : (isSxTruthy((name == "quasiquote")) ? sfQuasiquote(args, env) : (isSxTruthy((name == "->")) ? sfThreadFirst(args, env) : (isSxTruthy((name == "set!")) ? sfSetBang(args, env) : (isSxTruthy((name == "map")) ? hoMap(args, env) : (isSxTruthy((name == "map-indexed")) ? hoMapIndexed(args, env) : (isSxTruthy((name == "filter")) ? hoFilter(args, env) : (isSxTruthy((name == "reduce")) ? hoReduce(args, env) : (isSxTruthy((name == "some")) ? hoSome(args, env) : (isSxTruthy((name == "every?")) ? hoEvery(args, env) : (isSxTruthy((name == "for-each")) ? hoForEach(args, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
var mac = envGet(env, name);
return makeThunk(expandMacro(mac, args, env), env);
-})() : evalCall(head, args, env)))))))))))))))))))))))))))))));
+})() : (isSxTruthy(isRenderExpr(expr)) ? renderExpr(expr, env) : evalCall(head, args, env))))))))))))))))))))))))))))))));
})() : evalCall(head, args, env)));
})(); };
@@ -1149,11 +1173,12 @@
var morphNode = function(oldNode, newNode) { return (isSxTruthy(sxOr(domHasAttr(oldNode, "sx-preserve"), domHasAttr(oldNode, "sx-ignore"))) ? NIL : (isSxTruthy(sxOr(!(domNodeType(oldNode) == domNodeType(newNode)), !(domNodeName(oldNode) == domNodeName(newNode)))) ? domReplaceChild(domParent(oldNode), domClone(newNode), oldNode) : (isSxTruthy(sxOr((domNodeType(oldNode) == 3), (domNodeType(oldNode) == 8))) ? (isSxTruthy(!(domTextContent(oldNode) == domTextContent(newNode))) ? domSetTextContent(oldNode, domTextContent(newNode)) : NIL) : (isSxTruthy((domNodeType(oldNode) == 1)) ? (syncAttrs(oldNode, newNode), (isSxTruthy(!(isSxTruthy(domIsActiveElement(oldNode)) && domIsInputElement(oldNode))) ? morphChildren(oldNode, newNode) : NIL)) : NIL)))); };
// sync-attrs
- var syncAttrs = function(oldEl, newEl) { return forEach(function(attr) { return (function() {
+ var syncAttrs = function(oldEl, newEl) { { var _c = domAttrList(newEl); for (var _i = 0; _i < _c.length; _i++) { var attr = _c[_i]; (function() {
var name = first(attr);
var val = nth(attr, 1);
return (isSxTruthy(!(domGetAttr(oldEl, name) == val)) ? domSetAttr(oldEl, name, val) : NIL);
-})(); }, domAttrList(newEl)); };
+})(); } }
+return forEach(function(attr) { return (isSxTruthy(!domHasAttr(newEl, first(attr))) ? domRemoveAttr(oldEl, first(attr)) : NIL); }, domAttrList(oldEl)); };
// morph-children
var morphChildren = function(oldParent, newParent) { return (function() {
@@ -1272,7 +1297,7 @@
// init-css-tracking
var initCssTracking = function() { return (function() {
- var meta = domQuery("meta[name=\"sx-css-hash\"]");
+ var meta = domQuery("meta[name=\"sx-css-classes\"]");
return (isSxTruthy(meta) ? (function() {
var content = domGetAttr(meta, "content");
return (isSxTruthy(content) ? (_cssHash = content) : NIL);
@@ -1281,7 +1306,7 @@
// execute-request
var executeRequest = function(el, verbInfo, extraParams) { return (function() {
- var info = sxOr(verbInfo, getVerbInfo(el));
+ var info = sxOr(getVerbInfo(el), verbInfo);
return (isSxTruthy(isNil(info)) ? promiseResolve(NIL) : (function() {
var verb = get(info, "method");
var url = get(info, "url");
@@ -1373,11 +1398,14 @@
var rendered = sxRender(trimmed);
var container = domCreateElement("div", NIL);
domAppend(container, rendered);
- processOobSwaps(container, function(t, oob, s) { return swapDomNodes(t, oob, s); });
+ processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s);
+sxHydrate(t);
+return processElements(t); });
return (function() {
var selectSel = domGetAttr(el, "sx-select");
var content = (isSxTruthy(selectSel) ? selectFromContainer(container, selectSel) : childrenToFragment(container));
- return withTransition(useTransition, function() { return swapDomNodes(target, content, swapStyle); });
+ return withTransition(useTransition, function() { swapDomNodes(target, content, swapStyle);
+return postSwap(target); });
})();
})() : NIL);
})();
@@ -1391,13 +1419,16 @@
var selectSel = domGetAttr(el, "sx-select");
return (isSxTruthy(selectSel) ? (function() {
var html = selectHtmlFromDoc(doc, selectSel);
- return withTransition(useTransition, function() { return swapHtmlString(target, html, swapStyle); });
+ return withTransition(useTransition, function() { swapHtmlString(target, html, swapStyle);
+return postSwap(target); });
})() : (function() {
var container = domCreateElement("div", NIL);
domSetInnerHtml(container, domBodyInnerHtml(doc));
- processOobSwaps(container, function(t, oob, s) { return swapDomNodes(t, oob, s); });
+ processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s);
+return postSwap(t); });
hoistHeadElements(container);
- return withTransition(useTransition, function() { return swapDomNodes(target, childrenToFragment(container), swapStyle); });
+ return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
+return postSwap(target); });
})());
})() : NIL);
})(); };
@@ -1444,7 +1475,10 @@
})(); };
// post-swap
- var postSwap = function(root) { return activateScripts(root); };
+ var postSwap = function(root) { activateScripts(root);
+sxProcessScripts(root);
+sxHydrate(root);
+return processElements(root); };
// activate-scripts
var activateScripts = function(root) { return (isSxTruthy(root) ? (function() {
@@ -1472,13 +1506,43 @@
})(); };
// hoist-head-elements
- var hoistHeadElements = function(container) { return forEach(function(style) { return (isSxTruthy(domParent(style)) ? domRemoveChild(domParent(style), style) : NIL); }, domQueryAll(container, "style[data-sx-css]")); };
+ var hoistHeadElements = function(container) { { var _c = domQueryAll(container, "style[data-sx-css]"); for (var _i = 0; _i < _c.length; _i++) { var style = _c[_i]; if (isSxTruthy(domParent(style))) {
+ domRemoveChild(domParent(style), style);
+}
+domAppendToHead(style); } }
+return forEach(function(link) { if (isSxTruthy(domParent(link))) {
+ domRemoveChild(domParent(link), link);
+}
+return domAppendToHead(link); }, domQueryAll(container, "link[rel=\"stylesheet\"]")); };
// process-boosted
var processBoosted = function(root) { return forEach(function(container) { return boostDescendants(container); }, domQueryAll(sxOr(root, domBody()), "[sx-boost]")); };
// boost-descendants
- var boostDescendants = function(container) { return forEach(function(link) { return (isSxTruthy((isSxTruthy(!isProcessed(link, "boost")) && shouldBoostLink(link))) ? (markProcessed(link, "boost"), (isSxTruthy(!domHasAttr(link, "sx-target")) ? domSetAttr(link, "sx-target", "#main-panel") : NIL), (isSxTruthy(!domHasAttr(link, "sx-swap")) ? domSetAttr(link, "sx-swap", "innerHTML") : NIL), (isSxTruthy(!domHasAttr(link, "sx-push-url")) ? domSetAttr(link, "sx-push-url", "true") : NIL), bindBoostLink(link, domGetAttr(link, "href"))) : NIL); }, domQueryAll(container, "a[href]")); };
+ var boostDescendants = function(container) { { var _c = domQueryAll(container, "a[href]"); for (var _i = 0; _i < _c.length; _i++) { var link = _c[_i]; if (isSxTruthy((isSxTruthy(!isProcessed(link, "boost")) && shouldBoostLink(link)))) {
+ markProcessed(link, "boost");
+ if (isSxTruthy(!domHasAttr(link, "sx-target"))) {
+ domSetAttr(link, "sx-target", "#main-panel");
+}
+ if (isSxTruthy(!domHasAttr(link, "sx-swap"))) {
+ domSetAttr(link, "sx-swap", "innerHTML");
+}
+ if (isSxTruthy(!domHasAttr(link, "sx-push-url"))) {
+ domSetAttr(link, "sx-push-url", "true");
+}
+ bindBoostLink(link, domGetAttr(link, "href"));
+} } }
+return forEach(function(form) { return (isSxTruthy((isSxTruthy(!isProcessed(form, "boost")) && shouldBoostForm(form))) ? (markProcessed(form, "boost"), (function() {
+ var method = upper(sxOr(domGetAttr(form, "method"), "GET"));
+ var action = sxOr(domGetAttr(form, "action"), browserLocationHref());
+ if (isSxTruthy(!domHasAttr(form, "sx-target"))) {
+ domSetAttr(form, "sx-target", "#main-panel");
+}
+ if (isSxTruthy(!domHasAttr(form, "sx-swap"))) {
+ domSetAttr(form, "sx-swap", "innerHTML");
+}
+ return bindBoostForm(form, method, action);
+})()) : NIL); }, domQueryAll(container, "form")); };
// process-sse
var processSse = function(root) { return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "sse")) ? (markProcessed(el, "sse"), bindSse(el)) : NIL); }, domQueryAll(sxOr(root, domBody()), "[sx-sse]")); };
@@ -1504,8 +1568,10 @@
var rendered = sxRender(trimmed);
var container = domCreateElement("div", NIL);
domAppend(container, rendered);
- return withTransition(useTransition, function() { return swapDomNodes(target, childrenToFragment(container), swapStyle); });
-})() : withTransition(useTransition, function() { return swapHtmlString(target, trimmed, swapStyle); })) : NIL);
+ return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
+return postSwap(target); });
+})() : withTransition(useTransition, function() { swapHtmlString(target, trimmed, swapStyle);
+return postSwap(target); })) : NIL);
})(); };
// bind-inline-handlers
@@ -1540,10 +1606,13 @@
var VERB_SELECTOR = (String("[sx-get],[sx-post],[sx-put],[sx-delete],[sx-patch]"));
// process-elements
- var processElements = function(root) { return (function() {
+ var processElements = function(root) { (function() {
var els = domQueryAll(sxOr(root, domBody()), VERB_SELECTOR);
return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "verb")) ? (markProcessed(el, "verb"), processOne(el)) : NIL); }, els);
-})(); };
+})();
+processBoosted(root);
+processSse(root);
+return bindInlineHandlers(root); };
// process-one
var processOne = function(el) { return (function() {
@@ -1592,7 +1661,13 @@
var _injectedStyles = {};
// load-style-dict
- var loadStyleDict = function(data) { return (_styleAtoms = sxOr(get(data, "a"), {})); };
+ var loadStyleDict = function(data) { _styleAtoms = sxOr(get(data, "a"), {});
+_pseudoVariants = sxOr(get(data, "v"), {});
+_responsiveBreakpoints = sxOr(get(data, "b"), {});
+_styleKeyframes = sxOr(get(data, "k"), {});
+_childSelectorPrefixes = sxOr(get(data, "c"), []);
+_arbitraryPatterns = map(function(pair) { return {["re"]: compileRegex((String("^") + String(first(pair)) + String("$"))), ["tmpl"]: nth(pair, 1)}; }, sxOr(get(data, "p"), []));
+return (_styleCache = {}); };
// split-variant
var splitVariant = function(atom) { return (function() {
@@ -1714,7 +1789,10 @@
var allKf = [];
{ var _c = styles; for (var _i = 0; _i < _c.length; _i++) { var sv = _c[_i]; if (isSxTruthy(styleValueDeclarations(sv))) {
allDecls.push(styleValueDeclarations(sv));
-} } }
+}
+allMedia = concat(allMedia, styleValueMediaRules(sv));
+allPseudo = concat(allPseudo, styleValuePseudoRules(sv));
+allKf = concat(allKf, styleValueKeyframes_(sv)); } }
return (function() {
var hashInput = join(";", allDecls);
{ var _c = allMedia; for (var _i = 0; _i < _c.length; _i++) { var mr = _c[_i]; hashInput = (String(hashInput) + String("@") + String(first(mr)) + String("{") + String(nth(mr, 1)) + String("}")); } }
@@ -1796,7 +1874,8 @@
var comp = envGet(env, fullName);
return (isSxTruthy(!isComponent(comp)) ? error((String("Unknown component: ") + String(fullName))) : (function() {
var callExpr = [makeSymbol(fullName)];
- { var _c = keys(kwargs); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; callExpr.push(makeKeyword(toKebab(k))); } }
+ { var _c = keys(kwargs); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; callExpr.push(makeKeyword(toKebab(k)));
+callExpr.push(dictGet(kwargs, k)); } }
return renderToDom(callExpr, env, NIL);
})());
})();
@@ -1861,6 +1940,9 @@
var _hasDom = typeof document !== "undefined";
+ // Register DOM adapter as the render dispatch target for the evaluator.
+ _renderExprFn = function(expr, env) { return renderToDom(expr, env, null); };
+
var SVG_NS = "http://www.w3.org/2000/svg";
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
@@ -2142,7 +2224,7 @@
if (config.body && config.method !== "GET") opts.body = config.body;
if (config["cross-origin"]) opts.credentials = "include";
- var p = config.preloaded
+ var p = (config.preloaded && config.preloaded !== NIL)
? Promise.resolve({
ok: true, status: 200,
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
@@ -2538,23 +2620,25 @@
// --- SX API references ---
function sxRender(source) {
- var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
+ var SxObj = typeof Sx !== "undefined" ? Sx : null;
if (SxObj && SxObj.render) return SxObj.render(source);
throw new Error("No SX renderer available");
}
function sxProcessScripts(root) {
- var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
- if (SxObj && SxObj.processScripts) SxObj.processScripts(root || undefined);
+ var SxObj = typeof Sx !== "undefined" ? Sx : null;
+ var r = (root && root !== NIL) ? root : undefined;
+ if (SxObj && SxObj.processScripts) SxObj.processScripts(r);
}
function sxHydrate(root) {
- var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
- if (SxObj && SxObj.hydrate) SxObj.hydrate(root || undefined);
+ var SxObj = typeof Sx !== "undefined" ? Sx : null;
+ var r = (root && root !== NIL) ? root : undefined;
+ if (SxObj && SxObj.hydrate) SxObj.hydrate(r);
}
function loadedComponentNames() {
- var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
+ var SxObj = typeof Sx !== "undefined" ? Sx : null;
if (!SxObj) return [];
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
@@ -2563,7 +2647,7 @@
// --- Response processing ---
function stripComponentScripts(text) {
- var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
+ var SxObj = typeof Sx !== "undefined" ? Sx : null;
return text.replace(/
-
+