Update /docs/css page with CSSX native style primitives docs

Document css primitive, style atoms, variants, defstyle, defkeyframes,
and on-demand delivery protocol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 12:50:07 +00:00
parent 19d59f5f4b
commit 0f82294dc1

View File

@@ -413,45 +413,104 @@ async def _docs_primitives_sx() -> str:
def _docs_css_sx() -> str:
c1 = _code('# First page load:\n'
'GET / HTTP/1.1\n\n'
'HTTP/1.1 200 OK\n'
'Content-Type: text/html\n'
'# Full CSS in <style id="sx-css"> + hash in <meta name="sx-css-classes">\n\n'
'# Subsequent navigation:\n'
'GET /about HTTP/1.1\n'
'SX-Css: a1b2c3d4\n\n'
'HTTP/1.1 200 OK\n'
'Content-Type: text/sx\n'
'SX-Css-Hash: e5f6g7h8\n'
'SX-Css-Add: bg-blue-500,text-white,rounded-lg\n'
'# Only new rules in <style data-sx-css>', "bash")
c_css_basic = _code(';; Native style expressions\n'
'(div :style (css :flex :gap-4 :p-2) "hello")\n'
';; => <div class="sx-faa0d2">hello</div>\n'
';; with .sx-faa0d2{display:flex;gap:1rem;padding:.5rem}\n\n'
';; Pseudo-class variants\n'
'(button :style (css :bg-sky-500 :hover:bg-sky-600 :text-white :rounded) "Click")\n\n'
';; Responsive variants\n'
'(div :style (css :flex :flex-col :sm:flex-row :gap-4) ...)\n\n'
';; Arbitrary values\n'
'(div :style (css :w-[347px] :h-[60vh] :bg-[#f0f]) ...)')
c_defstyle = _code(';; Named styles with defstyle\n'
'(defstyle card-base\n'
' (css :rounded-xl :bg-white :shadow :hover:shadow-md :transition))\n\n'
'(div :style card-base "I am a card")\n\n'
';; Composition with merge-styles\n'
'(div :style (merge-styles card-base (css :p-4 :border :border-stone-200))\n'
' "Card with extra styles")')
c_defkeyframes = _code(';; Custom keyframes\n'
'(defkeyframes fade-in\n'
' (from (css :opacity-0))\n'
' (to (css :opacity-100)))\n\n'
'(defkeyframes slide-up\n'
' ("0%" (css :translate-y-4 :opacity-0))\n'
' ("100%" (css :translate-y-0 :opacity-100)))\n\n'
';; Use with animate-{name}\n'
'(div :style (css :animate-fade-in :duration-300) "Animated")')
c_protocol = _code('# First page load:\n'
'GET / HTTP/1.1\n\n'
'HTTP/1.1 200 OK\n'
'Content-Type: text/html\n'
'# Full CSS in <style id="sx-css"> + hash in <meta name="sx-css-classes">\n\n'
'# Subsequent navigation:\n'
'GET /about HTTP/1.1\n'
'SX-Css: a1b2c3d4\n\n'
'HTTP/1.1 200 OK\n'
'Content-Type: text/sx\n'
'SX-Css-Hash: e5f6g7h8\n'
'SX-Css-Add: bg-blue-500,text-white,rounded-lg\n'
'# Only new rules in <style data-sx-css>', "bash")
c_atoms = _code(';; The css primitive accepts keyword atoms\n'
';; Each atom maps to self-contained CSS declarations:\n'
';; :flex => display:flex\n'
';; :gap-4 => gap:1rem\n'
';; :bg-sky-100 => background-color:rgb(224 242 254)\n'
';; :shadow => box-shadow:0 1px 3px 0 rgba(0,0,0,.1),...\n\n'
';; Variant prefixes are split and wrapped automatically:\n'
';; :hover:bg-sky-200 => .sx-xxx:hover{background-color:...}\n'
';; :sm:flex-row => @media (min-width:640px){.sx-xxx{...}}\n'
';; :sm:hover:bg-sky-200 => compound variant (media + pseudo)')
return (
f'(~doc-page :title "On-Demand CSS"'
f'(~doc-page :title "CSS"'
f' (~doc-section :title "Native style expressions" :id "css-primitive"'
f' (p :class "text-stone-600"'
f' "The css primitive replaces Tailwind class strings with native SX expressions. '
f'Each keyword atom maps to self-contained CSS declarations. The result is a StyleValue '
f'with a content-addressed class name (sx-{{hash}}) and generated CSS rules.")'
f' {c_css_basic})'
f' (~doc-section :title "Style atoms" :id "atoms"'
f' (p :class "text-stone-600"'
f' "~500 atoms cover all standard utilities: display, position, flexbox, grid, spacing, '
f'sizing, typography, colors, borders, shadows, transitions, animations, and more. '
f'Atoms use the same names as Tailwind classes but resolve to self-contained CSS — '
f'no --tw-* custom properties needed.")'
f' {c_atoms})'
f' (~doc-section :title "Variants" :id "variants"'
f' (p :class "text-stone-600"'
f' "Pseudo-class variants: hover, focus, focus-within, focus-visible, active, disabled, '
f'first, last, odd, even, empty, open, placeholder, group-hover, group-open. '
f'Responsive breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px), 2xl (1536px). '
f'Variants can be combined: sm:hover:bg-sky-200."))'
f' (~doc-section :title "Named styles" :id "defstyle"'
f' (p :class "text-stone-600"'
f' "defstyle binds a css expression to a name for reuse. '
f'merge-styles combines multiple StyleValues into one, with later declarations winning.")'
f' {c_defstyle})'
f' (~doc-section :title "Keyframes" :id "defkeyframes"'
f' (p :class "text-stone-600"'
f' "defkeyframes defines custom CSS @keyframes animations. Each step takes a '
f'selector (from, to, or a percentage) and a css body. The keyframes are registered '
f'globally so animate-{{name}} atoms can reference them.")'
f' {c_defkeyframes})'
f' (~doc-section :title "On-demand delivery" :id "delivery"'
f' (p :class "text-stone-600"'
f' "Generated CSS rules flow through the same on-demand delivery pipeline as Tailwind classes. '
f'On the first page load, all used CSS is embedded in a <style> block. On subsequent navigations, '
f'the client sends a hash of known classes and the server sends only new rules.")'
f' {c_protocol})'
f' (~doc-section :title "How it works" :id "how"'
f' (p :class "text-stone-600"'
f' "sx scans every response for CSS class names used in :class attributes. '
f'It looks up only those classes in a pre-parsed Tailwind CSS registry and ships '
f'just the rules that are needed. No build step. No purging. No unused CSS.")'
f' "Server-side: the css primitive resolves atoms to a StyleValue with declarations. '
f'The HTML renderer converts :style StyleValue to a class attribute and registers the CSS rule '
f'in the on-demand registry. Rules are delivered via the SX-Css delta protocol.")'
f' (p :class "text-stone-600"'
f' "On the first page load, the full set of used classes is embedded in a <style> block. '
f'A hash of the class set is stored. On subsequent navigations, the client sends the hash '
f'in the SX-Css header. The server computes the diff and sends only new rules via '
f'SX-Css-Add and a <style data-sx-css> block."))'
f' (~doc-section :title "The protocol" :id "protocol"'
f' {c1})'
f' (~doc-section :title "Advantages" :id "advantages"'
f' (ul :class "space-y-2 text-stone-600"'
f' (li "Zero build step — no Tailwind CLI, no PostCSS, no purging")'
f' (li "Exact CSS — never ships a rule that isn\'t used on the page")'
f' (li "Incremental — subsequent navigations only ship new rules")'
f' (li "Component-aware — pre-scans component definitions at registration time")))'
f' (~doc-section :title "Disadvantages" :id "disadvantages"'
f' (ul :class "space-y-2 text-stone-600"'
f' (li "Requires the full Tailwind CSS file loaded in memory at startup (~4MB parsed)")'
f' (li "Regex-based class scanning — can miss dynamically constructed class names")'
f' (li "No @apply support — classes must be used directly")'
f' (li "Tied to Tailwind\'s utility class naming conventions"))))'
f' "Client-side: the style dictionary is delivered as a JSON payload in a '
f'<script type=text/sx-styles> tag, cached in localStorage with the same hash+cookie pattern '
f'as components. The client-side css primitive mirrors the server resolver — same atoms, '
f'same variant splitting, same content-addressed class names. Generated CSS is injected '
f'into <style id=sx-css>.")))'
)