From bd70ab621c237d00597d409fff2ad84ec8bc98a2 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Mon, 30 Mar 2026 10:33:36 +0200 Subject: [PATCH] fix: events dom access --- .../internal/client/dom/elements/events.js | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index e598a78949..23022170eb 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -11,6 +11,14 @@ import { set_active_reaction } from '../../runtime.js'; import { without_reactive_context } from './bindings/shared.js'; +import { + remove_attribute, + dispatch_event, + add_event_listener, + remove_event_listener, + get_parent_node +} from '../operations.js'; +import { renderer } from '../../custom-renderer/state.js'; /** * Used on elements, as a map of event type -> event handler, @@ -30,10 +38,11 @@ export const root_event_handles = new Set(); * @param {HTMLElement} dom */ export function replay_events(dom) { + // custom renderers safe since it immediately returns if not hydrating if (!hydrating) return; - dom.removeAttribute('onload'); - dom.removeAttribute('onerror'); + remove_attribute(dom, 'onload'); + remove_attribute(dom, 'onerror'); // @ts-expect-error const event = dom.__e; if (event !== undefined) { @@ -41,7 +50,7 @@ export function replay_events(dom) { dom.__e = undefined; queueMicrotask(() => { if (dom.isConnected) { - dom.dispatchEvent(event); + dispatch_event(dom, event); } }); } @@ -79,10 +88,10 @@ export function create_event(event_name, dom, handler, options = {}) { event_name === 'wheel' ) { queue_micro_task(() => { - dom.addEventListener(event_name, target_handler, options); + add_event_listener(dom, event_name, target_handler, options); }); } else { - dom.addEventListener(event_name, target_handler, options); + add_event_listener(dom, event_name, target_handler, options); } return target_handler; @@ -102,7 +111,7 @@ export function on(element, type, handler, options = {}) { var target_handler = create_event(type, element, handler, options); return () => { - element.removeEventListener(type, target_handler, options); + remove_event_listener(element, type, target_handler, options); }; } @@ -119,16 +128,18 @@ export function event(event_name, dom, handler, capture, passive) { var target_handler = create_event(event_name, dom, handler, options); if ( - dom === document.body || - // @ts-ignore - dom === window || - // @ts-ignore - dom === document || - // Firefox has quirky behavior, it can happen that we still get "canplay" events when the element is already removed - dom instanceof HTMLMediaElement + // if there's a renderer we will never add to body, window or document. + renderer == null && + (dom === document.body || + // @ts-ignore + dom === window || + // @ts-ignore + dom === document || + // Firefox has quirky behavior, it can happen that we still get "canplay" events when the element is already removed + dom instanceof HTMLMediaElement) ) { teardown(() => { - dom.removeEventListener(event_name, target_handler, options); + remove_event_listener(dom, event_name, target_handler, options); }); } } @@ -171,6 +182,7 @@ let last_propagated_event = null; * @returns {void} */ export function handle_event_propagation(event) { + // this function is custom renderers safe since it's invoked in `mount` var handler_element = this; var owner_document = /** @type {Node} */ (handler_element).ownerDocument; var event_name = event.type; @@ -260,7 +272,7 @@ export function handle_event_propagation(event) { /** @type {null | Element} */ var parent_element = current_target.assignedSlot || - current_target.parentNode || + get_parent_node(current_target) || /** @type {any} */ (current_target).host || null;