@humanspeak/svelte-motion
Version:
Framer Motion for Svelte 5. Declarative motion.<tag> components with AnimatePresence exit animations, gestures (hover, tap, drag, focus, in-view), variants, FLIP layout animations, shared-layout transitions, spring physics, and scroll-linked motion values
61 lines (60 loc) • 2.17 kB
JavaScript
import { pwLog } from './log';
import { hasFinishedPromise, isPromiseLike } from './promise';
import { animate } from 'motion';
/**
* Animation utilities for Svelte Motion.
*
* Provides helpers for composing transition objects and ensuring lifecycle
* callbacks fire consistently regardless of the underlying Motion control type.
*/
/**
* Merge Motion `AnimationOptions` objects without mutating the inputs.
*
* Later values override earlier ones. Use to combine root configuration from
* `MotionConfig` with local `transition` props. Accepts a variadic list.
*
* @param args List of `AnimationOptions` to merge in left-to-right order.
* @return A new merged `AnimationOptions` object.
*/
export const mergeTransitions = (...args) => {
return args.reduce((acc, next) => {
return { ...acc, ...next };
}, {});
};
/**
* Animate an element and invoke lifecycle callbacks around the main transition.
*
* Wraps `motion.animate` to ensure `onStart` and `onComplete` are called
* whether the returned control exposes a `finished` promise or is then-able.
*
* @param el Target element.
* @param keyframes Keyframes to animate to.
* @param transition Animation timing/options.
* @param onStart Optional lifecycle fired before animation starts.
* @param onComplete Optional lifecycle fired after animation completes.
*/
export const animateWithLifecycle = (el, keyframes, transition, onStart, onComplete) => {
const payload = keyframes;
const computed = getComputedStyle(el);
pwLog('[animateWithLifecycle] starting', {
keyframes: payload,
transition,
currentOpacity: el.style.opacity,
currentTransform: el.style.transform,
computedOpacity: computed.opacity,
computedTransform: computed.transform
});
onStart?.(payload);
const controls = animate(el, payload, transition);
if (hasFinishedPromise(controls)) {
;
controls.finished
?.then(() => onComplete?.(payload))
.catch(() => { });
return;
}
if (isPromiseLike(controls)) {
;
controls.then(() => onComplete?.(payload)).catch(() => { });
}
};