@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
50 lines (49 loc) • 2.08 kB
JavaScript
import { motionValue } from 'motion-dom';
import { augmentMotionValue } from './augmentMotionValue.svelte.js';
/**
* Creates a tracked, mutable value backed by motion-dom's `MotionValue`.
*
* Use `.set(v)` to write the value imperatively, `.get()` to sample it
* imperatively, and `.current` to read it inside Svelte 5 reactive scopes
* (templates, `$derived`, `$effect`). The same value also implements the
* Svelte readable store contract via `.subscribe(run)`, so legacy `$mv`
* template syntax and `svelte/store`'s `get()` keep working.
*
* Returned object is a real motion-dom `MotionValue` — it composes with
* `useTransform`, `useSpring`, `useVelocity`, the `animate()` driver, and
* passes `isMotionValue`. Unlike `useSpring`, writes are immediate — there
* is no follow source and no animation.
*
* Lifecycle: must be called during component initialization. Cleanup is
* registered via `$effect`; motion-dom's internal listeners and animation
* subscriptions are released when the surrounding component / effect tears
* down. Call `.destroy()` to clean up early.
*
* SSR-safe: motion-dom's `motionValue` runs without DOM access; on the
* server reads return the initial value and writes still work, with no
* timers or listeners attached.
*
* @template T The value type — typically `number` or `string`.
* @param initial The starting value.
* @returns A `MotionValue<T>` augmented with `.current` and `.subscribe`.
*
* @example
* ```svelte
* <script lang="ts">
* import { useMotionValue, useTransform } from '@humanspeak/svelte-motion'
*
* const x = useMotionValue(0)
* const opacity = useTransform(x, [0, 200], [0, 1])
* </script>
*
* <input type="range" min="0" max="200" oninput={(e) => x.set(+e.currentTarget.value)} />
* <div style="opacity: {opacity.current}">x = {x.current}</div>
* ```
*
* @see https://motion.dev/docs/react-motion-value
*/
export const useMotionValue = (initial) => {
const value = motionValue(initial);
$effect(() => () => value.destroy());
return augmentMotionValue(value);
};