Skip to content

Commit 521d124

Browse files
authored
fix: allow events to continue propagating following an error (#11263)
* fix: allow events to continue propagating following an error * test * appease eslint
1 parent 9721d56 commit 521d124

File tree

4 files changed

+70
-25
lines changed

4 files changed

+70
-25
lines changed

.changeset/light-penguins-invent.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: allow events to continue propagating following an error

packages/svelte/src/internal/client/dom/elements/events.js

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -122,36 +122,42 @@ export function handle_event_propagation(handler_element, event) {
122122
}
123123
});
124124

125-
while (current_target !== null) {
125+
/** @param {Element} current_target */
126+
function next(current_target) {
126127
/** @type {null | Element} */
127128
var parent_element =
128129
current_target.parentNode || /** @type {any} */ (current_target).host || null;
129-
var internal_prop_name = '__' + event_name;
130-
// @ts-ignore
131-
var delegated = current_target[internal_prop_name];
132-
133-
if (delegated !== undefined && !(/** @type {any} */ (current_target).disabled)) {
134-
if (is_array(delegated)) {
135-
var [fn, ...data] = delegated;
136-
fn.apply(current_target, [event, ...data]);
137-
} else {
138-
delegated.call(current_target, event);
139-
}
140-
}
141130

142-
if (
143-
event.cancelBubble ||
144-
parent_element === handler_element ||
145-
current_target === handler_element
146-
) {
147-
break;
131+
try {
132+
// @ts-expect-error
133+
var delegated = current_target['__' + event_name];
134+
135+
if (delegated !== undefined && !(/** @type {any} */ (current_target).disabled)) {
136+
if (is_array(delegated)) {
137+
var [fn, ...data] = delegated;
138+
fn.apply(current_target, [event, ...data]);
139+
} else {
140+
delegated.call(current_target, event);
141+
}
142+
}
143+
} finally {
144+
if (
145+
!event.cancelBubble &&
146+
parent_element !== handler_element &&
147+
parent_element !== null &&
148+
current_target !== handler_element
149+
) {
150+
next(parent_element);
151+
}
148152
}
149-
150-
current_target = parent_element;
151153
}
152154

153-
// @ts-expect-error is used above
154-
event.__root = handler_element;
155-
// @ts-expect-error is used above
156-
current_target = handler_element;
155+
try {
156+
next(current_target);
157+
} finally {
158+
// @ts-expect-error is used above
159+
event.__root = handler_element;
160+
// @ts-expect-error is used above
161+
current_target = handler_element;
162+
}
157163
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<div><button>0 0</button>`,
6+
7+
async test({ assert, target }) {
8+
const button1 = target.querySelector('button');
9+
10+
flushSync(() => button1?.click());
11+
assert.htmlEqual(target.innerHTML, `<div><button>1 1</button></div>`);
12+
},
13+
14+
runtime_error: 'nope'
15+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<script>
2+
let y = $state(0);
3+
let n = $state(0);
4+
5+
function yep() {
6+
y += 1;
7+
}
8+
9+
function nope() {
10+
n += 1;
11+
throw new Error('nope');
12+
}
13+
</script>
14+
15+
<div onclick={yep}>
16+
<button onclick={nope}>
17+
{y} {n}
18+
</button>
19+
</div>

0 commit comments

Comments
 (0)