fix: improve transition outro easing

pull/10190/head
Dominic Gannaway 3 years ago
parent 5dce70e6cf
commit 3ab389560f

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve transition outro easing

@ -256,6 +256,44 @@ function handle_raf(time) {
} }
} }
/**
* @param {{(t: number): number;(t: number): number;(arg0: number): any;}} easing_fn
* @param {((t: number, u: number) => string)} css_fn
* @param {number} duration
* @param {string} direction
* @param {boolean} reverse
*/
function create_keyframes(easing_fn, css_fn, duration, direction, reverse) {
/** @type {Keyframe[]} */
const keyframes = [];
// We need at least two frames
const frame_time = 16.666;
const max_duration = Math.max(duration, frame_time);
// Have a keyframe every fame for 60 FPS
for (let i = 0; i <= max_duration; i += frame_time) {
let time;
if (i + frame_time > max_duration) {
time = 1;
} else if (i === 0) {
time = 0;
} else {
time = i / max_duration;
}
let t = easing_fn(time);
if (reverse) {
t = 1 - t;
}
keyframes.push(css_to_keyframe(css_fn(t, 1 - t)));
}
if (direction === 'out' || reverse) {
keyframes.reverse();
}
return keyframes;
}
/** @param {number} t */
const linear = (t) => t;
/** /**
* @param {HTMLElement} dom * @param {HTMLElement} dom
* @param {() => import('./types.js').TransitionPayload} init * @param {() => import('./types.js').TransitionPayload} init
@ -286,38 +324,15 @@ function create_transition(dom, init, direction, effect) {
const delay = payload.delay ?? 0; const delay = payload.delay ?? 0;
const css_fn = payload.css; const css_fn = payload.css;
const tick_fn = payload.tick; const tick_fn = payload.tick;
/** @param {number} t */
const linear = (t) => t;
const easing_fn = payload.easing || linear; const easing_fn = payload.easing || linear;
/** @type {Keyframe[]} */
const keyframes = [];
if (typeof tick_fn === 'function') { if (typeof tick_fn === 'function') {
animation = new TickAnimation(tick_fn, duration, delay, direction === 'out'); animation = new TickAnimation(tick_fn, duration, delay, direction === 'out');
} else { } else {
if (typeof css_fn === 'function') { const keyframes =
// We need at least two frames typeof css_fn === 'function'
const frame_time = 16.666; ? create_keyframes(easing_fn, css_fn, duration, direction, false)
const max_duration = Math.max(duration, frame_time); : [];
// Have a keyframe every fame for 60 FPS
for (let i = 0; i <= max_duration; i += frame_time) {
let time;
if (i + frame_time > max_duration) {
time = 1;
} else if (i === 0) {
time = 0;
} else {
time = i / max_duration;
}
const t = easing_fn(time);
keyframes.push(css_to_keyframe(css_fn(t, 1 - t)));
}
if (direction === 'out') {
keyframes.reverse();
}
}
animation = dom.animate(keyframes, { animation = dom.animate(keyframes, {
duration, duration,
endDelay: delay, endDelay: delay,
@ -421,6 +436,23 @@ function create_transition(dom, init, direction, effect) {
} else { } else {
dispatch_event(dom, 'outrostart'); dispatch_event(dom, 'outrostart');
if (needs_reverse) { if (needs_reverse) {
const payload = transition.p;
const current_animation = /** @type {Animation} */ (animation);
if (
payload !== null &&
payload.css !== undefined &&
current_animation.playState === 'idle'
) {
const duration = payload.duration ?? 300;
const css_fn = payload.css;
const easing_fn = payload.easing || linear;
const keyframes = create_keyframes(easing_fn, css_fn, duration, direction, true);
const effect = current_animation.effect;
if (effect !== null) {
// @ts-ignore
effect.setKeyframes(keyframes);
}
}
/** @type {Animation | TickAnimation} */ (animation).reverse(); /** @type {Animation | TickAnimation} */ (animation).reverse();
} else { } else {
/** @type {Animation | TickAnimation} */ (animation).play(); /** @type {Animation | TickAnimation} */ (animation).play();

Loading…
Cancel
Save