diff --git a/.changeset/tame-spies-drum.md b/.changeset/tame-spies-drum.md new file mode 100644 index 0000000000..f22ed7ab62 --- /dev/null +++ b/.changeset/tame-spies-drum.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: improve event handling compatibility with delegation diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 6783603eae..bb1650748e 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -319,7 +319,15 @@ export function event(event_name, dom, handler, capture, passive) { capture, passive }; - const target_handler = handler; + /** + * @this {EventTarget} + */ + function target_handler(/** @type {Event} */ event) { + handle_event_propagation(dom, event); + if (!event.cancelBubble) { + return handler.call(this, event); + } + } dom.addEventListener(event_name, target_handler, options); // @ts-ignore if (dom === document.body || dom === window || dom === document) { diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/_config.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/_config.js new file mode 100644 index 0000000000..262240f5f3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + const [b1] = target.querySelectorAll('button'); + + flushSync(() => { + b1?.click(); + }); + + await Promise.resolve(); + assert.deepEqual(log, ['clicked button']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/log.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/main.svelte new file mode 100644 index 0000000000..dc5fdd214e --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-2/main.svelte @@ -0,0 +1,8 @@ + +
{ log.push('clicked div') }}> + +
diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/_config.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/_config.js new file mode 100644 index 0000000000..262240f5f3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + const [b1] = target.querySelectorAll('button'); + + flushSync(() => { + b1?.click(); + }); + + await Promise.resolve(); + assert.deepEqual(log, ['clicked button']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/log.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/main.svelte new file mode 100644 index 0000000000..4cead08260 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation-3/main.svelte @@ -0,0 +1,13 @@ + +
log.push('clicked container')} onkeydown={() => {}}> +
{ log.push('clicked div 1') }}> +
{ log.push('clicked div 2') }}> + +
+
+
diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/_config.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/_config.js new file mode 100644 index 0000000000..b1f5931a1e --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + const [b1] = target.querySelectorAll('button'); + + flushSync(() => { + b1?.click(); + }); + + await Promise.resolve(); + assert.deepEqual(log, [ + 'clicked button', + 'clicked div 2', + 'clicked div 1', + 'clicked container' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/log.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/main.svelte new file mode 100644 index 0000000000..8d3ac9fcc0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-delegation/main.svelte @@ -0,0 +1,13 @@ + +
log.push('clicked container')} onkeydown={() => {}}> +
{ log.push('clicked div 1') }}> +
{ log.push('clicked div 2') }}> + +
+
+