Skip to content

Commit bcc2ea9

Browse files
committed
fix: ensure event precedence when spreading event attributes
1 parent 7ab03ae commit bcc2ea9

File tree

6 files changed

+45
-2
lines changed

6 files changed

+45
-2
lines changed

packages/svelte/src/compiler/phases/3-transform/client/types.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ export interface ComponentClientTransformState extends ClientTransformState {
4242
/** Used if condition for singular prop is false (see comment above) */
4343
grouped: Statement;
4444
}[];
45-
/** Stuff that happens after the render effect (bindings, events, actions) */
45+
/** Stuff that happens just before the render effect (events) */
46+
readonly before_update: Statement[];
47+
/** Stuff that happens after the render effect (bindings, actions) */
4648
readonly after_update: Statement[];
4749
/** The HTML template string */
4850
readonly template: string[];

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ function create_block(parent, name, nodes, context) {
954954
init: [],
955955
update: [],
956956
update_effects: [],
957+
before_update: [],
957958
after_update: [],
958959
template: [],
959960
metadata: {
@@ -1035,6 +1036,8 @@ function create_block(parent, name, nodes, context) {
10351036
}
10361037
}
10371038

1039+
body.push(...state.before_update);
1040+
10381041
if (state.update.length > 0 || state.update_effects.length > 0) {
10391042
/** @type {import('estree').Statement | undefined} */
10401043
let update;
@@ -1220,7 +1223,7 @@ function serialize_event(node, context) {
12201223
delegated_assignment = handler;
12211224
}
12221225

1223-
state.after_update.push(
1226+
state.before_update.push(
12241227
b.stmt(
12251228
b.assignment(
12261229
'=',
@@ -1951,6 +1954,7 @@ export const template_visitors = {
19511954
init: [],
19521955
update: [],
19531956
update_effects: [],
1957+
before_update: [],
19541958
after_update: []
19551959
}
19561960
};
@@ -1998,6 +2002,7 @@ export const template_visitors = {
19982002

19992003
/** @type {import('estree').Statement[]} */
20002004
const inner = inner_context.state.init;
2005+
inner.push(...inner_context.state.before_update);
20012006
if (inner_context.state.update.length > 0 || inner_context.state.update_effects.length > 0) {
20022007
if (inner_context.state.update_effects.length > 0) {
20032008
for (const render of inner_context.state.update_effects) {

packages/svelte/src/internal/client/render.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,6 +2881,12 @@ export function spread_attributes(dom, prev, attrs, css_hash) {
28812881
dom.removeEventListener(event_name, /** @type {any} */ (prev[key]), opts);
28822882
}
28832883
if (value != null) {
2884+
const delegated_property = '__' + event_name;
2885+
// @ts-expect-error internal event property
2886+
if (dom[delegated_property]) {
2887+
// @ts-expect-error internal event property
2888+
dom[delegated_property] = undefined;
2889+
}
28842890
dom.addEventListener(event_name, value, opts);
28852891
}
28862892
} else if (value == null) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
const {log, ...restProps} = $props();
3+
</script>
4+
5+
<button onclick={() => log.push('internal!')} {...restProps}>
6+
<slot />
7+
</button>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<button>Test</button>`,
6+
7+
async test({ assert, target, component }) {
8+
const [b1] = target.querySelectorAll('button');
9+
10+
flushSync(() => {
11+
b1?.click();
12+
});
13+
14+
assert.deepEqual(component.log, ['external!']);
15+
}
16+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
import Button from "./Button.svelte";
3+
4+
const {log = []} = $props();
5+
</script>
6+
7+
<Button log={log} onclick={() => log.push('external!')}>Test</Button>

0 commit comments

Comments
 (0)