fix: use `passive` and `nonpassive` actions for `passive` and `nonpassive` modifiers

pull/13362/head
paoloricciuti 2 years ago
parent 5445056248
commit 2c5a34bcae

@ -7,12 +7,11 @@ import MagicString from 'magic-string';
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { parse } from '../phases/1-parse/index.js'; import { parse } from '../phases/1-parse/index.js';
import { analyze_component } from '../phases/2-analyze/index.js'; import { analyze_component } from '../phases/2-analyze/index.js';
import { validate_component_options } from '../validate-options.js';
import { get_rune } from '../phases/scope.js'; import { get_rune } from '../phases/scope.js';
import { reset, reset_warning_filter } from '../state.js'; import { reset, reset_warning_filter } from '../state.js';
import { extract_identifiers } from '../utils/ast.js'; import { extract_identifiers } from '../utils/ast.js';
import { regex_is_valid_identifier } from '../phases/patterns.js';
import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js'; import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js';
import { validate_component_options } from '../validate-options.js';
/** /**
* Does a best-effort migration of Svelte code towards using runes, event attributes and render tags. * Does a best-effort migration of Svelte code towards using runes, event attributes and render tags.
@ -63,7 +62,9 @@ export function migrate(source) {
self: analysis.root.unique('self').name, self: analysis.root.unique('self').name,
trusted: analysis.root.unique('trusted').name, trusted: analysis.root.unique('trusted').name,
createBubbler: analysis.root.unique('createBubbler').name, createBubbler: analysis.root.unique('createBubbler').name,
bubble: analysis.root.unique('bubble').name bubble: analysis.root.unique('bubble').name,
passive: analysis.root.unique('passive').name,
nonpassive: analysis.root.unique('nonpassive').name
}, },
legacy_imports: new Set(), legacy_imports: new Set(),
script_insertions: new Set() script_insertions: new Set()
@ -728,6 +729,7 @@ function handle_events(element, state) {
} }
const handlers = []; const handlers = [];
const explicit_passive_handlers = [];
for (let i = 0; i < nodes.length; i += 1) { for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i]; const node = nodes[i];
@ -755,17 +757,36 @@ function handle_events(element, state) {
); );
} }
let has_passive = false;
let has_nonpassive = false;
for (const modifier of sorted_modifier) { for (const modifier of sorted_modifier) {
has_passive ||= modifier === 'passive';
has_nonpassive ||= modifier === 'nonpassive';
if (modifier !== 'capture' && modifier !== 'passive' && modifier !== 'nonpassive') { if (modifier !== 'capture' && modifier !== 'passive' && modifier !== 'nonpassive') {
state.legacy_imports.add(modifier); state.legacy_imports.add(modifier);
body = `${state.legacy_imports_names[modifier]}(${body})`; body = `${state.legacy_imports_names[modifier]}(${body})`;
} }
} }
handlers.push({ if (has_passive || has_nonpassive) {
handler: body, if (has_passive) {
indent, state.legacy_imports.add('passive');
needs_line_delete }
}); if (has_nonpassive) {
state.legacy_imports.add('nonpassive');
}
explicit_passive_handlers.push({
handler: `use:${has_nonpassive ? state.legacy_imports_names.nonpassive : state.legacy_imports_names.passive}={{ handler: () => ${body}, event: '${node.name}' }}`,
indent,
needs_line_delete
});
} else {
handlers.push({
handler: body,
indent,
needs_line_delete
});
}
state.str.remove(needs_line_delete ? new_line_index : node.start, node.end); state.str.remove(needs_line_delete ? new_line_index : node.start, node.end);
} }
@ -773,17 +794,25 @@ function handle_events(element, state) {
if (first_node) { if (first_node) {
let handlers_body = ''; let handlers_body = '';
for (let handler of handlers) { for (const handler of handlers) {
handlers_body += `${handler.needs_line_delete || nodes.length > 1 ? `\n${handler.indent}` : ''}${handler.handler},`; handlers_body += `${handler.needs_line_delete || nodes.length > 1 ? `\n${handler.indent}` : ''}${handler.handler},`;
} }
handlers_body = handlers_body.substring(0, handlers_body.length - 1); handlers_body = handlers_body.substring(0, handlers_body.length - 1);
if (handlers_body === name) { if (handlers_body) {
state.str.overwrite(first_node.start, first_node.end, `{${name}}`); if (handlers_body === name) {
} else { state.str.overwrite(first_node.start, first_node.end, `{${name}}`);
state.str.overwrite( } else {
first_node.start, state.str.overwrite(
first_node.start,
first_node.end,
`${name}={${nodes.length > 1 ? `${state.legacy_imports_names.handlers}(` : ''}${handlers_body}${nodes.length > 1 ? ')' : ''}}`
);
}
}
for (const passive_handler of explicit_passive_handlers) {
state.str.appendRight(
first_node.end, first_node.end,
`${name}={${nodes.length > 1 ? `${state.legacy_imports_names.handlers}(` : ''}${handlers_body}${nodes.length > 1 ? ')' : ''}}` `${passive_handler.needs_line_delete || nodes.length > 1 ? `\n${passive_handler.indent}` : ''}${passive_handler.handler}`
); );
} }
} }

@ -1,3 +1,7 @@
import { noop } from '../../../shared/utils.js';
import { user_pre_effect } from '../../reactivity/effects.js';
import { on } from '../elements/events.js';
/** /**
* Substitute for the `trusted` event modifier * Substitute for the `trusted` event modifier
* @deprecated * @deprecated
@ -93,3 +97,29 @@ export function preventDefault(fn) {
return fn?.apply(this, args); return fn?.apply(this, args);
}; };
} }
/**
* Substitute for the `passive` event modifier. It's an action.
* @deprecated
* @type {import("svelte/action").Action<HTMLElement, { handler: () => EventListener, event: string }>}
*/
export function passive(node, { handler, event }) {
user_pre_effect(() => {
return on(node, event, handler() ?? noop, {
passive: true
});
});
}
/**
* Substitute for the `nonpassive` event modifier. It's an action.
* @deprecated
* @type {import("svelte/action").Action<HTMLElement, { handler: () => EventListener, event: string }>}
*/
export function nonpassive(node, { handler, event }) {
user_pre_effect(() => {
return on(node, event, handler() ?? noop, {
passive: false
});
});
}

@ -243,5 +243,7 @@ export {
self, self,
stopImmediatePropagation, stopImmediatePropagation,
stopPropagation, stopPropagation,
trusted trusted,
passive,
nonpassive
} from '../internal/client/dom/legacy/event-modifiers.js'; } from '../internal/client/dom/legacy/event-modifiers.js';

@ -8,6 +8,8 @@
let self; let self;
let createBubbler; let createBubbler;
let bubble; let bubble;
let passive;
let nonpassive;
</script> </script>
<button on:click={() => console.log('hi')} on:click>click me</button> <button on:click={() => console.log('hi')} on:click>click me</button>
@ -39,6 +41,28 @@
<button on:click|trusted|once={() => ''}>click me</button> <button on:click|trusted|once={() => ''}>click me</button>
<button on:click|once|preventDefault={() => ''}>click me</button> <button on:click|once|preventDefault={() => ''}>click me</button>
<button on:click|passive>click me</button>
<button on:click|nonpassive>click me</button>
<button on:click|passive={()=>''}>click me</button>
<button on:click|nonpassive={()=>''}>click me</button>
<button on:click|passive={foo}>click me</button>
<button on:click|nonpassive={foo}>click me</button>
<button on:click|stopPropagation|passive={()=>''}>click me</button>
<button on:click|trusted|nonpassive={()=>''}>click me</button>
<button
on:click|passive={()=>''}
on:click
on:click={()=>''}
>click me</button>
<button
on:click|nonpassive={()=>''}
on:click
on:click={()=>''}
>click me</button>
<button <button
on:click on:click
on:click={foo} on:click={foo}

@ -1,5 +1,5 @@
<script> <script>
import { handlers as handlers_1, createBubbler as createBubbler_1, preventDefault as preventDefault_1, stopPropagation as stopPropagation_1, stopImmediatePropagation as stopImmediatePropagation_1, self as self_1, trusted as trusted_1, once as once_1 } from 'svelte/legacy'; import { handlers as handlers_1, createBubbler as createBubbler_1, preventDefault as preventDefault_1, stopPropagation as stopPropagation_1, stopImmediatePropagation as stopImmediatePropagation_1, self as self_1, trusted as trusted_1, once as once_1, passive as passive_1, nonpassive as nonpassive_1 } from 'svelte/legacy';
const bubble_1 = createBubbler_1(); const bubble_1 = createBubbler_1();
@ -12,6 +12,8 @@
let self; let self;
let createBubbler; let createBubbler;
let bubble; let bubble;
let passive;
let nonpassive;
</script> </script>
<button onclick={handlers_1( <button onclick={handlers_1(
@ -52,6 +54,38 @@
<button onclick={once_1(trusted_1(() => ''))}>click me</button> <button onclick={once_1(trusted_1(() => ''))}>click me</button>
<button onclick={once_1(preventDefault_1(() => ''))}>click me</button> <button onclick={once_1(preventDefault_1(() => ''))}>click me</button>
<button
use:passive_1={{ handler: () => bubble_1('click'), event: 'click' }}>click me</button>
<button
use:nonpassive_1={{ handler: () => bubble_1('click'), event: 'click' }}>click me</button>
<button
use:passive_1={{ handler: () => ()=>'', event: 'click' }}>click me</button>
<button
use:nonpassive_1={{ handler: () => ()=>'', event: 'click' }}>click me</button>
<button
use:passive_1={{ handler: () => foo, event: 'click' }}>click me</button>
<button
use:nonpassive_1={{ handler: () => foo, event: 'click' }}>click me</button>
<button
use:passive_1={{ handler: () => stopPropagation_1(()=>''), event: 'click' }}>click me</button>
<button
use:nonpassive_1={{ handler: () => trusted_1(()=>''), event: 'click' }}>click me</button>
<button
onclick={handlers_1(
bubble_1('click'),
()=>'')}
use:passive_1={{ handler: () => ()=>'', event: 'click' }}
>click me</button>
<button
onclick={handlers_1(
bubble_1('click'),
()=>'')}
use:nonpassive_1={{ handler: () => ()=>'', event: 'click' }}
>click me</button>
<button <button
onclick={handlers_1( onclick={handlers_1(
bubble_1('click'), bubble_1('click'),

@ -27,6 +27,28 @@
<button on:click|trusted|once={() => ''}>click me</button> <button on:click|trusted|once={() => ''}>click me</button>
<button on:click|once|preventDefault={() => ''}>click me</button> <button on:click|once|preventDefault={() => ''}>click me</button>
<button on:click|passive>click me</button>
<button on:click|nonpassive>click me</button>
<button on:click|passive={()=>''}>click me</button>
<button on:click|nonpassive={()=>''}>click me</button>
<button on:click|passive={foo}>click me</button>
<button on:click|nonpassive={foo}>click me</button>
<button on:click|stopPropagation|passive={()=>''}>click me</button>
<button on:click|trusted|nonpassive={()=>''}>click me</button>
<button
on:click|passive={()=>''}
on:click
on:click={()=>''}
>click me</button>
<button
on:click|nonpassive={()=>''}
on:click
on:click={()=>''}
>click me</button>
<button <button
on:click on:click
on:click={foo} on:click={foo}

@ -1,5 +1,5 @@
<script> <script>
import { handlers, createBubbler, preventDefault, stopPropagation, stopImmediatePropagation, self, trusted, once } from 'svelte/legacy'; import { handlers, createBubbler, preventDefault, stopPropagation, stopImmediatePropagation, self, trusted, once, passive, nonpassive } from 'svelte/legacy';
const bubble = createBubbler(); const bubble = createBubbler();
@ -43,6 +43,38 @@
<button onclick={once(trusted(() => ''))}>click me</button> <button onclick={once(trusted(() => ''))}>click me</button>
<button onclick={once(preventDefault(() => ''))}>click me</button> <button onclick={once(preventDefault(() => ''))}>click me</button>
<button
use:passive={{ handler: () => bubble('click'), event: 'click' }}>click me</button>
<button
use:nonpassive={{ handler: () => bubble('click'), event: 'click' }}>click me</button>
<button
use:passive={{ handler: () => ()=>'', event: 'click' }}>click me</button>
<button
use:nonpassive={{ handler: () => ()=>'', event: 'click' }}>click me</button>
<button
use:passive={{ handler: () => foo, event: 'click' }}>click me</button>
<button
use:nonpassive={{ handler: () => foo, event: 'click' }}>click me</button>
<button
use:passive={{ handler: () => stopPropagation(()=>''), event: 'click' }}>click me</button>
<button
use:nonpassive={{ handler: () => trusted(()=>''), event: 'click' }}>click me</button>
<button
onclick={handlers(
bubble('click'),
()=>'')}
use:passive={{ handler: () => ()=>'', event: 'click' }}
>click me</button>
<button
onclick={handlers(
bubble('click'),
()=>'')}
use:nonpassive={{ handler: () => ()=>'', event: 'click' }}
>click me</button>
<button <button
onclick={handlers( onclick={handlers(
bubble('click'), bubble('click'),

Loading…
Cancel
Save