@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
96 lines (95 loc) • 3.61 kB
TypeScript
/**
* Tuple returned by {@link usePresence}, matching framer-motion's shape:
* `[true, null]` while present (or when not inside a `PresenceChild`), and
* `[false, () => void]` after the wrapper enters its exit hold.
*/
export type UsePresenceState = [true, null] | [false, () => void];
/**
* Returns whether the calling component is currently present in its parent
* `<PresenceChild>`. While the wrapper holds the component for an exit, this
* flips to `false` so the consumer can branch (render different markup, run
* a custom exit animation, etc.).
*
* Outside of a `<PresenceChild>` always returns `true`.
*
* Reactivity note: the boolean tracks the wrapper's state and updates in
* Svelte 5 reactive contexts (`$derived`, `$effect`, template). For non-
* reactive snapshots, prefer `usePresence()` which exposes the same state
* alongside the `safeToRemove` callback.
*
* @returns `true` while present, `false` while exiting.
* @see https://motion.dev/docs/react-use-is-present
*
* @example
* ```svelte
* <script lang="ts">
* import { useIsPresent } from '@humanspeak/svelte-motion'
* const isPresent = $derived(useIsPresent())
* </script>
* <div class:exiting={!isPresent}>{isPresent ? 'live' : 'goodbye'}</div>
* ```
*/
export declare const useIsPresent: () => boolean;
/**
* Returns `[isPresent, safeToRemove]`. `isPresent` reflects the wrapper's
* presence state; `safeToRemove` is the callback to invoke once a custom exit
* animation finishes. Calling it triggers the actual unmount and decrements
* the parent `<AnimatePresence>` exit-completion count.
*
* Outside of a `<PresenceChild>` returns `[true, null]` — the consumer is
* effectively always present and there is nothing to safely remove.
*
* `safeToRemove` is idempotent and versioned: a stale callback from a
* canceled exit cycle (re-entry before the consumer signaled completion) is
* a no-op.
*
* @returns `[true, null]` while present (or outside any `PresenceChild`),
* `[false, () => void]` while the wrapper holds the component for exit.
* @see https://motion.dev/docs/react-use-presence
*
* @example
* ```svelte
* <script lang="ts">
* import { usePresence } from '@humanspeak/svelte-motion'
*
* let node: HTMLElement | undefined = $state()
* const presence = $derived(usePresence())
*
* $effect(() => {
* const [isPresent, safeToRemove] = presence
* if (isPresent || !node) return
* const onEnd = () => safeToRemove()
* node.addEventListener('transitionend', onEnd, { once: true })
* node.classList.add('exiting')
* return () => node?.removeEventListener('transitionend', onEnd)
* })
* </script>
*
* <div bind:this={node}>…</div>
* ```
*/
export declare const usePresence: () => UsePresenceState;
/**
* Returns the nearest `<AnimatePresence custom={...}>` data.
*
* This mirrors Motion's `usePresenceData()` hook. It is useful for children
* that need the latest parent presence data while rendering enter/exit
* keyframes, for example directional slideshow controls.
*
* Outside of `<AnimatePresence>`, this returns `undefined`.
*
* @typeParam T Expected custom data type.
* @returns The current AnimatePresence custom data, or `undefined` outside a
* presence boundary.
* @see https://motion.dev/docs/react-use-presence-data
*
* @example
* ```svelte
* <script lang="ts">
* import { usePresenceData } from '@humanspeak/svelte-motion'
*
* const direction = $derived(usePresenceData<1 | -1>() ?? 1)
* </script>
* ```
*/
export declare const usePresenceData: <T = unknown>() => T | undefined;