@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
75 lines (74 loc) • 2.93 kB
TypeScript
import { type ElementOrGetter } from './dom.js';
/**
* Reference set of DOM `ElementOrGetter` inputs keyed by name.
*
* Each value is either a resolved element, a getter that returns one (used
* with Svelte's `bind:this` post-mount timing), or `undefined` when the
* caller does not need this slot.
*/
export type AttachableRefs = Record<string, ElementOrGetter | undefined>;
/**
* Map of resolved elements supplied to `onAttach`. Slots whose ref was
* `undefined` resolve to `undefined`.
*/
export type ResolvedRefs<R extends AttachableRefs> = {
[K in keyof R]: HTMLElement | undefined;
};
export type AttachableConfig<R extends AttachableRefs> = {
/** DOM refs that must resolve before `onAttach` runs. */
refs: R;
/**
* Called when every supplied ref has resolved. Receives a `stop` function
* that synchronously tears down the attachment - useful for one-shot
* latches that need to detach inside their own callback.
*
* Return a cleanup function for the standard "tear down on last
* unsubscribe" path.
*/
onAttach: (els: ResolvedRefs<R>, stop: VoidFunction) => VoidFunction | void;
/**
* When this returns `true`, `subscribe` short-circuits without attaching.
* Used by hooks that latch a value and stop observing (e.g. `once`).
* Subscribers added after the latch increment the refcount but never
* trigger `onAttach`; their unsubscribe is a clean no-op.
*/
isLatched?: () => boolean;
};
export type Attachable = {
/**
* Register a subscriber. Triggers `onAttach` on the first subscriber,
* polls on `requestAnimationFrame` until refs resolve. Returns a release
* function that cleans up when the last subscriber leaves.
*
* Callers must eventually unsubscribe; the rAF poll loop continues until
* either every ref resolves or the last subscriber releases.
*/
subscribe: () => () => void;
};
/**
* Builds a subscriber-refcounted DOM-attachment primitive. Both `useScroll`
* and `useInView` use this to defer observer setup until a subscriber arrives,
* poll for `bind:this` element resolution, and tear down on the last
* unsubscribe.
*
* @param config Attachment configuration: refs to resolve, an `onAttach`
* callback that returns a cleanup function, and an optional `isLatched`
* short-circuit.
* @returns An `Attachable` exposing `subscribe()` for use inside Svelte
* `readable(..., start)` callbacks.
* @example
* ```ts
* const attachable = createAttachable({
* refs: { target },
* onAttach: ({ target }) => {
* const stopObserving = startObserver(target!, ...)
* return stopObserving
* }
* })
* return readable(initial, (set) => {
* const release = attachable.subscribe()
* return release
* })
* ```
*/
export declare const createAttachable: <R extends AttachableRefs>(config: AttachableConfig<R>) => Attachable;