UNPKG

@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
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(() => { }); } };