fix: make onintrostart respect delay parameter (#17567)

* fix: make onintrostart respect delay parameter

Fixes #14009

The onintrostart event now fires after the delay period completes,
rather than immediately when the transition is initiated. This ensures
that the event accurately reflects when the intro animation actually
starts.

Changes:
- Added on_start callback parameter to animate() function
- Dispatch introstart event after delay animation finishes
- Handle edge case where duration is 0 but delay > 0

* fix: format code with prettier

* add (failing) tests

* fix

* changeset

* missed a spot

* fix

---------

Co-authored-by: Miner <miner@example.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/17575/head
PandaMan 3 months ago committed by GitHub
parent 06e6ef83b8
commit 16fec7207a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: fire introstart/outrostart events after delay, if specified

@ -239,8 +239,6 @@ export function transition(flags, element, get_fn, get_params) {
intro?.abort();
}
dispatch_event(element, 'introstart');
intro = animate(element, get_options(), outro, 1, () => {
dispatch_event(element, 'introend');
@ -260,8 +258,6 @@ export function transition(flags, element, get_fn, get_params) {
element.inert = true;
dispatch_event(element, 'outrostart');
outro = animate(element, get_options(), intro, 0, () => {
dispatch_event(element, 'outroend');
fn?.();
@ -345,7 +341,8 @@ function animate(element, options, counterpart, t2, on_finish) {
counterpart?.deactivate();
if (!options?.duration) {
if (!options?.duration && !options?.delay) {
dispatch_event(element, is_intro ? 'introstart' : 'outrostart');
on_finish();
return {
@ -385,6 +382,8 @@ function animate(element, options, counterpart, t2, on_finish) {
// remove dummy animation from the stack to prevent conflict with main animation
animation.cancel();
dispatch_event(element, is_intro ? 'introstart' : 'outrostart');
// for bidirectional transitions, we start from the current position,
// rather than doing a full intro/outro
var t1 = counterpart?.t() ?? 1 - t2;

@ -0,0 +1,32 @@
import { flushSync } from '../../../../src/index-client.js';
import { test } from '../../test';
export default test({
test({ assert, raf, target, logs }) {
const [btn] = target.querySelectorAll('button');
// in
flushSync(() => btn.click());
assert.deepEqual(logs, []);
raf.tick(1);
assert.deepEqual(logs, []);
raf.tick(100);
assert.deepEqual(logs, ['introstart']);
raf.tick(200);
assert.deepEqual(logs, ['introstart', 'introend']);
// out
flushSync(() => btn.click());
assert.deepEqual(logs, ['introstart', 'introend']);
raf.tick(201);
assert.deepEqual(logs, ['introstart', 'introend']);
raf.tick(300);
assert.deepEqual(logs, ['introstart', 'introend', 'outrostart']);
raf.tick(400);
assert.deepEqual(logs, ['introstart', 'introend', 'outrostart', 'outroend']);
}
});

@ -0,0 +1,23 @@
<script>
function fade(_) {
return {
delay: 100,
duration: 100,
css: (t) => `opacity: ${t}`
};
}
let visible = $state(false);
</script>
<button onclick={() => (visible = !visible)}>toggle</button>
{#if visible}
<p
transition:fade
onintrostart={() => console.log('introstart')}
onintroend={() => console.log('introend')}
onoutrostart={() => console.log('outrostart')}
onoutroend={() => console.log('outroend')}
>delayed fade</p>
{/if}

@ -0,0 +1,32 @@
import { flushSync } from '../../../../src/index-client.js';
import { test } from '../../test';
export default test({
test({ assert, raf, target, logs }) {
const [btn] = target.querySelectorAll('button');
// in
flushSync(() => btn.click());
assert.deepEqual(logs, []);
raf.tick(1);
assert.deepEqual(logs, []);
raf.tick(100);
assert.deepEqual(logs, ['introstart']);
raf.tick(200);
assert.deepEqual(logs, ['introstart', 'introend']);
// out
flushSync(() => btn.click());
assert.deepEqual(logs, ['introstart', 'introend']);
raf.tick(201);
assert.deepEqual(logs, ['introstart', 'introend']);
raf.tick(300);
assert.deepEqual(logs, ['introstart', 'introend', 'outrostart']);
raf.tick(400);
assert.deepEqual(logs, ['introstart', 'introend', 'outrostart', 'outroend']);
}
});

@ -0,0 +1,23 @@
<script>
function fade(node) {
return {
delay: 100,
duration: 100,
tick: (t) => node.style.opacity = t
};
}
let visible = $state(false);
</script>
<button onclick={() => (visible = !visible)}>toggle</button>
{#if visible}
<p
transition:fade
onintrostart={() => console.log('introstart')}
onintroend={() => console.log('introend')}
onoutrostart={() => console.log('outrostart')}
onoutroend={() => console.log('outroend')}
>delayed fade</p>
{/if}
Loading…
Cancel
Save