Keep a loop item's property from being read as a prop of the same name
A component that renders a list, such as FeatureGrid, passes each item
into a child: title={item.title || item.label || "Feature"}. The
compiler decided whether that attribute needed a client binding by
searching the expression for each prop name, so `item.label` matched the
grid's own `label` prop and a binding was emitted.
On hydration the binding is re-evaluated where the loop item is out of
scope, so the expression fell through to its default and replaced the
server's value: every card's title became "Feature". A name after a dot
belongs to whatever precedes it, so it no longer counts as a reference.
Timeline headings follow the same idea: its items were always h4, which
skipped a level and broke the heading order of a page that gives the
timeline no title of its own. They now take h3 in that case.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a4a31032b9
commit
a154e6c26e
3 files changed
+57
-10
No files matched your search
@@ -1174,6 +1174,38 @@ test("nested component props retain parent-owned reactive bindings", () => {
|
||||
expect(output).toContain("["value","{count}"]");
|
||||
expect(output).toContain('lowerName.startsWith("data-wrn-prop-bind-")');
|
||||
});
|
||||
test("a loop item's property is not mistaken for a prop of the same name", () => {
|
||||
// `item.label` reads the loop item, not this component's `label` prop. A
|
||||
// client binding here would be re-evaluated with the item out of scope, so
|
||||
// the card would fall back to its default and lose the rendered value.
|
||||
const output = generate(
|
||||
parse(`component Grid {
|
||||
props { items = [] label = "Features" }
|
||||
view {
|
||||
{#each items as item}
|
||||
<Card title={item.title || item.label || "Feature"} />
|
||||
{/each}
|
||||
}
|
||||
}`),
|
||||
);
|
||||
|
||||
// The helper boilerplate mentions the prefix, so match an emitted binding.
|
||||
expect(output).not.toContain("data-wrn-prop-bind-0");
|
||||
});
|
||||
test("a prop read directly still gets a parent-owned binding inside a loop", () => {
|
||||
const output = generate(
|
||||
parse(`component Grid {
|
||||
props { items = [] label = "Features" }
|
||||
view {
|
||||
{#each items as item}
|
||||
<Card title={label} />
|
||||
{/each}
|
||||
}
|
||||
}`),
|
||||
);
|
||||
|
||||
expect(output).toContain("data-wrn-prop-bind-0");
|
||||
});
|
||||
test("component functions are available during server rendering", () => {
|
||||
const output = generate(
|
||||
parse(`
|
||||
|
||||
Reference in new issue
Block a user