UNPKG

framer-motion

Version:

A simple and powerful JavaScript animation library

89 lines (86 loc) • 3.42 kB
import { removeEffect, addEffect, activeScope } from 'motion-dom'; import { Timeline } from '../timeline/index.mjs'; import { animateSubject } from './subject.mjs'; function isSequence(value) { return Array.isArray(value) && value.some(Array.isArray); } /** * Creates an animation function that is optionally scoped * to a specific element. */ function createScopedAnimate(options = {}) { const { scope, reduceMotion, skipAnimations } = options; /** * Implementation */ function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options) { const motionScope = activeScope.current; const scopeTransition = motionScope?.transition; const inherited = {}; if (reduceMotion !== undefined) inherited.reduceMotion = reduceMotion; if (skipAnimations !== undefined) inherited.skipAnimations = skipAnimations; let timeline; if (isSequence(subjectOrSequence)) { const sequenceOptions = { ...inherited, ...optionsOrKeyframes, scope, }; if (scopeTransition) { sequenceOptions.defaultTransition = { ...scopeTransition, ...sequenceOptions.defaultTransition, }; } timeline = new Timeline(subjectOrSequence, sequenceOptions); } else { // Extract top-level onComplete so it doesn't get applied per-value const { onComplete, ...rest } = options || {}; const transition = { ...inherited, ...scopeTransition, ...rest, }; /** * Play the animations directly, and only compile them as a * sequence if the timeline is changed. Values animated from a * number are animated via their onUpdate callback instead. */ const { onUpdate } = rest; const segment = (typeof subjectOrSequence === "number" || (typeof subjectOrSequence === "string" && (typeof optionsOrKeyframes === "string" || Array.isArray(optionsOrKeyframes))) ? [ onUpdate || (() => { }), Array.isArray(optionsOrKeyframes) ? optionsOrKeyframes : [subjectOrSequence, optionsOrKeyframes], { ...transition, onUpdate: undefined }, ] : [subjectOrSequence, optionsOrKeyframes, transition]); timeline = new Timeline([segment], { ...inherited, onComplete, scope }, animateSubject(subjectOrSequence, optionsOrKeyframes, transition, scope)); } if (motionScope) { timeline.finished.then(motionScope.add(() => timeline.stop())); } return timeline; } return scopedAnimate; } const animate = /* @__PURE__ */ Object.assign( /* @__PURE__ */ createScopedAnimate(), { /** * Register an effect so `animate()` can animate the subjects it * claims, for instance `animate.addEffect(threeEffect)`. The most * recently added effect is tested first. DOM elements are always * animated directly. */ addEffect, removeEffect, }); export { animate, createScopedAnimate }; //# sourceMappingURL=index.mjs.map