Skip to content

Commit 05789da

Browse files
authored
fix: allow transition undefined payload + microtask queue handling (#10117)
* fix: allow transition undefined payload * cleanup * cleanup * add microtask queue handling
1 parent b3d185d commit 05789da

File tree

5 files changed

+104
-10
lines changed

5 files changed

+104
-10
lines changed

.changeset/clever-chefs-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: allow transition undefined payload

packages/svelte/src/internal/client/runtime.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ let current_queued_effects = [];
5050

5151
/** @type {Array<() => void>} */
5252
let current_queued_tasks = [];
53+
/** @type {Array<() => void>} */
54+
let current_queued_microtasks = [];
5355
let flush_count = 0;
5456
// Handle signal reactivity tree dependencies and consumer
5557

@@ -579,6 +581,11 @@ function flush_queued_effects(effects) {
579581

580582
function process_microtask() {
581583
is_micro_task_queued = false;
584+
if (current_queued_microtasks.length > 0) {
585+
const tasks = current_queued_microtasks.slice();
586+
current_queued_microtasks = [];
587+
run_all(tasks);
588+
}
582589
if (flush_count > 101) {
583590
return;
584591
}
@@ -637,6 +644,18 @@ export function schedule_task(fn) {
637644
current_queued_tasks.push(fn);
638645
}
639646

647+
/**
648+
* @param {() => void} fn
649+
* @returns {void}
650+
*/
651+
export function schedule_microtask(fn) {
652+
if (!is_micro_task_queued) {
653+
is_micro_task_queued = true;
654+
queueMicrotask(process_microtask);
655+
}
656+
current_queued_microtasks.push(fn);
657+
}
658+
640659
/**
641660
* @returns {void}
642661
*/
@@ -697,6 +716,9 @@ export function flushSync(fn) {
697716
if (current_queued_pre_and_render_effects.length > 0 || effects.length > 0) {
698717
flushSync();
699718
}
719+
if (is_micro_task_queued) {
720+
process_microtask();
721+
}
700722
if (is_task_queued) {
701723
process_task();
702724
}

packages/svelte/src/internal/client/transitions.js

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
managed_effect,
2222
managed_pre_effect,
2323
mark_subtree_inert,
24-
schedule_task,
24+
schedule_microtask,
2525
untrack
2626
} from './runtime.js';
2727
import { raf } from './timing.js';
@@ -279,6 +279,9 @@ function create_transition(dom, init, direction, effect) {
279279
// @ts-ignore
280280
payload = payload({ direction: curr_direction });
281281
}
282+
if (payload == null) {
283+
return;
284+
}
282285
const duration = payload.duration ?? 300;
283286
const delay = payload.delay ?? 0;
284287
const css_fn = payload.css;
@@ -354,11 +357,15 @@ function create_transition(dom, init, direction, effect) {
354357
cancelled = false;
355358
create_animation();
356359
}
357-
dispatch_event(dom, 'introstart');
358-
if (needs_reverse) {
359-
/** @type {Animation | TickAnimation} */ (animation).reverse();
360+
if (animation === null) {
361+
transition.x();
362+
} else {
363+
dispatch_event(dom, 'introstart');
364+
if (needs_reverse) {
365+
/** @type {Animation | TickAnimation} */ (animation).reverse();
366+
}
367+
/** @type {Animation | TickAnimation} */ (animation).play();
360368
}
361-
/** @type {Animation | TickAnimation} */ (animation).play();
362369
},
363370
// out
364371
o() {
@@ -368,11 +375,15 @@ function create_transition(dom, init, direction, effect) {
368375
cancelled = false;
369376
create_animation();
370377
}
371-
dispatch_event(dom, 'outrostart');
372-
if (needs_reverse) {
373-
/** @type {Animation | TickAnimation} */ (animation).reverse();
378+
if (animation === null) {
379+
transition.x();
374380
} else {
375-
/** @type {Animation | TickAnimation} */ (animation).play();
381+
dispatch_event(dom, 'outrostart');
382+
if (needs_reverse) {
383+
/** @type {Animation | TickAnimation} */ (animation).reverse();
384+
} else {
385+
/** @type {Animation | TickAnimation} */ (animation).play();
386+
}
376387
}
377388
},
378389
// cancel
@@ -671,7 +682,7 @@ function each_item_animate(block, transitions, index, index_is_reactive) {
671682
transition.c();
672683
}
673684
}
674-
schedule_task(() => {
685+
schedule_microtask(() => {
675686
trigger_transitions(transitions, 'key', from);
676687
});
677688
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<button>show</button><button>animate</button>`,
6+
7+
async test({ assert, target }) {
8+
const [btn1, btn2] = target.querySelectorAll('button');
9+
10+
flushSync(() => {
11+
btn1.click();
12+
});
13+
14+
assert.htmlEqual(
15+
target.innerHTML,
16+
`<button>show</button><button>animate</button><h1>Hello\n!</h1>`
17+
);
18+
19+
flushSync(() => {
20+
btn1.click();
21+
});
22+
23+
assert.htmlEqual(target.innerHTML, `<button>show</button><button>animate</button>`);
24+
25+
flushSync(() => {
26+
btn2.click();
27+
});
28+
29+
assert.htmlEqual(target.innerHTML, `<button>show</button><button>animate</button>`);
30+
31+
flushSync(() => {
32+
btn1.click();
33+
});
34+
35+
assert.htmlEqual(
36+
target.innerHTML,
37+
`<button>show</button><button>animate</button><h1 style="opacity: 0;">Hello\n!</h1>`
38+
);
39+
}
40+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script>
2+
import { fade } from 'svelte/transition';
3+
4+
let show = $state(false);
5+
let animate = $state(false);
6+
7+
function maybe(node, animate) {
8+
if (animate) return fade(node);
9+
}
10+
</script>
11+
12+
<button onclick={() => show = !show}>show</button><button onclick={() => animate = !animate}>animate</button>
13+
14+
{#if show}
15+
<h1 transition:maybe={animate}>Hello {name}!</h1>
16+
{/if}

0 commit comments

Comments
 (0)