Update reference docs: fix event names, add demos, document sx-boost target

- Remove sx:afterSettle (not dispatched), rename sx:sendError → sx:requestError
- Add sx:clientRoute event (Phase 3 client-side routing)
- Add working demos for all 10 events (afterRequest, afterSwap, requestError,
  clientRoute, sseOpen, sseMessage, sseError were missing demos)
- Update sx-boost docs: configurable target selector, client routing behavior
- Remove app-specific nav logic from orchestration.sx, use sx:clientRoute event
- Pass page content deps to sx_response for component loading after server fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 23:12:38 +00:00
parent b9003eacb2
commit eee2954559
9 changed files with 333 additions and 117 deletions

View File

@@ -424,7 +424,8 @@
:class "text-violet-600 hover:text-violet-800 underline text-sm"
"sx-target"))
(p :class "text-xs text-stone-400"
"These links use AJAX navigation via sx-boost — no sx-get needed on each link.")))
"These links use AJAX navigation via sx-boost — no sx-get needed on each link. "
"Set the value to a CSS selector (e.g. sx-boost=\"#main-panel\") to configure the default swap target for all descendants.")))
;; ---------------------------------------------------------------------------
;; sx-preload
@@ -727,19 +728,42 @@
"Request is cancelled via preventDefault() if the input is empty.")))
;; ---------------------------------------------------------------------------
;; sx:afterSettle event demo
;; sx:afterRequest event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-after-settle-demo ()
(defcomp ~ref-event-after-request-demo ()
(div :class "space-y-3"
(button
:sx-get "/reference/api/time"
:sx-target "#ref-evt-ar-result"
:sx-swap "innerHTML"
:sx-on:sx:afterRequest "document.getElementById('ref-evt-ar-log').textContent = 'Response status: ' + (event.detail ? event.detail.status : '?')"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Load (logs after response)")
(div :id "ref-evt-ar-log"
:class "p-2 rounded bg-emerald-50 text-emerald-700 text-sm"
"Event log will appear here.")
(div :id "ref-evt-ar-result"
:class "p-3 rounded bg-stone-100 text-stone-400 text-sm"
"Click to load — afterRequest fires before the swap.")))
;; ---------------------------------------------------------------------------
;; sx:afterSwap event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-after-swap-demo ()
(div :class "space-y-3"
(button
:sx-get "/reference/api/swap-item"
:sx-target "#ref-evt-settle-list"
:sx-target "#ref-evt-as-list"
:sx-swap "beforeend"
:sx-on:sx:afterSettle "var items = document.querySelectorAll('#ref-evt-settle-list > div'); if (items.length) items[items.length-1].scrollIntoView({behavior:'smooth'})"
:sx-on:sx:afterSwap "var items = document.querySelectorAll('#ref-evt-as-list > div'); if (items.length) items[items.length-1].scrollIntoView({behavior:'smooth'}); document.getElementById('ref-evt-as-count').textContent = items.length + ' items'"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Add item (scrolls after settle)")
(div :id "ref-evt-settle-list"
"Add item (scrolls after swap)")
(div :id "ref-evt-as-count"
:class "text-sm text-emerald-700"
"1 items")
(div :id "ref-evt-as-list"
:class "p-3 rounded border border-stone-200 space-y-1 max-h-32 overflow-y-auto"
(div :class "text-sm text-stone-500" "Items will be appended and scrolled into view."))))
@@ -791,3 +815,102 @@
(div :id "ref-evt-vf-result"
:class "p-3 rounded bg-stone-100 text-stone-400 text-sm"
"Submit with empty/invalid email to trigger the event.")))
;; ---------------------------------------------------------------------------
;; sx:requestError event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-request-error-demo ()
(div :class "space-y-3"
(button
:sx-get "https://this-domain-does-not-exist.invalid/api"
:sx-target "#ref-evt-re-result"
:sx-swap "innerHTML"
:sx-on:sx:requestError "document.getElementById('ref-evt-re-status').style.display = 'block'; document.getElementById('ref-evt-re-status').textContent = 'Network error — request never reached a server'"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Request invalid domain")
(div :id "ref-evt-re-status"
:class "p-2 rounded bg-red-50 text-red-600 text-sm"
:style "display: none"
"")
(div :id "ref-evt-re-result"
:class "p-3 rounded bg-stone-100 text-stone-400 text-sm"
"Click to trigger a network error — sx:requestError fires.")))
;; ---------------------------------------------------------------------------
;; sx:clientRoute event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-client-route-demo ()
(div :class "space-y-3"
(p :class "text-sm text-stone-600"
"Open DevTools console, then navigate to a pure page (no :data expression). "
"You'll see \"sx:route client /path\" in the console — no network request is made.")
(div :class "flex gap-2 flex-wrap"
(a :href "/essays/"
:class "px-3 py-1 bg-violet-100 text-violet-700 rounded text-sm no-underline hover:bg-violet-200"
"Essays")
(a :href "/plans/"
:class "px-3 py-1 bg-violet-100 text-violet-700 rounded text-sm no-underline hover:bg-violet-200"
"Plans")
(a :href "/protocols/"
:class "px-3 py-1 bg-violet-100 text-violet-700 rounded text-sm no-underline hover:bg-violet-200"
"Protocols"))
(p :class "text-xs text-stone-400"
"The sx:clientRoute event fires on the swap target and bubbles to document.body. "
"Apps use it to update nav selection, analytics, or other post-navigation state.")))
;; ---------------------------------------------------------------------------
;; sx:sseOpen event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-sse-open-demo ()
(div :class "space-y-3"
(div :sx-sse "/reference/api/sse-time"
:sx-sse-swap "time"
:sx-swap "innerHTML"
:sx-on:sx:sseOpen "document.getElementById('ref-evt-sseopen-status').textContent = 'Connected'; document.getElementById('ref-evt-sseopen-status').className = 'inline-block px-2 py-0.5 rounded text-xs bg-emerald-100 text-emerald-700'"
(div :class "flex items-center gap-3"
(span :id "ref-evt-sseopen-status"
:class "inline-block px-2 py-0.5 rounded text-xs bg-amber-100 text-amber-700"
"Connecting...")
(span :class "text-sm text-stone-500" "SSE stream")))
(p :class "text-xs text-stone-400"
"The status badge turns green when the SSE connection opens.")))
;; ---------------------------------------------------------------------------
;; sx:sseMessage event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-sse-message-demo ()
(div :class "space-y-3"
(div :sx-sse "/reference/api/sse-time"
:sx-sse-swap "time"
:sx-swap "innerHTML"
:sx-on:sx:sseMessage "var c = parseInt(document.getElementById('ref-evt-ssemsg-count').dataset.count || '0') + 1; document.getElementById('ref-evt-ssemsg-count').dataset.count = c; document.getElementById('ref-evt-ssemsg-count').textContent = c + ' messages received'"
(div :id "ref-evt-ssemsg-output"
:class "p-3 rounded bg-stone-100 text-stone-600 text-sm font-mono"
"Waiting for SSE messages..."))
(div :id "ref-evt-ssemsg-count"
:class "text-sm text-emerald-700"
:data-count "0"
"0 messages received")))
;; ---------------------------------------------------------------------------
;; sx:sseError event demo
;; ---------------------------------------------------------------------------
(defcomp ~ref-event-sse-error-demo ()
(div :class "space-y-3"
(div :sx-sse "/reference/api/sse-time"
:sx-sse-swap "time"
:sx-swap "innerHTML"
:sx-on:sx:sseError "document.getElementById('ref-evt-sseerr-status').textContent = 'Disconnected'; document.getElementById('ref-evt-sseerr-status').className = 'inline-block px-2 py-0.5 rounded text-xs bg-red-100 text-red-700'"
:sx-on:sx:sseOpen "document.getElementById('ref-evt-sseerr-status').textContent = 'Connected'; document.getElementById('ref-evt-sseerr-status').className = 'inline-block px-2 py-0.5 rounded text-xs bg-emerald-100 text-emerald-700'"
(div :class "flex items-center gap-3"
(span :id "ref-evt-sseerr-status"
:class "inline-block px-2 py-0.5 rounded text-xs bg-amber-100 text-amber-700"
"Connecting...")
(span :class "text-sm text-stone-500" "SSE stream")))
(p :class "text-xs text-stone-400"
"If the SSE connection drops, the badge turns red via sx:sseError.")))