fix: don't hoist snippets with `bind:group`

dont-hoist-snippet-binding-group
paoloricciuti 8 months ago
parent 2aefc5430d
commit d18628aa2d

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: don't hoist snippets with `bind:group`

@ -199,6 +199,12 @@ export function BindDirective(node, context) {
throw new Error('Cannot find declaration for bind:group'); throw new Error('Cannot find declaration for bind:group');
} }
const snippet_parent = context.path.find((parent) => parent.type === 'SnippetBlock');
if (snippet_parent) {
snippet_parent.metadata.can_hoist = false;
}
// Traverse the path upwards and find all EachBlocks who are (indirectly) contributing to bind:group, // Traverse the path upwards and find all EachBlocks who are (indirectly) contributing to bind:group,
// i.e. one of their declarations is referenced in the binding. This allows group bindings to work // i.e. one of their declarations is referenced in the binding. This allows group bindings to work
// correctly when referencing a variable declared in an EachBlock by using the index of the each block // correctly when referencing a variable declared in an EachBlock by using the index of the each block

@ -42,7 +42,8 @@ export function SnippetBlock(node, context) {
} }
} }
node.metadata.can_hoist = can_hoist; node.metadata.can_hoist =
node.metadata.can_hoist != null ? node.metadata.can_hoist && can_hoist : can_hoist;
const { path } = context; const { path } = context;
const parent = path.at(-2); const parent = path.at(-2);

@ -0,0 +1,19 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
const [radio1, radio2] = target.querySelectorAll('input');
const p = target.querySelector('p');
assert.equal(p?.innerHTML, '');
flushSync(() => {
radio1.click();
});
assert.equal(p?.innerHTML, 'cool');
flushSync(() => {
radio2.click();
});
assert.equal(p?.innerHTML, 'cooler');
}
});

@ -0,0 +1,12 @@
<script>
let group = $state({ selected: undefined });
</script>
{#snippet radio(group, value)}
<input type="radio" bind:group={group.selected} {value}/>
{/snippet}
{@render radio(group, "cool")}
{@render radio(group, "cooler")}
<p>{group.selected}</p>
Loading…
Cancel
Save