diff --git a/.changeset/rich-cobras-exist.md b/.changeset/rich-cobras-exist.md new file mode 100644 index 0000000000..ca560d0e63 --- /dev/null +++ b/.changeset/rich-cobras-exist.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: simplify event delegation logic, only delegate event attributes diff --git a/packages/svelte/src/compiler/phases/1-parse/state/element.js b/packages/svelte/src/compiler/phases/1-parse/state/element.js index 6f90809596..5f2eda1f17 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -128,8 +128,7 @@ export default function tag(parser) { fragment: create_fragment(true), metadata: { svg: false, - has_spread: false, - can_delegate_events: null + has_spread: false }, parent: null } diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 1789afc5f3..0c207f9508 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -59,27 +59,23 @@ function get_component_name(filename) { } /** - * @param {Pick & { type: string }} node + * Checks if given event attribute can be delegated/hoisted and returns the corresponding info if so + * @param {string} event_name + * @param {import('estree').Expression | null} handler * @param {import('./types').Context} context * @returns {null | import('#compiler').DelegatedEvent} */ -function get_delegated_event(node, context) { - const handler = node.expression; - const event_name = node.name; - +function get_delegated_event(event_name, handler, context) { // Handle delegated event handlers. Bail-out if not a delegated event. - if (!handler || node.modifiers.includes('capture') || !DelegatedEvents.includes(event_name)) { + if (!handler || !DelegatedEvents.includes(event_name)) { return null; } + // If we are not working with a RegularElement, then bail-out. const element = context.path.at(-1); if (element?.type !== 'RegularElement') { return null; } - // If element says we can't delegate because we have multiple OnDirectives of the same type, bail-out. - if (!element.metadata.can_delegate_events) { - return null; - } /** @type {import('#compiler').DelegatedEvent} */ const non_hoistable = { type: 'non-hoistable' }; @@ -87,7 +83,7 @@ function get_delegated_event(node, context) { let target_function = null; let binding = null; - if (node.type === 'Attribute' && element.metadata.has_spread) { + if (element.metadata.has_spread) { // event attribute becomes part of the dynamic spread array return non_hoistable; } @@ -123,8 +119,7 @@ function get_delegated_event(node, context) { if (element && event_name) { if ( element.type !== 'RegularElement' || - !determine_element_spread_and_delegatable(element).metadata.can_delegate_events || - (element.metadata.has_spread && node.type === 'Attribute') || + determine_element_spread(element).metadata.has_spread || !DelegatedEvents.includes(event_name) ) { return non_hoistable; @@ -183,7 +178,8 @@ function get_delegated_event(node, context) { ) { return non_hoistable; } - // If we referebnce the index within an each block, then bail-out. + + // If we reference the index within an each block, then bail-out. if (binding !== null && binding.initial?.type === 'EachBlock') { return non_hoistable; } @@ -204,6 +200,7 @@ function get_delegated_event(node, context) { } visited_references.add(reference); } + return { type: 'hoistable', function: target_function }; } @@ -858,21 +855,9 @@ const common_visitors = { }); if (is_event_attribute(node)) { - /** @type {string[]} */ - const modifiers = []; const expression = node.value[0].expression; - let name = node.name.slice(2); - - if (is_capture_event(name)) { - name = name.slice(0, -7); - modifiers.push('capture'); - } - - const delegated_event = get_delegated_event( - { type: node.type, name, expression, modifiers }, - context - ); + const delegated_event = get_delegated_event(node.name.slice(2), expression, context); if (delegated_event !== null) { if (delegated_event.type === 'hoistable') { @@ -1032,18 +1017,6 @@ const common_visitors = { ) }; }, - OnDirective(node, context) { - node.metadata = { delegated: null }; - context.next(); - const delegated_event = get_delegated_event(node, context); - - if (delegated_event !== null) { - if (delegated_event.type === 'hoistable') { - delegated_event.function.metadata.hoistable = true; - } - node.metadata.delegated = delegated_event; - } - }, ArrowFunctionExpression: function_visitor, FunctionExpression: function_visitor, FunctionDeclaration: function_visitor, @@ -1052,7 +1025,7 @@ const common_visitors = { node.metadata.svg = true; } - determine_element_spread_and_delegatable(node); + determine_element_spread(node); // Special case: Move the children of