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

@@ -456,14 +456,18 @@ def sx_call(component_name: str, **kwargs: Any) -> str:
def components_for_request(source: str = "") -> str:
def components_for_request(source: str = "",
extra_names: set[str] | None = None) -> str:
"""Return defcomp/defmacro source for definitions the client doesn't have yet.
Reads the ``SX-Components`` header (comma-separated component names
like ``~card,~nav-item``) and returns only the definitions the client
is missing. If *source* is provided, only sends components needed
for that source (plus transitive deps). If the header is absent,
returns all needed defs.
for that source (plus transitive deps).
*extra_names* — additional component names to include beyond what
*source* references. Used by defpage to send components the page's
content expression needs for client-side routing.
"""
from quart import request
from .jinja_bridge import _COMPONENT_ENV
@@ -477,6 +481,12 @@ def components_for_request(source: str = "") -> str:
else:
needed = None # all
# Merge in extra names (e.g. from page content expression deps)
if extra_names and needed is not None:
needed = needed | extra_names
elif extra_names:
needed = extra_names
loaded_raw = request.headers.get("SX-Components", "")
loaded = set(loaded_raw.split(",")) if loaded_raw else set()
@@ -510,7 +520,8 @@ def components_for_request(source: str = "") -> str:
def sx_response(source: str, status: int = 200,
headers: dict | None = None):
headers: dict | None = None,
extra_component_names: set[str] | None = None):
"""Return an s-expression wire-format response.
Takes a raw sx string::
@@ -520,6 +531,10 @@ def sx_response(source: str, status: int = 200,
For SX requests, missing component definitions are prepended as a
``<script type="text/sx" data-components>`` block so the client
can process them before rendering OOB content.
*extra_component_names* — additional component names to include beyond
what *source* references. Used by defpage to send components the page's
content expression needs for client-side routing.
"""
from quart import request, Response
@@ -535,7 +550,7 @@ def sx_response(source: str, status: int = 200,
# For SX requests, prepend missing component definitions
comp_defs = ""
if request.headers.get("SX-Request"):
comp_defs = components_for_request(source)
comp_defs = components_for_request(source, extra_names=extra_component_names)
if comp_defs:
body = (f'<script type="text/sx" data-components>'
f'{comp_defs}</script>\n{body}')