UNPKG

@omicrxn/mercury

Version:

Mercury is a Svelte animation library powered by Motion. It simplifies complex animations with Svelte actions, provides layout and exit animations, and integrates seamlessly with Svelte features.

63 lines (62 loc) 2.72 kB
import { animate as motionAnimate } from 'motion'; import { handleGestures } from './gestures/index.js'; import { hasPendingWaitExit, registerMercuryControls, runAfterPendingExit, stopMercury } from './presence-coordinator.js'; import { mapTransitionToMotion } from './utils.js'; import { clearPresence } from './animate-presence.js'; /** Elements that have had a mercury `animate` applied at least once (for `animateOnMount: false`). */ const initialized = new WeakSet(); export const mercury = (options) => { return (element) => { let animation; let disposed = false; clearPresence(element); if (options?.animate && options.animateOnMount === false && !initialized.has(element)) { initialized.add(element); // animateOnMount: false — render the settled `animate` state on first // application (keyframe arrays snap to their last frame), animate on updates. motionAnimate(element, options.animate, { duration: 0 }); } else if (options?.animate) { initialized.add(element); const { animate, transition, callbacks } = options; const startAnimation = () => { if (disposed) return; const controls = motionAnimate(element, animate, mapTransitionToMotion(transition, callbacks)); registerMercuryControls(element, controls); const instance = { completed: false, play: () => controls.play(), pause: () => controls.pause(), stop: () => controls.stop(), cancel: () => controls.cancel(), onComplete: (onResolve, onReject) => controls.then(() => { onResolve(); instance.completed = true; }, onReject) }; animation = instance; options.instance?.(instance); }; const scheduleEnter = () => { if (disposed) return; if (hasPendingWaitExit(element)) { runAfterPendingExit(element, startAnimation); } else { startAnimation(); } }; // One microtask so out:presence can register wait in the same commit. queueMicrotask(scheduleEnter); } const cleanupGestures = handleGestures(element, options); return () => { disposed = true; stopMercury(element); animation?.stop(); cleanupGestures(); }; }; };