Implement CSSX Phase 2: native SX style primitives
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled

Replace Tailwind class strings with native SX expressions:
(css :flex :gap-4 :hover:bg-sky-200) instead of :class "flex gap-4 ..."

- Add style_dict.py: 516 atoms, variants, breakpoints, keyframes, patterns
- Add style_resolver.py: memoized resolver with variant splitting
- Add StyleValue type to types.py (frozen dataclass with class_name, declarations, etc.)
- Add css and merge-styles primitives to primitives.py
- Add defstyle and defkeyframes special forms to evaluator.py and async_eval.py
- Integrate StyleValue into html.py and async_eval.py render paths
- Add register_generated_rule() to css_registry.py, fix media query selector
- Add style dict JSON delivery with localStorage caching to helpers.py
- Add client-side css primitive, resolver, and style injection to sx.js

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 12:47:51 +00:00
parent 28388540d5
commit 19d59f5f4b
11 changed files with 1660 additions and 7 deletions

View File

@@ -147,6 +147,48 @@ def scan_classes_from_sx(source: str) -> set[str]:
return classes
def register_generated_rule(style_val: Any) -> None:
"""Register a generated StyleValue's CSS rules in the registry.
This allows generated class names (``sx-a3f2c1``) to flow through
the existing ``lookup_rules()`` → ``SX-Css`` delta pipeline.
"""
from .style_dict import CHILD_SELECTOR_ATOMS
cn = style_val.class_name
if cn in _REGISTRY:
return # already registered
parts: list[str] = []
# Base declarations
if style_val.declarations:
parts.append(f".{cn}{{{style_val.declarations}}}")
# Pseudo-class rules
for sel, decls in style_val.pseudo_rules:
if sel.startswith("::"):
parts.append(f".{cn}{sel}{{{decls}}}")
elif "&" in sel:
# group-hover pattern: ":is(.group:hover) &" → .group:hover .sx-abc
expanded = sel.replace("&", f".{cn}")
parts.append(f"{expanded}{{{decls}}}")
else:
parts.append(f".{cn}{sel}{{{decls}}}")
# Media-query rules
for query, decls in style_val.media_rules:
parts.append(f"@media {query}{{.{cn}{{{decls}}}}}")
# Keyframes
for _name, kf_rule in style_val.keyframes:
parts.append(kf_rule)
rule_text = "".join(parts)
order = len(_RULE_ORDER) + 10000 # after all tw.css rules
_REGISTRY[cn] = rule_text
_RULE_ORDER[cn] = order
def registry_loaded() -> bool:
"""True if the registry has been populated."""
return bool(_REGISTRY)