|
|
@ -495,133 +495,68 @@ function is_transition_block(block) {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* @template P
|
|
|
|
* @template P
|
|
|
|
* @param {HTMLElement} dom
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @param {() => import('./types.js').TransitionFn<P | undefined> | import('./types.js').AnimateFn<P | undefined>} get_transition_fn
|
|
|
|
* @param {() => import('./types.js').TransitionFn<P | undefined>} get_fn
|
|
|
|
* @param {(() => P) | null} props_fn
|
|
|
|
* @param {(() => P) | null} get_params
|
|
|
|
* @param {'in' | 'out' | 'both' | 'key'} direction
|
|
|
|
* @param {'in' | 'out' | 'both'} direction
|
|
|
|
* @param {boolean} global
|
|
|
|
* @param {boolean} global
|
|
|
|
* @returns {void}
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function bind_transition(dom, get_transition_fn, props_fn, direction, global) {
|
|
|
|
export function bind_transition(element, get_fn, get_params, direction, global) {
|
|
|
|
const transition_effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
|
|
|
|
const effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
|
|
|
|
const block = current_block;
|
|
|
|
|
|
|
|
const is_keyed_transition = direction === 'key';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let can_show_intro_on_mount = true;
|
|
|
|
let p = direction === 'out' ? 1 : 0;
|
|
|
|
let can_apply_lazy_transitions = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (is_keyed_transition) {
|
|
|
|
/** @type {Animation | null} */
|
|
|
|
// @ts-ignore
|
|
|
|
let current_animation;
|
|
|
|
dom.__animate = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @type {import('./types.js').Block | null} */
|
|
|
|
|
|
|
|
let transition_block = block;
|
|
|
|
|
|
|
|
main: while (transition_block !== null) {
|
|
|
|
|
|
|
|
if (is_transition_block(transition_block)) {
|
|
|
|
|
|
|
|
if (transition_block.t === EACH_ITEM_BLOCK) {
|
|
|
|
|
|
|
|
// Lazily apply the each block transition
|
|
|
|
|
|
|
|
transition_block.r = each_item_transition;
|
|
|
|
|
|
|
|
transition_block.a = each_item_animate;
|
|
|
|
|
|
|
|
transition_block = transition_block.p;
|
|
|
|
|
|
|
|
} else if (transition_block.t === AWAIT_BLOCK && transition_block.n /* pending */) {
|
|
|
|
|
|
|
|
can_show_intro_on_mount = true;
|
|
|
|
|
|
|
|
} else if (transition_block.t === IF_BLOCK) {
|
|
|
|
|
|
|
|
transition_block.r = if_block_transition;
|
|
|
|
|
|
|
|
if (can_show_intro_on_mount) {
|
|
|
|
|
|
|
|
/** @type {import('./types.js').Block | null} */
|
|
|
|
|
|
|
|
let if_block = transition_block;
|
|
|
|
|
|
|
|
while (if_block.t === IF_BLOCK) {
|
|
|
|
|
|
|
|
// If we have an if block parent that is currently falsy then
|
|
|
|
|
|
|
|
// we can show the intro on mount as long as that block is mounted
|
|
|
|
|
|
|
|
if (if_block.e !== null && !if_block.v) {
|
|
|
|
|
|
|
|
can_show_intro_on_mount = true;
|
|
|
|
|
|
|
|
break main;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if_block = if_block.p;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!can_apply_lazy_transitions && can_show_intro_on_mount) {
|
|
|
|
|
|
|
|
can_show_intro_on_mount = transition_block.e !== null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (can_show_intro_on_mount || !global) {
|
|
|
|
|
|
|
|
can_apply_lazy_transitions = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (transition_block.t === ROOT_BLOCK && !can_apply_lazy_transitions) {
|
|
|
|
|
|
|
|
can_show_intro_on_mount = transition_block.e !== null || transition_block.i;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
transition_block = transition_block.p;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {import('./types.js').Transition} */
|
|
|
|
/** @type {TODO} */
|
|
|
|
let transition;
|
|
|
|
let current_options;
|
|
|
|
|
|
|
|
|
|
|
|
effect(() => {
|
|
|
|
const transition = {
|
|
|
|
let already_mounted = false;
|
|
|
|
global,
|
|
|
|
if (transition !== undefined) {
|
|
|
|
to(target, callback) {
|
|
|
|
already_mounted = true;
|
|
|
|
if (current_animation) {
|
|
|
|
// Destroy any existing transitions first
|
|
|
|
// TODO get `p` from current_animation?
|
|
|
|
transition.x();
|
|
|
|
current_animation.cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const transition_fn = get_transition_fn();
|
|
|
|
|
|
|
|
/** @param {DOMRect} [from] */
|
|
|
|
|
|
|
|
const init = (from) =>
|
|
|
|
|
|
|
|
untrack(() => {
|
|
|
|
|
|
|
|
const props = props_fn === null ? {} : props_fn();
|
|
|
|
|
|
|
|
return is_keyed_transition
|
|
|
|
|
|
|
|
? /** @type {import('./types.js').AnimateFn<any>} */ (transition_fn)(
|
|
|
|
|
|
|
|
dom,
|
|
|
|
|
|
|
|
{ from: /** @type {DOMRect} */ (from), to: dom.getBoundingClientRect() },
|
|
|
|
|
|
|
|
props,
|
|
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
: /** @type {import('./types.js').TransitionFn<any>} */ (transition_fn)(dom, props, {
|
|
|
|
|
|
|
|
direction
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transition = create_transition(dom, init, direction, transition_effect);
|
|
|
|
|
|
|
|
const is_intro = direction === 'in';
|
|
|
|
|
|
|
|
const show_intro = can_show_intro_on_mount && (is_intro || direction === 'both');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (show_intro && !already_mounted) {
|
|
|
|
current_options ??= get_fn()(element, get_params?.(), { direction });
|
|
|
|
transition.p = transition.i();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const effect = managed_pre_effect(() => {
|
|
|
|
if (current_options.css) {
|
|
|
|
destroy_signal(effect);
|
|
|
|
// WAAPI
|
|
|
|
dom.inert = false;
|
|
|
|
const keyframes = [];
|
|
|
|
|
|
|
|
const n = current_options.duration / (1000 / 60);
|
|
|
|
|
|
|
|
|
|
|
|
if (show_intro && !already_mounted) {
|
|
|
|
for (let i = 0; i <= n; i += 1) {
|
|
|
|
transition.in();
|
|
|
|
const t = current_options.easing(p + ((target - p) * i) / n);
|
|
|
|
|
|
|
|
const css = current_options.css(t);
|
|
|
|
|
|
|
|
keyframes.push(css_to_keyframe(css));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {import('./types.js').Block | null} */
|
|
|
|
current_animation = element.animate(keyframes, {
|
|
|
|
let transition_block = block;
|
|
|
|
duration: current_options.duration,
|
|
|
|
while (!is_intro && transition_block !== null) {
|
|
|
|
easing: 'linear'
|
|
|
|
const parent = transition_block.p;
|
|
|
|
});
|
|
|
|
if (is_transition_block(transition_block)) {
|
|
|
|
|
|
|
|
if (transition_block.r !== null) {
|
|
|
|
current_animation.finished.then(() => {
|
|
|
|
transition_block.r(transition);
|
|
|
|
console.log('done');
|
|
|
|
}
|
|
|
|
current_animation = null;
|
|
|
|
if (
|
|
|
|
callback();
|
|
|
|
parent === null ||
|
|
|
|
});
|
|
|
|
(!global && (transition_block.t !== IF_BLOCK || parent.t !== IF_BLOCK || parent.v))
|
|
|
|
} else {
|
|
|
|
) {
|
|
|
|
// TODO timer
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
transition_block = parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO don't pass strings around like this, it's silly
|
|
|
|
|
|
|
|
if (direction === 'in' || direction === 'both') {
|
|
|
|
|
|
|
|
(effect.in ??= []).push(transition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, false);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (direction === 'key') {
|
|
|
|
if (direction === 'out' || direction === 'both') {
|
|
|
|
effect(() => {
|
|
|
|
(effect.out ??= []).push(transition);
|
|
|
|
return () => {
|
|
|
|
|
|
|
|
transition.x();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|