From 37bf4452f59443a3c17a8d61157574380bc50023 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 2 Apr 2026 09:30:25 +0200 Subject: [PATCH] fix: event listeners in spread --- .../client/dom/elements/attributes.js | 8 ++--- .../samples/event-handler-spread/_config.js | 29 +++++++++++++++++++ .../samples/event-handler-spread/main.svelte | 13 +++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 packages/svelte/tests/custom-renderers/samples/event-handler-spread/_config.js create mode 100644 packages/svelte/tests/custom-renderers/samples/event-handler-spread/main.svelte diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index ab34fe98d2..e1c3d805dc 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -395,7 +395,7 @@ function set_attributes( const opts = {}; const event_handle_key = '$$' + key; let event_name = key.slice(2); - var is_delegated = can_delegate_event(event_name); + var is_delegated = renderer == null && can_delegate_event(event_name); if (is_capture_event(event_name)) { event_name = event_name.slice(0, -7); @@ -419,10 +419,10 @@ function set_attributes( } else if (value != null) { /** * @this {any} - * @param {Event} evt + * @param {...any} args */ - function handle(evt) { - current[key].call(this, evt); + function handle(...args) { + current[key].apply(this, args); } current[event_handle_key] = create_event(event_name, element, handle, opts); diff --git a/packages/svelte/tests/custom-renderers/samples/event-handler-spread/_config.js b/packages/svelte/tests/custom-renderers/samples/event-handler-spread/_config.js new file mode 100644 index 0000000000..ebcd14cc16 --- /dev/null +++ b/packages/svelte/tests/custom-renderers/samples/event-handler-spread/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '

0

', + test({ assert, target, serialize, logs }) { + const button = target.children.find( + (/** @type {any} */ n) => n.type === 'element' && n.name === 'button' + ); + assert.ok(button); + + const listeners = button.listeners?.click; + assert.ok(listeners, 'button should have click listeners'); + + // Call the handler with multiple arguments. + // Custom renderers may pass multiple arguments to event handlers, + // so we need to make sure all arguments are forwarded through spreads too. + for (const { handler } of listeners) { + handler.call(button, { type: 'click' }, 'extra', 42); + } + flushSync(); + + const html = serialize(target); + assert.equal(html, '

1

'); + + // Verify all arguments were forwarded to the actual handler + assert.deepEqual(logs, [{ type: 'click' }, 'extra', 42]); + } +}); diff --git a/packages/svelte/tests/custom-renderers/samples/event-handler-spread/main.svelte b/packages/svelte/tests/custom-renderers/samples/event-handler-spread/main.svelte new file mode 100644 index 0000000000..eed8edde6f --- /dev/null +++ b/packages/svelte/tests/custom-renderers/samples/event-handler-spread/main.svelte @@ -0,0 +1,13 @@ + + + +

{count}