(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 "