63 lines
2.0 KiB
TypeScript
63 lines
2.0 KiB
TypeScript
import { cubicOut } from 'svelte/easing';
|
|
import type { TransitionConfig } from 'svelte/transition';
|
|
|
|
/**
|
|
* A utility function that converts a style object to a string.
|
|
* Credits: https://github.com/melt-ui/melt-ui/blob/42e2dd430c3e13f56062c4d610dabd84ea4e5517/src/lib/internal/helpers/style.ts
|
|
* License: MIT, https://github.com/melt-ui/melt-ui/blob/develop/LICENSE
|
|
*
|
|
* @param style - The style object to convert
|
|
* @returns The style object as a string
|
|
*/
|
|
export function styleToString(style: StyleObject): string {
|
|
return Object.keys(style).reduce((str, key) => {
|
|
if (style[key] === undefined) return str;
|
|
return str + `${key}:${style[key]};`;
|
|
}, '');
|
|
}
|
|
|
|
export type StyleObject = Record<string, number | string | undefined>;
|
|
|
|
/**
|
|
* Credits: https://github.com/melt-ui/melt-ui/blob/develop/src/docs/utils/transition.ts
|
|
* License: MIT, https://github.com/melt-ui/melt-ui/blob/develop/LICENSE
|
|
* Thanks to the Melt-UI team for such an awesome library!https://github.com/melt-ui/melt-ui/blob/develop/src/docs/utils/transition.ts
|
|
*/
|
|
|
|
const scaleConversion = (valueA: number, scaleA: [number, number], scaleB: [number, number]) => {
|
|
const [minA, maxA] = scaleA;
|
|
const [minB, maxB] = scaleB;
|
|
|
|
const percentage = (valueA - minA) / (maxA - minA);
|
|
const valueB = percentage * (maxB - minB) + minB;
|
|
|
|
return valueB;
|
|
};
|
|
|
|
type FlyAndScaleOptions = {
|
|
x?: number;
|
|
y?: number;
|
|
start: number;
|
|
duration?: number;
|
|
};
|
|
export const flyAndScale = (node: HTMLElement, options: FlyAndScaleOptions): TransitionConfig => {
|
|
const style = getComputedStyle(node);
|
|
const transform = style.transform === 'none' ? '' : style.transform;
|
|
|
|
return {
|
|
duration: options.duration ?? 150,
|
|
delay: 0,
|
|
css: (t) => {
|
|
const x = scaleConversion(t, [0, 1], [options.x ?? 0, 0]);
|
|
const y = scaleConversion(t, [0, 1], [options.y ?? 0, 0]);
|
|
const scale = scaleConversion(t, [0, 1], [options.start, 1]);
|
|
|
|
return styleToString({
|
|
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
|
|
opacity: t
|
|
});
|
|
},
|
|
easing: cubicOut
|
|
};
|
|
};
|