fix: allow transition undefined payload + microtask queue handling (#10117)

* fix: allow transition undefined payload

* cleanup

* cleanup

* add microtask queue handling
pull/10121/head
Dominic Gannaway 12 months ago committed by GitHub
parent b3d185da29
commit 05789daff9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: allow transition undefined payload

@ -50,6 +50,8 @@ let current_queued_effects = [];
/** @type {Array<() => void>} */ /** @type {Array<() => void>} */
let current_queued_tasks = []; let current_queued_tasks = [];
/** @type {Array<() => void>} */
let current_queued_microtasks = [];
let flush_count = 0; let flush_count = 0;
// Handle signal reactivity tree dependencies and consumer // Handle signal reactivity tree dependencies and consumer
@ -579,6 +581,11 @@ function flush_queued_effects(effects) {
function process_microtask() { function process_microtask() {
is_micro_task_queued = false; is_micro_task_queued = false;
if (current_queued_microtasks.length > 0) {
const tasks = current_queued_microtasks.slice();
current_queued_microtasks = [];
run_all(tasks);
}
if (flush_count > 101) { if (flush_count > 101) {
return; return;
} }
@ -637,6 +644,18 @@ export function schedule_task(fn) {
current_queued_tasks.push(fn); current_queued_tasks.push(fn);
} }
/**
* @param {() => void} fn
* @returns {void}
*/
export function schedule_microtask(fn) {
if (!is_micro_task_queued) {
is_micro_task_queued = true;
queueMicrotask(process_microtask);
}
current_queued_microtasks.push(fn);
}
/** /**
* @returns {void} * @returns {void}
*/ */
@ -697,6 +716,9 @@ export function flushSync(fn) {
if (current_queued_pre_and_render_effects.length > 0 || effects.length > 0) { if (current_queued_pre_and_render_effects.length > 0 || effects.length > 0) {
flushSync(); flushSync();
} }
if (is_micro_task_queued) {
process_microtask();
}
if (is_task_queued) { if (is_task_queued) {
process_task(); process_task();
} }

@ -21,7 +21,7 @@ import {
managed_effect, managed_effect,
managed_pre_effect, managed_pre_effect,
mark_subtree_inert, mark_subtree_inert,
schedule_task, schedule_microtask,
untrack untrack
} from './runtime.js'; } from './runtime.js';
import { raf } from './timing.js'; import { raf } from './timing.js';
@ -279,6 +279,9 @@ function create_transition(dom, init, direction, effect) {
// @ts-ignore // @ts-ignore
payload = payload({ direction: curr_direction }); payload = payload({ direction: curr_direction });
} }
if (payload == null) {
return;
}
const duration = payload.duration ?? 300; const duration = payload.duration ?? 300;
const delay = payload.delay ?? 0; const delay = payload.delay ?? 0;
const css_fn = payload.css; const css_fn = payload.css;
@ -354,11 +357,15 @@ function create_transition(dom, init, direction, effect) {
cancelled = false; cancelled = false;
create_animation(); create_animation();
} }
dispatch_event(dom, 'introstart'); if (animation === null) {
if (needs_reverse) { transition.x();
/** @type {Animation | TickAnimation} */ (animation).reverse(); } else {
dispatch_event(dom, 'introstart');
if (needs_reverse) {
/** @type {Animation | TickAnimation} */ (animation).reverse();
}
/** @type {Animation | TickAnimation} */ (animation).play();
} }
/** @type {Animation | TickAnimation} */ (animation).play();
}, },
// out // out
o() { o() {
@ -368,11 +375,15 @@ function create_transition(dom, init, direction, effect) {
cancelled = false; cancelled = false;
create_animation(); create_animation();
} }
dispatch_event(dom, 'outrostart'); if (animation === null) {
if (needs_reverse) { transition.x();
/** @type {Animation | TickAnimation} */ (animation).reverse();
} else { } else {
/** @type {Animation | TickAnimation} */ (animation).play(); dispatch_event(dom, 'outrostart');
if (needs_reverse) {
/** @type {Animation | TickAnimation} */ (animation).reverse();
} else {
/** @type {Animation | TickAnimation} */ (animation).play();
}
} }
}, },
// cancel // cancel
@ -671,7 +682,7 @@ function each_item_animate(block, transitions, index, index_is_reactive) {
transition.c(); transition.c();
} }
} }
schedule_task(() => { schedule_microtask(() => {
trigger_transitions(transitions, 'key', from); trigger_transitions(transitions, 'key', from);
}); });
} }

@ -0,0 +1,40 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
html: `<button>show</button><button>animate</button>`,
async test({ assert, target }) {
const [btn1, btn2] = target.querySelectorAll('button');
flushSync(() => {
btn1.click();
});
assert.htmlEqual(
target.innerHTML,
`<button>show</button><button>animate</button><h1>Hello\n!</h1>`
);
flushSync(() => {
btn1.click();
});
assert.htmlEqual(target.innerHTML, `<button>show</button><button>animate</button>`);
flushSync(() => {
btn2.click();
});
assert.htmlEqual(target.innerHTML, `<button>show</button><button>animate</button>`);
flushSync(() => {
btn1.click();
});
assert.htmlEqual(
target.innerHTML,
`<button>show</button><button>animate</button><h1 style="opacity: 0;">Hello\n!</h1>`
);
}
});

@ -0,0 +1,16 @@
<script>
import { fade } from 'svelte/transition';
let show = $state(false);
let animate = $state(false);
function maybe(node, animate) {
if (animate) return fade(node);
}
</script>
<button onclick={() => show = !show}>show</button><button onclick={() => animate = !animate}>animate</button>
{#if show}
<h1 transition:maybe={animate}>Hello {name}!</h1>
{/if}
Loading…
Cancel
Save