(defcomp
~geography/demo-example
(&key demo code)
(div
(~tw :tokens "grid grid-cols-1 lg:grid-cols-2 gap-4 my-6 items-start")
(div
(~tw :tokens "border border-dashed border-stone-300 rounded-lg p-4 bg-stone-50 min-h-[80px]")
demo)
(div
(~tw :tokens "not-prose bg-stone-100 rounded-lg p-4 overflow-x-auto")
(pre
(~tw :tokens "text-sm leading-relaxed whitespace-pre-wrap break-words")
(code code)))))
(defcomp
~geography/demo-callout
(&key type)
(make-spread
(cond
(= type "info")
{:data-callout "info" :style "border-left:4px solid #3b82f6;padding:0.5rem 0.75rem;background:#eff6ff;border-radius:0.25rem"}
(= type "warning")
{:data-callout "warning" :style "border-left:4px solid #f59e0b;padding:0.5rem 0.75rem;background:#fffbeb;border-radius:0.25rem"}
(= type "success")
{:data-callout "success" :style "border-left:4px solid #10b981;padding:0.5rem 0.75rem;background:#ecfdf5;border-radius:0.25rem"}
:else {:data-callout "default" :style "border-left:4px solid #78716c;padding:0.5rem 0.75rem;background:#fafaf9;border-radius:0.25rem"})))
(defcomp
~geography/demo-spread-basic
()
(div
(~tw :tokens "space-y-3")
(div
(~geography/demo-callout :type "info")
(p (~tw :tokens "text-sm") "Info — styled by its child."))
(div
(~geography/demo-callout :type "warning")
(p (~tw :tokens "text-sm") "Warning — same component, different type."))
(div
(~geography/demo-callout :type "success")
(p (~tw :tokens "text-sm") "Success — child tells parent how to look."))))
(defcomp
~geography/demo-cssx-tw
()
(div
(~tw :tokens "space-y-3")
(div
(~tw :tokens "bg-violet-100 rounded-lg p-4")
(h4
(~tw :tokens "text-violet-800 font-semibold text-lg")
"Styled via ~cssx/tw")
(p
(~tw :tokens "text-stone-600 text-sm mt-1")
"Classes injected from spread child."))
(div
(~tw :tokens "bg-rose-50 rounded-lg p-4 border border-rose-200")
(h4
(~tw :tokens "text-rose-700 font-semibold text-lg")
"Different tokens")
(p
(~tw :tokens "text-stone-600 text-sm mt-1")
"CSS rules JIT-generated. No build step."))))
(defcomp
~geography/demo-semantic-vars
()
(let
((card (~tw :tokens "bg-stone-50 rounded-lg p-4 shadow-sm border border-stone-200"))
(heading (~tw :tokens "text-violet-700 text-lg font-bold"))
(body-text (~tw :tokens "text-stone-600 text-sm mt-1")))
(div
(~tw :tokens "space-y-3")
(div
card
(h4 heading "First Card")
(p body-text "Named spreads bound with let."))
(div
card
(h4 heading "Second Card")
(p body-text "Same variables, consistent look.")))))
(defisland
~geography/demo-reactive-spread
()
(let
((colour (signal "violet")))
(div
(~tw
:tokens (str
"rounded-lg p-4 transition-all duration-300 bg-"
(deref colour)
"-100 border border-"
(deref colour)
"-300"))
(h4
(~tw
:tokens (str "text-" (deref colour) "-800 font-semibold text-lg"))
(str "Theme: " (deref colour)))
(p
(~tw :tokens "text-stone-600 text-sm mt-2 mb-3")
"Click to change theme. Reactive spreads surgically update classes.")
(div
(~tw :tokens "flex gap-2 flex-wrap")
(button
:on-click (fn (e) (reset! colour "violet"))
(~tw
:tokens "bg-violet-500 text-white px-3 py-1.5 rounded text-sm font-medium")
"Violet")
(button
:on-click (fn (e) (reset! colour "rose"))
(~tw
:tokens "bg-rose-500 text-white px-3 py-1.5 rounded text-sm font-medium")
"Rose")
(button
:on-click (fn (e) (reset! colour "amber"))
(~tw
:tokens "bg-amber-500 text-white px-3 py-1.5 rounded text-sm font-medium")
"Amber")
(button
:on-click (fn (e) (reset! colour "emerald"))
(~tw
:tokens "bg-emerald-500 text-white px-3 py-1.5 rounded text-sm font-medium")
"Emerald")))))
(defcomp
~geography/spreads-content
()
(~docs/page
:title "Spreads"
(p
(~tw :tokens "text-stone-500 text-sm italic mb-8")
"A spread is a value that, when returned as a child of an element, "
"injects attributes onto its parent instead of rendering as content. "
"Internally, spreads work through "
(a
:href "/sx/(geography.(scopes))"
(~tw :tokens "text-violet-600 hover:underline")
"scopes")
" — every element creates a scope, and spread children emit into it.")
(~docs/section
:title "How it works"
:id "mechanism"
(p
"Every element wraps its children in a "
(code "provide")
" scope named "
(code "\"element-attrs\"")
". When the renderer encounters a spread child, "
"it calls "
(code "emit!")
" to push the spread's attrs into that scope. "
"After all children render, the element collects the emitted attrs and merges them. "
"This is the "
(a
:href "/sx/(geography.(provide))"
(~tw :tokens "text-violet-600 hover:underline")
"provide/emit!")
" mechanism — spreads are one instance of it.")
(p
"The user-facing API is "
(code "make-spread")
" — it creates a spread value from a dict. "
(code "spread?")
" tests for one. "
(code "spread-attrs")
" extracts the dict. "
"But the actual delivery from child to parent goes through provide/emit!, not through "
"return-value inspection.")
(~geography/demo-example
:demo (~geography/demo-spread-basic)
:code (highlight
"(defcomp ~callout (&key type)\n (make-spread\n (cond\n (= type \"info\")\n {\"style\" \"border-left:4px solid\n #3b82f6; background:#eff6ff\"}\n (= type \"warning\")\n {\"style\" \"border-left:4px solid\n #f59e0b; background:#fffbeb\"}\n (= type \"success\")\n {\"style\" \"border-left:4px solid\n #10b981; background:#ecfdf5\"})))\n\n;; Child injects attrs onto parent:\n(div (~callout :type \"info\")\n \"This div gets the callout style.\")"
"lisp"))
(p
(code "class")
" values are appended (space-joined). "
(code "style")
" values are appended (semicolon-joined). "
"All other attributes overwrite.")
(p
"Tolerant "
(code "emit!")
" means a spread outside any element context "
"(in a fragment, "
(code "begin")
", or bare "
(code "map")
") silently vanishes "
"instead of crashing — there's no provider to emit into, so it's a no-op."))
(~docs/section
:title "collect! — the other upward channel"
:id "collect"
(p
"Spreads use "
(code "scope")
"/"
(code "emit!")
" (scoped, no dedup). "
(code "collect!")
"/"
(code "collected")
" is also backed by scopes — "
"a lazy root scope with automatic deduplication. Used for CSS rule accumulation.")
(~docs/code
:src (highlight
";; Deep inside a component tree:\n(collect! \"cssx\" \".sx-bg-red-500{background:red}\")\n\n;; At the flush point (once, in the layout):\n(let ((rules (collected \"cssx\")))\n (clear-collected! \"cssx\")\n (raw! (str \"\")))"
"lisp"))
(p
"Both are upward communication through the render tree, but with different "
"semantics — "
(code "emit!")
" is scoped to the nearest provider, "
(code "collect!")
" is global and deduplicates."))
(~docs/section
:title "Reactive spreads"
:id "reactive"
(~docs/subsection
:title "reactive-spread (islands)"
(p
"Inside an island, when a spread's value depends on signals, "
(code "reactive-spread")
" tracks signal dependencies and surgically "
"updates the parent element's attributes when signals change.")
(~geography/demo-example
:demo (~geography/demo-reactive-spread)
:code (highlight
"(defisland ~themed-card ()\n (let ((theme (signal \"violet\")))\n (div (~cssx/tw :tokens\n (str \"bg-\" (deref theme)\n \"-100 p-4\"))\n (button\n :on-click\n (fn (e) (reset! theme \"rose\"))\n \"change theme\"))))"
"lisp"))
(p "When " (code "theme") " changes:")
(ul
(~tw :tokens "list-disc pl-5 space-y-1 text-stone-600")
(li "Old classes are removed from the element")
(li "New classes are added")
(li
"New CSS rules are JIT-generated and flushed to the live stylesheet")
(li "No re-render. No VDOM. No diffing. Just attr surgery."))))
(~docs/section
:title "Orthogonality across boundaries"
:id "orthogonality"
(p
"Spread (via provide/emit!), collect!, and reactive-spread operate at different "
"levels of the render pipeline. They compose without knowing about each other.")
(~docs/table
:headers (list "Primitive" "Direction" "Boundary" "When")
:rows (list
(list "spread" "child → parent" "element boundary" "render time")
(list "collect!" "child → ancestor" "render tree" "render time")
(list
"reactive-spread"
"child → parent"
"element boundary"
"signal change")))
(~docs/subsection
:title "Server rendering (HTML adapter)"
(p
"On the server, "
(code "~cssx/tw")
" returns a spread. The HTML renderer "
"merges the class onto the parent element. "
(code "collect!")
" accumulates "
"CSS rules. "
(code "~cssx/flush")
" emits a single "
(code "