diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index e626e25148..af2f8ec919 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -585,7 +585,7 @@ export default class Element extends Node { if (modifier === 'passive') { if (passiveEvents.has(handler.name)) { - if (!handler.usesEventObject) { + if (handler.canMakePassive) { component.warn(handler, { code: 'redundant-event-modifier', message: `Touch event handlers that don't use the 'event' object are passive by default` @@ -609,7 +609,7 @@ export default class Element extends Node { } }); - if (passiveEvents.has(handler.name) && !handler.usesEventObject && !handler.modifiers.has('preventDefault')) { + if (passiveEvents.has(handler.name) && handler.canMakePassive && !handler.modifiers.has('preventDefault')) { // touch/wheel events should be passive by default handler.modifiers.add('passive'); } diff --git a/src/compile/nodes/EventHandler.ts b/src/compile/nodes/EventHandler.ts index a321796c08..ab91eba23f 100644 --- a/src/compile/nodes/EventHandler.ts +++ b/src/compile/nodes/EventHandler.ts @@ -8,7 +8,8 @@ export default class EventHandler extends Node { modifiers: Set; expression: Expression; handler_name: string; - usesContext: boolean; + usesContext = false; + canMakePassive = false; constructor(component: Component, parent, template_scope, info) { super(component, parent, template_scope, info); @@ -19,6 +20,24 @@ export default class EventHandler extends Node { if (info.expression) { this.expression = new Expression(component, this, template_scope, info.expression); this.usesContext = this.expression.usesContext; + + if (/FunctionExpression/.test(info.expression.type) && info.expression.params.length === 0) { + // TODO make this detection more accurate — if `event.preventDefault` isn't called, and + // `event` is passed to another function, we can make it passive + this.canMakePassive = true; + } else if (info.expression.type === 'Identifier') { + let node = component.node_for_declaration.get(info.expression.name); + + if (node && node.type === 'VariableDeclaration') { + // for `const handleClick = () => {...}`, we want the [arrow] function expression node + const declarator = node.declarations.find(d => d.id.name === info.expression.name); + node = declarator.init; + } + + if (node && /Function/.test(node.type) && node.params.length === 0) { + this.canMakePassive = true; + } + } } else { const name = component.getUniqueName(`${this.name}_handler`); component.declarations.push(name); diff --git a/test/js/samples/event-handler-no-passive/expected.js b/test/js/samples/event-handler-no-passive/expected.js new file mode 100644 index 0000000000..dad32a0875 --- /dev/null +++ b/test/js/samples/event-handler-no-passive/expected.js @@ -0,0 +1,50 @@ +/* generated by Svelte vX.Y.Z */ +import { SvelteComponent as SvelteComponent_1, addListener, createElement, detachNode, identity, init, insert, noop, run, safe_not_equal } from "svelte/internal"; + +function create_fragment(component, ctx) { + var a, current, dispose; + + return { + c() { + a = createElement("a"); + a.textContent = "this should not navigate to example.com"; + a.href = "https://example.com"; + dispose = addListener(a, "touchstart", touchstart_handler); + }, + + m(target, anchor) { + insert(target, a, anchor); + current = true; + }, + + p: noop, + + i(target, anchor) { + if (current) return; + this.m(target, anchor); + }, + + o: run, + + d(detach) { + if (detach) { + detachNode(a); + } + + dispose(); + } + }; +} + +function touchstart_handler(e) { + return e.preventDefault(); +} + +class SvelteComponent extends SvelteComponent_1 { + constructor(options) { + super(); + init(this, options, identity, create_fragment, safe_not_equal); + } +} + +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/event-handler-no-passive/input.html b/test/js/samples/event-handler-no-passive/input.html new file mode 100644 index 0000000000..3205782adb --- /dev/null +++ b/test/js/samples/event-handler-no-passive/input.html @@ -0,0 +1,3 @@ + + this should not navigate to example.com + \ No newline at end of file diff --git a/test/js/samples/event-modifiers/input.html b/test/js/samples/event-modifiers/input.html index 5bbcebb72a..225134f598 100644 --- a/test/js/samples/event-modifiers/input.html +++ b/test/js/samples/event-modifiers/input.html @@ -8,8 +8,8 @@ } -
- - - +
+ + +
\ No newline at end of file