diff --git a/.changeset/fresh-impalas-bow.md b/.changeset/fresh-impalas-bow.md new file mode 100644 index 000000000000..c0f1601afeeb --- /dev/null +++ b/.changeset/fresh-impalas-bow.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: prevent window listeners from triggering events twice diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 97cb748baea8..9bcb9f107d91 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -1383,6 +1383,7 @@ export function delegate(events) { * @returns {void} */ function handle_event_propagation(handler_element, event) { + const owner_document = handler_element.ownerDocument; const event_name = event.type; const path = event.composedPath?.() || []; let current_target = /** @type {null | Element} */ (path[0] || event.target); @@ -1402,12 +1403,15 @@ function handle_event_propagation(handler_element, event) { const handled_at = event.__root; if (handled_at) { const at_idx = path.indexOf(handled_at); - if (at_idx !== -1 && handler_element === document) { - // This is the fallback document listener but the event was already handled - // -> ignore, but set handle_at to document so that we're resetting the event + if ( + at_idx !== -1 && + (handler_element === document || handler_element === /** @type {any} */ (window)) + ) { + // This is the fallback document listener or a window listener, but the event was already handled + // -> ignore, but set handle_at to document/window so that we're resetting the event // chain in case someone manually dispatches the same event object again. // @ts-expect-error - event.__root = document; + event.__root = handler_element; return; } // We're deliberately not skipping if the index is higher, because @@ -1433,8 +1437,7 @@ function handle_event_propagation(handler_element, event) { define_property(event, 'currentTarget', { configurable: true, get() { - // TODO: ensure correct document? - return current_target || document; + return current_target || owner_document; } });