UNPKG

motion-v

Version:

<h1 align="center"> <img width="35" height="35" alt="Motion logo" src="https://github.com/user-attachments/assets/00d6d1c3-72c4-4c2f-a664-69da13182ffc" /><br />Motion for Vue</h1>

182 lines (181 loc) 7.12 kB
import { shallowCompare } from "./utils.mjs"; import { getVariantContext } from "./utils/get-variant-context.mjs"; import { animateVisualElement, calcChildStagger, isAnimationControls, isVariantLabel, resolveVariant } from "motion-dom"; var variantPriorityOrder = [ "animate", "whileInView", "whileFocus", "whileHover", "whilePress", "whileDrag", "exit" ]; var reversePriorityOrder = [...variantPriorityOrder].reverse(); var numAnimationTypes = variantPriorityOrder.length; function createTypeState(isActive = false) { return { isActive, protectedKeys: {}, needsAnimating: {}, prevResolvedValues: {} }; } function createState() { return { animate: createTypeState(true), whileInView: createTypeState(), whileHover: createTypeState(), whilePress: createTypeState(), whileDrag: createTypeState(), whileFocus: createTypeState(), exit: createTypeState() }; } function checkVariantsDidChange(prev, next) { if (typeof next === "string") return next !== prev; else if (Array.isArray(next)) return !shallowCompare(next, prev); return false; } function isKeyframesTarget(v) { return Array.isArray(v); } function createAnimateFunction(visualElement) { return (animations) => { return Promise.all(animations.map(({ animation, options }) => animateVisualElement(visualElement, animation, options))); }; } function createAnimationState(visualElement) { let animate = createAnimateFunction(visualElement); let state = createState(); let isInitialRender = true; const buildResolvedTypeValues = (type) => (acc, definition) => { const resolved = resolveVariant(visualElement, definition, type === "exit" ? visualElement.presenceContext?.custom : void 0); if (resolved) { const { transition, transitionEnd, ...target } = resolved; acc = { ...acc, ...target, ...transitionEnd }; } return acc; }; function setAnimateFunction(makeAnimator) { animate = makeAnimator(visualElement); } function animateChanges(changedActiveType) { const { props } = visualElement; const context = getVariantContext(visualElement.parent) || {}; const animations = []; const removedKeys = /* @__PURE__ */ new Set(); let encounteredKeys = {}; let removedVariantIndex = Infinity; for (let i = 0; i < numAnimationTypes; i++) { const type = reversePriorityOrder[i]; const typeState = state[type]; const prop = props[type] !== void 0 ? props[type] : context[type]; const propIsVariant = isVariantLabel(prop); const activeDelta = type === changedActiveType ? typeState.isActive : null; if (activeDelta === false) removedVariantIndex = i; let isInherited = prop === context[type] && prop !== props[type] && propIsVariant; if (isInherited && isInitialRender && visualElement.manuallyAnimateOnMount) isInherited = false; typeState.protectedKeys = { ...encounteredKeys }; if (!typeState.isActive && activeDelta === null || !prop && !typeState.prevProp || isAnimationControls(prop) || typeof prop === "boolean") continue; const variantDidChange = checkVariantsDidChange(typeState.prevProp, prop); let shouldAnimateType = variantDidChange || type === changedActiveType && typeState.isActive && !isInherited && propIsVariant || i > removedVariantIndex && propIsVariant; let handledRemovedValues = false; const definitionList = Array.isArray(prop) ? prop : [prop]; let resolvedValues = definitionList.reduce(buildResolvedTypeValues(type), {}); if (activeDelta === false) resolvedValues = {}; const { prevResolvedValues = {} } = typeState; const allKeys = { ...prevResolvedValues, ...resolvedValues }; const markToAnimate = (key) => { shouldAnimateType = true; if (removedKeys.has(key)) { handledRemovedValues = true; removedKeys.delete(key); } typeState.needsAnimating[key] = true; const motionValue$1 = visualElement.getValue(key); if (motionValue$1) motionValue$1.liveStyle = false; }; for (const key in allKeys) { const next = resolvedValues[key]; const prev = prevResolvedValues[key]; if (Object.hasOwnProperty.call(encounteredKeys, key)) continue; let valueHasChanged = false; if (isKeyframesTarget(next) && isKeyframesTarget(prev)) valueHasChanged = !shallowCompare(next, prev); else valueHasChanged = next !== prev; if (valueHasChanged) if (next !== void 0 && next !== null) markToAnimate(key); else removedKeys.add(key); else if (next !== void 0 && removedKeys.has(key)) markToAnimate(key); else typeState.protectedKeys[key] = true; } typeState.prevProp = prop; typeState.prevResolvedValues = resolvedValues; if (typeState.isActive) encounteredKeys = { ...encounteredKeys, ...resolvedValues }; if (isInitialRender && visualElement.blockInitialAnimation) shouldAnimateType = false; const willAnimateViaParent = isInherited && variantDidChange; if (shouldAnimateType && (!willAnimateViaParent || handledRemovedValues)) animations.push(...definitionList.map((animation) => { const options = { type }; if (typeof animation === "string" && isInitialRender && !willAnimateViaParent && visualElement.manuallyAnimateOnMount && visualElement.parent) { const { parent } = visualElement; const parentVariant = resolveVariant(parent, animation); if (parent.enteringChildren && parentVariant) { const { delayChildren } = parentVariant.transition || {}; options.delay = calcChildStagger(parent.enteringChildren, visualElement, delayChildren); } } return { animation, options }; })); } if (removedKeys.size) { const fallbackAnimation = {}; if (typeof props.initial !== "boolean") { const initialTransition = resolveVariant(visualElement, Array.isArray(props.initial) ? props.initial[0] : props.initial); if (initialTransition && initialTransition.transition) fallbackAnimation.transition = initialTransition.transition; } removedKeys.forEach((key) => { const fallbackTarget = visualElement.getBaseTarget(key); const motionValue$1 = visualElement.getValue(key); if (motionValue$1) motionValue$1.liveStyle = true; fallbackAnimation[key] = fallbackTarget ?? null; }); animations.push({ animation: fallbackAnimation }); } let shouldAnimate = Boolean(animations.length); if (isInitialRender && (props.initial === false || props.initial === props.animate) && !visualElement.manuallyAnimateOnMount) shouldAnimate = false; isInitialRender = false; return shouldAnimate ? animate(animations) : Promise.resolve(); } function setActive(type, isActive) { if (state[type].isActive === isActive) return Promise.resolve(); visualElement.variantChildren?.forEach((child) => { child.animationState?.setActive(type, isActive); }); state[type].isActive = isActive; const animations = animateChanges(type); for (const key in state) state[key].protectedKeys = {}; return animations; } return { animateChanges, setActive, setAnimateFunction, getState: () => state, reset: () => { state = createState(); isInitialRender = true; } }; } export { createAnimationState };