Skip to content

fix(core): handlers inside each lose their loop variables in the headless runtime - #142

Merged
DevRohit06 merged 1 commit into
mainfrom
fix/headless-loop-context
Sep 27, 2026
Merged

DevRohit06 merged 1 commit into
mainfrom
fix/headless-loop-context

Conversation

@DevRohit06

Copy link
Copy Markdown
Member

A button inside an each whose handler uses {item.id} works in NodeRenderer but writes an empty value in the headless runtime.

resolveTree expands the loop with item and index in scope, so props come out right. The loop variables weren't kept on the resolved node, though, and runtime.dispatch resolved handlers against {state, data} only. By the time a handler runs, the loop that produced the node is gone.

The fix:

  • ResolvedNode.loop holds the loop variables, and only nodes resolved inside an each get it. Every other node is byte-for-byte what it was.
  • dispatch layers node.loop back into the resolver context.
  • dispatchHandler takes an optional loop argument, so both paths share one context builder.

Tests: a two-row list where the test clicks the second row and expects b:1 (it got ':' before the fix; a one-row list could pass by accident), plus a check that nodes outside a loop carry no loop. The core suite passes (298), tsc is clean, and the svelte package's state-parity test passes.

🤖 Generated with Claude Code

…less runtime

resolveTree expands an each into one copy of its children per item, with
item and index in scope while props resolve. It didn't keep them on the node,
and dispatch resolved handlers against state and data only. A button in a list
with on_click setting '{item.id}' wrote an empty value. NodeRenderer passes
loop context to handlers, so the headless runtime disagreed with it.

Nodes resolved inside a loop now carry a loop field, and dispatch layers it
back into the resolver context. Nodes outside a loop are unchanged.
dispatchHandler takes an optional loop argument for the same reason.

The new test clicks the second of two rows, since a one-row loop could pass
by accident.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@DevRohit06
DevRohit06 added this pull request to stack #144 September 27, 2026 05:37
@DevRohit06
DevRohit06 merged commit e0c9152 into main Sep 27, 2026
1 check passed
@DevRohit06
DevRohit06 deleted the fix/headless-loop-context branch September 27, 2026 08:18
DevRohit06 added a commit that referenced this pull request Sep 27, 2026
…145)

Bumps @ripple-ui/svelte to 0.8.0 and @ripple-ui/core to 0.6.0 for the
release that carries the slim headless runtime, the slim manifest and the
loop-variable fix for headless handlers (#142, #143).

The release workflow used to try npm on every v* tag. Every such run failed
without an NPM_TOKEN, and with a token set anywhere a tag would publish
whether or not that was intended. npm publishing now runs only on a manual
dispatch with publish_npm: true. A tag creates the GitHub release alone.

That release now carries a packed tarball of each package next to the
manifest bundle, with svelte's core dependency rewritten to ^<core version>
as the npm step does, so it can be installed without npm. Simulated on a copy
of both packages: ripple-ui-core-0.6.0.tgz and ripple-ui-svelte-0.8.0.tgz,
the latter depending on @ripple-ui/core ^0.6.0.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant