'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var React = require('react'); var heyListen = require('hey-listen'); var styleValueTypes = require('style-value-types'); var popmotion = require('popmotion'); var sync = require('framesync'); var dom = require('@motionone/dom'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var sync__default = /*#__PURE__*/_interopDefaultLegacy(sync); /** * Browser-safe usage of process */ var defaultEnvironment = "production"; var env = typeof process === "undefined" || process.env === undefined ? defaultEnvironment : process.env.NODE_ENV || defaultEnvironment; var createDefinition = function (propNames) { return ({ isEnabled: function (props) { return propNames.some(function (name) { return !!props[name]; }); }, }); }; var featureDefinitions = { measureLayout: createDefinition(["layout", "layoutId", "drag"]), animation: createDefinition([ "animate", "exit", "variants", "whileHover", "whileTap", "whileFocus", "whileDrag", "whileInView", ]), exit: createDefinition(["exit"]), drag: createDefinition(["drag", "dragControls"]), focus: createDefinition(["whileFocus"]), hover: createDefinition(["whileHover", "onHoverStart", "onHoverEnd"]), tap: createDefinition(["whileTap", "onTap", "onTapStart", "onTapCancel"]), pan: createDefinition([ "onPan", "onPanStart", "onPanSessionStart", "onPanEnd", ]), inView: createDefinition([ "whileInView", "onViewportEnter", "onViewportLeave", ]), }; function loadFeatures(features) { for (var key in features) { if (features[key] === null) continue; if (key === "projectionNodeConstructor") { featureDefinitions.projectionNodeConstructor = features[key]; } else { featureDefinitions[key].Component = features[key]; } } } var LazyContext = React.createContext({ strict: false }); var featureNames = Object.keys(featureDefinitions); var numFeatures = featureNames.length; /** * Load features via renderless components based on the provided MotionProps. */ function useFeatures(props, visualElement, preloadedFeatures) { var features = []; var lazyContext = React.useContext(LazyContext); if (!visualElement) return null; /** * If we're in development mode, check to make sure we're not rendering a motion component * as a child of LazyMotion, as this will break the file-size benefits of using it. */ if (env !== "production" && preloadedFeatures && lazyContext.strict) { heyListen.invariant(false, "You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead."); } for (var i = 0; i < numFeatures; i++) { var name_1 = featureNames[i]; var _a = featureDefinitions[name_1], isEnabled = _a.isEnabled, Component = _a.Component; /** * It might be possible in the future to use this moment to * dynamically request functionality. In initial tests this * was producing a lot of duplication amongst bundles. */ if (isEnabled(props) && Component) { features.push(React__namespace.createElement(Component, tslib.__assign({ key: name_1 }, props, { visualElement: visualElement }))); } } return features; } /** * @public */ var MotionConfigContext = React.createContext({ transformPagePoint: function (p) { return p; }, isStatic: false, reducedMotion: "never", }); var MotionContext = React.createContext({}); function useVisualElementContext() { return React.useContext(MotionContext).visualElement; } /** * @public */ var PresenceContext = React.createContext(null); var isBrowser = typeof document !== "undefined"; var useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect; // Does this device prefer reduced motion? Returns `null` server-side. var prefersReducedMotion = { current: null }; var hasDetected = false; function initPrefersReducedMotion() { hasDetected = true; if (!isBrowser) return; if (window.matchMedia) { var motionMediaQuery_1 = window.matchMedia("(prefers-reduced-motion)"); var setReducedMotionPreferences = function () { return (prefersReducedMotion.current = motionMediaQuery_1.matches); }; motionMediaQuery_1.addListener(setReducedMotionPreferences); setReducedMotionPreferences(); } else { prefersReducedMotion.current = false; } } /** * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting. * * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion. * * It will actively respond to changes and re-render your components with the latest setting. * * ```jsx * export function Sidebar({ isOpen }) { * const shouldReduceMotion = useReducedMotion() * const closedX = shouldReduceMotion ? 0 : "-100%" * * return ( * * ) * } * ``` * * @return boolean * * @public */ function useReducedMotion() { /** * Lazy initialisation of prefersReducedMotion */ !hasDetected && initPrefersReducedMotion(); var _a = tslib.__read(React.useState(prefersReducedMotion.current), 1), shouldReduceMotion = _a[0]; /** * TODO See if people miss automatically updating shouldReduceMotion setting */ return shouldReduceMotion; } function useReducedMotionConfig() { var reducedMotionPreference = useReducedMotion(); var reducedMotion = React.useContext(MotionConfigContext).reducedMotion; if (reducedMotion === "never") { return false; } else if (reducedMotion === "always") { return true; } else { return reducedMotionPreference; } } function useVisualElement(Component, visualState, props, createVisualElement) { var lazyContext = React.useContext(LazyContext); var parent = useVisualElementContext(); var presenceContext = React.useContext(PresenceContext); var shouldReduceMotion = useReducedMotionConfig(); var visualElementRef = React.useRef(undefined); /** * If we haven't preloaded a renderer, check to see if we have one lazy-loaded */ if (!createVisualElement) createVisualElement = lazyContext.renderer; if (!visualElementRef.current && createVisualElement) { visualElementRef.current = createVisualElement(Component, { visualState: visualState, parent: parent, props: props, presenceId: presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.id, blockInitialAnimation: (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) === false, shouldReduceMotion: shouldReduceMotion, }); } var visualElement = visualElementRef.current; useIsomorphicLayoutEffect(function () { visualElement === null || visualElement === void 0 ? void 0 : visualElement.syncRender(); }); React.useEffect(function () { var _a; (_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.animationState) === null || _a === void 0 ? void 0 : _a.animateChanges(); }); useIsomorphicLayoutEffect(function () { return function () { return visualElement === null || visualElement === void 0 ? void 0 : visualElement.notifyUnmount(); }; }, []); return visualElement; } function isRefObject(ref) { return (typeof ref === "object" && Object.prototype.hasOwnProperty.call(ref, "current")); } /** * Creates a ref function that, when called, hydrates the provided * external ref and VisualElement. */ function useMotionRef(visualState, visualElement, externalRef) { return React.useCallback(function (instance) { var _a; instance && ((_a = visualState.mount) === null || _a === void 0 ? void 0 : _a.call(visualState, instance)); if (visualElement) { instance ? visualElement.mount(instance) : visualElement.unmount(); } if (externalRef) { if (typeof externalRef === "function") { externalRef(instance); } else if (isRefObject(externalRef)) { externalRef.current = instance; } } }, /** * Only pass a new ref callback to React if we've received a visual element * factory. Otherwise we'll be mounting/remounting every time externalRef * or other dependencies change. */ [visualElement]); } /** * Decides if the supplied variable is an array of variant labels */ function isVariantLabels(v) { return Array.isArray(v); } /** * Decides if the supplied variable is variant label */ function isVariantLabel(v) { return typeof v === "string" || isVariantLabels(v); } /** * Creates an object containing the latest state of every MotionValue on a VisualElement */ function getCurrent(visualElement) { var current = {}; visualElement.forEachValue(function (value, key) { return (current[key] = value.get()); }); return current; } /** * Creates an object containing the latest velocity of every MotionValue on a VisualElement */ function getVelocity$1(visualElement) { var velocity = {}; visualElement.forEachValue(function (value, key) { return (velocity[key] = value.getVelocity()); }); return velocity; } function resolveVariantFromProps(props, definition, custom, currentValues, currentVelocity) { var _a; if (currentValues === void 0) { currentValues = {}; } if (currentVelocity === void 0) { currentVelocity = {}; } /** * If the variant definition is a function, resolve. */ if (typeof definition === "function") { definition = definition(custom !== null && custom !== void 0 ? custom : props.custom, currentValues, currentVelocity); } /** * If the variant definition is a variant label, or * the function returned a variant label, resolve. */ if (typeof definition === "string") { definition = (_a = props.variants) === null || _a === void 0 ? void 0 : _a[definition]; } /** * At this point we've resolved both functions and variant labels, * but the resolved variant label might itself have been a function. * If so, resolve. This can only have returned a valid target object. */ if (typeof definition === "function") { definition = definition(custom !== null && custom !== void 0 ? custom : props.custom, currentValues, currentVelocity); } return definition; } function resolveVariant(visualElement, definition, custom) { var props = visualElement.getProps(); return resolveVariantFromProps(props, definition, custom !== null && custom !== void 0 ? custom : props.custom, getCurrent(visualElement), getVelocity$1(visualElement)); } function checkIfControllingVariants(props) { var _a; return (typeof ((_a = props.animate) === null || _a === void 0 ? void 0 : _a.start) === "function" || isVariantLabel(props.initial) || isVariantLabel(props.animate) || isVariantLabel(props.whileHover) || isVariantLabel(props.whileDrag) || isVariantLabel(props.whileTap) || isVariantLabel(props.whileFocus) || isVariantLabel(props.exit)); } function checkIfVariantNode(props) { return Boolean(checkIfControllingVariants(props) || props.variants); } function getCurrentTreeVariants(props, context) { if (checkIfControllingVariants(props)) { var initial = props.initial, animate = props.animate; return { initial: initial === false || isVariantLabel(initial) ? initial : undefined, animate: isVariantLabel(animate) ? animate : undefined, }; } return props.inherit !== false ? context : {}; } function useCreateMotionContext(props) { var _a = getCurrentTreeVariants(props, React.useContext(MotionContext)), initial = _a.initial, animate = _a.animate; return React.useMemo(function () { return ({ initial: initial, animate: animate }); }, [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate)]); } function variantLabelsAsDependency(prop) { return Array.isArray(prop) ? prop.join(" ") : prop; } /** * Creates a constant value over the lifecycle of a component. * * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer * a guarantee that it won't re-run for performance reasons later on. By using `useConstant` * you can ensure that initialisers don't execute twice or more. */ function useConstant(init) { var ref = React.useRef(null); if (ref.current === null) { ref.current = init(); } return ref.current; } /** * This should only ever be modified on the client otherwise it'll * persist through server requests. If we need instanced states we * could lazy-init via root. */ var globalProjectionState = { /** * Global flag as to whether the tree has animated since the last time * we resized the window */ hasAnimatedSinceResize: true, /** * We set this to true once, on the first update. Any nodes added to the tree beyond that * update will be given a `data-projection-id` attribute. */ hasEverUpdated: false, }; var id$1 = 1; function useProjectionId() { return useConstant(function () { if (globalProjectionState.hasEverUpdated) { return id$1++; } }); } var LayoutGroupContext = React.createContext({}); /** * Internal, exported only for usage in Framer */ var SwitchLayoutGroupContext = React.createContext({}); function useProjection(projectionId, _a, visualElement, ProjectionNodeConstructor) { var _b; var layoutId = _a.layoutId, layout = _a.layout, drag = _a.drag, dragConstraints = _a.dragConstraints, layoutScroll = _a.layoutScroll; var initialPromotionConfig = React.useContext(SwitchLayoutGroupContext); if (!ProjectionNodeConstructor || !visualElement || (visualElement === null || visualElement === void 0 ? void 0 : visualElement.projection)) { return; } visualElement.projection = new ProjectionNodeConstructor(projectionId, visualElement.getLatestValues(), (_b = visualElement.parent) === null || _b === void 0 ? void 0 : _b.projection); visualElement.projection.setOptions({ layoutId: layoutId, layout: layout, alwaysMeasureLayout: Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)), visualElement: visualElement, scheduleRender: function () { return visualElement.scheduleRender(); }, /** * TODO: Update options in an effect. This could be tricky as it'll be too late * to update by the time layout animations run. * We also need to fix this safeToRemove by linking it up to the one returned by usePresence, * ensuring it gets called if there's no potential layout animations. * */ animationType: typeof layout === "string" ? layout : "both", initialPromotionConfig: initialPromotionConfig, layoutScroll: layoutScroll, }); } var VisualElementHandler = /** @class */ (function (_super) { tslib.__extends(VisualElementHandler, _super); function VisualElementHandler() { return _super !== null && _super.apply(this, arguments) || this; } /** * Update visual element props as soon as we know this update is going to be commited. */ VisualElementHandler.prototype.getSnapshotBeforeUpdate = function () { this.updateProps(); return null; }; VisualElementHandler.prototype.componentDidUpdate = function () { }; VisualElementHandler.prototype.updateProps = function () { var _a = this.props, visualElement = _a.visualElement, props = _a.props; if (visualElement) visualElement.setProps(props); }; VisualElementHandler.prototype.render = function () { return this.props.children; }; return VisualElementHandler; }(React__default["default"].Component)); /** * Create a `motion` component. * * This function accepts a Component argument, which can be either a string (ie "div" * for `motion.div`), or an actual React component. * * Alongside this is a config option which provides a way of rendering the provided * component "offline", or outside the React render cycle. */ function createMotionComponent(_a) { var preloadedFeatures = _a.preloadedFeatures, createVisualElement = _a.createVisualElement, projectionNodeConstructor = _a.projectionNodeConstructor, useRender = _a.useRender, useVisualState = _a.useVisualState, Component = _a.Component; preloadedFeatures && loadFeatures(preloadedFeatures); function MotionComponent(props, externalRef) { var layoutId = useLayoutId(props); props = tslib.__assign(tslib.__assign({}, props), { layoutId: layoutId }); /** * If we're rendering in a static environment, we only visually update the component * as a result of a React-rerender rather than interactions or animations. This * means we don't need to load additional memory structures like VisualElement, * or any gesture/animation features. */ var config = React.useContext(MotionConfigContext); var features = null; var context = useCreateMotionContext(props); /** * Create a unique projection ID for this component. If a new component is added * during a layout animation we'll use this to query the DOM and hydrate its ref early, allowing * us to measure it as soon as any layout effect flushes pending layout animations. * * Performance note: It'd be better not to have to search the DOM for these elements. * For newly-entering components it could be enough to only correct treeScale, in which * case we could mount in a scale-correction mode. This wouldn't be enough for * shared element transitions however. Perhaps for those we could revert to a root node * that gets forceRendered and layout animations are triggered on its layout effect. */ var projectionId = config.isStatic ? undefined : useProjectionId(); /** * */ var visualState = useVisualState(props, config.isStatic); if (!config.isStatic && isBrowser) { /** * Create a VisualElement for this component. A VisualElement provides a common * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as * providing a way of rendering to these APIs outside of the React render loop * for more performant animations and interactions */ context.visualElement = useVisualElement(Component, visualState, tslib.__assign(tslib.__assign({}, config), props), createVisualElement); useProjection(projectionId, props, context.visualElement, projectionNodeConstructor || featureDefinitions.projectionNodeConstructor); /** * Load Motion gesture and animation features. These are rendered as renderless * components so each feature can optionally make use of React lifecycle methods. */ features = useFeatures(props, context.visualElement, preloadedFeatures); } /** * The mount order and hierarchy is specific to ensure our element ref * is hydrated by the time features fire their effects. */ return (React__namespace.createElement(VisualElementHandler, { visualElement: context.visualElement, props: tslib.__assign(tslib.__assign({}, config), props) }, features, React__namespace.createElement(MotionContext.Provider, { value: context }, useRender(Component, props, projectionId, useMotionRef(visualState, context.visualElement, externalRef), visualState, config.isStatic, context.visualElement)))); } return React.forwardRef(MotionComponent); } function useLayoutId(_a) { var _b; var layoutId = _a.layoutId; var layoutGroupId = (_b = React.useContext(LayoutGroupContext)) === null || _b === void 0 ? void 0 : _b.id; return layoutGroupId && layoutId !== undefined ? layoutGroupId + "-" + layoutId : layoutId; } /** * Convert any React component into a `motion` component. The provided component * **must** use `React.forwardRef` to the underlying DOM component you want to animate. * * ```jsx * const Component = React.forwardRef((props, ref) => { * return
* }) * * const MotionComponent = motion(Component) * ``` * * @public */ function createMotionProxy(createConfig) { function custom(Component, customMotionComponentConfig) { if (customMotionComponentConfig === void 0) { customMotionComponentConfig = {}; } return createMotionComponent(createConfig(Component, customMotionComponentConfig)); } if (typeof Proxy === "undefined") { return custom; } /** * A cache of generated `motion` components, e.g `motion.div`, `motion.input` etc. * Rather than generating them anew every render. */ var componentCache = new Map(); return new Proxy(custom, { /** * Called when `motion` is referenced with a prop: `motion.div`, `motion.input` etc. * The prop name is passed through as `key` and we can use that to generate a `motion` * DOM component with that name. */ get: function (_target, key) { /** * If this element doesn't exist in the component cache, create it and cache. */ if (!componentCache.has(key)) { componentCache.set(key, custom(key)); } return componentCache.get(key); }, }); } /** * We keep these listed seperately as we use the lowercase tag names as part * of the runtime bundle to detect SVG components */ var lowercaseSVGElements = [ "animate", "circle", "defs", "desc", "ellipse", "g", "image", "line", "filter", "marker", "mask", "metadata", "path", "pattern", "polygon", "polyline", "rect", "stop", "svg", "switch", "symbol", "text", "tspan", "use", "view", ]; function isSVGComponent(Component) { if ( /** * If it's not a string, it's a custom React component. Currently we only support * HTML custom React components. */ typeof Component !== "string" || /** * If it contains a dash, the element is a custom HTML webcomponent. */ Component.includes("-")) { return false; } else if ( /** * If it's in our list of lowercase SVG tags, it's an SVG component */ lowercaseSVGElements.indexOf(Component) > -1 || /** * If it contains a capital letter, it's an SVG component */ /[A-Z]/.test(Component)) { return true; } return false; } var scaleCorrectors = {}; function addScaleCorrector(correctors) { Object.assign(scaleCorrectors, correctors); } /** * A list of all transformable axes. We'll use this list to generated a version * of each axes for each transform. */ var transformAxes = ["", "X", "Y", "Z"]; /** * An ordered array of each transformable value. By default, transform values * will be sorted to this order. */ var order = ["translate", "scale", "rotate", "skew"]; /** * Generate a list of every possible transform key. */ var transformProps = ["transformPerspective", "x", "y", "z"]; order.forEach(function (operationKey) { return transformAxes.forEach(function (axesKey) { return transformProps.push(operationKey + axesKey); }); }); /** * A function to use with Array.sort to sort transform keys by their default order. */ function sortTransformProps(a, b) { return transformProps.indexOf(a) - transformProps.indexOf(b); } /** * A quick lookup for transform props. */ var transformPropSet = new Set(transformProps); function isTransformProp(key) { return transformPropSet.has(key); } /** * A quick lookup for transform origin props */ var transformOriginProps = new Set(["originX", "originY", "originZ"]); function isTransformOriginProp(key) { return transformOriginProps.has(key); } function isForcedMotionValue(key, _a) { var layout = _a.layout, layoutId = _a.layoutId; return (isTransformProp(key) || isTransformOriginProp(key) || ((layout || layoutId !== undefined) && (!!scaleCorrectors[key] || key === "opacity"))); } var isMotionValue = function (value) { return Boolean(value !== null && typeof value === "object" && value.getVelocity); }; var translateAlias = { x: "translateX", y: "translateY", z: "translateZ", transformPerspective: "perspective", }; /** * Build a CSS transform style from individual x/y/scale etc properties. * * This outputs with a default order of transforms/scales/rotations, this can be customised by * providing a transformTemplate function. */ function buildTransform(_a, _b, transformIsDefault, transformTemplate) { var transform = _a.transform, transformKeys = _a.transformKeys; var _c = _b.enableHardwareAcceleration, enableHardwareAcceleration = _c === void 0 ? true : _c, _d = _b.allowTransformNone, allowTransformNone = _d === void 0 ? true : _d; // The transform string we're going to build into. var transformString = ""; // Transform keys into their default order - this will determine the output order. transformKeys.sort(sortTransformProps); // Track whether the defined transform has a defined z so we don't add a // second to enable hardware acceleration var transformHasZ = false; // Loop over each transform and build them into transformString var numTransformKeys = transformKeys.length; for (var i = 0; i < numTransformKeys; i++) { var key = transformKeys[i]; transformString += "".concat(translateAlias[key] || key, "(").concat(transform[key], ") "); if (key === "z") transformHasZ = true; } if (!transformHasZ && enableHardwareAcceleration) { transformString += "translateZ(0)"; } else { transformString = transformString.trim(); } // If we have a custom `transform` template, pass our transform values and // generated transformString to that before returning if (transformTemplate) { transformString = transformTemplate(transform, transformIsDefault ? "" : transformString); } else if (allowTransformNone && transformIsDefault) { transformString = "none"; } return transformString; } /** * Build a transformOrigin style. Uses the same defaults as the browser for * undefined origins. */ function buildTransformOrigin(_a) { var _b = _a.originX, originX = _b === void 0 ? "50%" : _b, _c = _a.originY, originY = _c === void 0 ? "50%" : _c, _d = _a.originZ, originZ = _d === void 0 ? 0 : _d; return "".concat(originX, " ").concat(originY, " ").concat(originZ); } /** * Returns true if the provided key is a CSS variable */ function isCSSVariable$1(key) { return key.startsWith("--"); } /** * Provided a value and a ValueType, returns the value as that value type. */ var getValueAsType = function (value, type) { return type && typeof value === "number" ? type.transform(value) : value; }; var int = tslib.__assign(tslib.__assign({}, styleValueTypes.number), { transform: Math.round }); var numberValueTypes = { // Border props borderWidth: styleValueTypes.px, borderTopWidth: styleValueTypes.px, borderRightWidth: styleValueTypes.px, borderBottomWidth: styleValueTypes.px, borderLeftWidth: styleValueTypes.px, borderRadius: styleValueTypes.px, radius: styleValueTypes.px, borderTopLeftRadius: styleValueTypes.px, borderTopRightRadius: styleValueTypes.px, borderBottomRightRadius: styleValueTypes.px, borderBottomLeftRadius: styleValueTypes.px, // Positioning props width: styleValueTypes.px, maxWidth: styleValueTypes.px, height: styleValueTypes.px, maxHeight: styleValueTypes.px, size: styleValueTypes.px, top: styleValueTypes.px, right: styleValueTypes.px, bottom: styleValueTypes.px, left: styleValueTypes.px, // Spacing props padding: styleValueTypes.px, paddingTop: styleValueTypes.px, paddingRight: styleValueTypes.px, paddingBottom: styleValueTypes.px, paddingLeft: styleValueTypes.px, margin: styleValueTypes.px, marginTop: styleValueTypes.px, marginRight: styleValueTypes.px, marginBottom: styleValueTypes.px, marginLeft: styleValueTypes.px, // Transform props rotate: styleValueTypes.degrees, rotateX: styleValueTypes.degrees, rotateY: styleValueTypes.degrees, rotateZ: styleValueTypes.degrees, scale: styleValueTypes.scale, scaleX: styleValueTypes.scale, scaleY: styleValueTypes.scale, scaleZ: styleValueTypes.scale, skew: styleValueTypes.degrees, skewX: styleValueTypes.degrees, skewY: styleValueTypes.degrees, distance: styleValueTypes.px, translateX: styleValueTypes.px, translateY: styleValueTypes.px, translateZ: styleValueTypes.px, x: styleValueTypes.px, y: styleValueTypes.px, z: styleValueTypes.px, perspective: styleValueTypes.px, transformPerspective: styleValueTypes.px, opacity: styleValueTypes.alpha, originX: styleValueTypes.progressPercentage, originY: styleValueTypes.progressPercentage, originZ: styleValueTypes.px, // Misc zIndex: int, // SVG fillOpacity: styleValueTypes.alpha, strokeOpacity: styleValueTypes.alpha, numOctaves: int, }; function buildHTMLStyles(state, latestValues, options, transformTemplate) { var _a; var style = state.style, vars = state.vars, transform = state.transform, transformKeys = state.transformKeys, transformOrigin = state.transformOrigin; // Empty the transformKeys array. As we're throwing out refs to its items // this might not be as cheap as suspected. Maybe using the array as a buffer // with a manual incrementation would be better. transformKeys.length = 0; // Track whether we encounter any transform or transformOrigin values. var hasTransform = false; var hasTransformOrigin = false; // Does the calculated transform essentially equal "none"? var transformIsNone = true; /** * Loop over all our latest animated values and decide whether to handle them * as a style or CSS variable. * * Transforms and transform origins are kept seperately for further processing. */ for (var key in latestValues) { var value = latestValues[key]; /** * If this is a CSS variable we don't do any further processing. */ if (isCSSVariable$1(key)) { vars[key] = value; continue; } // Convert the value to its default value type, ie 0 -> "0px" var valueType = numberValueTypes[key]; var valueAsType = getValueAsType(value, valueType); if (isTransformProp(key)) { // If this is a transform, flag to enable further transform processing hasTransform = true; transform[key] = valueAsType; transformKeys.push(key); // If we already know we have a non-default transform, early return if (!transformIsNone) continue; // Otherwise check to see if this is a default transform if (value !== ((_a = valueType.default) !== null && _a !== void 0 ? _a : 0)) transformIsNone = false; } else if (isTransformOriginProp(key)) { transformOrigin[key] = valueAsType; // If this is a transform origin, flag and enable further transform-origin processing hasTransformOrigin = true; } else { style[key] = valueAsType; } } if (hasTransform) { style.transform = buildTransform(state, options, transformIsNone, transformTemplate); } else if (transformTemplate) { style.transform = transformTemplate({}, ""); } else if (!latestValues.transform && style.transform) { style.transform = "none"; } if (hasTransformOrigin) { style.transformOrigin = buildTransformOrigin(transformOrigin); } } var createHtmlRenderState = function () { return ({ style: {}, transform: {}, transformKeys: [], transformOrigin: {}, vars: {}, }); }; function copyRawValuesOnly(target, source, props) { for (var key in source) { if (!isMotionValue(source[key]) && !isForcedMotionValue(key, props)) { target[key] = source[key]; } } } function useInitialMotionValues(_a, visualState, isStatic) { var transformTemplate = _a.transformTemplate; return React.useMemo(function () { var state = createHtmlRenderState(); buildHTMLStyles(state, visualState, { enableHardwareAcceleration: !isStatic }, transformTemplate); var vars = state.vars, style = state.style; return tslib.__assign(tslib.__assign({}, vars), style); }, [visualState]); } function useStyle(props, visualState, isStatic) { var styleProp = props.style || {}; var style = {}; /** * Copy non-Motion Values straight into style */ copyRawValuesOnly(style, styleProp, props); Object.assign(style, useInitialMotionValues(props, visualState, isStatic)); if (props.transformValues) { style = props.transformValues(style); } return style; } function useHTMLProps(props, visualState, isStatic) { // The `any` isn't ideal but it is the type of createElement props argument var htmlProps = {}; var style = useStyle(props, visualState, isStatic); if (Boolean(props.drag) && props.dragListener !== false) { // Disable the ghost element when a user drags htmlProps.draggable = false; // Disable text selection style.userSelect = style.WebkitUserSelect = style.WebkitTouchCallout = "none"; // Disable scrolling on the draggable direction style.touchAction = props.drag === true ? "none" : "pan-".concat(props.drag === "x" ? "y" : "x"); } htmlProps.style = style; return htmlProps; } /** * A list of all valid MotionProps. * * @privateRemarks * This doesn't throw if a `MotionProp` name is missing - it should. */ var validMotionProps = new Set([ "initial", "animate", "exit", "style", "variants", "transition", "transformTemplate", "transformValues", "custom", "inherit", "layout", "layoutId", "layoutDependency", "onLayoutAnimationStart", "onLayoutAnimationComplete", "onLayoutMeasure", "onBeforeLayoutMeasure", "onAnimationStart", "onAnimationComplete", "onUpdate", "onDragStart", "onDrag", "onDragEnd", "onMeasureDragConstraints", "onDirectionLock", "onDragTransitionEnd", "drag", "dragControls", "dragListener", "dragConstraints", "dragDirectionLock", "dragSnapToOrigin", "_dragX", "_dragY", "dragElastic", "dragMomentum", "dragPropagation", "dragTransition", "whileDrag", "onPan", "onPanStart", "onPanEnd", "onPanSessionStart", "onTap", "onTapStart", "onTapCancel", "onHoverStart", "onHoverEnd", "whileFocus", "whileTap", "whileHover", "whileInView", "onViewportEnter", "onViewportLeave", "viewport", "layoutScroll", ]); /** * Check whether a prop name is a valid `MotionProp` key. * * @param key - Name of the property to check * @returns `true` is key is a valid `MotionProp`. * * @public */ function isValidMotionProp(key) { return validMotionProps.has(key); } var shouldForward = function (key) { return !isValidMotionProp(key); }; function loadExternalIsValidProp(isValidProp) { if (!isValidProp) return; // Explicitly filter our events shouldForward = function (key) { return key.startsWith("on") ? !isValidMotionProp(key) : isValidProp(key); }; } /** * Emotion and Styled Components both allow users to pass through arbitrary props to their components * to dynamically generate CSS. They both use the `@emotion/is-prop-valid` package to determine which * of these should be passed to the underlying DOM node. * * However, when styling a Motion component `styled(motion.div)`, both packages pass through *all* props * as it's seen as an arbitrary component rather than a DOM node. Motion only allows arbitrary props * passed through the `custom` prop so it doesn't *need* the payload or computational overhead of * `@emotion/is-prop-valid`, however to fix this problem we need to use it. * * By making it an optionalDependency we can offer this functionality only in the situations where it's * actually required. */ try { /** * We attempt to import this package but require won't be defined in esm environments, in that case * isPropValid will have to be provided via `MotionContext`. In a 6.0.0 this should probably be removed * in favour of explicit injection. */ loadExternalIsValidProp(require("@emotion/is-prop-valid").default); } catch (_a) { // We don't need to actually do anything here - the fallback is the existing `isPropValid`. } function filterProps(props, isDom, forwardMotionProps) { var filteredProps = {}; for (var key in props) { if (shouldForward(key) || (forwardMotionProps === true && isValidMotionProp(key)) || (!isDom && !isValidMotionProp(key)) || // If trying to use native HTML drag events, forward drag listeners (props["draggable"] && key.startsWith("onDrag"))) { filteredProps[key] = props[key]; } } return filteredProps; } function calcOrigin$1(origin, offset, size) { return typeof origin === "string" ? origin : styleValueTypes.px.transform(offset + size * origin); } /** * The SVG transform origin defaults are different to CSS and is less intuitive, * so we use the measured dimensions of the SVG to reconcile these. */ function calcSVGTransformOrigin(dimensions, originX, originY) { var pxOriginX = calcOrigin$1(originX, dimensions.x, dimensions.width); var pxOriginY = calcOrigin$1(originY, dimensions.y, dimensions.height); return "".concat(pxOriginX, " ").concat(pxOriginY); } var dashKeys = { offset: "stroke-dashoffset", array: "stroke-dasharray", }; var camelKeys = { offset: "strokeDashoffset", array: "strokeDasharray", }; /** * Build SVG path properties. Uses the path's measured length to convert * our custom pathLength, pathSpacing and pathOffset into stroke-dashoffset * and stroke-dasharray attributes. * * This function is mutative to reduce per-frame GC. */ function buildSVGPath(attrs, length, spacing, offset, useDashCase) { if (spacing === void 0) { spacing = 1; } if (offset === void 0) { offset = 0; } if (useDashCase === void 0) { useDashCase = true; } // Normalise path length by setting SVG attribute pathLength to 1 attrs.pathLength = 1; // We use dash case when setting attributes directly to the DOM node and camel case // when defining props on a React component. var keys = useDashCase ? dashKeys : camelKeys; // Build the dash offset attrs[keys.offset] = styleValueTypes.px.transform(-offset); // Build the dash array var pathLength = styleValueTypes.px.transform(length); var pathSpacing = styleValueTypes.px.transform(spacing); attrs[keys.array] = "".concat(pathLength, " ").concat(pathSpacing); } /** * Build SVG visual attrbutes, like cx and style.transform */ function buildSVGAttrs(state, _a, options, transformTemplate) { var attrX = _a.attrX, attrY = _a.attrY, originX = _a.originX, originY = _a.originY, pathLength = _a.pathLength, _b = _a.pathSpacing, pathSpacing = _b === void 0 ? 1 : _b, _c = _a.pathOffset, pathOffset = _c === void 0 ? 0 : _c, // This is object creation, which we try to avoid per-frame. latest = tslib.__rest(_a, ["attrX", "attrY", "originX", "originY", "pathLength", "pathSpacing", "pathOffset"]); buildHTMLStyles(state, latest, options, transformTemplate); state.attrs = state.style; state.style = {}; var attrs = state.attrs, style = state.style, dimensions = state.dimensions; /** * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs * and copy it into style. */ if (attrs.transform) { if (dimensions) style.transform = attrs.transform; delete attrs.transform; } // Parse transformOrigin if (dimensions && (originX !== undefined || originY !== undefined || style.transform)) { style.transformOrigin = calcSVGTransformOrigin(dimensions, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5); } // Treat x/y not as shortcuts but as actual attributes if (attrX !== undefined) attrs.x = attrX; if (attrY !== undefined) attrs.y = attrY; // Build SVG path if one has been defined if (pathLength !== undefined) { buildSVGPath(attrs, pathLength, pathSpacing, pathOffset, false); } } var createSvgRenderState = function () { return (tslib.__assign(tslib.__assign({}, createHtmlRenderState()), { attrs: {} })); }; function useSVGProps(props, visualState) { var visualProps = React.useMemo(function () { var state = createSvgRenderState(); buildSVGAttrs(state, visualState, { enableHardwareAcceleration: false }, props.transformTemplate); return tslib.__assign(tslib.__assign({}, state.attrs), { style: tslib.__assign({}, state.style) }); }, [visualState]); if (props.style) { var rawStyles = {}; copyRawValuesOnly(rawStyles, props.style, props); visualProps.style = tslib.__assign(tslib.__assign({}, rawStyles), visualProps.style); } return visualProps; } function createUseRender(forwardMotionProps) { if (forwardMotionProps === void 0) { forwardMotionProps = false; } var useRender = function (Component, props, projectionId, ref, _a, isStatic) { var latestValues = _a.latestValues; var useVisualProps = isSVGComponent(Component) ? useSVGProps : useHTMLProps; var visualProps = useVisualProps(props, latestValues, isStatic); var filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps); var elementProps = tslib.__assign(tslib.__assign(tslib.__assign({}, filteredProps), visualProps), { ref: ref }); if (projectionId) { elementProps["data-projection-id"] = projectionId; } return React.createElement(Component, elementProps); }; return useRender; } var CAMEL_CASE_PATTERN = /([a-z])([A-Z])/g; var REPLACE_TEMPLATE = "$1-$2"; /** * Convert camelCase to dash-case properties. */ var camelToDash = function (str) { return str.replace(CAMEL_CASE_PATTERN, REPLACE_TEMPLATE).toLowerCase(); }; function renderHTML(element, _a, styleProp, projection) { var style = _a.style, vars = _a.vars; Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp)); // Loop over any CSS variables and assign those. for (var key in vars) { element.style.setProperty(key, vars[key]); } } /** * A set of attribute names that are always read/written as camel case. */ var camelCaseAttributes = new Set([ "baseFrequency", "diffuseConstant", "kernelMatrix", "kernelUnitLength", "keySplines", "keyTimes", "limitingConeAngle", "markerHeight", "markerWidth", "numOctaves", "targetX", "targetY", "surfaceScale", "specularConstant", "specularExponent", "stdDeviation", "tableValues", "viewBox", "gradientTransform", "pathLength", ]); function renderSVG(element, renderState, _styleProp, projection) { renderHTML(element, renderState, undefined, projection); for (var key in renderState.attrs) { element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]); } } function scrapeMotionValuesFromProps$1(props) { var style = props.style; var newValues = {}; for (var key in style) { if (isMotionValue(style[key]) || isForcedMotionValue(key, props)) { newValues[key] = style[key]; } } return newValues; } function scrapeMotionValuesFromProps(props) { var newValues = scrapeMotionValuesFromProps$1(props); for (var key in props) { if (isMotionValue(props[key])) { var targetKey = key === "x" || key === "y" ? "attr" + key.toUpperCase() : key; newValues[targetKey] = props[key]; } } return newValues; } function isAnimationControls(v) { return typeof v === "object" && typeof v.start === "function"; } var isKeyframesTarget = function (v) { return Array.isArray(v); }; var isCustomValue = function (v) { return Boolean(v && typeof v === "object" && v.mix && v.toValue); }; var resolveFinalValueInKeyframes = function (v) { // TODO maybe throw if v.length - 1 is placeholder token? return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v; }; /** * If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself * * TODO: Remove and move to library */ function resolveMotionValue(value) { var unwrappedValue = isMotionValue(value) ? value.get() : value; return isCustomValue(unwrappedValue) ? unwrappedValue.toValue() : unwrappedValue; } function makeState(_a, props, context, presenceContext) { var scrapeMotionValuesFromProps = _a.scrapeMotionValuesFromProps, createRenderState = _a.createRenderState, onMount = _a.onMount; var state = { latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps), renderState: createRenderState(), }; if (onMount) { state.mount = function (instance) { return onMount(props, instance, state); }; } return state; } var makeUseVisualState = function (config) { return function (props, isStatic) { var context = React.useContext(MotionContext); var presenceContext = React.useContext(PresenceContext); return isStatic ? makeState(config, props, context, presenceContext) : useConstant(function () { return makeState(config, props, context, presenceContext); }); }; }; function makeLatestValues(props, context, presenceContext, scrapeMotionValues) { var values = {}; var blockInitialAnimation = (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) === false; var motionValues = scrapeMotionValues(props); for (var key in motionValues) { values[key] = resolveMotionValue(motionValues[key]); } var initial = props.initial, animate = props.animate; var isControllingVariants = checkIfControllingVariants(props); var isVariantNode = checkIfVariantNode(props); if (context && isVariantNode && !isControllingVariants && props.inherit !== false) { initial !== null && initial !== void 0 ? initial : (initial = context.initial); animate !== null && animate !== void 0 ? animate : (animate = context.animate); } var initialAnimationIsBlocked = blockInitialAnimation || initial === false; var variantToSet = initialAnimationIsBlocked ? animate : initial; if (variantToSet && typeof variantToSet !== "boolean" && !isAnimationControls(variantToSet)) { var list = Array.isArray(variantToSet) ? variantToSet : [variantToSet]; list.forEach(function (definition) { var resolved = resolveVariantFromProps(props, definition); if (!resolved) return; var transitionEnd = resolved.transitionEnd; resolved.transition; var target = tslib.__rest(resolved, ["transitionEnd", "transition"]); for (var key in target) { var valueTarget = target[key]; if (Array.isArray(valueTarget)) { /** * Take final keyframe if the initial animation is blocked because * we want to initialise at the end of that blocked animation. */ var index = initialAnimationIsBlocked ? valueTarget.length - 1 : 0; valueTarget = valueTarget[index]; } if (valueTarget !== null) { values[key] = valueTarget; } } for (var key in transitionEnd) values[key] = transitionEnd[key]; }); } return values; } var svgMotionConfig = { useVisualState: makeUseVisualState({ scrapeMotionValuesFromProps: scrapeMotionValuesFromProps, createRenderState: createSvgRenderState, onMount: function (props, instance, _a) { var renderState = _a.renderState, latestValues = _a.latestValues; try { renderState.dimensions = typeof instance.getBBox === "function" ? instance.getBBox() : instance.getBoundingClientRect(); } catch (e) { // Most likely trying to measure an unrendered element under Firefox renderState.dimensions = { x: 0, y: 0, width: 0, height: 0, }; } buildSVGAttrs(renderState, latestValues, { enableHardwareAcceleration: false }, props.transformTemplate); renderSVG(instance, renderState); }, }), }; var htmlMotionConfig = { useVisualState: makeUseVisualState({ scrapeMotionValuesFromProps: scrapeMotionValuesFromProps$1, createRenderState: createHtmlRenderState, }), }; function createDomMotionConfig(Component, _a, preloadedFeatures, createVisualElement, projectionNodeConstructor) { var _b = _a.forwardMotionProps, forwardMotionProps = _b === void 0 ? false : _b; var baseConfig = isSVGComponent(Component) ? svgMotionConfig : htmlMotionConfig; return tslib.__assign(tslib.__assign({}, baseConfig), { preloadedFeatures: preloadedFeatures, useRender: createUseRender(forwardMotionProps), createVisualElement: createVisualElement, projectionNodeConstructor: projectionNodeConstructor, Component: Component }); } exports.AnimationType = void 0; (function (AnimationType) { AnimationType["Animate"] = "animate"; AnimationType["Hover"] = "whileHover"; AnimationType["Tap"] = "whileTap"; AnimationType["Drag"] = "whileDrag"; AnimationType["Focus"] = "whileFocus"; AnimationType["InView"] = "whileInView"; AnimationType["Exit"] = "exit"; })(exports.AnimationType || (exports.AnimationType = {})); function addDomEvent(target, eventName, handler, options) { if (options === void 0) { options = { passive: true }; } target.addEventListener(eventName, handler, options); return function () { return target.removeEventListener(eventName, handler); }; } /** * Attaches an event listener directly to the provided DOM element. * * Bypassing React's event system can be desirable, for instance when attaching non-passive * event handlers. * * ```jsx * const ref = useRef(null) * * useDomEvent(ref, 'wheel', onWheel, { passive: false }) * * return
* ``` * * @param ref - React.RefObject that's been provided to the element you want to bind the listener to. * @param eventName - Name of the event you want listen for. * @param handler - Function to fire when receiving the event. * @param options - Options to pass to `Event.addEventListener`. * * @public */ function useDomEvent(ref, eventName, handler, options) { React.useEffect(function () { var element = ref.current; if (handler && element) { return addDomEvent(element, eventName, handler, options); } }, [ref, eventName, handler, options]); } /** * * @param props * @param ref * @internal */ function useFocusGesture(_a) { var whileFocus = _a.whileFocus, visualElement = _a.visualElement; var onFocus = function () { var _a; (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Focus, true); }; var onBlur = function () { var _a; (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Focus, false); }; useDomEvent(visualElement, "focus", whileFocus ? onFocus : undefined); useDomEvent(visualElement, "blur", whileFocus ? onBlur : undefined); } function isMouseEvent(event) { // PointerEvent inherits from MouseEvent so we can't use a straight instanceof check. if (typeof PointerEvent !== "undefined" && event instanceof PointerEvent) { return !!(event.pointerType === "mouse"); } return event instanceof MouseEvent; } function isTouchEvent(event) { var hasTouches = !!event.touches; return hasTouches; } /** * Filters out events not attached to the primary pointer (currently left mouse button) * @param eventHandler */ function filterPrimaryPointer(eventHandler) { return function (event) { var isMouseEvent = event instanceof MouseEvent; var isPrimaryPointer = !isMouseEvent || (isMouseEvent && event.button === 0); if (isPrimaryPointer) { eventHandler(event); } }; } var defaultPagePoint = { pageX: 0, pageY: 0 }; function pointFromTouch(e, pointType) { if (pointType === void 0) { pointType = "page"; } var primaryTouch = e.touches[0] || e.changedTouches[0]; var point = primaryTouch || defaultPagePoint; return { x: point[pointType + "X"], y: point[pointType + "Y"], }; } function pointFromMouse(point, pointType) { if (pointType === void 0) { pointType = "page"; } return { x: point[pointType + "X"], y: point[pointType + "Y"], }; } function extractEventInfo(event, pointType) { if (pointType === void 0) { pointType = "page"; } return { point: isTouchEvent(event) ? pointFromTouch(event, pointType) : pointFromMouse(event, pointType), }; } var wrapHandler = function (handler, shouldFilterPrimaryPointer) { if (shouldFilterPrimaryPointer === void 0) { shouldFilterPrimaryPointer = false; } var listener = function (event) { return handler(event, extractEventInfo(event)); }; return shouldFilterPrimaryPointer ? filterPrimaryPointer(listener) : listener; }; // We check for event support via functions in case they've been mocked by a testing suite. var supportsPointerEvents = function () { return isBrowser && window.onpointerdown === null; }; var supportsTouchEvents = function () { return isBrowser && window.ontouchstart === null; }; var supportsMouseEvents = function () { return isBrowser && window.onmousedown === null; }; var mouseEventNames = { pointerdown: "mousedown", pointermove: "mousemove", pointerup: "mouseup", pointercancel: "mousecancel", pointerover: "mouseover", pointerout: "mouseout", pointerenter: "mouseenter", pointerleave: "mouseleave", }; var touchEventNames = { pointerdown: "touchstart", pointermove: "touchmove", pointerup: "touchend", pointercancel: "touchcancel", }; function getPointerEventName(name) { if (supportsPointerEvents()) { return name; } else if (supportsTouchEvents()) { return touchEventNames[name]; } else if (supportsMouseEvents()) { return mouseEventNames[name]; } return name; } function addPointerEvent(target, eventName, handler, options) { return addDomEvent(target, getPointerEventName(eventName), wrapHandler(handler, eventName === "pointerdown"), options); } function usePointerEvent(ref, eventName, handler, options) { return useDomEvent(ref, getPointerEventName(eventName), handler && wrapHandler(handler, eventName === "pointerdown"), options); } function createLock(name) { var lock = null; return function () { var openLock = function () { lock = null; }; if (lock === null) { lock = name; return openLock; } return false; }; } var globalHorizontalLock = createLock("dragHorizontal"); var globalVerticalLock = createLock("dragVertical"); function getGlobalLock(drag) { var lock = false; if (drag === "y") { lock = globalVerticalLock(); } else if (drag === "x") { lock = globalHorizontalLock(); } else { var openHorizontal_1 = globalHorizontalLock(); var openVertical_1 = globalVerticalLock(); if (openHorizontal_1 && openVertical_1) { lock = function () { openHorizontal_1(); openVertical_1(); }; } else { // Release the locks because we don't use them if (openHorizontal_1) openHorizontal_1(); if (openVertical_1) openVertical_1(); } } return lock; } function isDragActive() { // Check the gesture lock - if we get it, it means no drag gesture is active // and we can safely fire the tap gesture. var openGestureLock = getGlobalLock(true); if (!openGestureLock) return true; openGestureLock(); return false; } function createHoverEvent(visualElement, isActive, callback) { return function (event, info) { var _a; if (!isMouseEvent(event) || isDragActive()) return; /** * Ensure we trigger animations before firing event callback */ (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Hover, isActive); callback === null || callback === void 0 ? void 0 : callback(event, info); }; } function useHoverGesture(_a) { var onHoverStart = _a.onHoverStart, onHoverEnd = _a.onHoverEnd, whileHover = _a.whileHover, visualElement = _a.visualElement; usePointerEvent(visualElement, "pointerenter", onHoverStart || whileHover ? createHoverEvent(visualElement, true, onHoverStart) : undefined, { passive: !onHoverStart }); usePointerEvent(visualElement, "pointerleave", onHoverEnd || whileHover ? createHoverEvent(visualElement, false, onHoverEnd) : undefined, { passive: !onHoverEnd }); } /** * Recursively traverse up the tree to check whether the provided child node * is the parent or a descendant of it. * * @param parent - Element to find * @param child - Element to test against parent */ var isNodeOrChild = function (parent, child) { if (!child) { return false; } else if (parent === child) { return true; } else { return isNodeOrChild(parent, child.parentElement); } }; function useUnmountEffect(callback) { return React.useEffect(function () { return function () { return callback(); }; }, []); } /** * @param handlers - * @internal */ function useTapGesture(_a) { var onTap = _a.onTap, onTapStart = _a.onTapStart, onTapCancel = _a.onTapCancel, whileTap = _a.whileTap, visualElement = _a.visualElement; var hasPressListeners = onTap || onTapStart || onTapCancel || whileTap; var isPressing = React.useRef(false); var cancelPointerEndListeners = React.useRef(null); /** * Only set listener to passive if there are no external listeners. */ var eventOptions = { passive: !(onTapStart || onTap || onTapCancel || onPointerDown), }; function removePointerEndListener() { var _a; (_a = cancelPointerEndListeners.current) === null || _a === void 0 ? void 0 : _a.call(cancelPointerEndListeners); cancelPointerEndListeners.current = null; } function checkPointerEnd() { var _a; removePointerEndListener(); isPressing.current = false; (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Tap, false); return !isDragActive(); } function onPointerUp(event, info) { if (!checkPointerEnd()) return; /** * We only count this as a tap gesture if the event.target is the same * as, or a child of, this component's element */ !isNodeOrChild(visualElement.getInstance(), event.target) ? onTapCancel === null || onTapCancel === void 0 ? void 0 : onTapCancel(event, info) : onTap === null || onTap === void 0 ? void 0 : onTap(event, info); } function onPointerCancel(event, info) { if (!checkPointerEnd()) return; onTapCancel === null || onTapCancel === void 0 ? void 0 : onTapCancel(event, info); } function onPointerDown(event, info) { var _a; removePointerEndListener(); if (isPressing.current) return; isPressing.current = true; cancelPointerEndListeners.current = popmotion.pipe(addPointerEvent(window, "pointerup", onPointerUp, eventOptions), addPointerEvent(window, "pointercancel", onPointerCancel, eventOptions)); /** * Ensure we trigger animations before firing event callback */ (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Tap, true); onTapStart === null || onTapStart === void 0 ? void 0 : onTapStart(event, info); } usePointerEvent(visualElement, "pointerdown", hasPressListeners ? onPointerDown : undefined, eventOptions); useUnmountEffect(removePointerEndListener); } var warned = new Set(); function warnOnce(condition, message, element) { if (condition || warned.has(message)) return; console.warn(message); if (element) console.warn(element); warned.add(message); } /** * Map an IntersectionHandler callback to an element. We only ever make one handler for one * element, so even though these handlers might all be triggered by different * observers, we can keep them in the same map. */ var observerCallbacks = new WeakMap(); /** * Multiple observers can be created for multiple element/document roots. Each with * different settings. So here we store dictionaries of observers to each root, * using serialised settings (threshold/margin) as lookup keys. */ var observers = new WeakMap(); var fireObserverCallback = function (entry) { var _a; (_a = observerCallbacks.get(entry.target)) === null || _a === void 0 ? void 0 : _a(entry); }; var fireAllObserverCallbacks = function (entries) { entries.forEach(fireObserverCallback); }; function initIntersectionObserver(_a) { var root = _a.root, options = tslib.__rest(_a, ["root"]); var lookupRoot = root || document; /** * If we don't have an observer lookup map for this root, create one. */ if (!observers.has(lookupRoot)) { observers.set(lookupRoot, {}); } var rootObservers = observers.get(lookupRoot); var key = JSON.stringify(options); /** * If we don't have an observer for this combination of root and settings, * create one. */ if (!rootObservers[key]) { rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, tslib.__assign({ root: root }, options)); } return rootObservers[key]; } function observeIntersection(element, options, callback) { var rootInteresectionObserver = initIntersectionObserver(options); observerCallbacks.set(element, callback); rootInteresectionObserver.observe(element); return function () { observerCallbacks.delete(element); rootInteresectionObserver.unobserve(element); }; } function useViewport(_a) { var visualElement = _a.visualElement, whileInView = _a.whileInView, onViewportEnter = _a.onViewportEnter, onViewportLeave = _a.onViewportLeave, _b = _a.viewport, viewport = _b === void 0 ? {} : _b; var state = React.useRef({ hasEnteredView: false, isInView: false, }); var shouldObserve = Boolean(whileInView || onViewportEnter || onViewportLeave); if (viewport.once && state.current.hasEnteredView) shouldObserve = false; var useObserver = typeof IntersectionObserver === "undefined" ? useMissingIntersectionObserver : useIntersectionObserver; useObserver(shouldObserve, state.current, visualElement, viewport); } var thresholdNames = { some: 0, all: 1, }; function useIntersectionObserver(shouldObserve, state, visualElement, _a) { var root = _a.root, rootMargin = _a.margin, _b = _a.amount, amount = _b === void 0 ? "some" : _b, once = _a.once; React.useEffect(function () { if (!shouldObserve) return; var options = { root: root === null || root === void 0 ? void 0 : root.current, rootMargin: rootMargin, threshold: typeof amount === "number" ? amount : thresholdNames[amount], }; var intersectionCallback = function (entry) { var _a; var isIntersecting = entry.isIntersecting; /** * If there's been no change in the viewport state, early return. */ if (state.isInView === isIntersecting) return; state.isInView = isIntersecting; /** * Handle hasEnteredView. If this is only meant to run once, and * element isn't visible, early return. Otherwise set hasEnteredView to true. */ if (once && !isIntersecting && state.hasEnteredView) { return; } else if (isIntersecting) { state.hasEnteredView = true; } (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.InView, isIntersecting); /** * Use the latest committed props rather than the ones in scope * when this observer is created */ var props = visualElement.getProps(); var callback = isIntersecting ? props.onViewportEnter : props.onViewportLeave; callback === null || callback === void 0 ? void 0 : callback(entry); }; return observeIntersection(visualElement.getInstance(), options, intersectionCallback); }, [shouldObserve, root, rootMargin, amount]); } /** * If IntersectionObserver is missing, we activate inView and fire onViewportEnter * on mount. This way, the page will be in the state the author expects users * to see it in for everyone. */ function useMissingIntersectionObserver(shouldObserve, state, visualElement, _a) { var _b = _a.fallback, fallback = _b === void 0 ? true : _b; React.useEffect(function () { if (!shouldObserve || !fallback) return; if (env !== "production") { warnOnce(false, "IntersectionObserver not available on this device. whileInView animations will trigger on mount."); } /** * Fire this in an rAF because, at this point, the animation state * won't have flushed for the first time and there's certain logic in * there that behaves differently on the initial animation. * * This hook should be quite rarely called so setting this in an rAF * is preferred to changing the behaviour of the animation state. */ requestAnimationFrame(function () { var _a; state.hasEnteredView = true; var onViewportEnter = visualElement.getProps().onViewportEnter; onViewportEnter === null || onViewportEnter === void 0 ? void 0 : onViewportEnter(null); (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.InView, true); }); }, [shouldObserve]); } var makeRenderlessComponent = function (hook) { return function (props) { hook(props); return null; }; }; var gestureAnimations = { inView: makeRenderlessComponent(useViewport), tap: makeRenderlessComponent(useTapGesture), focus: makeRenderlessComponent(useFocusGesture), hover: makeRenderlessComponent(useHoverGesture), }; var counter = 0; var incrementId = function () { return counter++; }; var useId = function () { return useConstant(incrementId); }; /** * Ideally we'd use the following code to support React 18 optionally. * But this fairly fails in Webpack (otherwise treeshaking wouldn't work at all). * Need to come up with a different way of figuring this out. */ // export const useId = (React as any).useId // ? (React as any).useId // : () => useConstant(incrementId) /** * When a component is the child of `AnimatePresence`, it can use `usePresence` * to access information about whether it's still present in the React tree. * * ```jsx * import { usePresence } from "framer-motion" * * export const Component = () => { * const [isPresent, safeToRemove] = usePresence() * * useEffect(() => { * !isPresent && setTimeout(safeToRemove, 1000) * }, [isPresent]) * * return
* } * ``` * * If `isPresent` is `false`, it means that a component has been removed the tree, but * `AnimatePresence` won't really remove it until `safeToRemove` has been called. * * @public */ function usePresence() { var context = React.useContext(PresenceContext); if (context === null) return [true, null]; var isPresent = context.isPresent, onExitComplete = context.onExitComplete, register = context.register; // It's safe to call the following hooks conditionally (after an early return) because the context will always // either be null or non-null for the lifespan of the component. // Replace with useId when released in React var id = useId(); React.useEffect(function () { return register(id); }, []); var safeToRemove = function () { return onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete(id); }; return !isPresent && onExitComplete ? [false, safeToRemove] : [true]; } /** * Similar to `usePresence`, except `useIsPresent` simply returns whether or not the component is present. * There is no `safeToRemove` function. * * ```jsx * import { useIsPresent } from "framer-motion" * * export const Component = () => { * const isPresent = useIsPresent() * * useEffect(() => { * !isPresent && console.log("I've been removed!") * }, [isPresent]) * * return
* } * ``` * * @public */ function useIsPresent() { return isPresent(React.useContext(PresenceContext)); } function isPresent(context) { return context === null ? true : context.isPresent; } function shallowCompare(next, prev) { if (!Array.isArray(prev)) return false; var prevLength = prev.length; if (prevLength !== next.length) return false; for (var i = 0; i < prevLength; i++) { if (prev[i] !== next[i]) return false; } return true; } /** * Converts seconds to milliseconds * * @param seconds - Time in seconds. * @return milliseconds - Converted time in milliseconds. */ var secondsToMilliseconds = function (seconds) { return seconds * 1000; }; var easingLookup = { linear: popmotion.linear, easeIn: popmotion.easeIn, easeInOut: popmotion.easeInOut, easeOut: popmotion.easeOut, circIn: popmotion.circIn, circInOut: popmotion.circInOut, circOut: popmotion.circOut, backIn: popmotion.backIn, backInOut: popmotion.backInOut, backOut: popmotion.backOut, anticipate: popmotion.anticipate, bounceIn: popmotion.bounceIn, bounceInOut: popmotion.bounceInOut, bounceOut: popmotion.bounceOut, }; var easingDefinitionToFunction = function (definition) { if (Array.isArray(definition)) { // If cubic bezier definition, create bezier curve heyListen.invariant(definition.length === 4, "Cubic bezier arrays must contain four numerical values."); var _a = tslib.__read(definition, 4), x1 = _a[0], y1 = _a[1], x2 = _a[2], y2 = _a[3]; return popmotion.cubicBezier(x1, y1, x2, y2); } else if (typeof definition === "string") { // Else lookup from table heyListen.invariant(easingLookup[definition] !== undefined, "Invalid easing type '".concat(definition, "'")); return easingLookup[definition]; } return definition; }; var isEasingArray = function (ease) { return Array.isArray(ease) && typeof ease[0] !== "number"; }; /** * Check if a value is animatable. Examples: * * ✅: 100, "100px", "#fff" * ❌: "block", "url(2.jpg)" * @param value * * @internal */ var isAnimatable = function (key, value) { // If the list of keys tat might be non-animatable grows, replace with Set if (key === "zIndex") return false; // If it's a number or a keyframes array, we can animate it. We might at some point // need to do a deep isAnimatable check of keyframes, or let Popmotion handle this, // but for now lets leave it like this for performance reasons if (typeof value === "number" || Array.isArray(value)) return true; if (typeof value === "string" && // It's animatable if we have a string styleValueTypes.complex.test(value) && // And it contains numbers and/or colors !value.startsWith("url(") // Unless it starts with "url(" ) { return true; } return false; }; var underDampedSpring = function () { return ({ type: "spring", stiffness: 500, damping: 25, restSpeed: 10, }); }; var criticallyDampedSpring = function (to) { return ({ type: "spring", stiffness: 550, damping: to === 0 ? 2 * Math.sqrt(550) : 30, restSpeed: 10, }); }; var linearTween = function () { return ({ type: "keyframes", ease: "linear", duration: 0.3, }); }; var keyframes = function (values) { return ({ type: "keyframes", duration: 0.8, values: values, }); }; var defaultTransitions = { x: underDampedSpring, y: underDampedSpring, z: underDampedSpring, rotate: underDampedSpring, rotateX: underDampedSpring, rotateY: underDampedSpring, rotateZ: underDampedSpring, scaleX: criticallyDampedSpring, scaleY: criticallyDampedSpring, scale: criticallyDampedSpring, opacity: linearTween, backgroundColor: linearTween, color: linearTween, default: criticallyDampedSpring, }; var getDefaultTransition = function (valueKey, to) { var transitionFactory; if (isKeyframesTarget(to)) { transitionFactory = keyframes; } else { transitionFactory = defaultTransitions[valueKey] || defaultTransitions.default; } return tslib.__assign({ to: to }, transitionFactory(to)); }; /** * A map of default value types for common values */ var defaultValueTypes = tslib.__assign(tslib.__assign({}, numberValueTypes), { // Color props color: styleValueTypes.color, backgroundColor: styleValueTypes.color, outlineColor: styleValueTypes.color, fill: styleValueTypes.color, stroke: styleValueTypes.color, // Border props borderColor: styleValueTypes.color, borderTopColor: styleValueTypes.color, borderRightColor: styleValueTypes.color, borderBottomColor: styleValueTypes.color, borderLeftColor: styleValueTypes.color, filter: styleValueTypes.filter, WebkitFilter: styleValueTypes.filter }); /** * Gets the default ValueType for the provided value key */ var getDefaultValueType = function (key) { return defaultValueTypes[key]; }; function getAnimatableNone(key, value) { var _a; var defaultValueType = getDefaultValueType(key); if (defaultValueType !== styleValueTypes.filter) defaultValueType = styleValueTypes.complex; // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target return (_a = defaultValueType.getAnimatableNone) === null || _a === void 0 ? void 0 : _a.call(defaultValueType, value); } var instantAnimationState = { current: false, }; /** * Decide whether a transition is defined on a given Transition. * This filters out orchestration options and returns true * if any options are left. */ function isTransitionDefined(_a) { _a.when; _a.delay; _a.delayChildren; _a.staggerChildren; _a.staggerDirection; _a.repeat; _a.repeatType; _a.repeatDelay; _a.from; var transition = tslib.__rest(_a, ["when", "delay", "delayChildren", "staggerChildren", "staggerDirection", "repeat", "repeatType", "repeatDelay", "from"]); return !!Object.keys(transition).length; } var legacyRepeatWarning = false; /** * Convert Framer Motion's Transition type into Popmotion-compatible options. */ function convertTransitionToAnimationOptions(_a) { var ease = _a.ease, times = _a.times, yoyo = _a.yoyo, flip = _a.flip, loop = _a.loop, transition = tslib.__rest(_a, ["ease", "times", "yoyo", "flip", "loop"]); var options = tslib.__assign({}, transition); if (times) options["offset"] = times; /** * Convert any existing durations from seconds to milliseconds */ if (transition.duration) options["duration"] = secondsToMilliseconds(transition.duration); if (transition.repeatDelay) options.repeatDelay = secondsToMilliseconds(transition.repeatDelay); /** * Map easing names to Popmotion's easing functions */ if (ease) { options["ease"] = isEasingArray(ease) ? ease.map(easingDefinitionToFunction) : easingDefinitionToFunction(ease); } /** * Support legacy transition API */ if (transition.type === "tween") options.type = "keyframes"; /** * TODO: These options are officially removed from the API. */ if (yoyo || loop || flip) { heyListen.warning(!legacyRepeatWarning, "yoyo, loop and flip have been removed from the API. Replace with repeat and repeatType options."); legacyRepeatWarning = true; if (yoyo) { options.repeatType = "reverse"; } else if (loop) { options.repeatType = "loop"; } else if (flip) { options.repeatType = "mirror"; } options.repeat = loop || yoyo || flip || transition.repeat; } /** * TODO: Popmotion 9 has the ability to automatically detect whether to use * a keyframes or spring animation, but does so by detecting velocity and other spring options. * It'd be good to introduce a similar thing here. */ if (transition.type !== "spring") options.type = "keyframes"; return options; } /** * Get the delay for a value by checking Transition with decreasing specificity. */ function getDelayFromTransition(transition, key) { var _a, _b; var valueTransition = getValueTransition(transition, key) || {}; return (_b = (_a = valueTransition.delay) !== null && _a !== void 0 ? _a : transition.delay) !== null && _b !== void 0 ? _b : 0; } function hydrateKeyframes(options) { if (Array.isArray(options.to) && options.to[0] === null) { options.to = tslib.__spreadArray([], tslib.__read(options.to), false); options.to[0] = options.from; } return options; } function getPopmotionAnimationOptions(transition, options, key) { var _a; if (Array.isArray(options.to)) { (_a = transition.duration) !== null && _a !== void 0 ? _a : (transition.duration = 0.8); } hydrateKeyframes(options); /** * Get a default transition if none is determined to be defined. */ if (!isTransitionDefined(transition)) { transition = tslib.__assign(tslib.__assign({}, transition), getDefaultTransition(key, options.to)); } return tslib.__assign(tslib.__assign({}, options), convertTransitionToAnimationOptions(transition)); } /** * */ function getAnimation(key, value, target, transition, onComplete) { var _a; var valueTransition = getValueTransition(transition, key); var origin = (_a = valueTransition.from) !== null && _a !== void 0 ? _a : value.get(); var isTargetAnimatable = isAnimatable(key, target); if (origin === "none" && isTargetAnimatable && typeof target === "string") { /** * If we're trying to animate from "none", try and get an animatable version * of the target. This could be improved to work both ways. */ origin = getAnimatableNone(key, target); } else if (isZero(origin) && typeof target === "string") { origin = getZeroUnit(target); } else if (!Array.isArray(target) && isZero(target) && typeof origin === "string") { target = getZeroUnit(origin); } var isOriginAnimatable = isAnimatable(key, origin); heyListen.warning(isOriginAnimatable === isTargetAnimatable, "You are trying to animate ".concat(key, " from \"").concat(origin, "\" to \"").concat(target, "\". ").concat(origin, " is not an animatable value - to enable this animation set ").concat(origin, " to a value animatable to ").concat(target, " via the `style` property.")); function start() { var options = { from: origin, to: target, velocity: value.getVelocity(), onComplete: onComplete, onUpdate: function (v) { return value.set(v); }, }; return valueTransition.type === "inertia" || valueTransition.type === "decay" ? popmotion.inertia(tslib.__assign(tslib.__assign({}, options), valueTransition)) : popmotion.animate(tslib.__assign(tslib.__assign({}, getPopmotionAnimationOptions(valueTransition, options, key)), { onUpdate: function (v) { var _a; options.onUpdate(v); (_a = valueTransition.onUpdate) === null || _a === void 0 ? void 0 : _a.call(valueTransition, v); }, onComplete: function () { var _a; options.onComplete(); (_a = valueTransition.onComplete) === null || _a === void 0 ? void 0 : _a.call(valueTransition); } })); } function set() { var _a, _b; var finalTarget = resolveFinalValueInKeyframes(target); value.set(finalTarget); onComplete(); (_a = valueTransition === null || valueTransition === void 0 ? void 0 : valueTransition.onUpdate) === null || _a === void 0 ? void 0 : _a.call(valueTransition, finalTarget); (_b = valueTransition === null || valueTransition === void 0 ? void 0 : valueTransition.onComplete) === null || _b === void 0 ? void 0 : _b.call(valueTransition); return { stop: function () { } }; } return !isOriginAnimatable || !isTargetAnimatable || valueTransition.type === false ? set : start; } function isZero(value) { return (value === 0 || (typeof value === "string" && parseFloat(value) === 0 && value.indexOf(" ") === -1)); } function getZeroUnit(potentialUnitType) { return typeof potentialUnitType === "number" ? 0 : getAnimatableNone("", potentialUnitType); } function getValueTransition(transition, key) { return transition[key] || transition["default"] || transition; } /** * Start animation on a MotionValue. This function is an interface between * Framer Motion and Popmotion */ function startAnimation(key, value, target, transition) { if (transition === void 0) { transition = {}; } if (instantAnimationState.current) { transition = { type: false }; } return value.start(function (onComplete) { var delayTimer; var controls; var animation = getAnimation(key, value, target, transition, onComplete); var delay = getDelayFromTransition(transition, key); var start = function () { return (controls = animation()); }; if (delay) { delayTimer = window.setTimeout(start, secondsToMilliseconds(delay)); } else { start(); } return function () { clearTimeout(delayTimer); controls === null || controls === void 0 ? void 0 : controls.stop(); }; }); } /** * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1" */ var isNumericalString = function (v) { return /^\-?\d*\.?\d+$/.test(v); }; /** * Check if the value is a zero value string like "0px" or "0%" */ var isZeroValueString = function (v) { return /^0[^.\s]+$/.test(v); }; function addUniqueItem(arr, item) { arr.indexOf(item) === -1 && arr.push(item); } function removeItem(arr, item) { var index = arr.indexOf(item); index > -1 && arr.splice(index, 1); } // Adapted from array-move function moveItem(_a, fromIndex, toIndex) { var _b = tslib.__read(_a), arr = _b.slice(0); var startIndex = fromIndex < 0 ? arr.length + fromIndex : fromIndex; if (startIndex >= 0 && startIndex < arr.length) { var endIndex = toIndex < 0 ? arr.length + toIndex : toIndex; var _c = tslib.__read(arr.splice(fromIndex, 1), 1), item = _c[0]; arr.splice(endIndex, 0, item); } return arr; } var SubscriptionManager = /** @class */ (function () { function SubscriptionManager() { this.subscriptions = []; } SubscriptionManager.prototype.add = function (handler) { var _this = this; addUniqueItem(this.subscriptions, handler); return function () { return removeItem(_this.subscriptions, handler); }; }; SubscriptionManager.prototype.notify = function (a, b, c) { var numSubscriptions = this.subscriptions.length; if (!numSubscriptions) return; if (numSubscriptions === 1) { /** * If there's only a single handler we can just call it without invoking a loop. */ this.subscriptions[0](a, b, c); } else { for (var i = 0; i < numSubscriptions; i++) { /** * Check whether the handler exists before firing as it's possible * the subscriptions were modified during this loop running. */ var handler = this.subscriptions[i]; handler && handler(a, b, c); } } }; SubscriptionManager.prototype.getSize = function () { return this.subscriptions.length; }; SubscriptionManager.prototype.clear = function () { this.subscriptions.length = 0; }; return SubscriptionManager; }()); var isFloat = function (value) { return !isNaN(parseFloat(value)); }; /** * `MotionValue` is used to track the state and velocity of motion values. * * @public */ var MotionValue = /** @class */ (function () { /** * @param init - The initiating value * @param config - Optional configuration options * * - `transformer`: A function to transform incoming values with. * * @internal */ function MotionValue(init) { var _this = this; /** * This will be replaced by the build step with the latest version number. * When MotionValues are provided to motion components, warn if versions are mixed. */ this.version = "6.5.1"; /** * Duration, in milliseconds, since last updating frame. * * @internal */ this.timeDelta = 0; /** * Timestamp of the last time this `MotionValue` was updated. * * @internal */ this.lastUpdated = 0; /** * Functions to notify when the `MotionValue` updates. * * @internal */ this.updateSubscribers = new SubscriptionManager(); /** * Functions to notify when the velocity updates. * * @internal */ this.velocityUpdateSubscribers = new SubscriptionManager(); /** * Functions to notify when the `MotionValue` updates and `render` is set to `true`. * * @internal */ this.renderSubscribers = new SubscriptionManager(); /** * Tracks whether this value can output a velocity. Currently this is only true * if the value is numerical, but we might be able to widen the scope here and support * other value types. * * @internal */ this.canTrackVelocity = false; this.updateAndNotify = function (v, render) { if (render === void 0) { render = true; } _this.prev = _this.current; _this.current = v; // Update timestamp var _a = sync.getFrameData(), delta = _a.delta, timestamp = _a.timestamp; if (_this.lastUpdated !== timestamp) { _this.timeDelta = delta; _this.lastUpdated = timestamp; sync__default["default"].postRender(_this.scheduleVelocityCheck); } // Update update subscribers if (_this.prev !== _this.current) { _this.updateSubscribers.notify(_this.current); } // Update velocity subscribers if (_this.velocityUpdateSubscribers.getSize()) { _this.velocityUpdateSubscribers.notify(_this.getVelocity()); } // Update render subscribers if (render) { _this.renderSubscribers.notify(_this.current); } }; /** * Schedule a velocity check for the next frame. * * This is an instanced and bound function to prevent generating a new * function once per frame. * * @internal */ this.scheduleVelocityCheck = function () { return sync__default["default"].postRender(_this.velocityCheck); }; /** * Updates `prev` with `current` if the value hasn't been updated this frame. * This ensures velocity calculations return `0`. * * This is an instanced and bound function to prevent generating a new * function once per frame. * * @internal */ this.velocityCheck = function (_a) { var timestamp = _a.timestamp; if (timestamp !== _this.lastUpdated) { _this.prev = _this.current; _this.velocityUpdateSubscribers.notify(_this.getVelocity()); } }; this.hasAnimated = false; this.prev = this.current = init; this.canTrackVelocity = isFloat(this.current); } /** * Adds a function that will be notified when the `MotionValue` is updated. * * It returns a function that, when called, will cancel the subscription. * * When calling `onChange` inside a React component, it should be wrapped with the * `useEffect` hook. As it returns an unsubscribe function, this should be returned * from the `useEffect` function to ensure you don't add duplicate subscribers.. * * ```jsx * export const MyComponent = () => { * const x = useMotionValue(0) * const y = useMotionValue(0) * const opacity = useMotionValue(1) * * useEffect(() => { * function updateOpacity() { * const maxXY = Math.max(x.get(), y.get()) * const newOpacity = transform(maxXY, [0, 100], [1, 0]) * opacity.set(newOpacity) * } * * const unsubscribeX = x.onChange(updateOpacity) * const unsubscribeY = y.onChange(updateOpacity) * * return () => { * unsubscribeX() * unsubscribeY() * } * }, []) * * return * } * ``` * * @privateRemarks * * We could look into a `useOnChange` hook if the above lifecycle management proves confusing. * * ```jsx * useOnChange(x, () => {}) * ``` * * @param subscriber - A function that receives the latest value. * @returns A function that, when called, will cancel this subscription. * * @public */ MotionValue.prototype.onChange = function (subscription) { return this.updateSubscribers.add(subscription); }; MotionValue.prototype.clearListeners = function () { this.updateSubscribers.clear(); }; /** * Adds a function that will be notified when the `MotionValue` requests a render. * * @param subscriber - A function that's provided the latest value. * @returns A function that, when called, will cancel this subscription. * * @internal */ MotionValue.prototype.onRenderRequest = function (subscription) { // Render immediately subscription(this.get()); return this.renderSubscribers.add(subscription); }; /** * Attaches a passive effect to the `MotionValue`. * * @internal */ MotionValue.prototype.attach = function (passiveEffect) { this.passiveEffect = passiveEffect; }; /** * Sets the state of the `MotionValue`. * * @remarks * * ```jsx * const x = useMotionValue(0) * x.set(10) * ``` * * @param latest - Latest value to set. * @param render - Whether to notify render subscribers. Defaults to `true` * * @public */ MotionValue.prototype.set = function (v, render) { if (render === void 0) { render = true; } if (!render || !this.passiveEffect) { this.updateAndNotify(v, render); } else { this.passiveEffect(v, this.updateAndNotify); } }; /** * Returns the latest state of `MotionValue` * * @returns - The latest state of `MotionValue` * * @public */ MotionValue.prototype.get = function () { return this.current; }; /** * @public */ MotionValue.prototype.getPrevious = function () { return this.prev; }; /** * Returns the latest velocity of `MotionValue` * * @returns - The latest velocity of `MotionValue`. Returns `0` if the state is non-numerical. * * @public */ MotionValue.prototype.getVelocity = function () { // This could be isFloat(this.prev) && isFloat(this.current), but that would be wasteful return this.canTrackVelocity ? // These casts could be avoided if parseFloat would be typed better popmotion.velocityPerSecond(parseFloat(this.current) - parseFloat(this.prev), this.timeDelta) : 0; }; /** * Registers a new animation to control this `MotionValue`. Only one * animation can drive a `MotionValue` at one time. * * ```jsx * value.start() * ``` * * @param animation - A function that starts the provided animation * * @internal */ MotionValue.prototype.start = function (animation) { var _this = this; this.stop(); return new Promise(function (resolve) { _this.hasAnimated = true; _this.stopAnimation = animation(resolve); }).then(function () { return _this.clearAnimation(); }); }; /** * Stop the currently active animation. * * @public */ MotionValue.prototype.stop = function () { if (this.stopAnimation) this.stopAnimation(); this.clearAnimation(); }; /** * Returns `true` if this value is currently animating. * * @public */ MotionValue.prototype.isAnimating = function () { return !!this.stopAnimation; }; MotionValue.prototype.clearAnimation = function () { this.stopAnimation = null; }; /** * Destroy and clean up subscribers to this `MotionValue`. * * The `MotionValue` hooks like `useMotionValue` and `useTransform` automatically * handle the lifecycle of the returned `MotionValue`, so this method is only necessary if you've manually * created a `MotionValue` via the `motionValue` function. * * @public */ MotionValue.prototype.destroy = function () { this.updateSubscribers.clear(); this.renderSubscribers.clear(); this.stop(); }; return MotionValue; }()); function motionValue(init) { return new MotionValue(init); } /** * Tests a provided value against a ValueType */ var testValueType = function (v) { return function (type) { return type.test(v); }; }; /** * ValueType for "auto" */ var auto = { test: function (v) { return v === "auto"; }, parse: function (v) { return v; }, }; /** * A list of value types commonly used for dimensions */ var dimensionValueTypes = [styleValueTypes.number, styleValueTypes.px, styleValueTypes.percent, styleValueTypes.degrees, styleValueTypes.vw, styleValueTypes.vh, auto]; /** * Tests a dimensional value against the list of dimension ValueTypes */ var findDimensionValueType = function (v) { return dimensionValueTypes.find(testValueType(v)); }; /** * A list of all ValueTypes */ var valueTypes = tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(dimensionValueTypes), false), [styleValueTypes.color, styleValueTypes.complex], false); /** * Tests a value against the list of ValueTypes */ var findValueType = function (v) { return valueTypes.find(testValueType(v)); }; /** * Set VisualElement's MotionValue, creating a new MotionValue for it if * it doesn't exist. */ function setMotionValue(visualElement, key, value) { if (visualElement.hasValue(key)) { visualElement.getValue(key).set(value); } else { visualElement.addValue(key, motionValue(value)); } } function setTarget(visualElement, definition) { var resolved = resolveVariant(visualElement, definition); var _a = resolved ? visualElement.makeTargetAnimatable(resolved, false) : {}, _b = _a.transitionEnd, transitionEnd = _b === void 0 ? {} : _b; _a.transition; var target = tslib.__rest(_a, ["transitionEnd", "transition"]); target = tslib.__assign(tslib.__assign({}, target), transitionEnd); for (var key in target) { var value = resolveFinalValueInKeyframes(target[key]); setMotionValue(visualElement, key, value); } } function setVariants(visualElement, variantLabels) { var reversedLabels = tslib.__spreadArray([], tslib.__read(variantLabels), false).reverse(); reversedLabels.forEach(function (key) { var _a; var variant = visualElement.getVariant(key); variant && setTarget(visualElement, variant); (_a = visualElement.variantChildren) === null || _a === void 0 ? void 0 : _a.forEach(function (child) { setVariants(child, variantLabels); }); }); } function setValues(visualElement, definition) { if (Array.isArray(definition)) { return setVariants(visualElement, definition); } else if (typeof definition === "string") { return setVariants(visualElement, [definition]); } else { setTarget(visualElement, definition); } } function checkTargetForNewValues(visualElement, target, origin) { var _a, _b, _c; var _d; var newValueKeys = Object.keys(target).filter(function (key) { return !visualElement.hasValue(key); }); var numNewValues = newValueKeys.length; if (!numNewValues) return; for (var i = 0; i < numNewValues; i++) { var key = newValueKeys[i]; var targetValue = target[key]; var value = null; /** * If the target is a series of keyframes, we can use the first value * in the array. If this first value is null, we'll still need to read from the DOM. */ if (Array.isArray(targetValue)) { value = targetValue[0]; } /** * If the target isn't keyframes, or the first keyframe was null, we need to * first check if an origin value was explicitly defined in the transition as "from", * if not read the value from the DOM. As an absolute fallback, take the defined target value. */ if (value === null) { value = (_b = (_a = origin[key]) !== null && _a !== void 0 ? _a : visualElement.readValue(key)) !== null && _b !== void 0 ? _b : target[key]; } /** * If value is still undefined or null, ignore it. Preferably this would throw, * but this was causing issues in Framer. */ if (value === undefined || value === null) continue; if (typeof value === "string" && (isNumericalString(value) || isZeroValueString(value))) { // If this is a number read as a string, ie "0" or "200", convert it to a number value = parseFloat(value); } else if (!findValueType(value) && styleValueTypes.complex.test(targetValue)) { value = getAnimatableNone(key, targetValue); } visualElement.addValue(key, motionValue(value)); (_c = (_d = origin)[key]) !== null && _c !== void 0 ? _c : (_d[key] = value); visualElement.setBaseTarget(key, value); } } function getOriginFromTransition(key, transition) { if (!transition) return; var valueTransition = transition[key] || transition["default"] || transition; return valueTransition.from; } function getOrigin(target, transition, visualElement) { var _a, _b; var origin = {}; for (var key in target) { origin[key] = (_a = getOriginFromTransition(key, transition)) !== null && _a !== void 0 ? _a : (_b = visualElement.getValue(key)) === null || _b === void 0 ? void 0 : _b.get(); } return origin; } function animateVisualElement(visualElement, definition, options) { if (options === void 0) { options = {}; } visualElement.notifyAnimationStart(definition); var animation; if (Array.isArray(definition)) { var animations = definition.map(function (variant) { return animateVariant(visualElement, variant, options); }); animation = Promise.all(animations); } else if (typeof definition === "string") { animation = animateVariant(visualElement, definition, options); } else { var resolvedDefinition = typeof definition === "function" ? resolveVariant(visualElement, definition, options.custom) : definition; animation = animateTarget(visualElement, resolvedDefinition, options); } return animation.then(function () { return visualElement.notifyAnimationComplete(definition); }); } function animateVariant(visualElement, variant, options) { var _a; if (options === void 0) { options = {}; } var resolved = resolveVariant(visualElement, variant, options.custom); var _b = (resolved || {}).transition, transition = _b === void 0 ? visualElement.getDefaultTransition() || {} : _b; if (options.transitionOverride) { transition = options.transitionOverride; } /** * If we have a variant, create a callback that runs it as an animation. * Otherwise, we resolve a Promise immediately for a composable no-op. */ var getAnimation = resolved ? function () { return animateTarget(visualElement, resolved, options); } : function () { return Promise.resolve(); }; /** * If we have children, create a callback that runs all their animations. * Otherwise, we resolve a Promise immediately for a composable no-op. */ var getChildAnimations = ((_a = visualElement.variantChildren) === null || _a === void 0 ? void 0 : _a.size) ? function (forwardDelay) { if (forwardDelay === void 0) { forwardDelay = 0; } var _a = transition.delayChildren, delayChildren = _a === void 0 ? 0 : _a, staggerChildren = transition.staggerChildren, staggerDirection = transition.staggerDirection; return animateChildren(visualElement, variant, delayChildren + forwardDelay, staggerChildren, staggerDirection, options); } : function () { return Promise.resolve(); }; /** * If the transition explicitly defines a "when" option, we need to resolve either * this animation or all children animations before playing the other. */ var when = transition.when; if (when) { var _c = tslib.__read(when === "beforeChildren" ? [getAnimation, getChildAnimations] : [getChildAnimations, getAnimation], 2), first = _c[0], last = _c[1]; return first().then(last); } else { return Promise.all([getAnimation(), getChildAnimations(options.delay)]); } } /** * @internal */ function animateTarget(visualElement, definition, _a) { var _b; var _c = _a === void 0 ? {} : _a, _d = _c.delay, delay = _d === void 0 ? 0 : _d, transitionOverride = _c.transitionOverride, type = _c.type; var _e = visualElement.makeTargetAnimatable(definition), _f = _e.transition, transition = _f === void 0 ? visualElement.getDefaultTransition() : _f, transitionEnd = _e.transitionEnd, target = tslib.__rest(_e, ["transition", "transitionEnd"]); if (transitionOverride) transition = transitionOverride; var animations = []; var animationTypeState = type && ((_b = visualElement.animationState) === null || _b === void 0 ? void 0 : _b.getState()[type]); for (var key in target) { var value = visualElement.getValue(key); var valueTarget = target[key]; if (!value || valueTarget === undefined || (animationTypeState && shouldBlockAnimation(animationTypeState, key))) { continue; } var valueTransition = tslib.__assign({ delay: delay }, transition); /** * Make animation instant if this is a transform prop and we should reduce motion. */ if (visualElement.shouldReduceMotion && isTransformProp(key)) { valueTransition = tslib.__assign(tslib.__assign({}, valueTransition), { type: false, delay: 0 }); } var animation = startAnimation(key, value, valueTarget, valueTransition); animations.push(animation); } return Promise.all(animations).then(function () { transitionEnd && setTarget(visualElement, transitionEnd); }); } function animateChildren(visualElement, variant, delayChildren, staggerChildren, staggerDirection, options) { if (delayChildren === void 0) { delayChildren = 0; } if (staggerChildren === void 0) { staggerChildren = 0; } if (staggerDirection === void 0) { staggerDirection = 1; } var animations = []; var maxStaggerDuration = (visualElement.variantChildren.size - 1) * staggerChildren; var generateStaggerDuration = staggerDirection === 1 ? function (i) { if (i === void 0) { i = 0; } return i * staggerChildren; } : function (i) { if (i === void 0) { i = 0; } return maxStaggerDuration - i * staggerChildren; }; Array.from(visualElement.variantChildren) .sort(sortByTreeOrder) .forEach(function (child, i) { animations.push(animateVariant(child, variant, tslib.__assign(tslib.__assign({}, options), { delay: delayChildren + generateStaggerDuration(i) })).then(function () { return child.notifyAnimationComplete(variant); })); }); return Promise.all(animations); } function stopAnimation(visualElement) { visualElement.forEachValue(function (value) { return value.stop(); }); } function sortByTreeOrder(a, b) { return a.sortNodePosition(b); } /** * Decide whether we should block this animation. Previously, we achieved this * just by checking whether the key was listed in protectedKeys, but this * posed problems if an animation was triggered by afterChildren and protectedKeys * had been set to true in the meantime. */ function shouldBlockAnimation(_a, key) { var protectedKeys = _a.protectedKeys, needsAnimating = _a.needsAnimating; var shouldBlock = protectedKeys.hasOwnProperty(key) && needsAnimating[key] !== true; needsAnimating[key] = false; return shouldBlock; } var variantPriorityOrder = [ exports.AnimationType.Animate, exports.AnimationType.InView, exports.AnimationType.Focus, exports.AnimationType.Hover, exports.AnimationType.Tap, exports.AnimationType.Drag, exports.AnimationType.Exit, ]; var reversePriorityOrder = tslib.__spreadArray([], tslib.__read(variantPriorityOrder), false).reverse(); var numAnimationTypes = variantPriorityOrder.length; function animateList(visualElement) { return function (animations) { return Promise.all(animations.map(function (_a) { var animation = _a.animation, options = _a.options; return animateVisualElement(visualElement, animation, options); })); }; } function createAnimationState(visualElement) { var animate = animateList(visualElement); var state = createState(); var allAnimatedKeys = {}; var isInitialRender = true; /** * This function will be used to reduce the animation definitions for * each active animation type into an object of resolved values for it. */ var buildResolvedTypeValues = function (acc, definition) { var resolved = resolveVariant(visualElement, definition); if (resolved) { resolved.transition; var transitionEnd = resolved.transitionEnd, target = tslib.__rest(resolved, ["transition", "transitionEnd"]); acc = tslib.__assign(tslib.__assign(tslib.__assign({}, acc), target), transitionEnd); } return acc; }; function isAnimated(key) { return allAnimatedKeys[key] !== undefined; } /** * This just allows us to inject mocked animation functions * @internal */ function setAnimateFunction(makeAnimator) { animate = makeAnimator(visualElement); } /** * When we receive new props, we need to: * 1. Create a list of protected keys for each type. This is a directory of * value keys that are currently being "handled" by types of a higher priority * so that whenever an animation is played of a given type, these values are * protected from being animated. * 2. Determine if an animation type needs animating. * 3. Determine if any values have been removed from a type and figure out * what to animate those to. */ function animateChanges(options, changedActiveType) { var _a; var props = visualElement.getProps(); var context = visualElement.getVariantContext(true) || {}; /** * A list of animations that we'll build into as we iterate through the animation * types. This will get executed at the end of the function. */ var animations = []; /** * Keep track of which values have been removed. Then, as we hit lower priority * animation types, we can check if they contain removed values and animate to that. */ var removedKeys = new Set(); /** * A dictionary of all encountered keys. This is an object to let us build into and * copy it without iteration. Each time we hit an animation type we set its protected * keys - the keys its not allowed to animate - to the latest version of this object. */ var encounteredKeys = {}; /** * If a variant has been removed at a given index, and this component is controlling * variant animations, we want to ensure lower-priority variants are forced to animate. */ var removedVariantIndex = Infinity; var _loop_1 = function (i) { var type = reversePriorityOrder[i]; var typeState = state[type]; var prop = (_a = props[type]) !== null && _a !== void 0 ? _a : context[type]; var propIsVariant = isVariantLabel(prop); /** * If this type has *just* changed isActive status, set activeDelta * to that status. Otherwise set to null. */ var activeDelta = type === changedActiveType ? typeState.isActive : null; if (activeDelta === false) removedVariantIndex = i; /** * If this prop is an inherited variant, rather than been set directly on the * component itself, we want to make sure we allow the parent to trigger animations. * * TODO: Can probably change this to a !isControllingVariants check */ var isInherited = prop === context[type] && prop !== props[type] && propIsVariant; /** * */ if (isInherited && isInitialRender && visualElement.manuallyAnimateOnMount) { isInherited = false; } /** * Set all encountered keys so far as the protected keys for this type. This will * be any key that has been animated or otherwise handled by active, higher-priortiy types. */ typeState.protectedKeys = tslib.__assign({}, encounteredKeys); // Check if we can skip analysing this prop early if ( // If it isn't active and hasn't *just* been set as inactive (!typeState.isActive && activeDelta === null) || // If we didn't and don't have any defined prop for this animation type (!prop && !typeState.prevProp) || // Or if the prop doesn't define an animation isAnimationControls(prop) || typeof prop === "boolean") { return "continue"; } /** * As we go look through the values defined on this type, if we detect * a changed value or a value that was removed in a higher priority, we set * this to true and add this prop to the animation list. */ var variantDidChange = checkVariantsDidChange(typeState.prevProp, prop); var shouldAnimateType = variantDidChange || // If we're making this variant active, we want to always make it active (type === changedActiveType && typeState.isActive && !isInherited && propIsVariant) || // If we removed a higher-priority variant (i is in reverse order) (i > removedVariantIndex && propIsVariant); /** * As animations can be set as variant lists, variants or target objects, we * coerce everything to an array if it isn't one already */ var definitionList = Array.isArray(prop) ? prop : [prop]; /** * Build an object of all the resolved values. We'll use this in the subsequent * animateChanges calls to determine whether a value has changed. */ var resolvedValues = definitionList.reduce(buildResolvedTypeValues, {}); if (activeDelta === false) resolvedValues = {}; /** * Now we need to loop through all the keys in the prev prop and this prop, * and decide: * 1. If the value has changed, and needs animating * 2. If it has been removed, and needs adding to the removedKeys set * 3. If it has been removed in a higher priority type and needs animating * 4. If it hasn't been removed in a higher priority but hasn't changed, and * needs adding to the type's protectedKeys list. */ var _b = typeState.prevResolvedValues, prevResolvedValues = _b === void 0 ? {} : _b; var allKeys = tslib.__assign(tslib.__assign({}, prevResolvedValues), resolvedValues); var markToAnimate = function (key) { shouldAnimateType = true; removedKeys.delete(key); typeState.needsAnimating[key] = true; }; for (var key in allKeys) { var next = resolvedValues[key]; var prev = prevResolvedValues[key]; // If we've already handled this we can just skip ahead if (encounteredKeys.hasOwnProperty(key)) continue; /** * If the value has changed, we probably want to animate it. */ if (next !== prev) { /** * If both values are keyframes, we need to shallow compare them to * detect whether any value has changed. If it has, we animate it. */ if (isKeyframesTarget(next) && isKeyframesTarget(prev)) { if (!shallowCompare(next, prev) || variantDidChange) { markToAnimate(key); } else { /** * If it hasn't changed, we want to ensure it doesn't animate by * adding it to the list of protected keys. */ typeState.protectedKeys[key] = true; } } else if (next !== undefined) { // If next is defined and doesn't equal prev, it needs animating markToAnimate(key); } else { // If it's undefined, it's been removed. removedKeys.add(key); } } else if (next !== undefined && removedKeys.has(key)) { /** * If next hasn't changed and it isn't undefined, we want to check if it's * been removed by a higher priority */ markToAnimate(key); } else { /** * If it hasn't changed, we add it to the list of protected values * to ensure it doesn't get animated. */ typeState.protectedKeys[key] = true; } } /** * Update the typeState so next time animateChanges is called we can compare the * latest prop and resolvedValues to these. */ typeState.prevProp = prop; typeState.prevResolvedValues = resolvedValues; /** * */ if (typeState.isActive) { encounteredKeys = tslib.__assign(tslib.__assign({}, encounteredKeys), resolvedValues); } if (isInitialRender && visualElement.blockInitialAnimation) { shouldAnimateType = false; } /** * If this is an inherited prop we want to hard-block animations * TODO: Test as this should probably still handle animations triggered * by removed values? */ if (shouldAnimateType && !isInherited) { animations.push.apply(animations, tslib.__spreadArray([], tslib.__read(definitionList.map(function (animation) { return ({ animation: animation, options: tslib.__assign({ type: type }, options), }); })), false)); } }; /** * Iterate through all animation types in reverse priority order. For each, we want to * detect which values it's handling and whether or not they've changed (and therefore * need to be animated). If any values have been removed, we want to detect those in * lower priority props and flag for animation. */ for (var i = 0; i < numAnimationTypes; i++) { _loop_1(i); } allAnimatedKeys = tslib.__assign({}, encounteredKeys); /** * If there are some removed value that haven't been dealt with, * we need to create a new animation that falls back either to the value * defined in the style prop, or the last read value. */ if (removedKeys.size) { var fallbackAnimation_1 = {}; removedKeys.forEach(function (key) { var fallbackTarget = visualElement.getBaseTarget(key); if (fallbackTarget !== undefined) { fallbackAnimation_1[key] = fallbackTarget; } }); animations.push({ animation: fallbackAnimation_1 }); } var shouldAnimate = Boolean(animations.length); if (isInitialRender && props.initial === false && !visualElement.manuallyAnimateOnMount) { shouldAnimate = false; } isInitialRender = false; return shouldAnimate ? animate(animations) : Promise.resolve(); } /** * Change whether a certain animation type is active. */ function setActive(type, isActive, options) { var _a; // If the active state hasn't changed, we can safely do nothing here if (state[type].isActive === isActive) return Promise.resolve(); // Propagate active change to children (_a = visualElement.variantChildren) === null || _a === void 0 ? void 0 : _a.forEach(function (child) { var _a; return (_a = child.animationState) === null || _a === void 0 ? void 0 : _a.setActive(type, isActive); }); state[type].isActive = isActive; var animations = animateChanges(options, type); for (var key in state) { state[key].protectedKeys = {}; } return animations; } return { isAnimated: isAnimated, animateChanges: animateChanges, setActive: setActive, setAnimateFunction: setAnimateFunction, getState: function () { return state; }, }; } function checkVariantsDidChange(prev, next) { if (typeof next === "string") { return next !== prev; } else if (isVariantLabels(next)) { return !shallowCompare(next, prev); } return false; } function createTypeState(isActive) { if (isActive === void 0) { isActive = false; } return { isActive: isActive, protectedKeys: {}, needsAnimating: {}, prevResolvedValues: {}, }; } function createState() { var _a; return _a = {}, _a[exports.AnimationType.Animate] = createTypeState(true), _a[exports.AnimationType.InView] = createTypeState(), _a[exports.AnimationType.Hover] = createTypeState(), _a[exports.AnimationType.Tap] = createTypeState(), _a[exports.AnimationType.Drag] = createTypeState(), _a[exports.AnimationType.Focus] = createTypeState(), _a[exports.AnimationType.Exit] = createTypeState(), _a; } var animations = { animation: makeRenderlessComponent(function (_a) { var visualElement = _a.visualElement, animate = _a.animate; /** * We dynamically generate the AnimationState manager as it contains a reference * to the underlying animation library. We only want to load that if we load this, * so people can optionally code split it out using the `m` component. */ visualElement.animationState || (visualElement.animationState = createAnimationState(visualElement)); /** * Subscribe any provided AnimationControls to the component's VisualElement */ if (isAnimationControls(animate)) { React.useEffect(function () { return animate.subscribe(visualElement); }, [animate]); } }), exit: makeRenderlessComponent(function (props) { var custom = props.custom, visualElement = props.visualElement; var _a = tslib.__read(usePresence(), 2), isPresent = _a[0], safeToRemove = _a[1]; var presenceContext = React.useContext(PresenceContext); React.useEffect(function () { var _a, _b; visualElement.isPresent = isPresent; var animation = (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(exports.AnimationType.Exit, !isPresent, { custom: (_b = presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.custom) !== null && _b !== void 0 ? _b : custom }); !isPresent && (animation === null || animation === void 0 ? void 0 : animation.then(safeToRemove)); }, [isPresent]); }), }; /** * @internal */ var PanSession = /** @class */ (function () { function PanSession(event, handlers, _a) { var _this = this; var _b = _a === void 0 ? {} : _a, transformPagePoint = _b.transformPagePoint; /** * @internal */ this.startEvent = null; /** * @internal */ this.lastMoveEvent = null; /** * @internal */ this.lastMoveEventInfo = null; /** * @internal */ this.handlers = {}; this.updatePoint = function () { if (!(_this.lastMoveEvent && _this.lastMoveEventInfo)) return; var info = getPanInfo(_this.lastMoveEventInfo, _this.history); var isPanStarted = _this.startEvent !== null; // Only start panning if the offset is larger than 3 pixels. If we make it // any larger than this we'll want to reset the pointer history // on the first update to avoid visual snapping to the cursoe. var isDistancePastThreshold = popmotion.distance(info.offset, { x: 0, y: 0 }) >= 3; if (!isPanStarted && !isDistancePastThreshold) return; var point = info.point; var timestamp = sync.getFrameData().timestamp; _this.history.push(tslib.__assign(tslib.__assign({}, point), { timestamp: timestamp })); var _a = _this.handlers, onStart = _a.onStart, onMove = _a.onMove; if (!isPanStarted) { onStart && onStart(_this.lastMoveEvent, info); _this.startEvent = _this.lastMoveEvent; } onMove && onMove(_this.lastMoveEvent, info); }; this.handlePointerMove = function (event, info) { _this.lastMoveEvent = event; _this.lastMoveEventInfo = transformPoint(info, _this.transformPagePoint); // Because Safari doesn't trigger mouseup events when it's above a `