Level 2-3: lake morphing — server content flows through reactive islands
Lake tag (lake :id "name" children...) creates server-morphable slots within islands. During morph, the engine enters hydrated islands and updates data-sx-lake elements by ID while preserving surrounding reactive DOM (signals, effects, event listeners). Specced in .sx, bootstrapped to JS and Python: - adapter-dom.sx: render-dom-lake, reactive-attr marks data-sx-reactive-attrs - adapter-html.sx: render-html-lake SSR output - adapter-sx.sx: lake serialized in wire format - engine.sx: morph-island-children (lake-by-ID matching), sync-attrs skips reactive attributes - ~sx-header uses lakes for logo and copyright - Hegelian essay updated with lake code example Also includes: lambda nil-padding for missing args, page env ordering fix Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -469,6 +469,38 @@ def _render_island(island: Island, args: list, env: dict[str, Any]) -> str:
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def _render_lake(args: list, env: dict[str, Any]) -> str:
|
||||
"""Render a server-morphable lake slot.
|
||||
|
||||
(lake :id "name" :tag "div" children...)
|
||||
→ <div data-sx-lake="name">children</div>
|
||||
|
||||
Lakes are server territory inside reactive islands. During morph,
|
||||
the server can update lake content while surrounding reactive DOM
|
||||
is preserved.
|
||||
"""
|
||||
lake_id = ""
|
||||
lake_tag = "div"
|
||||
children: list[Any] = []
|
||||
i = 0
|
||||
while i < len(args):
|
||||
arg = args[i]
|
||||
if isinstance(arg, Keyword) and i + 1 < len(args):
|
||||
kname = arg.name
|
||||
kval = _eval(args[i + 1], env)
|
||||
if kname == "id":
|
||||
lake_id = str(kval) if kval is not None and kval is not NIL else ""
|
||||
elif kname == "tag":
|
||||
lake_tag = str(kval) if kval is not None and kval is not NIL else "div"
|
||||
i += 2
|
||||
else:
|
||||
children.append(arg)
|
||||
i += 1
|
||||
|
||||
body = "".join(_render(c, env) for c in children)
|
||||
return f'<{lake_tag} data-sx-lake="{_escape_attr(lake_id)}">{body}</{lake_tag}>'
|
||||
|
||||
|
||||
def _render_list(expr: list, env: dict[str, Any]) -> str:
|
||||
"""Render a list expression — could be an HTML element, special form,
|
||||
component call, or data list."""
|
||||
@@ -494,6 +526,10 @@ def _render_list(expr: list, env: dict[str, Any]) -> str:
|
||||
if name == "<>":
|
||||
return "".join(_render(child, env) for child in expr[1:])
|
||||
|
||||
# --- lake → server-morphable slot within island -------------------
|
||||
if name == "lake":
|
||||
return _render_lake(expr[1:], env)
|
||||
|
||||
# --- html: prefix → force tag rendering --------------------------
|
||||
if name.startswith("html:"):
|
||||
return _render_element(name[5:], expr[1:], env)
|
||||
|
||||
Reference in New Issue
Block a user