Skip to content

Commit d18628a

Browse files
committed
fix: don't hoist snippets with bind:group
1 parent 2aefc54 commit d18628a

File tree

5 files changed

+44
-1
lines changed

5 files changed

+44
-1
lines changed

.changeset/lazy-carrots-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: don't hoist snippets with `bind:group`

packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ export function BindDirective(node, context) {
199199
throw new Error('Cannot find declaration for bind:group');
200200
}
201201

202+
const snippet_parent = context.path.find((parent) => parent.type === 'SnippetBlock');
203+
204+
if (snippet_parent) {
205+
snippet_parent.metadata.can_hoist = false;
206+
}
207+
202208
// Traverse the path upwards and find all EachBlocks who are (indirectly) contributing to bind:group,
203209
// i.e. one of their declarations is referenced in the binding. This allows group bindings to work
204210
// correctly when referencing a variable declared in an EachBlock by using the index of the each block

packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export function SnippetBlock(node, context) {
4242
}
4343
}
4444

45-
node.metadata.can_hoist = can_hoist;
45+
node.metadata.can_hoist =
46+
node.metadata.can_hoist != null ? node.metadata.can_hoist && can_hoist : can_hoist;
4647

4748
const { path } = context;
4849
const parent = path.at(-2);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
const [radio1, radio2] = target.querySelectorAll('input');
7+
const p = target.querySelector('p');
8+
9+
assert.equal(p?.innerHTML, '');
10+
flushSync(() => {
11+
radio1.click();
12+
});
13+
assert.equal(p?.innerHTML, 'cool');
14+
flushSync(() => {
15+
radio2.click();
16+
});
17+
assert.equal(p?.innerHTML, 'cooler');
18+
}
19+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
let group = $state({ selected: undefined });
3+
</script>
4+
5+
{#snippet radio(group, value)}
6+
<input type="radio" bind:group={group.selected} {value}/>
7+
{/snippet}
8+
9+
{@render radio(group, "cool")}
10+
{@render radio(group, "cooler")}
11+
12+
<p>{group.selected}</p>

0 commit comments

Comments
 (0)