UNPKG

motion-v

Version:

<p align="center"> <img width="100" height="100" alt="Motion logo" src="https://user-images.githubusercontent.com/7850794/164965523-3eced4c4-6020-467e-acde-f11b7900ad62.png" /> </p> <h1 align="center">Motion for Vue</h1>

189 lines (188 loc) 6.45 kB
import { invariant } from "hey-listen"; import { isSVGElement, resolveVariant, isAnimateChanged } from "./utils.mjs"; import { FeatureManager } from "../features/feature-manager.mjs"; import { doneCallbacks } from "../components/presence.mjs"; import { isVariantLabels } from "./utils/is-variant-labels.mjs"; import { noop } from "../external/.pnpm/motion-utils@12.5.0/external/motion-utils/dist/es/noop.mjs"; import "../external/.pnpm/motion-utils@12.5.0/external/motion-utils/dist/es/errors.mjs"; import { frame, cancelFrame } from "../external/.pnpm/motion-dom@12.5.0/external/motion-dom/dist/es/frameloop/frame.mjs"; const mountedStates = /* @__PURE__ */ new WeakMap(); let id = 0; const mountedLayoutIds = /* @__PURE__ */ new Set(); class MotionState { constructor(options, parent) { var _a; this.element = null; this.isSafeToRemove = false; this.isVShow = false; this.children = /* @__PURE__ */ new Set(); this.activeStates = { initial: true, animate: true }; this.currentProcess = null; this._context = null; this.animateUpdates = noop; this.id = `motion-state-${id++}`; this.options = options; this.parent = parent; (_a = parent == null ? void 0 : parent.children) == null ? void 0 : _a.add(this); this.depth = (parent == null ? void 0 : parent.depth) + 1 || 0; const initialVariantSource = this.context.initial === false ? ["initial", "animate"] : ["initial"]; this.initTarget(initialVariantSource); this.featureManager = new FeatureManager(this); this.type = isSVGElement(this.options.as) ? "svg" : "html"; } // Get animation context, falling back to parent context for inheritance get context() { if (!this._context) { const handler = { get: (target, prop) => { var _a; return isVariantLabels(this.options[prop]) ? this.options[prop] : (_a = this.parent) == null ? void 0 : _a.context[prop]; } }; this._context = new Proxy({}, handler); } return this._context; } // Initialize animation target values initTarget(initialVariantSource) { this.baseTarget = initialVariantSource.reduce((acc, variant) => { return { ...acc, ...resolveVariant(this.options[variant] || this.context[variant], this.options.variants) }; }, {}); this.target = {}; } // Update visual element with new options updateOptions() { var _a; (_a = this.visualElement) == null ? void 0 : _a.update({ ...this.options, whileTap: this.options.whilePress, reducedMotionConfig: this.options.motionConfig.reduceMotion }, { isPresent: !doneCallbacks.has(this.element) }); } // Called before mounting, executes in parent-to-child order beforeMount() { this.featureManager.beforeMount(); } // Mount motion state to DOM element, handles parent-child relationships mount(element, options, notAnimate = false) { var _a; invariant( Boolean(element), "Animation state must be mounted with valid Element" ); this.element = element; this.options = options; this.updateOptions(); this.featureManager.mount(); if (!notAnimate && this.options.animate) { if (this.type === "svg") { this.visualElement.updateDimensions(); } (_a = this.startAnimation) == null ? void 0 : _a.call(this); } if (this.options.layoutId) { mountedLayoutIds.add(this.options.layoutId); frame.render(() => { mountedLayoutIds.clear(); }); } } clearAnimation() { var _a, _b; this.currentProcess && cancelFrame(this.currentProcess); this.currentProcess = null; (_b = (_a = this.visualElement) == null ? void 0 : _a.variantChildren) == null ? void 0 : _b.forEach((child) => { child.state.clearAnimation(); }); } // update trigger animation startAnimation() { this.clearAnimation(); this.currentProcess = frame.render(() => { this.currentProcess = null; this.animateUpdates(); }); } // Called before unmounting, executes in child-to-parent order beforeUnmount() { this.featureManager.beforeUnmount(); } // Unmount motion state and optionally unmount children // Handles unmounting in the correct order based on component tree unmount(unMountChildren = false) { const shouldDelay = this.options.layoutId && !mountedLayoutIds.has(this.options.layoutId); const unmount = () => { if (unMountChildren) { Array.from(this.children).reverse().forEach(this.unmountChild); } const unmountState = () => { var _a, _b, _c; (_b = (_a = this.parent) == null ? void 0 : _a.children) == null ? void 0 : _b.delete(this); mountedStates.delete(this.element); this.featureManager.unmount(); (_c = this.visualElement) == null ? void 0 : _c.unmount(); }; if (shouldDelay) { Promise.resolve().then(unmountState); } else { unmountState(); } }; unmount(); } unmountChild(child) { child.unmount(true); } // Called before updating, executes in parent-to-child order beforeUpdate() { this.featureManager.beforeUpdate(); } // Update motion state with new options update(options) { const hasAnimateChange = isAnimateChanged(this.options, options); this.options = options; this.updateOptions(); this.featureManager.update(); if (hasAnimateChange) { this.startAnimation(); } } // Set animation state active status and propagate to children setActive(name, isActive, isAnimate = true) { var _a; if (!this.element || this.activeStates[name] === isActive) return; this.activeStates[name] = isActive; (_a = this.visualElement.variantChildren) == null ? void 0 : _a.forEach((child) => { child.state.setActive(name, isActive, false); }); if (isAnimate) { this.animateUpdates({ isFallback: !isActive && name !== "exit" && this.visualElement.isControllingVariants, isExit: name === "exit" && this.activeStates.exit }); } } isMounted() { return Boolean(this.element); } // Called before layout updates to prepare for changes willUpdate(label) { var _a; if (this.options.layout || this.options.layoutId) { (_a = this.visualElement.projection) == null ? void 0 : _a.willUpdate(); } } } export { MotionState, mountedStates };