fix: Abort outro when intro starts (#12321)

Fixes #12319

---------

Co-authored-by: Leon Scherer <info@leonscherer.com>
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
pull/12395/head
Leon Scherer 4 months ago committed by GitHub
parent 95422e22b6
commit fd7b950e7d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: abort outro when intro starts

@ -190,6 +190,9 @@ export function transition(flags, element, get_fn, get_params) {
in() { in() {
element.inert = inert; element.inert = inert;
// abort the outro to prevent overlap with the intro
outro?.abort();
if (is_intro) { if (is_intro) {
dispatch_event(element, 'introstart'); dispatch_event(element, 'introstart');
intro = animate(element, get_options(), outro, 1, () => { intro = animate(element, get_options(), outro, 1, () => {
@ -197,7 +200,6 @@ export function transition(flags, element, get_fn, get_params) {
intro = current_options = undefined; intro = current_options = undefined;
}); });
} else { } else {
outro?.abort();
reset?.(); reset?.();
} }
}, },

@ -12,24 +12,48 @@ export default test({
async test({ assert, component, target, raf }) { async test({ assert, component, target, raf }) {
component.visible = false; component.visible = false;
// abort halfway through the outro transition raf.tick(25);
raf.tick(50); assert.htmlEqual(
target.innerHTML,
`
<div style="opacity: 0.75;">a</div>
<div style="opacity: 0.75;">a</div>
`
);
// abort 1/4 through the outro transition
await component.$set({ await component.$set({
visible: true, visible: true,
array: ['a', 'b', 'c'] array: ['a', 'b', 'c']
}); });
raf.tick(50);
assert.htmlEqual( assert.htmlEqual(
target.innerHTML, target.innerHTML,
// because outro is aborted it will be finished earlier with the intro than the new items
` `
<div>a</div> <div style="">a</div>
<div>b</div> <div style="opacity: 0.25;">b</div>
<div>c</div> <div style="opacity: 0.25;">c</div>
<div>a</div> <div style="">a</div>
<div>b</div> <div style="opacity: 0.25;">b</div>
<div>c</div> <div style="opacity: 0.25;">c</div>
`
);
// intros of new items almost finished, aborted outro shouldn't overlap re-intro
raf.tick(75);
assert.htmlEqual(
target.innerHTML,
`
<div style="">a</div>
<div style="opacity: 0.5;">b</div>
<div style="opacity: 0.5;">c</div>
<div style="">a</div>
<div style="opacity: 0.5;">b</div>
<div style="opacity: 0.5;">c</div>
` `
); );
} }

@ -2,20 +2,22 @@
export let array = ['a']; export let array = ['a'];
export let visible = true; export let visible = true;
function slide(_, params) { function slide(_) {
return params; return {
duration: 100,
css: (t) => `opacity: ${t}`
};
} }
</script> </script>
{#if visible} {#if visible}
{#each array as item} {#each array as item}
<div transition:slide={{duration:100}}>{item}</div> <div transition:slide|global>{item}</div>
{/each} {/each}
{/if} {/if}
{#if !visible} {#if !visible}{:else}
{:else}
{#each array as item} {#each array as item}
<div transition:slide={{duration:100}}>{item}</div> <div transition:slide|global>{item}</div>
{/each} {/each}
{/if} {/if}
Loading…
Cancel
Save