@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
TypeScript
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>;