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

67 lines (66 loc) 2.08 kB
import { createScopedAnimate } from 'motion'; /** * Imperative animation API mirroring framer-motion's `useAnimate`. Returns a * tuple `[scope, animate]`: * * - `scope` is a Svelte 5 attachment: spread it on the parent element with * `{@attach scope}`. Once mounted, `scope.current` is the element and * `animate('selector', ...)` resolves selectors against it. * - `animate(target, keyframes, transition)` accepts the same overloads as * motion's standalone `animate` — strings, elements, motion values, and * sequences. * * When the attached element detaches, every animation started through the * scoped `animate` is stopped and `scope.animations` is cleared. * * `animate` ignores calls before the attachment fires — `scope.current` is * still `undefined`, and motion throws when asked to query selectors against * a missing root. Trigger animations from user events or `$effect` after * mount. * * @template T The parent element type. Defaults to `HTMLElement`. * @returns A `[scope, animate]` tuple. * @see https://motion.dev/docs/react-use-animate * * @example * ```svelte * <script lang="ts"> * import { useAnimate } from '@humanspeak/svelte-motion' * * const [scope, animate] = useAnimate() * * const run = () => * animate( * [ * ['li', { opacity: 1, x: 0 }, { delay: stagger(0.1) }], * ['button', { scale: 1.05 }, { at: '-0.2' }] * ] * ) * </script> * * <ul {@attach scope}> * <li>One</li> * <li>Two</li> * <li>Three</li> * </ul> * <button onclick={run}>Animate</button> * ``` */ export const useAnimate = () => { const scope = ((node) => { scope.current = node; return () => { for (const animation of scope.animations) { animation.stop(); } scope.animations.length = 0; scope.current = undefined; }; }); scope.current = undefined; scope.animations = []; const animate = createScopedAnimate({ scope: scope }); return [scope, animate]; };