@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
JavaScript
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();
};
};
};