Merge branch 'worktree-cssx-components' into macros
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 14m0s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 14m0s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -207,10 +207,6 @@ class JSEmitter:
|
||||
"ho-every": "hoEvery",
|
||||
"ho-for-each": "hoForEach",
|
||||
"sf-defstyle": "sfDefstyle",
|
||||
"sf-defkeyframes": "sfDefkeyframes",
|
||||
"build-keyframes": "buildKeyframes",
|
||||
"style-value?": "isStyleValue",
|
||||
"style-value-class": "styleValueClass",
|
||||
"kf-name": "kfName",
|
||||
"special-form?": "isSpecialForm",
|
||||
"ho-form?": "isHoForm",
|
||||
@@ -460,32 +456,6 @@ class JSEmitter:
|
||||
"format-date": "formatDate",
|
||||
"format-decimal": "formatDecimal",
|
||||
"parse-int": "parseInt_",
|
||||
# cssx.sx
|
||||
"_style-atoms": "_styleAtoms",
|
||||
"_pseudo-variants": "_pseudoVariants",
|
||||
"_responsive-breakpoints": "_responsiveBreakpoints",
|
||||
"_style-keyframes": "_styleKeyframes",
|
||||
"_arbitrary-patterns": "_arbitraryPatterns",
|
||||
"_child-selector-prefixes": "_childSelectorPrefixes",
|
||||
"_style-cache": "_styleCache",
|
||||
"_injected-styles": "_injectedStyles",
|
||||
"load-style-dict": "loadStyleDict",
|
||||
"split-variant": "splitVariant",
|
||||
"resolve-atom": "resolveAtom",
|
||||
"is-child-selector-atom?": "isChildSelectorAtom",
|
||||
"hash-style": "hashStyle",
|
||||
"resolve-style": "resolveStyle",
|
||||
"merge-style-values": "mergeStyleValues",
|
||||
"fnv1a-hash": "fnv1aHash",
|
||||
"compile-regex": "compileRegex",
|
||||
"regex-match": "regexMatch",
|
||||
"regex-replace-groups": "regexReplaceGroups",
|
||||
"make-style-value": "makeStyleValue_",
|
||||
"style-value-declarations": "styleValueDeclarations",
|
||||
"style-value-media-rules": "styleValueMediaRules",
|
||||
"style-value-pseudo-rules": "styleValuePseudoRules",
|
||||
"style-value-keyframes": "styleValueKeyframes_",
|
||||
"inject-style-value": "injectStyleValue",
|
||||
# boot.sx
|
||||
"HEAD_HOIST_SELECTOR": "HEAD_HOIST_SELECTOR",
|
||||
"hoist-head-elements-full": "hoistHeadElementsFull",
|
||||
@@ -495,7 +465,6 @@ class JSEmitter:
|
||||
"sx-render-component": "sxRenderComponent",
|
||||
"process-sx-scripts": "processSxScripts",
|
||||
"process-component-script": "processComponentScript",
|
||||
"init-style-dict": "initStyleDict",
|
||||
"SX_VERSION": "SX_VERSION",
|
||||
"boot-init": "bootInit",
|
||||
"resolve-suspense": "resolveSuspense",
|
||||
@@ -507,21 +476,17 @@ class JSEmitter:
|
||||
"set-document-title": "setDocumentTitle",
|
||||
"remove-head-element": "removeHeadElement",
|
||||
"query-sx-scripts": "querySxScripts",
|
||||
"query-style-scripts": "queryStyleScripts",
|
||||
"local-storage-get": "localStorageGet",
|
||||
"local-storage-set": "localStorageSet",
|
||||
"local-storage-remove": "localStorageRemove",
|
||||
"set-sx-comp-cookie": "setSxCompCookie",
|
||||
"clear-sx-comp-cookie": "clearSxCompCookie",
|
||||
"set-sx-styles-cookie": "setSxStylesCookie",
|
||||
"clear-sx-styles-cookie": "clearSxStylesCookie",
|
||||
"parse-env-attr": "parseEnvAttr",
|
||||
"store-env-attr": "storeEnvAttr",
|
||||
"to-kebab": "toKebab",
|
||||
"log-info": "logInfo",
|
||||
"log-warn": "logWarn",
|
||||
"log-parse-error": "logParseError",
|
||||
"parse-and-load-style-dict": "parseAndLoadStyleDict",
|
||||
"_page-routes": "_pageRoutes",
|
||||
"process-page-scripts": "processPageScripts",
|
||||
"query-page-scripts": "queryPageScripts",
|
||||
@@ -1066,7 +1031,6 @@ ADAPTER_FILES = {
|
||||
"dom": ("adapter-dom.sx", "adapter-dom"),
|
||||
"engine": ("engine.sx", "engine"),
|
||||
"orchestration": ("orchestration.sx","orchestration"),
|
||||
"cssx": ("cssx.sx", "cssx"),
|
||||
"boot": ("boot.sx", "boot"),
|
||||
}
|
||||
|
||||
@@ -1074,8 +1038,7 @@ ADAPTER_FILES = {
|
||||
ADAPTER_DEPS = {
|
||||
"engine": ["dom"],
|
||||
"orchestration": ["engine", "dom"],
|
||||
"cssx": [],
|
||||
"boot": ["dom", "engine", "orchestration", "cssx", "parser"],
|
||||
"boot": ["dom", "engine", "orchestration", "parser"],
|
||||
"parser": [],
|
||||
}
|
||||
|
||||
@@ -1314,7 +1277,7 @@ ASYNC_IO_JS = '''
|
||||
|
||||
// define/defcomp/defmacro — eval for side effects
|
||||
if (hname === "define" || hname === "defcomp" || hname === "defmacro" ||
|
||||
hname === "defstyle" || hname === "defkeyframes" || hname === "defhandler") {
|
||||
hname === "defstyle" || hname === "defhandler") {
|
||||
trampoline(evalExpr(expr, env));
|
||||
return null;
|
||||
}
|
||||
@@ -1436,11 +1399,7 @@ ASYNC_IO_JS = '''
|
||||
})(attrName, attrVal);
|
||||
} else {
|
||||
if (!isNil(attrVal) && attrVal !== false) {
|
||||
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||
el.setAttribute("class", (el.getAttribute("class") || "") + " " + attrVal.className);
|
||||
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||
el.setAttribute("class", (el.getAttribute("class") || "") + " " + attrVal.className);
|
||||
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||
} else if (attrVal === true) {
|
||||
el.setAttribute(attrName, "");
|
||||
@@ -1851,7 +1810,6 @@ def compile_ref_to_js(
|
||||
"dom": PLATFORM_DOM_JS,
|
||||
"engine": PLATFORM_ENGINE_PURE_JS,
|
||||
"orchestration": PLATFORM_ORCHESTRATION_JS,
|
||||
"cssx": PLATFORM_CSSX_JS,
|
||||
"boot": PLATFORM_BOOT_JS,
|
||||
}
|
||||
|
||||
@@ -1886,7 +1844,7 @@ def compile_ref_to_js(
|
||||
("eval.sx", "eval"),
|
||||
("render.sx", "render (core)"),
|
||||
]
|
||||
for name in ("parser", "html", "sx", "dom", "engine", "orchestration", "cssx", "boot"):
|
||||
for name in ("parser", "html", "sx", "dom", "engine", "orchestration", "boot"):
|
||||
if name in adapter_set:
|
||||
sx_files.append(ADAPTER_FILES[name])
|
||||
for name in sorted(spec_mod_set):
|
||||
@@ -1917,7 +1875,6 @@ def compile_ref_to_js(
|
||||
has_dom = "dom" in adapter_set
|
||||
has_engine = "engine" in adapter_set
|
||||
has_orch = "orchestration" in adapter_set
|
||||
has_cssx = "cssx" in adapter_set
|
||||
has_boot = "boot" in adapter_set
|
||||
has_parser = "parser" in adapter_set
|
||||
adapter_label = "+".join(sorted(adapter_set)) if adapter_set else "core-only"
|
||||
@@ -1959,7 +1916,7 @@ def compile_ref_to_js(
|
||||
# Platform JS for selected adapters
|
||||
if not has_dom:
|
||||
parts.append("\n var _hasDom = false;\n")
|
||||
for name in ("dom", "engine", "orchestration", "cssx", "boot"):
|
||||
for name in ("dom", "engine", "orchestration", "boot"):
|
||||
if name in adapter_set and name in adapter_platform:
|
||||
parts.append(adapter_platform[name])
|
||||
|
||||
@@ -1968,7 +1925,7 @@ def compile_ref_to_js(
|
||||
parts.append(CONTINUATIONS_JS)
|
||||
if has_dom:
|
||||
parts.append(ASYNC_IO_JS)
|
||||
parts.append(public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has_boot, has_parser, adapter_label, has_deps, has_router))
|
||||
parts.append(public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_boot, has_parser, adapter_label, has_deps, has_router))
|
||||
parts.append(EPILOGUE)
|
||||
from datetime import datetime, timezone
|
||||
build_ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
@@ -2042,15 +1999,6 @@ PREAMBLE = '''\
|
||||
function RawHTML(html) { this.html = html; }
|
||||
RawHTML.prototype._raw = true;
|
||||
|
||||
function StyleValue(className, declarations, mediaRules, pseudoRules, keyframes) {
|
||||
this.className = className;
|
||||
this.declarations = declarations || "";
|
||||
this.mediaRules = mediaRules || [];
|
||||
this.pseudoRules = pseudoRules || [];
|
||||
this.keyframes = keyframes || [];
|
||||
}
|
||||
StyleValue.prototype._styleValue = true;
|
||||
|
||||
function isSym(x) { return x != null && x._sym === true; }
|
||||
function isKw(x) { return x != null && x._kw === true; }
|
||||
|
||||
@@ -2247,30 +2195,6 @@ PRIMITIVES_JS_MODULES: dict[str, str] = {
|
||||
PRIMITIVES["strip-tags"] = function(s) { return String(s).replace(/<[^>]+>/g, ""); };
|
||||
''',
|
||||
|
||||
"stdlib.style": '''
|
||||
// stdlib.style
|
||||
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 new StyleValue("sx-" + atoms.join("-"), atoms.join(";"), [], [], []);
|
||||
};
|
||||
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];
|
||||
var allDecls = valid.map(function(v) { return v.declarations; }).join(";");
|
||||
return new StyleValue("sx-merged", allDecls, [], [], []);
|
||||
};
|
||||
''',
|
||||
|
||||
"stdlib.debug": '''
|
||||
// stdlib.debug
|
||||
PRIMITIVES["assert"] = function(cond, msg) {
|
||||
@@ -2318,7 +2242,6 @@ PLATFORM_JS_PRE = '''
|
||||
if (x._component) return "component";
|
||||
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";
|
||||
@@ -2366,27 +2289,6 @@ PLATFORM_JS_PRE = '''
|
||||
function isComponent(x) { return x != null && x._component === true; }
|
||||
function isMacro(x) { return x != null && x._macro === true; }
|
||||
|
||||
function isStyleValue(x) { return x != null && x._styleValue === true; }
|
||||
function styleValueClass(x) { return x.className; }
|
||||
function styleValue_p(x) { return x != null && x._styleValue === true; }
|
||||
|
||||
function buildKeyframes(kfName, steps, env) {
|
||||
// Platform implementation of defkeyframes
|
||||
var parts = [];
|
||||
for (var i = 0; i < steps.length; i++) {
|
||||
var step = steps[i];
|
||||
var selector = isSym(step[0]) ? step[0].name : String(step[0]);
|
||||
var body = trampoline(evalExpr(step[1], env));
|
||||
var decls = isStyleValue(body) ? body.declarations : String(body);
|
||||
parts.push(selector + "{" + decls + "}");
|
||||
}
|
||||
var kfRule = "@keyframes " + kfName + "{" + parts.join("") + "}";
|
||||
var cn = "sx-ref-kf-" + kfName;
|
||||
var sv = new StyleValue(cn, "animation-name:" + kfName, [], [], [[kfName, kfRule]]);
|
||||
env[kfName] = sv;
|
||||
return sv;
|
||||
}
|
||||
|
||||
function envHas(env, name) { return name in env; }
|
||||
function envGet(env, name) { return env[name]; }
|
||||
function envSet(env, name, val) { env[name] = val; }
|
||||
@@ -2512,7 +2414,7 @@ PLATFORM_JS_POST = '''
|
||||
function isSpecialForm(n) { return n in {
|
||||
"if":1,"when":1,"cond":1,"case":1,"and":1,"or":1,"let":1,"let*":1,
|
||||
"lambda":1,"fn":1,"define":1,"defcomp":1,"defmacro":1,"defstyle":1,
|
||||
"defkeyframes":1,"defhandler":1,"begin":1,"do":1,
|
||||
"defhandler":1,"begin":1,"do":1,
|
||||
"quote":1,"quasiquote":1,"->":1,"set!":1
|
||||
}; }
|
||||
function isHoForm(n) { return n in {
|
||||
@@ -2523,7 +2425,7 @@ PLATFORM_JS_POST = '''
|
||||
|
||||
function isDefinitionForm(name) {
|
||||
return name === "define" || name === "defcomp" || name === "defmacro" ||
|
||||
name === "defstyle" || name === "defkeyframes" || name === "defhandler";
|
||||
name === "defstyle" || name === "defhandler";
|
||||
}
|
||||
|
||||
function indexOf_(s, ch) {
|
||||
@@ -2901,11 +2803,7 @@ PLATFORM_DOM_JS = """
|
||||
var attrVal = trampoline(evalExpr(args[i + 1], env));
|
||||
i++; // skip value
|
||||
if (isNil(attrVal) || attrVal === false) continue;
|
||||
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||
extraClasses.push(attrVal.className);
|
||||
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||
} else if (attrVal === true) {
|
||||
el.setAttribute(attrName, "");
|
||||
@@ -3787,102 +3685,6 @@ PLATFORM_ORCHESTRATION_JS = """
|
||||
}
|
||||
"""
|
||||
|
||||
PLATFORM_CSSX_JS = """
|
||||
// =========================================================================
|
||||
// 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 = [];
|
||||
// Child-selector atoms are now routed to pseudoRules by the resolver
|
||||
// with selector ">:not(:first-child)", so base declarations are always
|
||||
// applied directly to the class.
|
||||
if (sv.declarations) {
|
||||
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_BOOT_JS = """
|
||||
// =========================================================================
|
||||
// Platform interface — Boot (mount, hydrate, scripts, cookies)
|
||||
@@ -3940,12 +3742,6 @@ PLATFORM_BOOT_JS = """
|
||||
r.querySelectorAll('script[type="text/sx"]'));
|
||||
}
|
||||
|
||||
function queryStyleScripts() {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
document.querySelectorAll('script[type="text/sx-styles"]'));
|
||||
}
|
||||
|
||||
function queryPageScripts() {
|
||||
if (!_hasDom) return [];
|
||||
return Array.prototype.slice.call(
|
||||
@@ -3977,14 +3773,6 @@ PLATFORM_BOOT_JS = """
|
||||
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) {
|
||||
@@ -4033,10 +3821,6 @@ PLATFORM_BOOT_JS = """
|
||||
}
|
||||
}
|
||||
|
||||
function parseAndLoadStyleDict(text) {
|
||||
try { loadStyleDict(JSON.parse(text)); }
|
||||
catch (e) { if (typeof console !== "undefined") console.warn("[sx-ref] style dict parse error", e); }
|
||||
}
|
||||
"""
|
||||
|
||||
def fixups_js(has_html, has_sx, has_dom):
|
||||
@@ -4063,7 +3847,7 @@ def fixups_js(has_html, has_sx, has_dom):
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has_boot, has_parser, adapter_label, has_deps=False, has_router=False):
|
||||
def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_boot, has_parser, adapter_label, has_deps=False, has_router=False):
|
||||
# Parser: use compiled sxParse from parser.sx, or inline a minimal fallback
|
||||
if has_parser:
|
||||
parser = '''
|
||||
|
||||
Reference in New Issue
Block a user