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

171 lines (170 loc) 7.67 kB
import { type MotionValue, type TransformOptions } from 'motion-dom'; import { type Readable } from 'svelte/store'; import { type AugmentedMotionValue } from './augmentMotionValue.svelte.js'; export type TransformValues = Partial<{ x: number; y: number; scale: number; scaleX: number; scaleY: number; rotate: number; }>; /** * Build a CSS transform string from numeric values (no matrices). * * @param values Partial map of translate/scale/rotate values. * @returns A space-separated CSS `transform` string, or `""` when all values are defaults. * * @example * ```ts * buildTransform({ x: 10, y: 20, scale: 1.5 }) * // => "translate(10px, 20px) scale(1.5)" * * buildTransform({ x: 0, y: 0, rotate: 0 }) // all defaults * // => "" * ``` */ export declare const buildTransform: (values: TransformValues) => string; /** * Lightweight safety check for transform magnitudes and NaN values. * * @param values Transform values to validate. * @param opts Optional configuration; `maxScale` caps allowable absolute scale (default 8). * @returns `true` if all scale values are finite and within bounds. * * @example * ```ts * isSafeTransform({ scale: 2 }) // true * isSafeTransform({ scale: 100 }) // false (exceeds default maxScale=8) * isSafeTransform({ scale: 100 }, { maxScale: 200 }) // true * isSafeTransform({ scale: NaN }) // false * ``` */ export declare const isSafeTransform: (values: TransformValues, opts?: { maxScale?: number; }) => boolean; /** * Extract the uniform scale factor from a CSS `matrix()` string. * * @param matrix A CSS `matrix(...)` value, `"none"`, `null`, or `undefined`. * @returns The `a` component of the matrix (uniform scale), or `null` if unparseable. * * @example * ```ts * parseMatrixScale('matrix(1.5, 0, 0, 1.5, 0, 0)') // 1.5 * parseMatrixScale('none') // null * parseMatrixScale(null) // null * ``` */ export declare const parseMatrixScale: (matrix: string | null | undefined) => number | null; export type { TransformOptions }; /** * Any motion-value shape this library accepts as a transform input: the raw * motion-dom `MotionValue<T>` and our augmented `AugmentedMotionValue<T>` are * both runtime-identical (the augmentation is a Svelte 5 retype, not a * subclass), but TypeScript's private-field nominal typing means the two * aren't structurally assignable in public signatures. This alias accepts * both so call sites compile cleanly. */ export type AnyMotionValue<T> = MotionValue<T> | AugmentedMotionValue<T>; /** * A source for {@link useTransform}'s mapping form: any motion value or a * Svelte readable store. Svelte readables are bridged into a `MotionValue` * internally so motion-dom's `mapValue` / `transformValue` can track them. */ export type TransformSource<T> = AnyMotionValue<T> | Readable<T>; /** * Single-input transformer signature: `(latest) => output`. */ export type SingleTransformer<I, O> = (input: I) => O; /** * Multi-input transformer signature: `([latestA, latestB, ...]) => output`. */ export type MultiTransformer<I, O> = (inputs: I[]) => O; /** * Output map for the multi-output mapping form: `{ key: [stop, …] }`. The * keys are stable per call and each entry produces its own `MotionValue`. */ export type TransformOutputMap<O> = { [key: string]: O[]; }; /** * Creates an augmented `MotionValue<O>` derived from one or more `MotionValue`s * (or Svelte readables), composed via a range mapping or a compute function. * * Mirrors framer-motion's `useTransform` 1:1 with five forms: * * - **Mapping form** — `useTransform(source, input, output, options?)` maps a * numeric source's value across `input → output` stops with clamp, easing, * and a pluggable mixer for non-numeric outputs. Delegates to motion-dom's * `mapValue` (which is itself `transformValue` over the curried mapper). * - **Multi-output mapping form** — `useTransform(source, input, outputMap, options?)` * produces an object of motion values, one per key in `outputMap`. Each * value is the same mapping form applied to that key's output stops. * - **Single-transformer form** — `useTransform(mv, (latest) => O)` recomputes * on every change of `mv`. Auto-tracks via `transformValue`. * - **Multi-transformer form** — `useTransform([mv1, mv2, …], ([latest, …]) => O)` * recomputes on every change of any input. Auto-tracks via `transformValue`. * - **Compute form** — `useTransform(() => compute)` recomputes whenever any * `MotionValue` referenced inside `compute` (via `.get()` or `.current`) * changes. Auto-tracks via `transformValue` — no explicit deps array; the * `collectMotionValues` session inside `transformValue` discovers them. * * Returns an {@link AugmentedMotionValue<O>} — a real motion-dom `MotionValue` * (composes with `useSpring`, `useVelocity`, `animate()`, etc.) plus a * `$state`-backed `.current` getter and a Svelte readable `.subscribe` shim. * * Lifecycle: must be called during component initialization. Source * subscriptions, the underlying motion value, and any Svelte-readable bridges * are torn down when the surrounding `$effect` scope unmounts. * * @template O Output value type. * @param sourceOrCompute A motion value / readable (mapping forms), a single * `MotionValue` (single-transformer form), an array of `MotionValue`s * (multi-transformer form), or a compute function (compute form). * @param inputOrTransformer Input stops `number[]` (mapping forms) or a * transformer function (`(latest) => O` / `(latest[]) => O`). * @param outputOrOutputMap Output stops `O[]` (single-output mapping) or an * output map `{ [key]: O[] }` (multi-output mapping). * @param options Optional `TransformOptions` — `clamp`, `ease`, `mixer`. * @returns An `AugmentedMotionValue<O>` for single-output forms, or an object * of motion values keyed by `outputMap` for the multi-output form. * * @example * ```svelte * <script lang="ts"> * import { useMotionValue, useTransform } from '@humanspeak/svelte-motion' * * const x = useMotionValue(0) * * // Mapping form * const opacity = useTransform(x, [0, 100], [0, 1]) * * // Single-MV transformer * const doubled = useTransform(x, (latest) => latest * 2) * * // Compute form — auto-tracks via collectMotionValues * const y = useMotionValue(0) * const sum = useTransform(() => x.get() + y.get()) * * // Multi-output mapping * const { rotate, scale } = useTransform(x, [0, 100], { * rotate: [0, 360], * scale: [1, 2] * }) * </script> * * <div style="opacity: {opacity.current}; transform: rotate({rotate.current}deg) scale({scale.current})"> * {sum.current} * </div> * ``` * * @see https://motion.dev/docs/react-use-transform */ export declare function useTransform<O>(source: TransformSource<number>, input: number[], output: O[], options?: TransformOptions<O>): AugmentedMotionValue<O>; export declare function useTransform<T extends TransformOutputMap<unknown>>(source: TransformSource<number>, input: number[], outputMap: T, options?: TransformOptions<T[keyof T][number]>): { [K in keyof T]: AugmentedMotionValue<T[K][number]>; }; export declare function useTransform<I, O>(source: AnyMotionValue<I>, transformer: SingleTransformer<I, O>): AugmentedMotionValue<O>; export declare function useTransform<I, O>(sources: ReadonlyArray<AnyMotionValue<I>>, transformer: MultiTransformer<I, O>): AugmentedMotionValue<O>; export declare function useTransform<O>(compute: () => O): AugmentedMotionValue<O>;