Fix reactive islands client-side navigation and hydration
Three bugs prevented islands from working during SX wire navigation: 1. components_for_request() only bundled Component and Macro defs, not Island defs — client never received defisland definitions during navigation (components_for_page for initial HTML shell was correct). 2. hydrate-island used morph-children which can't transfer addEventListener event handlers from freshly rendered DOM to existing nodes. Changed to clear+append so reactive DOM with live signal subscriptions is inserted directly. 3. asyncRenderToDom (client-side async page eval) checked _component but not _island on ~-prefixed names — islands fell through to generic eval which failed. Now delegates to renderDomIsland. 4. setInterval_/setTimeout_ passed SX Lambda objects directly to native timers. JS coerced them to "[object Object]" and tried to eval as code, causing "missing ] after element list". Added _wrapSxFn to convert SX lambdas to JS functions before passing to timers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,7 @@ import contextvars
|
||||
import inspect
|
||||
from typing import Any
|
||||
|
||||
from .types import Component, Keyword, Lambda, Macro, NIL, Symbol
|
||||
from .types import Component, Island, Keyword, Lambda, Macro, NIL, Symbol
|
||||
|
||||
# When True, _aser expands known components server-side instead of serializing
|
||||
# them for client rendering. Set during page slot evaluation so Python-only
|
||||
@@ -1219,6 +1219,8 @@ async def _eval_slot_inner(
|
||||
if isinstance(result, str):
|
||||
return SxExpr(result)
|
||||
return SxExpr(serialize(result))
|
||||
elif isinstance(comp, Island):
|
||||
pass # Islands serialize as SX for client-side rendering
|
||||
else:
|
||||
import logging
|
||||
logging.getLogger("sx.eval").error(
|
||||
@@ -1596,6 +1598,14 @@ async def _assf_define(expr, env, ctx):
|
||||
return NIL
|
||||
|
||||
|
||||
async def _assf_defisland(expr, env, ctx):
|
||||
"""Evaluate defisland AND serialize it — client needs the definition."""
|
||||
import logging
|
||||
logging.getLogger("sx.eval").info("_assf_defisland called for: %s", expr[1] if len(expr) > 1 else expr)
|
||||
await async_eval(expr, env, ctx)
|
||||
return serialize(expr)
|
||||
|
||||
|
||||
async def _assf_lambda(expr, env, ctx):
|
||||
return await _asf_lambda(expr, env, ctx)
|
||||
|
||||
@@ -1703,7 +1713,7 @@ _ASER_FORMS: dict[str, Any] = {
|
||||
"defcomp": _assf_define,
|
||||
"defmacro": _assf_define,
|
||||
"defhandler": _assf_define,
|
||||
"defisland": _assf_define,
|
||||
"defisland": _assf_defisland,
|
||||
"begin": _assf_begin,
|
||||
"do": _assf_begin,
|
||||
"quote": _assf_quote,
|
||||
|
||||
Reference in New Issue
Block a user