|
|
|
@ -106,7 +106,7 @@ export function animation(element, get_fn, get_params) {
|
|
|
|
|
) {
|
|
|
|
|
const options = get_fn()(this.element, { from, to }, get_params?.());
|
|
|
|
|
|
|
|
|
|
animation = animate(this.element, options, undefined, 1, () => {
|
|
|
|
|
animation = animate(this.element, options, false, undefined, 1, () => {
|
|
|
|
|
animation?.abort();
|
|
|
|
|
animation = undefined;
|
|
|
|
|
});
|
|
|
|
@ -169,7 +169,7 @@ export function transition(flags, element, get_fn, get_params) {
|
|
|
|
|
|
|
|
|
|
if (is_intro) {
|
|
|
|
|
dispatch_event(element, 'introstart');
|
|
|
|
|
intro = animate(element, get_options(), outro, 1, () => {
|
|
|
|
|
intro = animate(element, get_options(), false, outro, 1, () => {
|
|
|
|
|
dispatch_event(element, 'introend');
|
|
|
|
|
intro = current_options = undefined;
|
|
|
|
|
});
|
|
|
|
@ -178,12 +178,12 @@ export function transition(flags, element, get_fn, get_params) {
|
|
|
|
|
reset?.();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
out(fn) {
|
|
|
|
|
out(fn, position_absolute = false) {
|
|
|
|
|
if (is_outro) {
|
|
|
|
|
element.inert = true;
|
|
|
|
|
|
|
|
|
|
dispatch_event(element, 'outrostart');
|
|
|
|
|
outro = animate(element, get_options(), intro, 0, () => {
|
|
|
|
|
outro = animate(element, get_options(), position_absolute, intro, 0, () => {
|
|
|
|
|
dispatch_event(element, 'outroend');
|
|
|
|
|
outro = current_options = undefined;
|
|
|
|
|
fn?.();
|
|
|
|
@ -229,12 +229,13 @@ export function transition(flags, element, get_fn, get_params) {
|
|
|
|
|
* Animates an element, according to the provided configuration
|
|
|
|
|
* @param {Element} element
|
|
|
|
|
* @param {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig)} options
|
|
|
|
|
* @param {boolean} position_absolute
|
|
|
|
|
* @param {import('#client').Animation | undefined} counterpart The corresponding intro/outro to this outro/intro
|
|
|
|
|
* @param {number} t2 The target `t` value — `1` for intro, `0` for outro
|
|
|
|
|
* @param {(() => void) | undefined} callback
|
|
|
|
|
* @returns {import('#client').Animation}
|
|
|
|
|
*/
|
|
|
|
|
function animate(element, options, counterpart, t2, callback) {
|
|
|
|
|
function animate(element, options, position_absolute, counterpart, t2, callback) {
|
|
|
|
|
if (is_function(options)) {
|
|
|
|
|
// In the case of a deferred transition (such as `crossfade`), `option` will be
|
|
|
|
|
// a function rather than an `AnimationConfig`. We need to call this function
|
|
|
|
@ -244,7 +245,7 @@ function animate(element, options, counterpart, t2, callback) {
|
|
|
|
|
|
|
|
|
|
effect(() => {
|
|
|
|
|
var o = untrack(() => options({ direction: t2 === 1 ? 'in' : 'out' }));
|
|
|
|
|
a = animate(element, o, counterpart, t2, callback);
|
|
|
|
|
a = animate(element, o, position_absolute, counterpart, t2, callback);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ...but we want to do so without using `async`/`await` everywhere, so
|
|
|
|
@ -284,6 +285,9 @@ function animate(element, options, counterpart, t2, callback) {
|
|
|
|
|
/** @type {import('#client').Task} */
|
|
|
|
|
var task;
|
|
|
|
|
|
|
|
|
|
/** @type {null | { position: string, width: string, height: string }} */
|
|
|
|
|
var original_styles = null;
|
|
|
|
|
|
|
|
|
|
if (css) {
|
|
|
|
|
// WAAPI
|
|
|
|
|
var keyframes = [];
|
|
|
|
@ -295,6 +299,37 @@ function animate(element, options, counterpart, t2, callback) {
|
|
|
|
|
keyframes.push(css_to_keyframe(styles));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (position_absolute) {
|
|
|
|
|
// we take the element out of the flow, so that sibling elements with an `animate:`
|
|
|
|
|
// directive can transform to the correct position
|
|
|
|
|
var computed_style = getComputedStyle(element);
|
|
|
|
|
|
|
|
|
|
if (computed_style.position !== 'absolute' && computed_style.position !== 'fixed') {
|
|
|
|
|
var style = /** @type {HTMLElement | SVGElement} */ (element).style;
|
|
|
|
|
|
|
|
|
|
original_styles = {
|
|
|
|
|
position: style.position,
|
|
|
|
|
width: style.width,
|
|
|
|
|
height: style.height
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var rect_a = element.getBoundingClientRect();
|
|
|
|
|
style.position = 'absolute';
|
|
|
|
|
style.width = computed_style.width;
|
|
|
|
|
style.height = computed_style.height;
|
|
|
|
|
var rect_b = element.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
if (rect_a.left !== rect_b.left || rect_a.top !== rect_b.top) {
|
|
|
|
|
var transform = `translate(${rect_a.left - rect_b.left}px, ${rect_a.top - rect_b.top}px)`;
|
|
|
|
|
for (var keyframe of keyframes) {
|
|
|
|
|
keyframe.transform = keyframe.transform
|
|
|
|
|
? `${keyframe.transform} ${transform}`
|
|
|
|
|
: transform;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
animation = element.animate(keyframes, {
|
|
|
|
|
delay,
|
|
|
|
|
duration,
|
|
|
|
@ -345,6 +380,15 @@ function animate(element, options, counterpart, t2, callback) {
|
|
|
|
|
task?.abort();
|
|
|
|
|
},
|
|
|
|
|
deactivate: () => {
|
|
|
|
|
if (original_styles) {
|
|
|
|
|
// revert `animate:` position fixing
|
|
|
|
|
var style = /** @type {HTMLElement | SVGElement} */ (element).style;
|
|
|
|
|
|
|
|
|
|
style.position = original_styles.position;
|
|
|
|
|
style.width = original_styles.width;
|
|
|
|
|
style.height = original_styles.height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback = undefined;
|
|
|
|
|
},
|
|
|
|
|
reset: () => {
|
|
|
|
|