vert/src/lib/animation/index.ts

83 lines
2.4 KiB
TypeScript

import { isMobile, effects } from "$lib/store/index.svelte";
import type { AnimationConfig, FlipParams } from "svelte/animate";
import { cubicOut } from "svelte/easing";
import {
fade as svelteFade,
fly as svelteFly,
type FadeParams,
type FlyParams,
} from "svelte/transition";
// Subscribe to stores
let effectsEnabled = true;
let isMobileDevice = false;
effects.subscribe(value => {
effectsEnabled = value;
});
isMobile.subscribe(value => {
isMobileDevice = value;
});
export const transition =
"linear(0,0.006,0.025 2.8%,0.101 6.1%,0.539 18.9%,0.721 25.3%,0.849 31.5%,0.937 38.1%,0.968 41.8%,0.991 45.7%,1.006 50.1%,1.015 55%,1.017 63.9%,1.001)";
export const duration = 500;
export function fade(node: HTMLElement, options: FadeParams) {
if (!effectsEnabled) return {};
const animation = svelteFade(node, options);
return animation;
}
export function fly(node: HTMLElement, options: FlyParams) {
if (!effectsEnabled || isMobileDevice) return {};
const animation = svelteFly(node, options);
return animation;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
export function is_function(thing: unknown): thing is Function {
return typeof thing === "function";
}
type Params = FlipParams & {};
/**
* The flip function calculates the start and end position of an element and animates between them, translating the x and y values.
* `flip` stands for [First, Last, Invert, Play](https://aerotwist.com/blog/flip-your-animations/).
*
* https://svelte.dev/docs/svelte-animate#flip
*/
export function flip(
node: HTMLElement,
{ from, to }: { from: DOMRect; to: DOMRect },
params: Params = {},
): AnimationConfig {
const style = getComputedStyle(node);
const transform = style.transform === "none" ? "" : style.transform;
const [ox, oy] = style.transformOrigin.split(" ").map(parseFloat);
const dx = from.left + (from.width * ox) / to.width - (to.left + ox);
const dy = from.top + (from.height * oy) / to.height - (to.top + oy);
const {
delay = 0,
duration = (d) => Math.sqrt(d) * 120,
easing = cubicOut,
} = params;
return {
delay,
duration: is_function(duration)
? duration(Math.sqrt(dx * dx + dy * dy))
: duration,
easing,
css: (_t, u) => {
const x = u * dx;
const y = u * dy;
// const sx = scale ? t + (u * from.width) / to.width : 1;
// const sy = scale ? t + (u * from.height) / to.height : 1;
return `transform: ${transform} translate(${x}px, ${y}px);`;
},
};
}