Add CSSX and boot adapters to SX spec (style dictionary + browser lifecycle)
- cssx.sx: on-demand CSS style dictionary (variant splitting, atom resolution, content-addressed hashing, style merging) - boot.sx: browser boot lifecycle (script processing, mount/hydrate/update, component caching, head element hoisting) - bootstrap_js.py: platform JS for cssx (FNV-1a hash, regex, CSS injection) and boot (localStorage, cookies, DOM mounting) - Rebuilt sx-browser.js (136K) and sx-ref.js (148K) with all adapters Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1565,6 +1565,296 @@
|
||||
var engineInit = function() { return (initCssTracking(), sxProcessScripts(NIL), sxHydrate(NIL), processElements(NIL)); };
|
||||
|
||||
|
||||
// === Transpiled from cssx ===
|
||||
|
||||
// _style-atoms
|
||||
var _styleAtoms = {};
|
||||
|
||||
// _pseudo-variants
|
||||
var _pseudoVariants = {};
|
||||
|
||||
// _responsive-breakpoints
|
||||
var _responsiveBreakpoints = {};
|
||||
|
||||
// _style-keyframes
|
||||
var _styleKeyframes = {};
|
||||
|
||||
// _arbitrary-patterns
|
||||
var _arbitraryPatterns = [];
|
||||
|
||||
// _child-selector-prefixes
|
||||
var _childSelectorPrefixes = [];
|
||||
|
||||
// _style-cache
|
||||
var _styleCache = {};
|
||||
|
||||
// _injected-styles
|
||||
var _injectedStyles = {};
|
||||
|
||||
// load-style-dict
|
||||
var loadStyleDict = function(data) { return (_styleAtoms = sxOr(get(data, "a"), {})); };
|
||||
|
||||
// split-variant
|
||||
var splitVariant = function(atom) { return (function() {
|
||||
var result = NIL;
|
||||
{ var _c = keys(_responsiveBreakpoints); for (var _i = 0; _i < _c.length; _i++) { var bp = _c[_i]; if (isSxTruthy(isNil(result))) {
|
||||
(function() {
|
||||
var prefix = (String(bp) + String(":"));
|
||||
return (isSxTruthy(startsWith(atom, prefix)) ? (function() {
|
||||
var restAtom = slice(atom, len(prefix));
|
||||
return (function() {
|
||||
var innerMatch = NIL;
|
||||
{ var _c = keys(_pseudoVariants); for (var _i = 0; _i < _c.length; _i++) { var pv = _c[_i]; if (isSxTruthy(isNil(innerMatch))) {
|
||||
(function() {
|
||||
var innerPrefix = (String(pv) + String(":"));
|
||||
return (isSxTruthy(startsWith(restAtom, innerPrefix)) ? (innerMatch = [(String(bp) + String(":") + String(pv)), slice(restAtom, len(innerPrefix))]) : NIL);
|
||||
})();
|
||||
} } }
|
||||
return (result = sxOr(innerMatch, [bp, restAtom]));
|
||||
})();
|
||||
})() : NIL);
|
||||
})();
|
||||
} } }
|
||||
if (isSxTruthy(isNil(result))) {
|
||||
{ var _c = keys(_pseudoVariants); for (var _i = 0; _i < _c.length; _i++) { var pv = _c[_i]; if (isSxTruthy(isNil(result))) {
|
||||
(function() {
|
||||
var prefix = (String(pv) + String(":"));
|
||||
return (isSxTruthy(startsWith(atom, prefix)) ? (result = [pv, slice(atom, len(prefix))]) : NIL);
|
||||
})();
|
||||
} } }
|
||||
}
|
||||
return sxOr(result, [NIL, atom]);
|
||||
})(); };
|
||||
|
||||
// resolve-atom
|
||||
var resolveAtom = function(atom) { return (function() {
|
||||
var decls = dictGet(_styleAtoms, atom);
|
||||
return (isSxTruthy(!isNil(decls)) ? decls : (isSxTruthy(startsWith(atom, "animate-")) ? (function() {
|
||||
var kfName = slice(atom, 8);
|
||||
return (isSxTruthy(dictHas(_styleKeyframes, kfName)) ? (String("animation-name:") + String(kfName)) : NIL);
|
||||
})() : (function() {
|
||||
var matchResult = NIL;
|
||||
{ var _c = _arbitraryPatterns; for (var _i = 0; _i < _c.length; _i++) { var pat = _c[_i]; if (isSxTruthy(isNil(matchResult))) {
|
||||
(function() {
|
||||
var m = regexMatch(get(pat, "re"), atom);
|
||||
return (isSxTruthy(m) ? (matchResult = regexReplaceGroups(get(pat, "tmpl"), m)) : NIL);
|
||||
})();
|
||||
} } }
|
||||
return matchResult;
|
||||
})()));
|
||||
})(); };
|
||||
|
||||
// is-child-selector-atom?
|
||||
var isChildSelectorAtom = function(atom) { return some(function(prefix) { return startsWith(atom, prefix); }, _childSelectorPrefixes); };
|
||||
|
||||
// hash-style
|
||||
var hashStyle = function(input) { return fnv1aHash(input); };
|
||||
|
||||
// resolve-style
|
||||
var resolveStyle = function(atoms) { return (function() {
|
||||
var key = join("\\0", atoms);
|
||||
return (function() {
|
||||
var cached = dictGet(_styleCache, key);
|
||||
return (isSxTruthy(!isNil(cached)) ? cached : (function() {
|
||||
var baseDecls = [];
|
||||
var mediaRules = [];
|
||||
var pseudoRules = [];
|
||||
var kfNeeded = [];
|
||||
{ var _c = atoms; for (var _i = 0; _i < _c.length; _i++) { var a = _c[_i]; if (isSxTruthy(a)) {
|
||||
(function() {
|
||||
var clean = (isSxTruthy(startsWith(a, ":")) ? slice(a, 1) : a);
|
||||
return (function() {
|
||||
var parts = splitVariant(clean);
|
||||
return (function() {
|
||||
var variant = first(parts);
|
||||
var base = nth(parts, 1);
|
||||
var decls = resolveAtom(base);
|
||||
return (isSxTruthy(decls) ? ((isSxTruthy(startsWith(base, "animate-")) ? (function() {
|
||||
var kfName = slice(base, 8);
|
||||
return (isSxTruthy(dictHas(_styleKeyframes, kfName)) ? append_b(kfNeeded, [kfName, dictGet(_styleKeyframes, kfName)]) : NIL);
|
||||
})() : NIL), (isSxTruthy(isNil(variant)) ? append_b(baseDecls, decls) : (isSxTruthy(dictHas(_responsiveBreakpoints, variant)) ? append_b(mediaRules, [dictGet(_responsiveBreakpoints, variant), decls]) : (isSxTruthy(dictHas(_pseudoVariants, variant)) ? append_b(pseudoRules, [dictGet(_pseudoVariants, variant), decls]) : (function() {
|
||||
var vparts = split(variant, ":");
|
||||
var mediaPart = NIL;
|
||||
var pseudoPart = NIL;
|
||||
{ var _c = vparts; for (var _i = 0; _i < _c.length; _i++) { var vp = _c[_i]; (isSxTruthy(dictHas(_responsiveBreakpoints, vp)) ? (mediaPart = dictGet(_responsiveBreakpoints, vp)) : (isSxTruthy(dictHas(_pseudoVariants, vp)) ? (pseudoPart = dictGet(_pseudoVariants, vp)) : NIL)); } }
|
||||
if (isSxTruthy(mediaPart)) {
|
||||
mediaRules.push([mediaPart, decls]);
|
||||
}
|
||||
if (isSxTruthy(pseudoPart)) {
|
||||
pseudoRules.push([pseudoPart, decls]);
|
||||
}
|
||||
return (isSxTruthy((isSxTruthy(isNil(mediaPart)) && isNil(pseudoPart))) ? append_b(baseDecls, decls) : NIL);
|
||||
})())))) : NIL);
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
} } }
|
||||
return (function() {
|
||||
var hashInput = join(";", baseDecls);
|
||||
{ var _c = chunkEvery(mediaRules, 2); 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("}")); } }
|
||||
{ var _c = chunkEvery(pseudoRules, 2); for (var _i = 0; _i < _c.length; _i++) { var pr = _c[_i]; hashInput = (String(hashInput) + String(first(pr)) + String("{") + String(nth(pr, 1)) + String("}")); } }
|
||||
{ var _c = chunkEvery(kfNeeded, 2); for (var _i = 0; _i < _c.length; _i++) { var kf = _c[_i]; hashInput = (String(hashInput) + String(nth(kf, 1))); } }
|
||||
return (function() {
|
||||
var cn = (String("sx-") + String(hashStyle(hashInput)));
|
||||
var sv = makeStyleValue_(cn, join(";", baseDecls), chunkEvery(mediaRules, 2), chunkEvery(pseudoRules, 2), chunkEvery(kfNeeded, 2));
|
||||
_styleCache[key] = sv;
|
||||
injectStyleValue(sv, atoms);
|
||||
return sv;
|
||||
})();
|
||||
})();
|
||||
})());
|
||||
})();
|
||||
})(); };
|
||||
|
||||
// merge-style-values
|
||||
var mergeStyleValues = function(styles) { return (isSxTruthy((len(styles) == 1)) ? first(styles) : (function() {
|
||||
var allDecls = [];
|
||||
var allMedia = [];
|
||||
var allPseudo = [];
|
||||
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));
|
||||
} } }
|
||||
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("}")); } }
|
||||
{ var _c = allPseudo; for (var _i = 0; _i < _c.length; _i++) { var pr = _c[_i]; hashInput = (String(hashInput) + String(first(pr)) + String("{") + String(nth(pr, 1)) + String("}")); } }
|
||||
{ var _c = allKf; for (var _i = 0; _i < _c.length; _i++) { var kf = _c[_i]; hashInput = (String(hashInput) + String(nth(kf, 1))); } }
|
||||
return (function() {
|
||||
var cn = (String("sx-") + String(hashStyle(hashInput)));
|
||||
var merged = makeStyleValue_(cn, join(";", allDecls), allMedia, allPseudo, allKf);
|
||||
injectStyleValue(merged, []);
|
||||
return merged;
|
||||
})();
|
||||
})();
|
||||
})()); };
|
||||
|
||||
|
||||
// === Transpiled from boot ===
|
||||
|
||||
// HEAD_HOIST_SELECTOR
|
||||
var HEAD_HOIST_SELECTOR = "meta, title, link[rel='canonical'], script[type='application/ld+json']";
|
||||
|
||||
// hoist-head-elements-full
|
||||
var hoistHeadElementsFull = function(root) { return (function() {
|
||||
var els = domQueryAll(root, HEAD_HOIST_SELECTOR);
|
||||
return forEach(function(el) { return (function() {
|
||||
var tag = lower(domTagName(el));
|
||||
return (isSxTruthy((tag == "title")) ? (setDocumentTitle(domTextContent(el)), domRemoveChild(domParent(el), el)) : (isSxTruthy((tag == "meta")) ? ((function() {
|
||||
var name = domGetAttr(el, "name");
|
||||
var prop = domGetAttr(el, "property");
|
||||
if (isSxTruthy(name)) {
|
||||
removeHeadElement((String("meta[name=\"") + String(name) + String("\"]")));
|
||||
}
|
||||
return (isSxTruthy(prop) ? removeHeadElement((String("meta[property=\"") + String(prop) + String("\"]"))) : NIL);
|
||||
})(), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (isSxTruthy((isSxTruthy((tag == "link")) && (domGetAttr(el, "rel") == "canonical"))) ? (removeHeadElement("link[rel=\"canonical\"]"), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (domRemoveChild(domParent(el), el), domAppendToHead(el)))));
|
||||
})(); }, els);
|
||||
})(); };
|
||||
|
||||
// sx-mount
|
||||
var sxMount = function(target, source, extraEnv) { return (function() {
|
||||
var el = resolveMountTarget(target);
|
||||
return (isSxTruthy(el) ? (function() {
|
||||
var node = sxRenderWithEnv(source, extraEnv);
|
||||
domSetTextContent(el, "");
|
||||
domAppend(el, node);
|
||||
hoistHeadElementsFull(el);
|
||||
processElements(el);
|
||||
return sxHydrateElements(el);
|
||||
})() : NIL);
|
||||
})(); };
|
||||
|
||||
// sx-hydrate-elements
|
||||
var sxHydrateElements = function(root) { return (function() {
|
||||
var els = domQueryAll(sxOr(root, domBody()), "[data-sx]");
|
||||
return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "hydrated")) ? (markProcessed(el, "hydrated"), sxUpdateElement(el, NIL)) : NIL); }, els);
|
||||
})(); };
|
||||
|
||||
// sx-update-element
|
||||
var sxUpdateElement = function(el, newEnv) { return (function() {
|
||||
var target = resolveMountTarget(el);
|
||||
return (isSxTruthy(target) ? (function() {
|
||||
var source = domGetAttr(target, "data-sx");
|
||||
return (isSxTruthy(source) ? (function() {
|
||||
var baseEnv = parseEnvAttr(target);
|
||||
var env = mergeEnvs(baseEnv, newEnv);
|
||||
return (function() {
|
||||
var node = sxRenderWithEnv(source, env);
|
||||
domSetTextContent(target, "");
|
||||
domAppend(target, node);
|
||||
return (isSxTruthy(newEnv) ? storeEnvAttr(target, baseEnv, newEnv) : NIL);
|
||||
})();
|
||||
})() : NIL);
|
||||
})() : NIL);
|
||||
})(); };
|
||||
|
||||
// sx-render-component
|
||||
var sxRenderComponent = function(name, kwargs, extraEnv) { return (function() {
|
||||
var fullName = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||||
return (function() {
|
||||
var env = getRenderEnv(extraEnv);
|
||||
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))); } }
|
||||
return renderToDom(callExpr, env, NIL);
|
||||
})());
|
||||
})();
|
||||
})(); };
|
||||
|
||||
// process-sx-scripts
|
||||
var processSxScripts = function(root) { return (function() {
|
||||
var scripts = querySxScripts(root);
|
||||
return forEach(function(s) { return (isSxTruthy(!isProcessed(s, "script")) ? (markProcessed(s, "script"), (function() {
|
||||
var text = domTextContent(s);
|
||||
return (isSxTruthy(domHasAttr(s, "data-components")) ? processComponentScript(s, text) : (isSxTruthy(sxOr(isNil(text), isEmpty(trim(text)))) ? NIL : (isSxTruthy(domHasAttr(s, "data-mount")) ? (function() {
|
||||
var mountSel = domGetAttr(s, "data-mount");
|
||||
var target = domQuery(mountSel);
|
||||
return (isSxTruthy(target) ? sxMount(target, text, NIL) : NIL);
|
||||
})() : sxLoadComponents(text))));
|
||||
})()) : NIL); }, scripts);
|
||||
})(); };
|
||||
|
||||
// process-component-script
|
||||
var processComponentScript = function(script, text) { return (function() {
|
||||
var hash = domGetAttr(script, "data-hash");
|
||||
return (isSxTruthy(isNil(hash)) ? (isSxTruthy((isSxTruthy(text) && !isEmpty(trim(text)))) ? sxLoadComponents(text) : NIL) : (function() {
|
||||
var hasInline = (isSxTruthy(text) && !isEmpty(trim(text)));
|
||||
(function() {
|
||||
var cachedHash = localStorageGet("sx-components-hash");
|
||||
return (isSxTruthy((cachedHash == hash)) ? (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo("components: downloaded (cookie stale)")) : (function() {
|
||||
var cached = localStorageGet("sx-components-src");
|
||||
return (isSxTruthy(cached) ? (sxLoadComponents(cached), logInfo((String("components: cached (") + String(hash) + String(")")))) : (clearSxCompCookie(), browserReload()));
|
||||
})()) : (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo((String("components: downloaded (") + String(hash) + String(")")))) : (localStorageRemove("sx-components-hash"), localStorageRemove("sx-components-src"), clearSxCompCookie(), browserReload())));
|
||||
})();
|
||||
return setSxCompCookie(hash);
|
||||
})());
|
||||
})(); };
|
||||
|
||||
// init-style-dict
|
||||
var initStyleDict = function() { return (function() {
|
||||
var scripts = queryStyleScripts();
|
||||
return forEach(function(s) { return (isSxTruthy(!isProcessed(s, "styles")) ? (markProcessed(s, "styles"), (function() {
|
||||
var text = domTextContent(s);
|
||||
var hash = domGetAttr(s, "data-hash");
|
||||
return (isSxTruthy(isNil(hash)) ? (isSxTruthy((isSxTruthy(text) && !isEmpty(trim(text)))) ? parseAndLoadStyleDict(text) : NIL) : (function() {
|
||||
var hasInline = (isSxTruthy(text) && !isEmpty(trim(text)));
|
||||
(function() {
|
||||
var cachedHash = localStorageGet("sx-styles-hash");
|
||||
return (isSxTruthy((cachedHash == hash)) ? (isSxTruthy(hasInline) ? (localStorageSet("sx-styles-src", text), parseAndLoadStyleDict(text), logInfo("styles: downloaded (cookie stale)")) : (function() {
|
||||
var cached = localStorageGet("sx-styles-src");
|
||||
return (isSxTruthy(cached) ? (parseAndLoadStyleDict(cached), logInfo((String("styles: cached (") + String(hash) + String(")")))) : (clearSxStylesCookie(), browserReload()));
|
||||
})()) : (isSxTruthy(hasInline) ? (localStorageSet("sx-styles-hash", hash), localStorageSet("sx-styles-src", text), parseAndLoadStyleDict(text), logInfo((String("styles: downloaded (") + String(hash) + String(")")))) : (localStorageRemove("sx-styles-hash"), localStorageRemove("sx-styles-src"), clearSxStylesCookie(), browserReload())));
|
||||
})();
|
||||
return setSxStylesCookie(hash);
|
||||
})());
|
||||
})()) : NIL); }, scripts);
|
||||
})(); };
|
||||
|
||||
// boot-init
|
||||
var bootInit = function() { return (initCssTracking(), initStyleDict(), processSxScripts(NIL), sxHydrateElements(NIL), processElements(NIL)); };
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — DOM adapter (browser-only)
|
||||
// =========================================================================
|
||||
@@ -2317,6 +2607,252 @@
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — CSSX (style dictionary)
|
||||
// =========================================================================
|
||||
|
||||
function fnv1aHash(input) {
|
||||
var h = 0x811c9dc5;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
h ^= input.charCodeAt(i);
|
||||
h = (h * 0x01000193) >>> 0;
|
||||
}
|
||||
return h.toString(16).padStart(8, "0").substring(0, 6);
|
||||
}
|
||||
|
||||
function compileRegex(pattern) {
|
||||
try { return new RegExp(pattern); } catch (e) { return null; }
|
||||
}
|
||||
|
||||
function regexMatch(re, s) {
|
||||
if (!re) return NIL;
|
||||
var m = s.match(re);
|
||||
return m ? Array.prototype.slice.call(m) : NIL;
|
||||
}
|
||||
|
||||
function regexReplaceGroups(tmpl, match) {
|
||||
var result = tmpl;
|
||||
for (var j = 1; j < match.length; j++) {
|
||||
result = result.split("{" + (j - 1) + "}").join(match[j]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function makeStyleValue_(cn, decls, media, pseudo, kf) {
|
||||
return new StyleValue(cn, decls || "", media || [], pseudo || [], kf || []);
|
||||
}
|
||||
|
||||
function styleValueDeclarations(sv) { return sv.declarations; }
|
||||
function styleValueMediaRules(sv) { return sv.mediaRules; }
|
||||
function styleValuePseudoRules(sv) { return sv.pseudoRules; }
|
||||
function styleValueKeyframes_(sv) { return sv.keyframes; }
|
||||
|
||||
function injectStyleValue(sv, atoms) {
|
||||
if (_injectedStyles[sv.className]) return;
|
||||
_injectedStyles[sv.className] = true;
|
||||
|
||||
if (!_hasDom) return;
|
||||
var cssTarget = document.getElementById("sx-css");
|
||||
if (!cssTarget) return;
|
||||
|
||||
var rules = [];
|
||||
if (sv.declarations) {
|
||||
var hasChild = false;
|
||||
if (atoms) {
|
||||
for (var ai = 0; ai < atoms.length; ai++) {
|
||||
if (isChildSelectorAtom(atoms[ai])) { hasChild = true; break; }
|
||||
}
|
||||
}
|
||||
if (hasChild) {
|
||||
rules.push("." + sv.className + ">:not(:first-child){" + sv.declarations + "}");
|
||||
} else {
|
||||
rules.push("." + sv.className + "{" + sv.declarations + "}");
|
||||
}
|
||||
}
|
||||
for (var pi = 0; pi < sv.pseudoRules.length; pi++) {
|
||||
var sel = sv.pseudoRules[pi][0], decls = sv.pseudoRules[pi][1];
|
||||
if (sel.indexOf("&") >= 0) {
|
||||
rules.push(sel.replace(/&/g, "." + sv.className) + "{" + decls + "}");
|
||||
} else {
|
||||
rules.push("." + sv.className + sel + "{" + decls + "}");
|
||||
}
|
||||
}
|
||||
for (var mi = 0; mi < sv.mediaRules.length; mi++) {
|
||||
rules.push("@media " + sv.mediaRules[mi][0] + "{." + sv.className + "{" + sv.mediaRules[mi][1] + "}}");
|
||||
}
|
||||
for (var ki = 0; ki < sv.keyframes.length; ki++) {
|
||||
rules.push(sv.keyframes[ki][1]);
|
||||
}
|
||||
cssTarget.textContent += rules.join("");
|
||||
}
|
||||
|
||||
// Replace stub css primitive with real CSSX implementation
|
||||
PRIMITIVES["css"] = function() {
|
||||
var atoms = [];
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var a = arguments[i];
|
||||
if (isNil(a) || a === false) continue;
|
||||
atoms.push(isKw(a) ? a.name : String(a));
|
||||
}
|
||||
if (!atoms.length) return NIL;
|
||||
return resolveStyle(atoms);
|
||||
};
|
||||
|
||||
PRIMITIVES["merge-styles"] = function() {
|
||||
var valid = [];
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (isStyleValue(arguments[i])) valid.push(arguments[i]);
|
||||
}
|
||||
if (!valid.length) return NIL;
|
||||
if (valid.length === 1) return valid[0];
|
||||
return mergeStyleValues(valid);
|
||||
};
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — Boot (mount, hydrate, scripts, cookies)
|
||||
// =========================================================================
|
||||
|
||||
function resolveMountTarget(target) {
|
||||
if (typeof target === "string") return _hasDom ? document.querySelector(target) : null;
|
||||
return target;
|
||||
}
|
||||
|
||||
function sxRenderWithEnv(source, extraEnv) {
|
||||
var env = extraEnv ? merge(componentEnv, extraEnv) : componentEnv;
|
||||
var exprs = parse(source);
|
||||
if (!_hasDom) return null;
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < exprs.length; i++) {
|
||||
var node = renderToDom(exprs[i], env, null);
|
||||
if (node) frag.appendChild(node);
|
||||
}
|
||||
return frag;
|
||||
}
|
||||
|
||||
function getRenderEnv(extraEnv) {
|
||||
return extraEnv ? merge(componentEnv, extraEnv) : componentEnv;
|
||||
}
|
||||
|
||||
function mergeEnvs(base, newEnv) {
|
||||
return newEnv ? merge(componentEnv, base, newEnv) : merge(componentEnv, base);
|
||||
}
|
||||
|
||||
function sxLoadComponents(text) {
|
||||
try {
|
||||
var exprs = parse(text);
|
||||
for (var i = 0; i < exprs.length; i++) trampoline(evalExpr(exprs[i], componentEnv));
|
||||
} catch (err) {
|
||||
logParseError("loadComponents", text, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function setDocumentTitle(s) {
|
||||
if (_hasDom) document.title = s || "";
|
||||
}
|
||||
|
||||
function removeHeadElement(sel) {
|
||||
if (!_hasDom) return;
|
||||
var old = document.head.querySelector(sel);
|
||||
if (old) old.parentNode.removeChild(old);
|
||||
}
|
||||
|
||||
function querySxScripts(root) {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
(root || document).querySelectorAll('script[type="text/sx"]'));
|
||||
}
|
||||
|
||||
function queryStyleScripts() {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
document.querySelectorAll('script[type="text/sx-styles"]'));
|
||||
}
|
||||
|
||||
// --- localStorage ---
|
||||
|
||||
function localStorageGet(key) {
|
||||
try { var v = localStorage.getItem(key); return v === null ? NIL : v; }
|
||||
catch (e) { return NIL; }
|
||||
}
|
||||
|
||||
function localStorageSet(key, val) {
|
||||
try { localStorage.setItem(key, val); } catch (e) {}
|
||||
}
|
||||
|
||||
function localStorageRemove(key) {
|
||||
try { localStorage.removeItem(key); } catch (e) {}
|
||||
}
|
||||
|
||||
// --- Cookies ---
|
||||
|
||||
function setSxCompCookie(hash) {
|
||||
if (_hasDom) document.cookie = "sx-comp-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax";
|
||||
}
|
||||
|
||||
function clearSxCompCookie() {
|
||||
if (_hasDom) document.cookie = "sx-comp-hash=;path=/;max-age=0;SameSite=Lax";
|
||||
}
|
||||
|
||||
function setSxStylesCookie(hash) {
|
||||
if (_hasDom) document.cookie = "sx-styles-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax";
|
||||
}
|
||||
|
||||
function clearSxStylesCookie() {
|
||||
if (_hasDom) document.cookie = "sx-styles-hash=;path=/;max-age=0;SameSite=Lax";
|
||||
}
|
||||
|
||||
// --- Env helpers ---
|
||||
|
||||
function parseEnvAttr(el) {
|
||||
var attr = el && el.getAttribute ? el.getAttribute("data-sx-env") : null;
|
||||
if (!attr) return {};
|
||||
try { return JSON.parse(attr); } catch (e) { return {}; }
|
||||
}
|
||||
|
||||
function storeEnvAttr(el, base, newEnv) {
|
||||
var merged = merge(base, newEnv);
|
||||
if (el && el.setAttribute) el.setAttribute("data-sx-env", JSON.stringify(merged));
|
||||
}
|
||||
|
||||
function toKebab(s) { return s.replace(/_/g, "-"); }
|
||||
|
||||
// --- Logging ---
|
||||
|
||||
function logInfo(msg) {
|
||||
if (typeof console !== "undefined") console.log("[sx-ref] " + msg);
|
||||
}
|
||||
|
||||
function logParseError(label, text, err) {
|
||||
if (typeof console === "undefined") return;
|
||||
var msg = err && err.message ? err.message : String(err);
|
||||
var colMatch = msg.match(/col (\d+)/);
|
||||
var lineMatch = msg.match(/line (\d+)/);
|
||||
if (colMatch && text) {
|
||||
var errLine = lineMatch ? parseInt(lineMatch[1]) : 1;
|
||||
var errCol = parseInt(colMatch[1]);
|
||||
var lines = text.split("\n");
|
||||
var pos = 0;
|
||||
for (var i = 0; i < errLine - 1 && i < lines.length; i++) pos += lines[i].length + 1;
|
||||
pos += errCol;
|
||||
var ws = 80;
|
||||
var start = Math.max(0, pos - ws);
|
||||
var end = Math.min(text.length, pos + ws);
|
||||
console.error("[sx-ref] " + label + ":", msg,
|
||||
"\n around error (pos ~" + pos + "):",
|
||||
"\n \u00ab" + text.substring(start, pos) + "\u26d4" + text.substring(pos, end) + "\u00bb");
|
||||
} else {
|
||||
console.error("[sx-ref] " + label + ":", msg);
|
||||
}
|
||||
}
|
||||
|
||||
function parseAndLoadStyleDict(text) {
|
||||
try { loadStyleDict(JSON.parse(text)); }
|
||||
catch (e) { if (typeof console !== "undefined") console.warn("[sx-ref] style dict parse error", e); }
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Post-transpilation fixups
|
||||
// =========================================================================
|
||||
@@ -2472,8 +3008,14 @@
|
||||
process: typeof processElements === "function" ? processElements : null,
|
||||
executeRequest: typeof executeRequest === "function" ? executeRequest : null,
|
||||
postSwap: typeof postSwap === "function" ? postSwap : null,
|
||||
init: typeof engineInit === "function" ? engineInit : null,
|
||||
_version: "ref-2.0 (dom+engine+orchestration, bootstrap-compiled)"
|
||||
processScripts: typeof processSxScripts === "function" ? processSxScripts : null,
|
||||
mount: typeof sxMount === "function" ? sxMount : null,
|
||||
hydrate: typeof sxHydrateElements === "function" ? sxHydrateElements : null,
|
||||
update: typeof sxUpdateElement === "function" ? sxUpdateElement : null,
|
||||
renderComponent: typeof sxRenderComponent === "function" ? sxRenderComponent : null,
|
||||
getEnv: function() { return componentEnv; },
|
||||
init: typeof bootInit === "function" ? bootInit : null,
|
||||
_version: "ref-2.0 (boot+cssx+dom+engine+orchestration, bootstrap-compiled)"
|
||||
};
|
||||
|
||||
|
||||
@@ -2486,7 +3028,7 @@
|
||||
|
||||
// --- Auto-init ---
|
||||
if (typeof document !== "undefined") {
|
||||
var _sxRefInit = function() { engineInit(); };
|
||||
var _sxRefInit = function() { bootInit(); };
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
||||
} else {
|
||||
|
||||
@@ -1713,6 +1713,296 @@
|
||||
var engineInit = function() { return (initCssTracking(), sxProcessScripts(NIL), sxHydrate(NIL), processElements(NIL)); };
|
||||
|
||||
|
||||
// === Transpiled from cssx ===
|
||||
|
||||
// _style-atoms
|
||||
var _styleAtoms = {};
|
||||
|
||||
// _pseudo-variants
|
||||
var _pseudoVariants = {};
|
||||
|
||||
// _responsive-breakpoints
|
||||
var _responsiveBreakpoints = {};
|
||||
|
||||
// _style-keyframes
|
||||
var _styleKeyframes = {};
|
||||
|
||||
// _arbitrary-patterns
|
||||
var _arbitraryPatterns = [];
|
||||
|
||||
// _child-selector-prefixes
|
||||
var _childSelectorPrefixes = [];
|
||||
|
||||
// _style-cache
|
||||
var _styleCache = {};
|
||||
|
||||
// _injected-styles
|
||||
var _injectedStyles = {};
|
||||
|
||||
// load-style-dict
|
||||
var loadStyleDict = function(data) { return (_styleAtoms = sxOr(get(data, "a"), {})); };
|
||||
|
||||
// split-variant
|
||||
var splitVariant = function(atom) { return (function() {
|
||||
var result = NIL;
|
||||
{ var _c = keys(_responsiveBreakpoints); for (var _i = 0; _i < _c.length; _i++) { var bp = _c[_i]; if (isSxTruthy(isNil(result))) {
|
||||
(function() {
|
||||
var prefix = (String(bp) + String(":"));
|
||||
return (isSxTruthy(startsWith(atom, prefix)) ? (function() {
|
||||
var restAtom = slice(atom, len(prefix));
|
||||
return (function() {
|
||||
var innerMatch = NIL;
|
||||
{ var _c = keys(_pseudoVariants); for (var _i = 0; _i < _c.length; _i++) { var pv = _c[_i]; if (isSxTruthy(isNil(innerMatch))) {
|
||||
(function() {
|
||||
var innerPrefix = (String(pv) + String(":"));
|
||||
return (isSxTruthy(startsWith(restAtom, innerPrefix)) ? (innerMatch = [(String(bp) + String(":") + String(pv)), slice(restAtom, len(innerPrefix))]) : NIL);
|
||||
})();
|
||||
} } }
|
||||
return (result = sxOr(innerMatch, [bp, restAtom]));
|
||||
})();
|
||||
})() : NIL);
|
||||
})();
|
||||
} } }
|
||||
if (isSxTruthy(isNil(result))) {
|
||||
{ var _c = keys(_pseudoVariants); for (var _i = 0; _i < _c.length; _i++) { var pv = _c[_i]; if (isSxTruthy(isNil(result))) {
|
||||
(function() {
|
||||
var prefix = (String(pv) + String(":"));
|
||||
return (isSxTruthy(startsWith(atom, prefix)) ? (result = [pv, slice(atom, len(prefix))]) : NIL);
|
||||
})();
|
||||
} } }
|
||||
}
|
||||
return sxOr(result, [NIL, atom]);
|
||||
})(); };
|
||||
|
||||
// resolve-atom
|
||||
var resolveAtom = function(atom) { return (function() {
|
||||
var decls = dictGet(_styleAtoms, atom);
|
||||
return (isSxTruthy(!isNil(decls)) ? decls : (isSxTruthy(startsWith(atom, "animate-")) ? (function() {
|
||||
var kfName = slice(atom, 8);
|
||||
return (isSxTruthy(dictHas(_styleKeyframes, kfName)) ? (String("animation-name:") + String(kfName)) : NIL);
|
||||
})() : (function() {
|
||||
var matchResult = NIL;
|
||||
{ var _c = _arbitraryPatterns; for (var _i = 0; _i < _c.length; _i++) { var pat = _c[_i]; if (isSxTruthy(isNil(matchResult))) {
|
||||
(function() {
|
||||
var m = regexMatch(get(pat, "re"), atom);
|
||||
return (isSxTruthy(m) ? (matchResult = regexReplaceGroups(get(pat, "tmpl"), m)) : NIL);
|
||||
})();
|
||||
} } }
|
||||
return matchResult;
|
||||
})()));
|
||||
})(); };
|
||||
|
||||
// is-child-selector-atom?
|
||||
var isChildSelectorAtom = function(atom) { return some(function(prefix) { return startsWith(atom, prefix); }, _childSelectorPrefixes); };
|
||||
|
||||
// hash-style
|
||||
var hashStyle = function(input) { return fnv1aHash(input); };
|
||||
|
||||
// resolve-style
|
||||
var resolveStyle = function(atoms) { return (function() {
|
||||
var key = join("\\0", atoms);
|
||||
return (function() {
|
||||
var cached = dictGet(_styleCache, key);
|
||||
return (isSxTruthy(!isNil(cached)) ? cached : (function() {
|
||||
var baseDecls = [];
|
||||
var mediaRules = [];
|
||||
var pseudoRules = [];
|
||||
var kfNeeded = [];
|
||||
{ var _c = atoms; for (var _i = 0; _i < _c.length; _i++) { var a = _c[_i]; if (isSxTruthy(a)) {
|
||||
(function() {
|
||||
var clean = (isSxTruthy(startsWith(a, ":")) ? slice(a, 1) : a);
|
||||
return (function() {
|
||||
var parts = splitVariant(clean);
|
||||
return (function() {
|
||||
var variant = first(parts);
|
||||
var base = nth(parts, 1);
|
||||
var decls = resolveAtom(base);
|
||||
return (isSxTruthy(decls) ? ((isSxTruthy(startsWith(base, "animate-")) ? (function() {
|
||||
var kfName = slice(base, 8);
|
||||
return (isSxTruthy(dictHas(_styleKeyframes, kfName)) ? append_b(kfNeeded, [kfName, dictGet(_styleKeyframes, kfName)]) : NIL);
|
||||
})() : NIL), (isSxTruthy(isNil(variant)) ? append_b(baseDecls, decls) : (isSxTruthy(dictHas(_responsiveBreakpoints, variant)) ? append_b(mediaRules, [dictGet(_responsiveBreakpoints, variant), decls]) : (isSxTruthy(dictHas(_pseudoVariants, variant)) ? append_b(pseudoRules, [dictGet(_pseudoVariants, variant), decls]) : (function() {
|
||||
var vparts = split(variant, ":");
|
||||
var mediaPart = NIL;
|
||||
var pseudoPart = NIL;
|
||||
{ var _c = vparts; for (var _i = 0; _i < _c.length; _i++) { var vp = _c[_i]; (isSxTruthy(dictHas(_responsiveBreakpoints, vp)) ? (mediaPart = dictGet(_responsiveBreakpoints, vp)) : (isSxTruthy(dictHas(_pseudoVariants, vp)) ? (pseudoPart = dictGet(_pseudoVariants, vp)) : NIL)); } }
|
||||
if (isSxTruthy(mediaPart)) {
|
||||
mediaRules.push([mediaPart, decls]);
|
||||
}
|
||||
if (isSxTruthy(pseudoPart)) {
|
||||
pseudoRules.push([pseudoPart, decls]);
|
||||
}
|
||||
return (isSxTruthy((isSxTruthy(isNil(mediaPart)) && isNil(pseudoPart))) ? append_b(baseDecls, decls) : NIL);
|
||||
})())))) : NIL);
|
||||
})();
|
||||
})();
|
||||
})();
|
||||
} } }
|
||||
return (function() {
|
||||
var hashInput = join(";", baseDecls);
|
||||
{ var _c = chunkEvery(mediaRules, 2); 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("}")); } }
|
||||
{ var _c = chunkEvery(pseudoRules, 2); for (var _i = 0; _i < _c.length; _i++) { var pr = _c[_i]; hashInput = (String(hashInput) + String(first(pr)) + String("{") + String(nth(pr, 1)) + String("}")); } }
|
||||
{ var _c = chunkEvery(kfNeeded, 2); for (var _i = 0; _i < _c.length; _i++) { var kf = _c[_i]; hashInput = (String(hashInput) + String(nth(kf, 1))); } }
|
||||
return (function() {
|
||||
var cn = (String("sx-") + String(hashStyle(hashInput)));
|
||||
var sv = makeStyleValue_(cn, join(";", baseDecls), chunkEvery(mediaRules, 2), chunkEvery(pseudoRules, 2), chunkEvery(kfNeeded, 2));
|
||||
_styleCache[key] = sv;
|
||||
injectStyleValue(sv, atoms);
|
||||
return sv;
|
||||
})();
|
||||
})();
|
||||
})());
|
||||
})();
|
||||
})(); };
|
||||
|
||||
// merge-style-values
|
||||
var mergeStyleValues = function(styles) { return (isSxTruthy((len(styles) == 1)) ? first(styles) : (function() {
|
||||
var allDecls = [];
|
||||
var allMedia = [];
|
||||
var allPseudo = [];
|
||||
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));
|
||||
} } }
|
||||
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("}")); } }
|
||||
{ var _c = allPseudo; for (var _i = 0; _i < _c.length; _i++) { var pr = _c[_i]; hashInput = (String(hashInput) + String(first(pr)) + String("{") + String(nth(pr, 1)) + String("}")); } }
|
||||
{ var _c = allKf; for (var _i = 0; _i < _c.length; _i++) { var kf = _c[_i]; hashInput = (String(hashInput) + String(nth(kf, 1))); } }
|
||||
return (function() {
|
||||
var cn = (String("sx-") + String(hashStyle(hashInput)));
|
||||
var merged = makeStyleValue_(cn, join(";", allDecls), allMedia, allPseudo, allKf);
|
||||
injectStyleValue(merged, []);
|
||||
return merged;
|
||||
})();
|
||||
})();
|
||||
})()); };
|
||||
|
||||
|
||||
// === Transpiled from boot ===
|
||||
|
||||
// HEAD_HOIST_SELECTOR
|
||||
var HEAD_HOIST_SELECTOR = "meta, title, link[rel='canonical'], script[type='application/ld+json']";
|
||||
|
||||
// hoist-head-elements-full
|
||||
var hoistHeadElementsFull = function(root) { return (function() {
|
||||
var els = domQueryAll(root, HEAD_HOIST_SELECTOR);
|
||||
return forEach(function(el) { return (function() {
|
||||
var tag = lower(domTagName(el));
|
||||
return (isSxTruthy((tag == "title")) ? (setDocumentTitle(domTextContent(el)), domRemoveChild(domParent(el), el)) : (isSxTruthy((tag == "meta")) ? ((function() {
|
||||
var name = domGetAttr(el, "name");
|
||||
var prop = domGetAttr(el, "property");
|
||||
if (isSxTruthy(name)) {
|
||||
removeHeadElement((String("meta[name=\"") + String(name) + String("\"]")));
|
||||
}
|
||||
return (isSxTruthy(prop) ? removeHeadElement((String("meta[property=\"") + String(prop) + String("\"]"))) : NIL);
|
||||
})(), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (isSxTruthy((isSxTruthy((tag == "link")) && (domGetAttr(el, "rel") == "canonical"))) ? (removeHeadElement("link[rel=\"canonical\"]"), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (domRemoveChild(domParent(el), el), domAppendToHead(el)))));
|
||||
})(); }, els);
|
||||
})(); };
|
||||
|
||||
// sx-mount
|
||||
var sxMount = function(target, source, extraEnv) { return (function() {
|
||||
var el = resolveMountTarget(target);
|
||||
return (isSxTruthy(el) ? (function() {
|
||||
var node = sxRenderWithEnv(source, extraEnv);
|
||||
domSetTextContent(el, "");
|
||||
domAppend(el, node);
|
||||
hoistHeadElementsFull(el);
|
||||
processElements(el);
|
||||
return sxHydrateElements(el);
|
||||
})() : NIL);
|
||||
})(); };
|
||||
|
||||
// sx-hydrate-elements
|
||||
var sxHydrateElements = function(root) { return (function() {
|
||||
var els = domQueryAll(sxOr(root, domBody()), "[data-sx]");
|
||||
return forEach(function(el) { return (isSxTruthy(!isProcessed(el, "hydrated")) ? (markProcessed(el, "hydrated"), sxUpdateElement(el, NIL)) : NIL); }, els);
|
||||
})(); };
|
||||
|
||||
// sx-update-element
|
||||
var sxUpdateElement = function(el, newEnv) { return (function() {
|
||||
var target = resolveMountTarget(el);
|
||||
return (isSxTruthy(target) ? (function() {
|
||||
var source = domGetAttr(target, "data-sx");
|
||||
return (isSxTruthy(source) ? (function() {
|
||||
var baseEnv = parseEnvAttr(target);
|
||||
var env = mergeEnvs(baseEnv, newEnv);
|
||||
return (function() {
|
||||
var node = sxRenderWithEnv(source, env);
|
||||
domSetTextContent(target, "");
|
||||
domAppend(target, node);
|
||||
return (isSxTruthy(newEnv) ? storeEnvAttr(target, baseEnv, newEnv) : NIL);
|
||||
})();
|
||||
})() : NIL);
|
||||
})() : NIL);
|
||||
})(); };
|
||||
|
||||
// sx-render-component
|
||||
var sxRenderComponent = function(name, kwargs, extraEnv) { return (function() {
|
||||
var fullName = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||||
return (function() {
|
||||
var env = getRenderEnv(extraEnv);
|
||||
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))); } }
|
||||
return renderToDom(callExpr, env, NIL);
|
||||
})());
|
||||
})();
|
||||
})(); };
|
||||
|
||||
// process-sx-scripts
|
||||
var processSxScripts = function(root) { return (function() {
|
||||
var scripts = querySxScripts(root);
|
||||
return forEach(function(s) { return (isSxTruthy(!isProcessed(s, "script")) ? (markProcessed(s, "script"), (function() {
|
||||
var text = domTextContent(s);
|
||||
return (isSxTruthy(domHasAttr(s, "data-components")) ? processComponentScript(s, text) : (isSxTruthy(sxOr(isNil(text), isEmpty(trim(text)))) ? NIL : (isSxTruthy(domHasAttr(s, "data-mount")) ? (function() {
|
||||
var mountSel = domGetAttr(s, "data-mount");
|
||||
var target = domQuery(mountSel);
|
||||
return (isSxTruthy(target) ? sxMount(target, text, NIL) : NIL);
|
||||
})() : sxLoadComponents(text))));
|
||||
})()) : NIL); }, scripts);
|
||||
})(); };
|
||||
|
||||
// process-component-script
|
||||
var processComponentScript = function(script, text) { return (function() {
|
||||
var hash = domGetAttr(script, "data-hash");
|
||||
return (isSxTruthy(isNil(hash)) ? (isSxTruthy((isSxTruthy(text) && !isEmpty(trim(text)))) ? sxLoadComponents(text) : NIL) : (function() {
|
||||
var hasInline = (isSxTruthy(text) && !isEmpty(trim(text)));
|
||||
(function() {
|
||||
var cachedHash = localStorageGet("sx-components-hash");
|
||||
return (isSxTruthy((cachedHash == hash)) ? (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo("components: downloaded (cookie stale)")) : (function() {
|
||||
var cached = localStorageGet("sx-components-src");
|
||||
return (isSxTruthy(cached) ? (sxLoadComponents(cached), logInfo((String("components: cached (") + String(hash) + String(")")))) : (clearSxCompCookie(), browserReload()));
|
||||
})()) : (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo((String("components: downloaded (") + String(hash) + String(")")))) : (localStorageRemove("sx-components-hash"), localStorageRemove("sx-components-src"), clearSxCompCookie(), browserReload())));
|
||||
})();
|
||||
return setSxCompCookie(hash);
|
||||
})());
|
||||
})(); };
|
||||
|
||||
// init-style-dict
|
||||
var initStyleDict = function() { return (function() {
|
||||
var scripts = queryStyleScripts();
|
||||
return forEach(function(s) { return (isSxTruthy(!isProcessed(s, "styles")) ? (markProcessed(s, "styles"), (function() {
|
||||
var text = domTextContent(s);
|
||||
var hash = domGetAttr(s, "data-hash");
|
||||
return (isSxTruthy(isNil(hash)) ? (isSxTruthy((isSxTruthy(text) && !isEmpty(trim(text)))) ? parseAndLoadStyleDict(text) : NIL) : (function() {
|
||||
var hasInline = (isSxTruthy(text) && !isEmpty(trim(text)));
|
||||
(function() {
|
||||
var cachedHash = localStorageGet("sx-styles-hash");
|
||||
return (isSxTruthy((cachedHash == hash)) ? (isSxTruthy(hasInline) ? (localStorageSet("sx-styles-src", text), parseAndLoadStyleDict(text), logInfo("styles: downloaded (cookie stale)")) : (function() {
|
||||
var cached = localStorageGet("sx-styles-src");
|
||||
return (isSxTruthy(cached) ? (parseAndLoadStyleDict(cached), logInfo((String("styles: cached (") + String(hash) + String(")")))) : (clearSxStylesCookie(), browserReload()));
|
||||
})()) : (isSxTruthy(hasInline) ? (localStorageSet("sx-styles-hash", hash), localStorageSet("sx-styles-src", text), parseAndLoadStyleDict(text), logInfo((String("styles: downloaded (") + String(hash) + String(")")))) : (localStorageRemove("sx-styles-hash"), localStorageRemove("sx-styles-src"), clearSxStylesCookie(), browserReload())));
|
||||
})();
|
||||
return setSxStylesCookie(hash);
|
||||
})());
|
||||
})()) : NIL); }, scripts);
|
||||
})(); };
|
||||
|
||||
// boot-init
|
||||
var bootInit = function() { return (initCssTracking(), initStyleDict(), processSxScripts(NIL), sxHydrateElements(NIL), processElements(NIL)); };
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — DOM adapter (browser-only)
|
||||
// =========================================================================
|
||||
@@ -2465,6 +2755,252 @@
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — CSSX (style dictionary)
|
||||
// =========================================================================
|
||||
|
||||
function fnv1aHash(input) {
|
||||
var h = 0x811c9dc5;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
h ^= input.charCodeAt(i);
|
||||
h = (h * 0x01000193) >>> 0;
|
||||
}
|
||||
return h.toString(16).padStart(8, "0").substring(0, 6);
|
||||
}
|
||||
|
||||
function compileRegex(pattern) {
|
||||
try { return new RegExp(pattern); } catch (e) { return null; }
|
||||
}
|
||||
|
||||
function regexMatch(re, s) {
|
||||
if (!re) return NIL;
|
||||
var m = s.match(re);
|
||||
return m ? Array.prototype.slice.call(m) : NIL;
|
||||
}
|
||||
|
||||
function regexReplaceGroups(tmpl, match) {
|
||||
var result = tmpl;
|
||||
for (var j = 1; j < match.length; j++) {
|
||||
result = result.split("{" + (j - 1) + "}").join(match[j]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function makeStyleValue_(cn, decls, media, pseudo, kf) {
|
||||
return new StyleValue(cn, decls || "", media || [], pseudo || [], kf || []);
|
||||
}
|
||||
|
||||
function styleValueDeclarations(sv) { return sv.declarations; }
|
||||
function styleValueMediaRules(sv) { return sv.mediaRules; }
|
||||
function styleValuePseudoRules(sv) { return sv.pseudoRules; }
|
||||
function styleValueKeyframes_(sv) { return sv.keyframes; }
|
||||
|
||||
function injectStyleValue(sv, atoms) {
|
||||
if (_injectedStyles[sv.className]) return;
|
||||
_injectedStyles[sv.className] = true;
|
||||
|
||||
if (!_hasDom) return;
|
||||
var cssTarget = document.getElementById("sx-css");
|
||||
if (!cssTarget) return;
|
||||
|
||||
var rules = [];
|
||||
if (sv.declarations) {
|
||||
var hasChild = false;
|
||||
if (atoms) {
|
||||
for (var ai = 0; ai < atoms.length; ai++) {
|
||||
if (isChildSelectorAtom(atoms[ai])) { hasChild = true; break; }
|
||||
}
|
||||
}
|
||||
if (hasChild) {
|
||||
rules.push("." + sv.className + ">:not(:first-child){" + sv.declarations + "}");
|
||||
} else {
|
||||
rules.push("." + sv.className + "{" + sv.declarations + "}");
|
||||
}
|
||||
}
|
||||
for (var pi = 0; pi < sv.pseudoRules.length; pi++) {
|
||||
var sel = sv.pseudoRules[pi][0], decls = sv.pseudoRules[pi][1];
|
||||
if (sel.indexOf("&") >= 0) {
|
||||
rules.push(sel.replace(/&/g, "." + sv.className) + "{" + decls + "}");
|
||||
} else {
|
||||
rules.push("." + sv.className + sel + "{" + decls + "}");
|
||||
}
|
||||
}
|
||||
for (var mi = 0; mi < sv.mediaRules.length; mi++) {
|
||||
rules.push("@media " + sv.mediaRules[mi][0] + "{." + sv.className + "{" + sv.mediaRules[mi][1] + "}}");
|
||||
}
|
||||
for (var ki = 0; ki < sv.keyframes.length; ki++) {
|
||||
rules.push(sv.keyframes[ki][1]);
|
||||
}
|
||||
cssTarget.textContent += rules.join("");
|
||||
}
|
||||
|
||||
// Replace stub css primitive with real CSSX implementation
|
||||
PRIMITIVES["css"] = function() {
|
||||
var atoms = [];
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var a = arguments[i];
|
||||
if (isNil(a) || a === false) continue;
|
||||
atoms.push(isKw(a) ? a.name : String(a));
|
||||
}
|
||||
if (!atoms.length) return NIL;
|
||||
return resolveStyle(atoms);
|
||||
};
|
||||
|
||||
PRIMITIVES["merge-styles"] = function() {
|
||||
var valid = [];
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (isStyleValue(arguments[i])) valid.push(arguments[i]);
|
||||
}
|
||||
if (!valid.length) return NIL;
|
||||
if (valid.length === 1) return valid[0];
|
||||
return mergeStyleValues(valid);
|
||||
};
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Platform interface — Boot (mount, hydrate, scripts, cookies)
|
||||
// =========================================================================
|
||||
|
||||
function resolveMountTarget(target) {
|
||||
if (typeof target === "string") return _hasDom ? document.querySelector(target) : null;
|
||||
return target;
|
||||
}
|
||||
|
||||
function sxRenderWithEnv(source, extraEnv) {
|
||||
var env = extraEnv ? merge(componentEnv, extraEnv) : componentEnv;
|
||||
var exprs = parse(source);
|
||||
if (!_hasDom) return null;
|
||||
var frag = document.createDocumentFragment();
|
||||
for (var i = 0; i < exprs.length; i++) {
|
||||
var node = renderToDom(exprs[i], env, null);
|
||||
if (node) frag.appendChild(node);
|
||||
}
|
||||
return frag;
|
||||
}
|
||||
|
||||
function getRenderEnv(extraEnv) {
|
||||
return extraEnv ? merge(componentEnv, extraEnv) : componentEnv;
|
||||
}
|
||||
|
||||
function mergeEnvs(base, newEnv) {
|
||||
return newEnv ? merge(componentEnv, base, newEnv) : merge(componentEnv, base);
|
||||
}
|
||||
|
||||
function sxLoadComponents(text) {
|
||||
try {
|
||||
var exprs = parse(text);
|
||||
for (var i = 0; i < exprs.length; i++) trampoline(evalExpr(exprs[i], componentEnv));
|
||||
} catch (err) {
|
||||
logParseError("loadComponents", text, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function setDocumentTitle(s) {
|
||||
if (_hasDom) document.title = s || "";
|
||||
}
|
||||
|
||||
function removeHeadElement(sel) {
|
||||
if (!_hasDom) return;
|
||||
var old = document.head.querySelector(sel);
|
||||
if (old) old.parentNode.removeChild(old);
|
||||
}
|
||||
|
||||
function querySxScripts(root) {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
(root || document).querySelectorAll('script[type="text/sx"]'));
|
||||
}
|
||||
|
||||
function queryStyleScripts() {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
document.querySelectorAll('script[type="text/sx-styles"]'));
|
||||
}
|
||||
|
||||
// --- localStorage ---
|
||||
|
||||
function localStorageGet(key) {
|
||||
try { var v = localStorage.getItem(key); return v === null ? NIL : v; }
|
||||
catch (e) { return NIL; }
|
||||
}
|
||||
|
||||
function localStorageSet(key, val) {
|
||||
try { localStorage.setItem(key, val); } catch (e) {}
|
||||
}
|
||||
|
||||
function localStorageRemove(key) {
|
||||
try { localStorage.removeItem(key); } catch (e) {}
|
||||
}
|
||||
|
||||
// --- Cookies ---
|
||||
|
||||
function setSxCompCookie(hash) {
|
||||
if (_hasDom) document.cookie = "sx-comp-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax";
|
||||
}
|
||||
|
||||
function clearSxCompCookie() {
|
||||
if (_hasDom) document.cookie = "sx-comp-hash=;path=/;max-age=0;SameSite=Lax";
|
||||
}
|
||||
|
||||
function setSxStylesCookie(hash) {
|
||||
if (_hasDom) document.cookie = "sx-styles-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax";
|
||||
}
|
||||
|
||||
function clearSxStylesCookie() {
|
||||
if (_hasDom) document.cookie = "sx-styles-hash=;path=/;max-age=0;SameSite=Lax";
|
||||
}
|
||||
|
||||
// --- Env helpers ---
|
||||
|
||||
function parseEnvAttr(el) {
|
||||
var attr = el && el.getAttribute ? el.getAttribute("data-sx-env") : null;
|
||||
if (!attr) return {};
|
||||
try { return JSON.parse(attr); } catch (e) { return {}; }
|
||||
}
|
||||
|
||||
function storeEnvAttr(el, base, newEnv) {
|
||||
var merged = merge(base, newEnv);
|
||||
if (el && el.setAttribute) el.setAttribute("data-sx-env", JSON.stringify(merged));
|
||||
}
|
||||
|
||||
function toKebab(s) { return s.replace(/_/g, "-"); }
|
||||
|
||||
// --- Logging ---
|
||||
|
||||
function logInfo(msg) {
|
||||
if (typeof console !== "undefined") console.log("[sx-ref] " + msg);
|
||||
}
|
||||
|
||||
function logParseError(label, text, err) {
|
||||
if (typeof console === "undefined") return;
|
||||
var msg = err && err.message ? err.message : String(err);
|
||||
var colMatch = msg.match(/col (\d+)/);
|
||||
var lineMatch = msg.match(/line (\d+)/);
|
||||
if (colMatch && text) {
|
||||
var errLine = lineMatch ? parseInt(lineMatch[1]) : 1;
|
||||
var errCol = parseInt(colMatch[1]);
|
||||
var lines = text.split("\n");
|
||||
var pos = 0;
|
||||
for (var i = 0; i < errLine - 1 && i < lines.length; i++) pos += lines[i].length + 1;
|
||||
pos += errCol;
|
||||
var ws = 80;
|
||||
var start = Math.max(0, pos - ws);
|
||||
var end = Math.min(text.length, pos + ws);
|
||||
console.error("[sx-ref] " + label + ":", msg,
|
||||
"\n around error (pos ~" + pos + "):",
|
||||
"\n \u00ab" + text.substring(start, pos) + "\u26d4" + text.substring(pos, end) + "\u00bb");
|
||||
} else {
|
||||
console.error("[sx-ref] " + label + ":", msg);
|
||||
}
|
||||
}
|
||||
|
||||
function parseAndLoadStyleDict(text) {
|
||||
try { loadStyleDict(JSON.parse(text)); }
|
||||
catch (e) { if (typeof console !== "undefined") console.warn("[sx-ref] style dict parse error", e); }
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// Post-transpilation fixups
|
||||
// =========================================================================
|
||||
@@ -2638,8 +3174,14 @@
|
||||
process: typeof processElements === "function" ? processElements : null,
|
||||
executeRequest: typeof executeRequest === "function" ? executeRequest : null,
|
||||
postSwap: typeof postSwap === "function" ? postSwap : null,
|
||||
init: typeof engineInit === "function" ? engineInit : null,
|
||||
_version: "ref-2.0 (dom+engine+html+orchestration+sx, bootstrap-compiled)"
|
||||
processScripts: typeof processSxScripts === "function" ? processSxScripts : null,
|
||||
mount: typeof sxMount === "function" ? sxMount : null,
|
||||
hydrate: typeof sxHydrateElements === "function" ? sxHydrateElements : null,
|
||||
update: typeof sxUpdateElement === "function" ? sxUpdateElement : null,
|
||||
renderComponent: typeof sxRenderComponent === "function" ? sxRenderComponent : null,
|
||||
getEnv: function() { return componentEnv; },
|
||||
init: typeof bootInit === "function" ? bootInit : null,
|
||||
_version: "ref-2.0 (boot+cssx+dom+engine+html+orchestration+sx, bootstrap-compiled)"
|
||||
};
|
||||
|
||||
|
||||
@@ -2652,7 +3194,7 @@
|
||||
|
||||
// --- Auto-init ---
|
||||
if (typeof document !== "undefined") {
|
||||
var _sxRefInit = function() { engineInit(); };
|
||||
var _sxRefInit = function() { bootInit(); };
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user