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 { parse } from '../phases/1-parse/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 { reset, reset_warning_filter } from '../state.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 { validate_component_options } from '../validate-options.js';
/**
* 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,
trusted: analysis.root.unique('trusted').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(),
script_insertions: new Set()
@ -728,6 +729,7 @@ function handle_events(element, state) {
}
const handlers = [];
const explicit_passive_handlers = [];
for (let i = 0; i < nodes.length; i += 1) {
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) {
has_passive ||= modifier === 'passive';
has_nonpassive ||= modifier === 'nonpassive';
if (modifier !== 'capture' && modifier !== 'passive' && modifier !== 'nonpassive') {
state.legacy_imports.add(modifier);
body = `${state.legacy_imports_names[modifier]}(${body})`;
}
}
handlers.push({
handler: body,
indent,
needs_line_delete
});
if (has_passive || has_nonpassive) {
if (has_passive) {
state.legacy_imports.add('passive');
}
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);
}
@ -773,17 +794,25 @@ function handle_events(element, state) {
if (first_node) {
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 = handlers_body.substring(0, handlers_body.length - 1);
if (handlers_body === name) {
state.str.overwrite(first_node.start, first_node.end, `{${name}}`);
} else {
state.str.overwrite(
first_node.start,
if (handlers_body) {
if (handlers_body === name) {
state.str.overwrite(first_node.start, first_node.end, `{${name}}`);
} else {
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,
`${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
* @deprecated
@ -93,3 +97,29 @@ export function preventDefault(fn) {
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,
stopImmediatePropagation,
stopPropagation,
trusted
trusted,
passive,
nonpassive
} from '../internal/client/dom/legacy/event-modifiers.js';

@ -8,6 +8,8 @@
let self;
let createBubbler;
let bubble;
let passive;
let nonpassive;
</script>
<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|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
on:click
on:click={foo}

@ -1,5 +1,5 @@
<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();
@ -12,6 +12,8 @@
let self;
let createBubbler;
let bubble;
let passive;
let nonpassive;
</script>
<button onclick={handlers_1(
@ -52,6 +54,38 @@
<button onclick={once_1(trusted_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
onclick={handlers_1(
bubble_1('click'),

@ -27,6 +27,28 @@
<button on:click|trusted|once={() => ''}>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
on:click
on:click={foo}

@ -1,5 +1,5 @@
<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();
@ -43,6 +43,38 @@
<button onclick={once(trusted(() => ''))}>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
onclick={handlers(
bubble('click'),

Loading…
Cancel
Save