diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index bf3135844e..cb242228cc 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -87,8 +87,6 @@ export function transition(flags, element, get_fn, get_params) { const direction = is_intro && is_outro ? 'both' : is_intro ? 'in' : 'out'; - let p = 0; - /** @type {import('#client').TransitionPayload | ((opts: { direction: 'in' | 'out' }) => import('#client').TransitionPayload) | undefined} */ let current_options; @@ -118,12 +116,12 @@ export function transition(flags, element, get_fn, get_params) { element.inert = inert; if (is_intro) { - intro = animate(element, get_options(), outro?.p() ?? 0, 1, () => { + intro = animate(element, get_options(), outro, 1, () => { intro = current_options = undefined; }); outro?.neuter(); - reset = intro.reset; + reset = intro.reset; // TODO handle this inside `animate` } else { outro?.abort(); reset?.(); @@ -136,7 +134,7 @@ export function transition(flags, element, get_fn, get_params) { callback = fn; element.inert = true; - outro = animate(element, get_options(), intro?.p() ?? 1, 0, () => { + outro = animate(element, get_options(), intro, 0, () => { outro = current_options = undefined; fn?.(); }); @@ -167,20 +165,18 @@ export function transition(flags, element, get_fn, get_params) { user_effect(() => { untrack(() => transition.in()); }); - } else { - p = 1; } } /** * @param {Element} element * @param {import('#client').TransitionPayload | ((opts: { direction: 'in' | 'out' }) => import('#client').TransitionPayload)} options - * @param {number} p + * @param {import('#client').Animation | undefined} counterpart * @param {number} target * @param {(() => void) | undefined} callback * @returns {import('#client').Animation} */ -function animate(element, options, p, target, callback) { +function animate(element, options, counterpart, target, callback) { dispatch_event(element, target === 1 ? 'introstart' : 'outrostart'); if (is_function(options)) { @@ -189,14 +185,14 @@ function animate(element, options, p, target, callback) { user_effect(() => { var o = untrack(() => options({ direction: target === 1 ? 'in' : 'out' })); - a = animate(element, o, p, target, callback); + a = animate(element, o, counterpart, target, callback); }); return { abort: () => a.abort(), neuter: () => a.neuter(), reset: noop, - p: () => a.p() + p: (now) => a.p(now) }; } @@ -213,12 +209,11 @@ function animate(element, options, p, target, callback) { const { delay = 0, duration, css, tick, easing = linear } = options; const n = options.duration / (1000 / 60); - const current_delta = target - p; - - const adjusted_duration = duration * Math.abs(current_delta); const start_time = raf.now() + delay; - const start_p = p; + const start_p = counterpart?.p(start_time) ?? 1 - target; + const current_delta = target - start_p; + const adjusted_duration = duration * Math.abs(current_delta); const end_time = start_time + adjusted_duration; if (css) { @@ -227,7 +222,7 @@ function animate(element, options, p, target, callback) { for (let i = 0; i <= n; i += 1) { const eased = easing(i / n); - const t = p + current_delta * eased; + const t = start_p + current_delta * eased; const styles = css(t, 1 - t); keyframes.push(css_to_keyframe(styles)); } @@ -271,8 +266,8 @@ function animate(element, options, p, target, callback) { } // Timer - if (p === 0) { - tick?.(p, 1 - p); // TODO put in nested effect, to avoid interleaved reads/writes? + if (start_p === 0) { + tick?.(0, 1); // TODO put in nested effect, to avoid interleaved reads/writes? } var task = loop((now) => { @@ -290,7 +285,7 @@ function animate(element, options, p, target, callback) { } if (now >= start_time) { - p = start_p + current_delta * easing((now - start_time) / adjusted_duration); + var p = start_p + current_delta * easing((now - start_time) / adjusted_duration); tick?.(p, 1 - p); } @@ -310,7 +305,9 @@ function animate(element, options, p, target, callback) { tick?.(1, 0); } }, - p: () => p + p: (now) => { + return clamp(start_p + current_delta * easing((now - start_time) / adjusted_duration), 0, 1); + } }; } diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index 4ca11944cf..ef5c7e0ed3 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -166,7 +166,7 @@ export interface Animation { abort: () => void; neuter: () => void; reset: () => void; - p: () => number; + p: (now: number) => number; } export type TransitionFn

= (