'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var index = require('./index-6W16WHlG.js');
var motionDom = require('motion-dom');
var featureBundle = require('./feature-bundle-frRcWALD.js');
var motionUtils = require('motion-utils');

function _interopNamespaceDefault(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__*/_interopNamespaceDefault(React);

/**
 * Taken from https://github.com/radix-ui/primitives/blob/main/packages/react/compose-refs/src/compose-refs.tsx
 */
/**
 * Set a given ref to a given value
 * This utility takes care of different types of refs: callback refs and RefObject(s)
 */
function setRef(ref, value) {
    if (typeof ref === "function") {
        return ref(value);
    }
    else if (ref !== null && ref !== undefined) {
        ref.current = value;
    }
}
/**
 * A utility to compose multiple refs together
 * Accepts callback refs and RefObject(s)
 */
function composeRefs(...refs) {
    return (node) => {
        let hasCleanup = false;
        const cleanups = refs.map((ref) => {
            const cleanup = setRef(ref, node);
            if (!hasCleanup && typeof cleanup === "function") {
                hasCleanup = true;
            }
            return cleanup;
        });
        // React <19 will log an error to the console if a callback ref returns a
        // value. We don't use ref cleanups internally so this will only happen if a
        // user's ref callback returns a value, which we only expect if they are
        // using the cleanup functionality added in React 19.
        if (hasCleanup) {
            return () => {
                for (let i = 0; i < cleanups.length; i++) {
                    const cleanup = cleanups[i];
                    if (typeof cleanup === "function") {
                        cleanup();
                    }
                    else {
                        setRef(refs[i], null);
                    }
                }
            };
        }
    };
}
/**
 * A custom hook that composes multiple refs
 * Accepts callback refs and RefObject(s)
 */
function useComposedRefs(...refs) {
    // eslint-disable-next-line react-hooks/exhaustive-deps
    return React__namespace.useCallback(composeRefs(...refs), refs);
}

/**
 * Measurement functionality has to be within a separate component
 * to leverage snapshot lifecycle.
 */
class PopChildMeasure extends React__namespace.Component {
    getSnapshotBeforeUpdate(prevProps) {
        const element = this.props.childRef.current;
        if (motionDom.isHTMLElement(element) && prevProps.isPresent && !this.props.isPresent && this.props.pop !== false) {
            const parent = element.offsetParent;
            const parentWidth = motionDom.isHTMLElement(parent)
                ? parent.offsetWidth || 0
                : 0;
            const parentHeight = motionDom.isHTMLElement(parent)
                ? parent.offsetHeight || 0
                : 0;
            const computedStyle = getComputedStyle(element);
            const size = this.props.sizeRef.current;
            size.height = parseFloat(computedStyle.height);
            size.width = parseFloat(computedStyle.width);
            size.top = element.offsetTop;
            size.left = element.offsetLeft;
            size.right = parentWidth - size.width - size.left;
            size.bottom = parentHeight - size.height - size.top;
            size.direction = computedStyle.direction;
        }
        return null;
    }
    /**
     * Required with getSnapshotBeforeUpdate to stop React complaining.
     */
    componentDidUpdate() { }
    render() {
        return this.props.children;
    }
}
function PopChild({ children, isPresent, anchorX, anchorY, root, pop }) {
    const id = React.useId();
    const ref = React.useRef(null);
    const size = React.useRef({
        width: 0,
        height: 0,
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        direction: "ltr",
    });
    const { nonce } = React.useContext(index.MotionConfigContext);
    /**
     * In React 19, refs are passed via props.ref instead of element.ref.
     * We check props.ref first (React 19) and fall back to element.ref (React 18).
     */
    const childRef = children.props?.ref ??
        children?.ref;
    const composedRef = useComposedRefs(ref, childRef);
    /**
     * We create and inject a style block so we can apply this explicit
     * sizing in a non-destructive manner by just deleting the style block.
     *
     * We can't apply size via render as the measurement happens
     * in getSnapshotBeforeUpdate (post-render), likewise if we apply the
     * styles directly on the DOM node, we might be overwriting
     * styles set via the style prop.
     */
    React.useInsertionEffect(() => {
        const { width, height, top, left, right, bottom, direction } = size.current;
        if (isPresent || pop === false || !ref.current || !width || !height)
            return;
        const isRTL = direction === "rtl";
        const x = anchorX === "left"
            ? (isRTL ? `right: ${right}` : `left: ${left}`)
            : (isRTL ? `left: ${left}` : `right: ${right}`);
        const y = anchorY === "bottom" ? `bottom: ${bottom}` : `top: ${top}`;
        ref.current.dataset.motionPopId = id;
        const style = document.createElement("style");
        if (nonce)
            style.nonce = nonce;
        const parent = root ?? document.head;
        parent.appendChild(style);
        if (style.sheet) {
            style.sheet.insertRule(`
          [data-motion-pop-id="${id}"] {
            position: absolute !important;
            width: ${width}px !important;
            height: ${height}px !important;
            ${x}px !important;
            ${y}px !important;
          }
        `);
        }
        return () => {
            ref.current?.removeAttribute("data-motion-pop-id");
            if (parent.contains(style)) {
                parent.removeChild(style);
            }
        };
    }, [isPresent]);
    return (jsxRuntime.jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, pop: pop, children: pop === false
            ? children
            : React__namespace.cloneElement(children, { ref: composedRef }) }));
}

const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, anchorX, anchorY, root }) => {
    const presenceChildren = index.useConstant(newChildrenMap);
    const id = React.useId();
    let isReusedContext = true;
    let context = React.useMemo(() => {
        isReusedContext = false;
        return {
            id,
            initial,
            isPresent,
            custom,
            onExitComplete: (childId) => {
                presenceChildren.set(childId, true);
                for (const isComplete of presenceChildren.values()) {
                    if (!isComplete)
                        return; // can stop searching when any is incomplete
                }
                onExitComplete && onExitComplete();
            },
            register: (childId) => {
                presenceChildren.set(childId, false);
                return () => presenceChildren.delete(childId);
            },
        };
    }, [isPresent, presenceChildren, onExitComplete]);
    /**
     * If the presence of a child affects the layout of the components around it,
     * we want to make a new context value to ensure they get re-rendered
     * so they can detect that layout change.
     */
    if (presenceAffectsLayout && isReusedContext) {
        context = { ...context };
    }
    React.useMemo(() => {
        presenceChildren.forEach((_, key) => presenceChildren.set(key, false));
    }, [isPresent]);
    /**
     * If there's no `motion` components to fire exit animations, we want to remove this
     * component immediately.
     */
    React__namespace.useEffect(() => {
        !isPresent &&
            !presenceChildren.size &&
            onExitComplete &&
            onExitComplete();
    }, [isPresent]);
    children = (jsxRuntime.jsx(PopChild, { pop: mode === "popLayout", isPresent: isPresent, anchorX: anchorX, anchorY: anchorY, root: root, children: children }));
    return (jsxRuntime.jsx(index.PresenceContext.Provider, { value: context, children: children }));
};
function newChildrenMap() {
    return new Map();
}

const getChildKey = (child) => child.key || "";
function onlyElements(children) {
    const filtered = [];
    // We use forEach here instead of map as map mutates the component key by preprending `.$`
    React.Children.forEach(children, (child) => {
        if (React.isValidElement(child))
            filtered.push(child);
    });
    return filtered;
}

/**
 * `AnimatePresence` enables the animation of components that have been removed from the tree.
 *
 * When adding/removing more than a single child, every child **must** be given a unique `key` prop.
 *
 * Any `motion` components that have an `exit` property defined will animate out when removed from
 * the tree.
 *
 * ```jsx
 * import { motion, AnimatePresence } from 'framer-motion'
 *
 * export const Items = ({ items }) => (
 *   <AnimatePresence>
 *     {items.map(item => (
 *       <motion.div
 *         key={item.id}
 *         initial={{ opacity: 0 }}
 *         animate={{ opacity: 1 }}
 *         exit={{ opacity: 0 }}
 *       />
 *     ))}
 *   </AnimatePresence>
 * )
 * ```
 *
 * You can sequence exit animations throughout a tree using variants.
 *
 * If a child contains multiple `motion` components with `exit` props, it will only unmount the child
 * once all `motion` components have finished animating out. Likewise, any components using
 * `usePresence` all need to call `safeToRemove`.
 *
 * @public
 */
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = "sync", propagate = false, anchorX = "left", anchorY = "top", root }) => {
    const [isParentPresent, safeToRemove] = featureBundle.usePresence(propagate);
    /**
     * Filter any children that aren't ReactElements. We can only track components
     * between renders with a props.key.
     */
    const presentChildren = React.useMemo(() => onlyElements(children), [children]);
    /**
     * Track the keys of the currently rendered children. This is used to
     * determine which children are exiting.
     */
    const presentKeys = propagate && !isParentPresent ? [] : presentChildren.map(getChildKey);
    /**
     * If `initial={false}` we only want to pass this to components in the first render.
     */
    const isInitialRender = React.useRef(true);
    /**
     * A ref containing the currently present children. When all exit animations
     * are complete, we use this to re-render the component with the latest children
     * *committed* rather than the latest children *rendered*.
     */
    const pendingPresentChildren = React.useRef(presentChildren);
    /**
     * Track which exiting children have finished animating out.
     */
    const exitComplete = index.useConstant(() => new Map());
    /**
     * Track which components are currently processing exit to prevent duplicate processing.
     */
    const exitingComponents = React.useRef(new Set());
    /**
     * Save children to render as React state. To ensure this component is concurrent-safe,
     * we check for exiting children via an effect.
     */
    const [diffedChildren, setDiffedChildren] = React.useState(presentChildren);
    const [renderedChildren, setRenderedChildren] = React.useState(presentChildren);
    index.useIsomorphicLayoutEffect(() => {
        isInitialRender.current = false;
        pendingPresentChildren.current = presentChildren;
        /**
         * Update complete status of exiting children.
         */
        for (let i = 0; i < renderedChildren.length; i++) {
            const key = getChildKey(renderedChildren[i]);
            if (!presentKeys.includes(key)) {
                if (exitComplete.get(key) !== true) {
                    exitComplete.set(key, false);
                }
            }
            else {
                exitComplete.delete(key);
                exitingComponents.current.delete(key);
            }
        }
    }, [renderedChildren, presentKeys.length, presentKeys.join("-")]);
    const exitingChildren = [];
    if (presentChildren !== diffedChildren) {
        let nextChildren = [...presentChildren];
        /**
         * Loop through all the currently rendered components and decide which
         * are exiting.
         */
        for (let i = 0; i < renderedChildren.length; i++) {
            const child = renderedChildren[i];
            const key = getChildKey(child);
            if (!presentKeys.includes(key)) {
                nextChildren.splice(i, 0, child);
                exitingChildren.push(child);
            }
        }
        /**
         * If we're in "wait" mode, and we have exiting children, we want to
         * only render these until they've all exited.
         */
        if (mode === "wait" && exitingChildren.length) {
            nextChildren = exitingChildren;
        }
        setRenderedChildren(onlyElements(nextChildren));
        setDiffedChildren(presentChildren);
        /**
         * Early return to ensure once we've set state with the latest diffed
         * children, we can immediately re-render.
         */
        return null;
    }
    if (process.env.NODE_ENV !== "production" &&
        mode === "wait" &&
        renderedChildren.length > 1) {
        console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
    }
    /**
     * If we've been provided a forceRender function by the LayoutGroupContext,
     * we can use it to force a re-render amongst all surrounding components once
     * all components have finished animating out.
     */
    const { forceRender } = React.useContext(index.LayoutGroupContext);
    return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderedChildren.map((child) => {
            const key = getChildKey(child);
            const isPresent = propagate && !isParentPresent
                ? false
                : presentChildren === renderedChildren ||
                    presentKeys.includes(key);
            const onExit = () => {
                if (exitingComponents.current.has(key)) {
                    return;
                }
                if (exitComplete.has(key)) {
                    exitingComponents.current.add(key);
                    exitComplete.set(key, true);
                }
                else {
                    return;
                }
                let isEveryExitComplete = true;
                exitComplete.forEach((isExitComplete) => {
                    if (!isExitComplete)
                        isEveryExitComplete = false;
                });
                if (isEveryExitComplete) {
                    forceRender?.();
                    setRenderedChildren(pendingPresentChildren.current);
                    propagate && safeToRemove?.();
                    onExitComplete && onExitComplete();
                }
            };
            return (jsxRuntime.jsx(PresenceChild, { isPresent: isPresent, initial: !isInitialRender.current || initial
                    ? undefined
                    : false, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode, root: root, onExitComplete: isPresent ? undefined : onExit, anchorX: anchorX, anchorY: anchorY, children: child }, key));
        }) }));
};

/**
 * Note: Still used by components generated by old versions of Framer
 *
 * @deprecated
 */
const DeprecatedLayoutGroupContext = React.createContext(null);

function useIsMounted() {
    const isMounted = React.useRef(false);
    index.useIsomorphicLayoutEffect(() => {
        isMounted.current = true;
        return () => {
            isMounted.current = false;
        };
    }, []);
    return isMounted;
}

function useForceUpdate() {
    const isMounted = useIsMounted();
    const [forcedRenderCount, setForcedRenderCount] = React.useState(0);
    const forceRender = React.useCallback(() => {
        isMounted.current && setForcedRenderCount(forcedRenderCount + 1);
    }, [forcedRenderCount]);
    /**
     * Defer this to the end of the next animation frame in case there are multiple
     * synchronous calls.
     */
    const deferredForceRender = React.useCallback(() => motionDom.frame.postRender(forceRender), [forceRender]);
    return [deferredForceRender, forcedRenderCount];
}

const shouldInheritGroup = (inherit) => inherit === true;
const shouldInheritId = (inherit) => shouldInheritGroup(inherit === true) || inherit === "id";
const LayoutGroup = ({ children, id, inherit = true }) => {
    const layoutGroupContext = React.useContext(index.LayoutGroupContext);
    const deprecatedLayoutGroupContext = React.useContext(DeprecatedLayoutGroupContext);
    const [forceRender, key] = useForceUpdate();
    const context = React.useRef(null);
    const upstreamId = layoutGroupContext.id || deprecatedLayoutGroupContext;
    if (context.current === null) {
        if (shouldInheritId(inherit) && upstreamId) {
            id = id ? upstreamId + "-" + id : upstreamId;
        }
        context.current = {
            id,
            group: shouldInheritGroup(inherit)
                ? layoutGroupContext.group || motionDom.nodeGroup()
                : motionDom.nodeGroup(),
        };
    }
    const memoizedContext = React.useMemo(() => ({ ...context.current, forceRender }), [key]);
    return (jsxRuntime.jsx(index.LayoutGroupContext.Provider, { value: memoizedContext, children: children }));
};

/**
 * Used in conjunction with the `m` component to reduce bundle size.
 *
 * `m` is a version of the `motion` component that only loads functionality
 * critical for the initial render.
 *
 * `LazyMotion` can then be used to either synchronously or asynchronously
 * load animation and gesture support.
 *
 * ```jsx
 * // Synchronous loading
 * import { LazyMotion, m, domAnimation } from "framer-motion"
 *
 * function App() {
 *   return (
 *     <LazyMotion features={domAnimation}>
 *       <m.div animate={{ scale: 2 }} />
 *     </LazyMotion>
 *   )
 * }
 *
 * // Asynchronous loading
 * import { LazyMotion, m } from "framer-motion"
 *
 * function App() {
 *   return (
 *     <LazyMotion features={() => import('./path/to/domAnimation')}>
 *       <m.div animate={{ scale: 2 }} />
 *     </LazyMotion>
 *   )
 * }
 * ```
 *
 * @public
 */
function LazyMotion({ children, features, strict = false }) {
    const [, setIsLoaded] = React.useState(!isLazyBundle(features));
    const loadedRenderer = React.useRef(undefined);
    /**
     * If this is a synchronous load, load features immediately
     */
    if (!isLazyBundle(features)) {
        const { renderer, ...loadedFeatures } = features;
        loadedRenderer.current = renderer;
        index.loadFeatures(loadedFeatures);
    }
    React.useEffect(() => {
        if (isLazyBundle(features)) {
            features().then(({ renderer, ...loadedFeatures }) => {
                index.loadFeatures(loadedFeatures);
                loadedRenderer.current = renderer;
                setIsLoaded(true);
            });
        }
    }, []);
    return (jsxRuntime.jsx(index.LazyContext.Provider, { value: { renderer: loadedRenderer.current, strict }, children: children }));
}
function isLazyBundle(features) {
    return typeof features === "function";
}

/**
 * `MotionConfig` is used to set configuration options for all children `motion` components.
 *
 * ```jsx
 * import { motion, MotionConfig } from "framer-motion"
 *
 * export function App() {
 *   return (
 *     <MotionConfig transition={{ type: "spring" }}>
 *       <motion.div animate={{ x: 100 }} />
 *     </MotionConfig>
 *   )
 * }
 * ```
 *
 * @public
 */
function MotionConfig({ children, isValidProp, ...config }) {
    isValidProp && index.loadExternalIsValidProp(isValidProp);
    /**
     * Inherit props from any parent MotionConfig components
     */
    const parentConfig = React.useContext(index.MotionConfigContext);
    config = { ...parentConfig, ...config };
    config.transition = motionDom.resolveTransition(config.transition, parentConfig.transition);
    /**
     * Don't allow isStatic to change between renders as it affects how many hooks
     * motion components fire.
     */
    config.isStatic = index.useConstant(() => config.isStatic);
    /**
     * Creating a new config context object will re-render every `motion` component
     * every time it renders. So we only want to create a new one sparingly.
     */
    const context = React.useMemo(() => config, [
        JSON.stringify(config.transition),
        config.transformPagePoint,
        config.reducedMotion,
        config.skipAnimations,
    ]);
    return (jsxRuntime.jsx(index.MotionConfigContext.Provider, { value: context, children: children }));
}

const ReorderContext = React.createContext(null);

function createMotionProxy(preloadedFeatures, createVisualElement) {
    if (typeof Proxy === "undefined") {
        return index.createMotionComponent;
    }
    /**
     * A cache of generated `motion` components, e.g `motion.div`, `motion.input` etc.
     * Rather than generating them anew every render.
     */
    const componentCache = new Map();
    const factory = (Component, options) => {
        return index.createMotionComponent(Component, options, preloadedFeatures, createVisualElement);
    };
    /**
     * Support for deprecated`motion(Component)` pattern
     */
    const deprecatedFactoryFunction = (Component, options) => {
        if (process.env.NODE_ENV !== "production") {
            motionUtils.warnOnce(false, "motion() is deprecated. Use motion.create() instead.");
        }
        return factory(Component, options);
    };
    return new Proxy(deprecatedFactoryFunction, {
        /**
         * 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: (_target, key) => {
            if (key === "create")
                return factory;
            /**
             * If this element doesn't exist in the component cache, create it and cache.
             */
            if (!componentCache.has(key)) {
                componentCache.set(key, index.createMotionComponent(key, undefined, preloadedFeatures, createVisualElement));
            }
            return componentCache.get(key);
        },
    });
}

const motion = /*@__PURE__*/ createMotionProxy(featureBundle.featureBundle, featureBundle.createDomVisualElement);

function checkReorder(order, value, offset, velocity) {
    if (!velocity)
        return order;
    const index = order.findIndex((item) => item.value === value);
    if (index === -1)
        return order;
    const nextOffset = velocity > 0 ? 1 : -1;
    const nextItem = order[index + nextOffset];
    if (!nextItem)
        return order;
    const item = order[index];
    const nextLayout = nextItem.layout;
    const nextItemCenter = motionDom.mixNumber(nextLayout.min, nextLayout.max, 0.5);
    if ((nextOffset === 1 && item.layout.max + offset > nextItemCenter) ||
        (nextOffset === -1 && item.layout.min + offset < nextItemCenter)) {
        return motionUtils.moveItem(order, index, index + nextOffset);
    }
    return order;
}

function ReorderGroupComponent({ children, as = "ul", axis = "y", onReorder, values, ...props }, externalRef) {
    const Component = index.useConstant(() => motion[as]);
    const order = [];
    const isReordering = React.useRef(false);
    const groupRef = React.useRef(null);
    motionUtils.invariant(Boolean(values), "Reorder.Group must be provided a values prop", "reorder-values");
    const context = {
        axis,
        groupRef,
        registerItem: (value, layout) => {
            // If the entry was already added, update it rather than adding it again
            const idx = order.findIndex((entry) => value === entry.value);
            if (idx !== -1) {
                order[idx].layout = layout[axis];
            }
            else {
                order.push({ value: value, layout: layout[axis] });
            }
            order.sort(compareMin);
        },
        updateOrder: (item, offset, velocity) => {
            if (isReordering.current)
                return;
            const newOrder = checkReorder(order, item, offset, velocity);
            if (order !== newOrder) {
                isReordering.current = true;
                // Find which two values swapped and apply that swap
                // to the full values array. This preserves unmeasured
                // items (e.g. in virtualized lists).
                const newValues = [...values];
                for (let i = 0; i < newOrder.length; i++) {
                    if (order[i].value !== newOrder[i].value) {
                        const a = values.indexOf(order[i].value);
                        const b = values.indexOf(newOrder[i].value);
                        if (a !== -1 && b !== -1) {
                            [newValues[a], newValues[b]] = [newValues[b], newValues[a]];
                        }
                        break;
                    }
                }
                onReorder(newValues);
            }
        },
    };
    React.useEffect(() => {
        isReordering.current = false;
    });
    // Combine refs if external ref is provided
    const setRef = (element) => {
        groupRef.current = element;
        if (typeof externalRef === "function") {
            externalRef(element);
        }
        else if (externalRef) {
            externalRef.current = element;
        }
    };
    /**
     * Disable browser scroll anchoring on the group container.
     * When items reorder, scroll anchoring can cause the browser to adjust
     * the scroll position, which interferes with drag position calculations.
     */
    const groupStyle = {
        overflowAnchor: "none",
        ...props.style,
    };
    return (jsxRuntime.jsx(Component, { ...props, style: groupStyle, ref: setRef, ignoreStrict: true, children: jsxRuntime.jsx(ReorderContext.Provider, { value: context, children: children }) }));
}
const ReorderGroup = /*@__PURE__*/ React.forwardRef(ReorderGroupComponent);
function compareMin(a, b) {
    return a.layout.min - b.layout.min;
}

/**
 * Creates a `MotionValue` to track the state and velocity of a value.
 *
 * Usually, these are created automatically. For advanced use-cases, like use with `useTransform`, you can create `MotionValue`s externally and pass them into the animated component via the `style` prop.
 *
 * ```jsx
 * export const MyComponent = () => {
 *   const scale = useMotionValue(1)
 *
 *   return <motion.div style={{ scale }} />
 * }
 * ```
 *
 * @param initial - The initial state.
 *
 * @public
 */
function useMotionValue(initial) {
    const value = index.useConstant(() => motionDom.motionValue(initial));
    /**
     * If this motion value is being used in static mode, like on
     * the Framer canvas, force components to rerender when the motion
     * value is updated.
     */
    const { isStatic } = React.useContext(index.MotionConfigContext);
    if (isStatic) {
        const [, setLatest] = React.useState(initial);
        React.useEffect(() => value.on("change", setLatest), []);
    }
    return value;
}

function useCombineMotionValues(values, combineValues) {
    /**
     * Initialise the returned motion value. This remains the same between renders.
     */
    const value = useMotionValue(combineValues());
    /**
     * Create a function that will update the template motion value with the latest values.
     * This is pre-bound so whenever a motion value updates it can schedule its
     * execution in Framesync. If it's already been scheduled it won't be fired twice
     * in a single frame.
     */
    const updateValue = () => value.set(combineValues());
    /**
     * Synchronously update the motion value with the latest values during the render.
     * This ensures that within a React render, the styles applied to the DOM are up-to-date.
     */
    updateValue();
    /**
     * Subscribe to all motion values found within the template. Whenever any of them change,
     * schedule an update.
     */
    index.useIsomorphicLayoutEffect(() => {
        const scheduleUpdate = () => motionDom.frame.preRender(updateValue, false, true);
        const subscriptions = values.map((v) => v.on("change", scheduleUpdate));
        return () => {
            subscriptions.forEach((unsubscribe) => unsubscribe());
            motionDom.cancelFrame(updateValue);
        };
    });
    return value;
}

function useComputed(compute) {
    /**
     * Open session of collectMotionValues. Any MotionValue that calls get()
     * will be saved into this array.
     */
    motionDom.collectMotionValues.current = [];
    compute();
    const value = useCombineMotionValues(motionDom.collectMotionValues.current, compute);
    /**
     * Synchronously close session of collectMotionValues.
     */
    motionDom.collectMotionValues.current = undefined;
    return value;
}

function useTransform(input, inputRangeOrTransformer, outputRangeOrMap, options) {
    if (typeof input === "function") {
        return useComputed(input);
    }
    /**
     * Detect if outputRangeOrMap is an output map (object with keys)
     * rather than an output range (array).
     */
    const isOutputMap = outputRangeOrMap !== undefined &&
        !Array.isArray(outputRangeOrMap) &&
        typeof inputRangeOrTransformer !== "function";
    if (isOutputMap) {
        return useMapTransform(input, inputRangeOrTransformer, outputRangeOrMap, options);
    }
    const outputRange = outputRangeOrMap;
    const transformer = typeof inputRangeOrTransformer === "function"
        ? inputRangeOrTransformer
        : motionDom.transform(inputRangeOrTransformer, outputRange, options);
    const result = Array.isArray(input)
        ? useListTransform(input, transformer)
        : useListTransform([input], ([latest]) => transformer(latest));
    const inputAccelerate = !Array.isArray(input)
        ? input.accelerate
        : undefined;
    if (inputAccelerate &&
        !inputAccelerate.isTransformed &&
        typeof inputRangeOrTransformer !== "function" &&
        Array.isArray(outputRangeOrMap) &&
        options?.clamp !== false) {
        result.accelerate = {
            ...inputAccelerate,
            times: inputRangeOrTransformer,
            keyframes: outputRangeOrMap,
            isTransformed: true,
            ...(options?.ease ? { ease: options.ease } : {}),
        };
    }
    return result;
}
function useListTransform(values, transformer) {
    const latest = index.useConstant(() => []);
    return useCombineMotionValues(values, () => {
        latest.length = 0;
        const numValues = values.length;
        for (let i = 0; i < numValues; i++) {
            latest[i] = values[i].get();
        }
        return transformer(latest);
    });
}
function useMapTransform(inputValue, inputRange, outputMap, options) {
    /**
     * Capture keys once to ensure hooks are called in consistent order.
     */
    const keys = index.useConstant(() => Object.keys(outputMap));
    const output = index.useConstant(() => ({}));
    for (const key of keys) {
        output[key] = useTransform(inputValue, inputRange, outputMap[key], options);
    }
    return output;
}

const threshold = 50;
const maxSpeed = 25;
const overflowStyles = new Set(["auto", "scroll"]);
// Track initial scroll limits per scrollable element (Bug 1 fix)
const initialScrollLimits = new WeakMap();
const activeScrollEdge = new WeakMap();
// Track which group element is currently dragging to clear state on end
let currentGroupElement = null;
function resetAutoScrollState() {
    if (currentGroupElement) {
        const scrollableAncestor = findScrollableAncestor(currentGroupElement, "y");
        if (scrollableAncestor) {
            activeScrollEdge.delete(scrollableAncestor);
            initialScrollLimits.delete(scrollableAncestor);
        }
        // Also try x axis
        const scrollableAncestorX = findScrollableAncestor(currentGroupElement, "x");
        if (scrollableAncestorX && scrollableAncestorX !== scrollableAncestor) {
            activeScrollEdge.delete(scrollableAncestorX);
            initialScrollLimits.delete(scrollableAncestorX);
        }
        currentGroupElement = null;
    }
}
function isScrollableElement(element, axis) {
    const style = getComputedStyle(element);
    const overflow = axis === "x" ? style.overflowX : style.overflowY;
    const isDocumentScroll = element === document.body ||
        element === document.documentElement;
    return overflowStyles.has(overflow) || isDocumentScroll;
}
function findScrollableAncestor(element, axis) {
    let current = element?.parentElement;
    while (current) {
        if (isScrollableElement(current, axis)) {
            return current;
        }
        current = current.parentElement;
    }
    return null;
}
function getScrollAmount(pointerPosition, scrollElement, axis) {
    const rect = scrollElement.getBoundingClientRect();
    const start = axis === "x" ? Math.max(0, rect.left) : Math.max(0, rect.top);
    const end = axis === "x" ? Math.min(window.innerWidth, rect.right) : Math.min(window.innerHeight, rect.bottom);
    const distanceFromStart = pointerPosition - start;
    const distanceFromEnd = end - pointerPosition;
    if (distanceFromStart < threshold) {
        const intensity = 1 - distanceFromStart / threshold;
        return { amount: -maxSpeed * intensity * intensity, edge: "start" };
    }
    else if (distanceFromEnd < threshold) {
        const intensity = 1 - distanceFromEnd / threshold;
        return { amount: maxSpeed * intensity * intensity, edge: "end" };
    }
    return { amount: 0, edge: null };
}
function autoScrollIfNeeded(groupElement, pointerPosition, axis, velocity) {
    if (!groupElement)
        return;
    // Track the group element for cleanup
    currentGroupElement = groupElement;
    const scrollableAncestor = findScrollableAncestor(groupElement, axis);
    if (!scrollableAncestor)
        return;
    // Convert pointer position from page coordinates to viewport coordinates.
    // The gesture system uses pageX/pageY but getBoundingClientRect() returns
    // viewport-relative coordinates, so we need to account for page scroll.
    const viewportPointerPosition = pointerPosition - (axis === "x" ? window.scrollX : window.scrollY);
    const { amount: scrollAmount, edge } = getScrollAmount(viewportPointerPosition, scrollableAncestor, axis);
    // If not in any threshold zone, clear all state
    if (edge === null) {
        activeScrollEdge.delete(scrollableAncestor);
        initialScrollLimits.delete(scrollableAncestor);
        return;
    }
    const currentActiveEdge = activeScrollEdge.get(scrollableAncestor);
    const isDocumentScroll = scrollableAncestor === document.body ||
        scrollableAncestor === document.documentElement;
    // If not currently scrolling this edge, check velocity to see if we should start
    if (currentActiveEdge !== edge) {
        // Only start scrolling if velocity is towards the edge
        const shouldStart = (edge === "start" && velocity < 0) ||
            (edge === "end" && velocity > 0);
        if (!shouldStart)
            return;
        // Activate this edge
        activeScrollEdge.set(scrollableAncestor, edge);
        // Record initial scroll limit (prevents infinite scroll)
        const maxScroll = axis === "x"
            ? scrollableAncestor.scrollWidth - (isDocumentScroll ? window.innerWidth : scrollableAncestor.clientWidth)
            : scrollableAncestor.scrollHeight - (isDocumentScroll ? window.innerHeight : scrollableAncestor.clientHeight);
        initialScrollLimits.set(scrollableAncestor, maxScroll);
    }
    // Cap scrolling at initial limit (prevents infinite scroll)
    if (scrollAmount > 0) {
        const initialLimit = initialScrollLimits.get(scrollableAncestor);
        const currentScroll = axis === "x"
            ? (isDocumentScroll ? window.scrollX : scrollableAncestor.scrollLeft)
            : (isDocumentScroll ? window.scrollY : scrollableAncestor.scrollTop);
        if (currentScroll >= initialLimit)
            return;
    }
    // Apply scroll
    if (axis === "x") {
        if (isDocumentScroll) {
            window.scrollBy({ left: scrollAmount });
        }
        else {
            scrollableAncestor.scrollLeft += scrollAmount;
        }
    }
    else {
        if (isDocumentScroll) {
            window.scrollBy({ top: scrollAmount });
        }
        else {
            scrollableAncestor.scrollTop += scrollAmount;
        }
    }
}

function useDefaultMotionValue(value, defaultValue = 0) {
    return motionDom.isMotionValue(value) ? value : useMotionValue(defaultValue);
}
function ReorderItemComponent({ children, style = {}, value, as = "li", onDrag, onDragEnd, layout = true, ...props }, externalRef) {
    const Component = index.useConstant(() => motion[as]);
    const context = React.useContext(ReorderContext);
    const point = {
        x: useDefaultMotionValue(style.x),
        y: useDefaultMotionValue(style.y),
    };
    const zIndex = useTransform([point.x, point.y], ([latestX, latestY]) => latestX || latestY ? 1 : "unset");
    motionUtils.invariant(Boolean(context), "Reorder.Item must be a child of Reorder.Group", "reorder-item-child");
    const { axis, registerItem, updateOrder, groupRef } = context;
    return (jsxRuntime.jsx(Component, { drag: axis, ...props, dragSnapToOrigin: true, style: { ...style, x: point.x, y: point.y, zIndex }, layout: layout, onDrag: (event, gesturePoint) => {
            const { velocity, point: pointerPoint } = gesturePoint;
            const offset = point[axis].get();
            // Always attempt to update order - checkReorder handles the logic
            updateOrder(value, offset, velocity[axis]);
            autoScrollIfNeeded(groupRef.current, pointerPoint[axis], axis, velocity[axis]);
            onDrag && onDrag(event, gesturePoint);
        }, onDragEnd: (event, gesturePoint) => {
            resetAutoScrollState();
            onDragEnd && onDragEnd(event, gesturePoint);
        }, onLayoutMeasure: (measured) => {
            registerItem(value, measured);
        }, ref: externalRef, ignoreStrict: true, children: children }));
}
const ReorderItem = /*@__PURE__*/ React.forwardRef(ReorderItemComponent);

var namespace = /*#__PURE__*/Object.freeze({
    __proto__: null,
    Group: ReorderGroup,
    Item: ReorderItem
});

function isDOMKeyframes(keyframes) {
    return typeof keyframes === "object" && !Array.isArray(keyframes);
}

function resolveSubjects(subject, keyframes, scope, selectorCache) {
    if (subject == null) {
        return [];
    }
    if (typeof subject === "string" && isDOMKeyframes(keyframes)) {
        return motionDom.resolveElements(subject, scope, selectorCache);
    }
    else if (subject instanceof NodeList) {
        return Array.from(subject);
    }
    else if (Array.isArray(subject)) {
        return subject.filter((s) => s != null);
    }
    else {
        return [subject];
    }
}

function calculateRepeatDuration(duration, repeat, repeatDelay) {
    return duration * (repeat + 1) + repeatDelay * repeat;
}

/**
 * Given a absolute or relative time definition and current/prev time state of the sequence,
 * calculate an absolute time for the next keyframes.
 */
function calcNextTime(current, next, prev, labels) {
    if (typeof next === "number") {
        return next;
    }
    else if (next.startsWith("-") || next.startsWith("+")) {
        return Math.max(0, current + parseFloat(next));
    }
    else if (next === "<") {
        return prev;
    }
    else if (next.startsWith("<")) {
        return Math.max(0, prev + parseFloat(next.slice(1)));
    }
    else {
        return labels.get(next) ?? current;
    }
}

function eraseKeyframes(sequence, startTime, endTime) {
    for (let i = 0; i < sequence.length; i++) {
        const keyframe = sequence[i];
        if (keyframe.at > startTime && keyframe.at < endTime) {
            motionUtils.removeItem(sequence, keyframe);
            // If we remove this item we have to push the pointer back one
            i--;
        }
    }
}
function addKeyframes(sequence, keyframes, easing, offset, startTime, endTime) {
    /**
     * Erase every existing value between currentTime and targetTime,
     * this will essentially splice this timeline into any currently
     * defined ones.
     */
    eraseKeyframes(sequence, startTime, endTime);
    for (let i = 0; i < keyframes.length; i++) {
        sequence.push({
            value: keyframes[i],
            at: motionDom.mixNumber(startTime, endTime, offset[i]),
            easing: motionUtils.getEasingForSegment(easing, i),
        });
    }
}

/**
 * Take an array of times that represent repeated keyframes. For instance
 * if we have original times of [0, 0.5, 1] then our repeated times will
 * be [0, 0.5, 1, 1, 1.5, 2]. Loop over the times and scale them back
 * down to a 0-1 scale.
 *
 * `repeatDelayUnits` is the repeatDelay expressed in units of a single
 * iteration's duration, so the total span equals `(repeat + 1) + repeat * repeatDelayUnits`.
 */
function normalizeTimes(times, repeat, repeatDelayUnits = 0) {
    const totalUnits = repeat + 1 + repeat * repeatDelayUnits;
    for (let i = 0; i < times.length; i++) {
        times[i] = times[i] / totalUnits;
    }
}

function compareByTime(a, b) {
    if (a.at === b.at) {
        if (a.value === null)
            return 1;
        if (b.value === null)
            return -1;
        return 0;
    }
    else {
        return a.at - b.at;
    }
}

const defaultSegmentEasing = "easeInOut";
const MAX_REPEAT = 20;
function createAnimationsFromSequence(sequence, { defaultTransition = {}, ...sequenceTransition } = {}, scope, generators) {
    const defaultDuration = defaultTransition.duration || 0.3;
    const animationDefinitions = new Map();
    const sequences = new Map();
    const elementCache = {};
    const timeLabels = new Map();
    let prevTime = 0;
    let currentTime = 0;
    let totalDuration = 0;
    /**
     * Build the timeline by mapping over the sequence array and converting
     * the definitions into keyframes and offsets with absolute time values.
     * These will later get converted into relative offsets in a second pass.
     */
    for (let i = 0; i < sequence.length; i++) {
        const segment = sequence[i];
        /**
         * If this is a timeline label, mark it and skip the rest of this iteration.
         */
        if (typeof segment === "string") {
            timeLabels.set(segment, currentTime);
            continue;
        }
        else if (!Array.isArray(segment)) {
            timeLabels.set(segment.name, calcNextTime(currentTime, segment.at, prevTime, timeLabels));
            continue;
        }
        let [subject, keyframes, transition = {}] = segment;
        /**
         * If a relative or absolute time value has been specified we need to resolve
         * it in relation to the currentTime.
         */
        if (transition.at !== undefined) {
            currentTime = calcNextTime(currentTime, transition.at, prevTime, timeLabels);
        }
        /**
         * Keep track of the maximum duration in this definition. This will be
         * applied to currentTime once the definition has been parsed.
         */
        let maxDuration = 0;
        const resolveValueSequence = (valueKeyframes, valueTransition, valueSequence, elementIndex = 0, numSubjects = 0) => {
            const valueKeyframesAsList = keyframesAsList(valueKeyframes);
            const { delay = 0, times = motionDom.defaultOffset(valueKeyframesAsList), type = defaultTransition.type || "keyframes", repeat, repeatType, repeatDelay = 0, ...remainingTransition } = valueTransition;
            let { ease = defaultTransition.ease || "easeOut", duration } = valueTransition;
            /**
             * Resolve stagger() if defined.
             */
            const calculatedDelay = typeof delay === "function"
                ? delay(elementIndex, numSubjects)
                : delay;
            /**
             * If this animation should and can use a spring, generate a spring easing function.
             */
            const numKeyframes = valueKeyframesAsList.length;
            const createGenerator = motionDom.isGenerator(type)
                ? type
                : generators?.[type || "keyframes"];
            if (numKeyframes <= 2 && createGenerator) {
                /**
                 * As we're creating an easing function from a spring,
                 * ideally we want to generate it using the real distance
                 * between the two keyframes. However this isn't always
                 * possible - in these situations we use 0-100.
                 */
                let absoluteDelta = 100;
                if (numKeyframes === 2 &&
                    isNumberKeyframesArray(valueKeyframesAsList)) {
                    const delta = valueKeyframesAsList[1] - valueKeyframesAsList[0];
                    absoluteDelta = Math.abs(delta);
                }
                const springTransition = {
                    ...defaultTransition,
                    ...remainingTransition,
                };
                if (duration !== undefined) {
                    springTransition.duration = motionUtils.secondsToMilliseconds(duration);
                }
                const springEasing = motionDom.createGeneratorEasing(springTransition, absoluteDelta, createGenerator);
                ease = springEasing.ease;
                duration = springEasing.duration;
            }
            duration ?? (duration = defaultDuration);
            const startTime = currentTime + calculatedDelay;
            /**
             * If there's only one time offset of 0, fill in a second with length 1
             */
            if (times.length === 1 && times[0] === 0) {
                times[1] = 1;
            }
            /**
             * Fill out if offset if fewer offsets than keyframes
             */
            const remainder = times.length - valueKeyframesAsList.length;
            remainder > 0 && motionDom.fillOffset(times, remainder);
            /**
             * If only one value has been set, ie [1], push a null to the start of
             * the keyframe array. This will let us mark a keyframe at this point
             * that will later be hydrated with the previous value.
             */
            valueKeyframesAsList.length === 1 &&
                valueKeyframesAsList.unshift(null);
            /**
             * Segments can't express `repeat: Infinity` or very large
             * counts — they'd leave dead time after the segment or
             * explode the keyframe array. Ignore with a warning.
             */
            if (repeat) {
                motionUtils.warning(repeat < MAX_REPEAT, `Sequence segments can't repeat ${repeat} times — ignoring repeat option. Use a value below ${MAX_REPEAT} or apply repeat at the sequence level instead.`);
            }
            if (repeat && repeat < MAX_REPEAT) {
                /**
                 * Express repeatDelay in units of a single iteration's duration
                 * so it can be added to the per-iteration time offsets below
                 * before they're normalized to 0-1.
                 */
                const repeatDelayUnits = duration > 0 ? repeatDelay / duration : 0;
                duration = calculateRepeatDuration(duration, repeat, repeatDelay);
                const originalKeyframes = [...valueKeyframesAsList];
                const originalTimes = [...times];
                ease = Array.isArray(ease) ? [...ease] : [ease];
                const originalEase = [...ease];
                /**
                 * For reverse/mirror, alternate iterations play the segment
                 * backwards. mirror matches JSAnimation's mirroredGenerator:
                 * reversed keyframes, easings unchanged. reverse matches
                 * JSAnimation's iterationProgress = 1 - p: reversed
                 * keyframes, easing array reversed AND each function easing
                 * mapped through reverseEasing (string easings unchanged —
                 * they're resolved later by the keyframes engine).
                 */
                const isFlipping = repeatType === "reverse" || repeatType === "mirror";
                let flippedKeyframes = originalKeyframes;
                let flippedEases = originalEase;
                if (isFlipping) {
                    flippedKeyframes = [...originalKeyframes].reverse();
                    if (repeatType === "reverse") {
                        flippedEases = [...originalEase]
                            .reverse()
                            .map((e) => typeof e === "function"
                            ? motionUtils.reverseEasing(e)
                            : e);
                    }
                }
                for (let repeatIndex = 0; repeatIndex < repeat; repeatIndex++) {
                    const isFlipped = isFlipping && repeatIndex % 2 === 0;
                    const iterKeyframes = isFlipped
                        ? flippedKeyframes
                        : originalKeyframes;
                    const iterEase = isFlipped ? flippedEases : originalEase;
                    const iterStartOffset = (repeatIndex + 1) * (1 + repeatDelayUnits);
                    /**
                     * If repeatDelay is set, hold the previous iteration's
                     * final value through the delay by inserting a keyframe
                     * at the moment the next iteration begins.
                     */
                    if (repeatDelayUnits > 0) {
                        valueKeyframesAsList.push(valueKeyframesAsList[valueKeyframesAsList.length - 1]);
                        times.push(iterStartOffset);
                        ease.push("linear");
                    }
                    valueKeyframesAsList.push(...iterKeyframes);
                    for (let keyframeIndex = 0; keyframeIndex < iterKeyframes.length; keyframeIndex++) {
                        times.push(originalTimes[keyframeIndex] + iterStartOffset);
                        ease.push(keyframeIndex === 0
                            ? "linear"
                            : motionUtils.getEasingForSegment(iterEase, keyframeIndex - 1));
                    }
                }
                normalizeTimes(times, repeat, repeatDelayUnits);
            }
            const targetTime = startTime + duration;
            /**
             * Add keyframes, mapping offsets to absolute time.
             */
            addKeyframes(valueSequence, valueKeyframesAsList, ease, times, startTime, targetTime);
            maxDuration = Math.max(calculatedDelay + duration, maxDuration);
            totalDuration = Math.max(targetTime, totalDuration);
        };
        if (motionDom.isMotionValue(subject)) {
            const subjectSequence = getSubjectSequence(subject, sequences);
            resolveValueSequence(keyframes, transition, getValueSequence("default", subjectSequence));
        }
        else {
            const subjects = resolveSubjects(subject, keyframes, scope, elementCache);
            const numSubjects = subjects.length;
            /**
             * For every element in this segment, process the defined values.
             */
            for (let subjectIndex = 0; subjectIndex < numSubjects; subjectIndex++) {
                /**
                 * Cast necessary, but we know these are of this type
                 */
                keyframes = keyframes;
                transition = transition;
                const thisSubject = subjects[subjectIndex];
                const subjectSequence = getSubjectSequence(thisSubject, sequences);
                for (const key in keyframes) {
                    resolveValueSequence(keyframes[key], getValueTransition(transition, key), getValueSequence(key, subjectSequence), subjectIndex, numSubjects);
                }
            }
        }
        prevTime = currentTime;
        currentTime += maxDuration;
    }
    /**
     * For every element and value combination create a new animation.
     */
    sequences.forEach((valueSequences, element) => {
        for (const key in valueSequences) {
            const valueSequence = valueSequences[key];
            /**
             * Arrange all the keyframes in ascending time order.
             */
            valueSequence.sort(compareByTime);
            const keyframes = [];
            const valueOffset = [];
            const valueEasing = [];
            /**
             * For each keyframe, translate absolute times into
             * relative offsets based on the total duration of the timeline.
             */
            for (let i = 0; i < valueSequence.length; i++) {
                const { at, value, easing } = valueSequence[i];
                keyframes.push(value);
                valueOffset.push(motionUtils.progress(0, totalDuration, at));
                valueEasing.push(easing || "easeOut");
            }
            /**
             * If the first keyframe doesn't land on offset: 0
             * provide one by duplicating the initial keyframe. This ensures
             * it snaps to the first keyframe when the animation starts.
             */
            if (valueOffset[0] !== 0) {
                valueOffset.unshift(0);
                keyframes.unshift(keyframes[0]);
                valueEasing.unshift(defaultSegmentEasing);
            }
            /**
             * If the last keyframe doesn't land on offset: 1
             * provide one with a null wildcard value. This will ensure it
             * stays static until the end of the animation.
             */
            if (valueOffset[valueOffset.length - 1] !== 1) {
                valueOffset.push(1);
                keyframes.push(null);
            }
            if (!animationDefinitions.has(element)) {
                animationDefinitions.set(element, {
                    keyframes: {},
                    transition: {},
                });
            }
            const definition = animationDefinitions.get(element);
            definition.keyframes[key] = keyframes;
            /**
             * Exclude `type` from defaultTransition since springs have been
             * converted to duration-based easing functions in resolveValueSequence.
             * Including `type: "spring"` would cause JSAnimation to error when
             * the merged keyframes array has more than 2 keyframes.
             */
            const { type: _type, ...remainingDefaultTransition } = defaultTransition;
            definition.transition[key] = {
                ...remainingDefaultTransition,
                duration: totalDuration,
                ease: valueEasing,
                times: valueOffset,
                ...sequenceTransition,
            };
        }
    });
    return animationDefinitions;
}
function getSubjectSequence(subject, sequences) {
    !sequences.has(subject) && sequences.set(subject, {});
    return sequences.get(subject);
}
function getValueSequence(name, sequences) {
    if (!sequences[name])
        sequences[name] = [];
    return sequences[name];
}
function keyframesAsList(keyframes) {
    return Array.isArray(keyframes) ? keyframes : [keyframes];
}
function getValueTransition(transition, key) {
    return transition && transition[key]
        ? {
            ...transition,
            ...transition[key],
        }
        : { ...transition };
}
const isNumber = (keyframe) => typeof keyframe === "number";
const isNumberKeyframesArray = (keyframes) => keyframes.every(isNumber);

function createDOMVisualElement(element) {
    const options = {
        presenceContext: null,
        props: {},
        visualState: {
            renderState: {
                transform: {},
                transformOrigin: {},
                style: {},
                vars: {},
                attrs: {},
            },
            latestValues: {},
        },
    };
    const node = motionDom.isSVGElement(element) && !motionDom.isSVGSVGElement(element)
        ? new motionDom.SVGVisualElement(options)
        : new motionDom.HTMLVisualElement(options);
    node.mount(element);
    motionDom.visualElementStore.set(element, node);
}
function createObjectVisualElement(subject) {
    const options = {
        presenceContext: null,
        props: {},
        visualState: {
            renderState: {
                output: {},
            },
            latestValues: {},
        },
    };
    const node = new motionDom.ObjectVisualElement(options);
    node.mount(subject);
    motionDom.visualElementStore.set(subject, node);
}

function isSingleValue(subject, keyframes) {
    return (motionDom.isMotionValue(subject) ||
        typeof subject === "number" ||
        (typeof subject === "string" && !isDOMKeyframes(keyframes)));
}
/**
 * Implementation
 */
function animateSubject(subject, keyframes, options, scope) {
    const animations = [];
    if (isSingleValue(subject, keyframes)) {
        animations.push(motionDom.animateSingleValue(subject, isDOMKeyframes(keyframes)
            ? keyframes.default || keyframes
            : keyframes, options ? options.default || options : options));
    }
    else {
        // Gracefully handle null/undefined subjects (e.g., from querySelector returning null)
        if (subject == null) {
            return animations;
        }
        const subjects = resolveSubjects(subject, keyframes, scope);
        const numSubjects = subjects.length;
        motionUtils.invariant(Boolean(numSubjects), "No valid elements provided.", "no-valid-elements");
        for (let i = 0; i < numSubjects; i++) {
            const thisSubject = subjects[i];
            const createVisualElement = thisSubject instanceof Element
                ? createDOMVisualElement
                : createObjectVisualElement;
            if (!motionDom.visualElementStore.has(thisSubject)) {
                createVisualElement(thisSubject);
            }
            const visualElement = motionDom.visualElementStore.get(thisSubject);
            const transition = { ...options };
            /**
             * Resolve stagger function if provided.
             */
            if ("delay" in transition &&
                typeof transition.delay === "function") {
                transition.delay = transition.delay(i, numSubjects);
            }
            animations.push(...motionDom.animateTarget(visualElement, { ...keyframes, transition }, {}));
        }
    }
    return animations;
}

function animateSequence(sequence, options, scope) {
    const animations = [];
    /**
     * Pre-process: replace function segments with MotionValue segments,
     * subscribe callbacks immediately
     */
    const processedSequence = sequence.map((segment) => {
        if (Array.isArray(segment) && typeof segment[0] === "function") {
            const callback = segment[0];
            const mv = motionDom.motionValue(0);
            mv.on("change", callback);
            if (segment.length === 1) {
                return [mv, [0, 1]];
            }
            else if (segment.length === 2) {
                return [mv, [0, 1], segment[1]];
            }
            else {
                return [mv, segment[1], segment[2]];
            }
        }
        return segment;
    });
    const animationDefinitions = createAnimationsFromSequence(processedSequence, options, scope, { spring: motionDom.spring });
    animationDefinitions.forEach(({ keyframes, transition }, subject) => {
        animations.push(...animateSubject(subject, keyframes, transition));
    });
    return animations;
}

function isSequence(value) {
    return Array.isArray(value) && value.some(Array.isArray);
}
/**
 * Creates an animation function that is optionally scoped
 * to a specific element.
 */
function createScopedAnimate(options = {}) {
    const { scope, reduceMotion, skipAnimations } = options;
    /**
     * Implementation
     */
    function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options) {
        let animations = [];
        let animationOnComplete;
        const inherited = {};
        if (reduceMotion !== undefined)
            inherited.reduceMotion = reduceMotion;
        if (skipAnimations !== undefined)
            inherited.skipAnimations = skipAnimations;
        if (isSequence(subjectOrSequence)) {
            const { onComplete, ...sequenceOptions } = optionsOrKeyframes || {};
            if (typeof onComplete === "function") {
                animationOnComplete = onComplete;
            }
            animations = animateSequence(subjectOrSequence, { ...inherited, ...sequenceOptions }, scope);
        }
        else {
            // Extract top-level onComplete so it doesn't get applied per-value
            const { onComplete, ...rest } = options || {};
            if (typeof onComplete === "function") {
                animationOnComplete = onComplete;
            }
            animations = animateSubject(subjectOrSequence, optionsOrKeyframes, { ...inherited, ...rest }, scope);
        }
        const animation = new motionDom.GroupAnimationWithThen(animations);
        if (animationOnComplete) {
            animation.finished.then(animationOnComplete);
        }
        if (scope) {
            scope.animations.push(animation);
            animation.finished.then(() => {
                motionUtils.removeItem(scope.animations, animation);
            });
        }
        return animation;
    }
    return scopedAnimate;
}
const animate = createScopedAnimate();

function animateElements(elementOrSelector, keyframes, options, scope) {
    // Gracefully handle null/undefined elements (e.g., from querySelector returning null)
    if (elementOrSelector == null) {
        return [];
    }
    const elements = motionDom.resolveElements(elementOrSelector, scope);
    const numElements = elements.length;
    motionUtils.invariant(Boolean(numElements), "No valid elements provided.", "no-valid-elements");
    /**
     * WAAPI doesn't support interrupting animations.
     *
     * Therefore, starting animations requires a three-step process:
     * 1. Stop existing animations (write styles to DOM)
     * 2. Resolve keyframes (read styles from DOM)
     * 3. Create new animations (write styles to DOM)
     *
     * The hybrid `animate()` function uses AsyncAnimation to resolve
     * keyframes before creating new animations, which removes style
     * thrashing. Here, we have much stricter filesize constraints.
     * Therefore we do this in a synchronous way that ensures that
     * at least within `animate()` calls there is no style thrashing.
     *
     * In the motion-native-animate-mini-interrupt benchmark this
     * was 80% faster than a single loop.
     */
    const animationDefinitions = [];
    /**
     * Step 1: Build options and stop existing animations (write)
     */
    for (let i = 0; i < numElements; i++) {
        const element = elements[i];
        const elementTransition = { ...options };
        /**
         * Resolve stagger function if provided.
         */
        if (typeof elementTransition.delay === "function") {
            elementTransition.delay = elementTransition.delay(i, numElements);
        }
        for (const valueName in keyframes) {
            let valueKeyframes = keyframes[valueName];
            if (!Array.isArray(valueKeyframes)) {
                valueKeyframes = [valueKeyframes];
            }
            const valueOptions = {
                ...motionDom.getValueTransition(elementTransition, valueName),
            };
            valueOptions.duration && (valueOptions.duration = motionUtils.secondsToMilliseconds(valueOptions.duration));
            valueOptions.delay && (valueOptions.delay = motionUtils.secondsToMilliseconds(valueOptions.delay));
            /**
             * If there's an existing animation playing on this element then stop it
             * before creating a new one.
             */
            const map = motionDom.getAnimationMap(element);
            const key = motionDom.animationMapKey(valueName, valueOptions.pseudoElement || "");
            const currentAnimation = map.get(key);
            currentAnimation && currentAnimation.stop();
            animationDefinitions.push({
                map,
                key,
                unresolvedKeyframes: valueKeyframes,
                options: {
                    ...valueOptions,
                    element,
                    name: valueName,
                    allowFlatten: !elementTransition.type && !elementTransition.ease,
                },
            });
        }
    }
    /**
     * Step 2: Resolve keyframes (read)
     */
    for (let i = 0; i < animationDefinitions.length; i++) {
        const { unresolvedKeyframes, options: animationOptions } = animationDefinitions[i];
        const { element, name, pseudoElement } = animationOptions;
        if (!pseudoElement && unresolvedKeyframes[0] === null) {
            unresolvedKeyframes[0] = motionDom.getComputedStyle(element, name);
        }
        motionDom.fillWildcards(unresolvedKeyframes);
        motionDom.applyPxDefaults(unresolvedKeyframes, name);
        /**
         * If we only have one keyframe, explicitly read the initial keyframe
         * from the computed style. This is to ensure consistency with WAAPI behaviour
         * for restarting animations, for instance .play() after finish, when it
         * has one vs two keyframes.
         */
        if (!pseudoElement && unresolvedKeyframes.length < 2) {
            unresolvedKeyframes.unshift(motionDom.getComputedStyle(element, name));
        }
        animationOptions.keyframes = unresolvedKeyframes;
    }
    /**
     * Step 3: Create new animations (write)
     */
    const animations = [];
    for (let i = 0; i < animationDefinitions.length; i++) {
        const { map, key, options: animationOptions } = animationDefinitions[i];
        const animation = new motionDom.NativeAnimation(animationOptions);
        map.set(key, animation);
        animation.finished.finally(() => map.delete(key));
        animations.push(animation);
    }
    return animations;
}

const createScopedWaapiAnimate = (scope) => {
    function scopedAnimate(elementOrSelector, keyframes, options) {
        return new motionDom.GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
    }
    return scopedAnimate;
};
const animateMini = /*@__PURE__*/ createScopedWaapiAnimate();

function canUseNativeTimeline(target) {
    if (typeof window === "undefined")
        return false;
    return target ? motionDom.supportsViewTimeline() : motionDom.supportsScrollTimeline();
}

/**
 * A time in milliseconds, beyond which we consider the scroll velocity to be 0.
 */
const maxElapsed = 50;
const createAxisInfo = () => ({
    current: 0,
    offset: [],
    progress: 0,
    scrollLength: 0,
    targetOffset: 0,
    targetLength: 0,
    containerLength: 0,
    velocity: 0,
});
const createScrollInfo = () => ({
    time: 0,
    x: createAxisInfo(),
    y: createAxisInfo(),
});
const keys = {
    x: {
        length: "Width",
        position: "Left",
    },
    y: {
        length: "Height",
        position: "Top",
    },
};
function updateAxisInfo(element, axisName, info, time) {
    const axis = info[axisName];
    const { length, position } = keys[axisName];
    const prev = axis.current;
    const prevTime = info.time;
    axis.current = Math.abs(element[`scroll${position}`]);
    axis.scrollLength = element[`scroll${length}`] - element[`client${length}`];
    axis.offset.length = 0;
    axis.offset[0] = 0;
    axis.offset[1] = axis.scrollLength;
    axis.progress = motionUtils.progress(0, axis.scrollLength, axis.current);
    const elapsed = time - prevTime;
    axis.velocity =
        elapsed > maxElapsed
            ? 0
            : motionUtils.velocityPerSecond(axis.current - prev, elapsed);
}
function updateScrollInfo(element, info, time) {
    updateAxisInfo(element, "x", info, time);
    updateAxisInfo(element, "y", info, time);
    info.time = time;
}

function calcInset(element, container) {
    const inset = { x: 0, y: 0 };
    let current = element;
    while (current && current !== container) {
        if (motionDom.isHTMLElement(current)) {
            inset.x += current.offsetLeft;
            inset.y += current.offsetTop;
            current = current.offsetParent;
        }
        else if (current.tagName === "svg") {
            /**
             * This isn't an ideal approach to measuring the offset of <svg /> tags.
             * It would be preferable, given they behave like HTMLElements in most ways
             * to use offsetLeft/Top. But these don't exist on <svg />. Likewise we
             * can't use .getBBox() like most SVG elements as these provide the offset
             * relative to the SVG itself, which for <svg /> is usually 0x0.
             */
            const svgBoundingBox = current.getBoundingClientRect();
            current = current.parentElement;
            const parentBoundingBox = current.getBoundingClientRect();
            inset.x += svgBoundingBox.left - parentBoundingBox.left;
            inset.y += svgBoundingBox.top - parentBoundingBox.top;
        }
        else if (current instanceof SVGGraphicsElement) {
            const { x, y } = current.getBBox();
            inset.x += x;
            inset.y += y;
            let svg = null;
            let parent = current.parentNode;
            while (!svg) {
                if (parent.tagName === "svg") {
                    svg = parent;
                }
                parent = current.parentNode;
            }
            current = svg;
        }
        else {
            break;
        }
    }
    return inset;
}

const namedEdges = {
    start: 0,
    center: 0.5,
    end: 1,
};
function resolveEdge(edge, length, inset = 0) {
    let delta = 0;
    /**
     * If we have this edge defined as a preset, replace the definition
     * with the numerical value.
     */
    if (edge in namedEdges) {
        edge = namedEdges[edge];
    }
    /**
     * Handle unit values
     */
    if (typeof edge === "string") {
        const asNumber = parseFloat(edge);
        if (edge.endsWith("px")) {
            delta = asNumber;
        }
        else if (edge.endsWith("%")) {
            edge = asNumber / 100;
        }
        else if (edge.endsWith("vw")) {
            delta = (asNumber / 100) * document.documentElement.clientWidth;
        }
        else if (edge.endsWith("vh")) {
            delta = (asNumber / 100) * document.documentElement.clientHeight;
        }
        else {
            edge = asNumber;
        }
    }
    /**
     * If the edge is defined as a number, handle as a progress value.
     */
    if (typeof edge === "number") {
        delta = length * edge;
    }
    return inset + delta;
}

const defaultOffset = [0, 0];
function resolveOffset(offset, containerLength, targetLength, targetInset) {
    let offsetDefinition = Array.isArray(offset) ? offset : defaultOffset;
    let targetPoint = 0;
    let containerPoint = 0;
    if (typeof offset === "number") {
        /**
         * If we're provided offset: [0, 0.5, 1] then each number x should become
         * [x, x], so we default to the behaviour of mapping 0 => 0 of both target
         * and container etc.
         */
        offsetDefinition = [offset, offset];
    }
    else if (typeof offset === "string") {
        offset = offset.trim();
        if (offset.includes(" ")) {
            offsetDefinition = offset.split(" ");
        }
        else {
            /**
             * If we're provided a definition like "100px" then we want to apply
             * that only to the top of the target point, leaving the container at 0.
             * Whereas a named offset like "end" should be applied to both.
             */
            offsetDefinition = [offset, namedEdges[offset] ? offset : `0`];
        }
    }
    targetPoint = resolveEdge(offsetDefinition[0], targetLength, targetInset);
    containerPoint = resolveEdge(offsetDefinition[1], containerLength);
    return targetPoint - containerPoint;
}

const ScrollOffset = {
    Enter: [
        [0, 1],
        [1, 1],
    ],
    Exit: [
        [0, 0],
        [1, 0],
    ],
    Any: [
        [1, 0],
        [0, 1],
    ],
    All: [
        [0, 0],
        [1, 1],
    ],
};

const point = { x: 0, y: 0 };
function getTargetSize(target) {
    return "getBBox" in target && target.tagName !== "svg"
        ? target.getBBox()
        : { width: target.clientWidth, height: target.clientHeight };
}
function resolveOffsets(container, info, options) {
    const { offset: offsetDefinition = ScrollOffset.All } = options;
    const { target = container, axis = "y" } = options;
    const lengthLabel = axis === "y" ? "height" : "width";
    const inset = target !== container ? calcInset(target, container) : point;
    /**
     * Measure the target and container. If they're the same thing then we
     * use the container's scrollWidth/Height as the target, from there
     * all other calculations can remain the same.
     */
    const targetSize = target === container
        ? { width: container.scrollWidth, height: container.scrollHeight }
        : getTargetSize(target);
    const containerSize = {
        width: container.clientWidth,
        height: container.clientHeight,
    };
    /**
     * Reset the length of the resolved offset array rather than creating a new one.
     * TODO: More reusable data structures for targetSize/containerSize would also be good.
     */
    info[axis].offset.length = 0;
    /**
     * Populate the offset array by resolving the user's offset definition into
     * a list of pixel scroll offets.
     */
    let hasChanged = !info[axis].interpolate;
    const numOffsets = offsetDefinition.length;
    for (let i = 0; i < numOffsets; i++) {
        const offset = resolveOffset(offsetDefinition[i], containerSize[lengthLabel], targetSize[lengthLabel], inset[axis]);
        if (!hasChanged && offset !== info[axis].interpolatorOffsets[i]) {
            hasChanged = true;
        }
        info[axis].offset[i] = offset;
    }
    /**
     * If the pixel scroll offsets have changed, create a new interpolator function
     * to map scroll value into a progress.
     */
    if (hasChanged) {
        info[axis].interpolate = motionDom.interpolate(info[axis].offset, motionDom.defaultOffset(offsetDefinition), { clamp: false });
        info[axis].interpolatorOffsets = [...info[axis].offset];
    }
    info[axis].progress = motionUtils.clamp(0, 1, info[axis].interpolate(info[axis].current));
}

function measure(container, target = container, info) {
    /**
     * Find inset of target within scrollable container
     */
    info.x.targetOffset = 0;
    info.y.targetOffset = 0;
    if (target !== container) {
        let node = target;
        while (node && node !== container) {
            info.x.targetOffset += node.offsetLeft;
            info.y.targetOffset += node.offsetTop;
            node = node.offsetParent;
        }
    }
    info.x.targetLength =
        target === container ? target.scrollWidth : target.clientWidth;
    info.y.targetLength =
        target === container ? target.scrollHeight : target.clientHeight;
    info.x.containerLength = container.clientWidth;
    info.y.containerLength = container.clientHeight;
    /**
     * In development mode ensure scroll containers aren't position: static as this makes
     * it difficult to measure their relative positions. The document scrolling element
     * is exempt: offsetParent measurements naturally resolve relative to the document.
     */
    if (process.env.NODE_ENV !== "production") {
        if (container &&
            target &&
            target !== container &&
            container !== document.documentElement &&
            container !== document.scrollingElement &&
            container !== document.body) {
            motionUtils.warnOnce(getComputedStyle(container).position !== "static", "Please ensure that the container has a non-static position, like 'relative', 'fixed', or 'absolute' to ensure scroll offset is calculated correctly.");
        }
    }
}
function createOnScrollHandler(element, onScroll, info, options = {}) {
    return {
        measure: (time) => {
            measure(element, options.target, info);
            updateScrollInfo(element, info, time);
            if (options.offset || options.target) {
                resolveOffsets(element, info, options);
            }
        },
        notify: () => onScroll(info),
    };
}

const scrollListeners = new WeakMap();
const resizeListeners = new WeakMap();
const onScrollHandlers = new WeakMap();
const scrollSize = new WeakMap();
const dimensionCheckProcesses = new WeakMap();
const getEventTarget = (element) => element === document.scrollingElement ? window : element;
function scrollInfo(onScroll, { container = document.scrollingElement, trackContentSize = false, ...options } = {}) {
    if (!container)
        return motionUtils.noop;
    let containerHandlers = onScrollHandlers.get(container);
    /**
     * Get the onScroll handlers for this container.
     * If one isn't found, create a new one.
     */
    if (!containerHandlers) {
        containerHandlers = new Set();
        onScrollHandlers.set(container, containerHandlers);
    }
    /**
     * Create a new onScroll handler for the provided callback.
     */
    const info = createScrollInfo();
    const containerHandler = createOnScrollHandler(container, onScroll, info, options);
    containerHandlers.add(containerHandler);
    /**
     * Check if there's a scroll event listener for this container.
     * If not, create one.
     */
    if (!scrollListeners.has(container)) {
        const measureAll = () => {
            for (const handler of containerHandlers) {
                handler.measure(motionDom.frameData.timestamp);
            }
            motionDom.frame.preUpdate(notifyAll);
        };
        const notifyAll = () => {
            for (const handler of containerHandlers) {
                handler.notify();
            }
        };
        const listener = () => motionDom.frame.read(measureAll);
        scrollListeners.set(container, listener);
        const target = getEventTarget(container);
        window.addEventListener("resize", listener);
        if (container !== document.documentElement) {
            resizeListeners.set(container, motionDom.resize(container, listener));
        }
        target.addEventListener("scroll", listener);
        listener();
    }
    /**
     * Enable content size tracking if requested and not already enabled.
     */
    if (trackContentSize && !dimensionCheckProcesses.has(container)) {
        const listener = scrollListeners.get(container);
        // Store initial scroll dimensions (object is reused to avoid allocation)
        const size = {
            width: container.scrollWidth,
            height: container.scrollHeight,
        };
        scrollSize.set(container, size);
        // Add frame-based scroll dimension checking to detect content changes
        const checkScrollDimensions = () => {
            const newWidth = container.scrollWidth;
            const newHeight = container.scrollHeight;
            if (size.width !== newWidth || size.height !== newHeight) {
                listener();
                size.width = newWidth;
                size.height = newHeight;
            }
        };
        // Schedule with keepAlive=true to run every frame
        const dimensionCheckProcess = motionDom.frame.read(checkScrollDimensions, true);
        dimensionCheckProcesses.set(container, dimensionCheckProcess);
    }
    const listener = scrollListeners.get(container);
    motionDom.frame.read(listener, false, true);
    return () => {
        motionDom.cancelFrame(listener);
        /**
         * Check if we even have any handlers for this container.
         */
        const currentHandlers = onScrollHandlers.get(container);
        if (!currentHandlers)
            return;
        currentHandlers.delete(containerHandler);
        if (currentHandlers.size)
            return;
        /**
         * If no more handlers, remove the scroll listener too.
         */
        const scrollListener = scrollListeners.get(container);
        scrollListeners.delete(container);
        if (scrollListener) {
            getEventTarget(container).removeEventListener("scroll", scrollListener);
            resizeListeners.get(container)?.();
            window.removeEventListener("resize", scrollListener);
        }
        // Clean up scroll dimension checking
        const dimensionCheckProcess = dimensionCheckProcesses.get(container);
        if (dimensionCheckProcess) {
            motionDom.cancelFrame(dimensionCheckProcess);
            dimensionCheckProcesses.delete(container);
        }
        scrollSize.delete(container);
    };
}

/**
 * Maps from ProgressIntersection pairs used by Motion's preset offsets to
 * ViewTimeline named ranges. Returns undefined for unrecognised patterns,
 * which signals the caller to fall back to JS-based scroll tracking.
 */
const presets = [
    [ScrollOffset.Enter, "entry"],
    [ScrollOffset.Exit, "exit"],
    [ScrollOffset.Any, "cover"],
    [ScrollOffset.All, "contain"],
];
const stringToProgress = {
    start: 0,
    end: 1,
};
function parseStringOffset(s) {
    const parts = s.trim().split(/\s+/);
    if (parts.length !== 2)
        return undefined;
    const a = stringToProgress[parts[0]];
    const b = stringToProgress[parts[1]];
    if (a === undefined || b === undefined)
        return undefined;
    return [a, b];
}
function normaliseOffset(offset) {
    if (offset.length !== 2)
        return undefined;
    const result = [];
    for (const item of offset) {
        if (Array.isArray(item)) {
            result.push(item);
        }
        else if (typeof item === "string") {
            const parsed = parseStringOffset(item);
            if (!parsed)
                return undefined;
            result.push(parsed);
        }
        else {
            return undefined;
        }
    }
    return result;
}
function matchesPreset(offset, preset) {
    const normalised = normaliseOffset(offset);
    if (!normalised)
        return false;
    for (let i = 0; i < 2; i++) {
        const o = normalised[i];
        const p = preset[i];
        if (o[0] !== p[0] || o[1] !== p[1])
            return false;
    }
    return true;
}
function offsetToViewTimelineRange(offset) {
    if (!offset) {
        return { rangeStart: "contain 0%", rangeEnd: "contain 100%" };
    }
    for (const [preset, name] of presets) {
        if (matchesPreset(offset, preset)) {
            return { rangeStart: `${name} 0%`, rangeEnd: `${name} 100%` };
        }
    }
    return undefined;
}

const timelineCache = new Map();
function scrollTimelineFallback(options) {
    const currentTime = { value: 0 };
    const cancel = scrollInfo((info) => {
        currentTime.value = info[options.axis].progress * 100;
    }, options);
    return { currentTime, cancel };
}
function getTimeline({ source, container, ...options }) {
    const { axis } = options;
    if (source)
        container = source;
    let containerCache = timelineCache.get(container);
    if (!containerCache) {
        containerCache = new Map();
        timelineCache.set(container, containerCache);
    }
    const targetKey = options.target ?? "self";
    let targetCache = containerCache.get(targetKey);
    if (!targetCache) {
        targetCache = {};
        containerCache.set(targetKey, targetCache);
    }
    const axisKey = axis + (options.offset ?? []).join(",");
    if (!targetCache[axisKey]) {
        if (options.target && canUseNativeTimeline(options.target)) {
            const range = offsetToViewTimelineRange(options.offset);
            if (range) {
                targetCache[axisKey] = new ViewTimeline({
                    subject: options.target,
                    axis,
                });
            }
            else {
                targetCache[axisKey] = scrollTimelineFallback({
                    container,
                    ...options,
                });
            }
        }
        else if (canUseNativeTimeline()) {
            targetCache[axisKey] = new ScrollTimeline({
                source: container,
                axis,
            });
        }
        else {
            targetCache[axisKey] = scrollTimelineFallback({
                container,
                ...options,
            });
        }
    }
    return targetCache[axisKey];
}

function attachToAnimation(animation, options) {
    const timeline = getTimeline(options);
    const range = options.target
        ? offsetToViewTimelineRange(options.offset)
        : undefined;
    /**
     * Use native timeline when:
     * - No target: ScrollTimeline (existing behaviour)
     * - Target with mappable offset: ViewTimeline with named range
     * - Target with unmappable offset: fall back to JS observe
     */
    const useNative = options.target
        ? canUseNativeTimeline(options.target) && !!range
        : canUseNativeTimeline();
    return animation.attachTimeline({
        timeline: useNative ? timeline : undefined,
        ...(range &&
            useNative && {
            rangeStart: range.rangeStart,
            rangeEnd: range.rangeEnd,
        }),
        observe: (valueAnimation) => {
            valueAnimation.pause();
            return motionDom.observeTimeline((progress) => {
                valueAnimation.time =
                    valueAnimation.iterationDuration * progress;
            }, timeline);
        },
    });
}

/**
 * Currently, we only support element tracking with `scrollInfo`, though in
 * the future we can also offer ViewTimeline support.
 */
function isElementTracking(options) {
    return options && (options.target || options.offset);
}

/**
 * If the onScroll function has two arguments, it's expecting
 * more specific information about the scroll from scrollInfo.
 */
function isOnScrollWithInfo(onScroll) {
    return onScroll.length === 2;
}
function attachToFunction(onScroll, options) {
    if (isOnScrollWithInfo(onScroll) || isElementTracking(options)) {
        return scrollInfo((info) => {
            onScroll(info[options.axis].progress, info);
        }, options);
    }
    else {
        return motionDom.observeTimeline(onScroll, getTimeline(options));
    }
}

function scroll(onScroll, { axis = "y", container = document.scrollingElement, ...options } = {}) {
    if (!container)
        return motionUtils.noop;
    const optionsWithDefaults = { axis, container, ...options };
    return typeof onScroll === "function"
        ? attachToFunction(onScroll, optionsWithDefaults)
        : attachToAnimation(onScroll, optionsWithDefaults);
}

const thresholds = {
    some: 0,
    all: 1,
};
function inView(elementOrSelector, onStart, { root, margin: rootMargin, amount = "some" } = {}) {
    const elements = motionDom.resolveElements(elementOrSelector);
    const activeIntersections = new WeakMap();
    const onIntersectionChange = (entries) => {
        entries.forEach((entry) => {
            const onEnd = activeIntersections.get(entry.target);
            /**
             * If there's no change to the intersection, we don't need to
             * do anything here.
             */
            if (entry.isIntersecting === Boolean(onEnd))
                return;
            if (entry.isIntersecting) {
                const newOnEnd = onStart(entry.target, entry);
                if (typeof newOnEnd === "function") {
                    activeIntersections.set(entry.target, newOnEnd);
                }
                else {
                    observer.unobserve(entry.target);
                }
            }
            else if (typeof onEnd === "function") {
                onEnd(entry);
                activeIntersections.delete(entry.target);
            }
        });
    };
    const observer = new IntersectionObserver(onIntersectionChange, {
        root,
        rootMargin,
        threshold: typeof amount === "number" ? amount : thresholds[amount],
    });
    elements.forEach((element) => observer.observe(element));
    return () => observer.disconnect();
}

const m = /*@__PURE__*/ createMotionProxy();

function useUnmountEffect(callback) {
    return React.useEffect(() => () => callback(), []);
}

/**
 * @public
 */
const domAnimation = {
    renderer: featureBundle.createDomVisualElement,
    ...featureBundle.animations,
    ...featureBundle.gestureAnimations,
};

/**
 * @public
 */
const domMax = {
    ...domAnimation,
    ...featureBundle.drag,
    ...featureBundle.layout,
};

/**
 * @public
 */
const domMin = {
    renderer: featureBundle.createDomVisualElement,
    ...featureBundle.animations,
};

function useMotionValueEvent(value, event, callback) {
    /**
     * useInsertionEffect will create subscriptions before any other
     * effects will run. Effects run upwards through the tree so it
     * can be that binding a useLayoutEffect higher up the tree can
     * miss changes from lower down the tree.
     */
    React.useInsertionEffect(() => value.on(event, callback), [value, event, callback]);
}

const createScrollMotionValues = () => ({
    scrollX: motionDom.motionValue(0),
    scrollY: motionDom.motionValue(0),
    scrollXProgress: motionDom.motionValue(0),
    scrollYProgress: motionDom.motionValue(0),
});
const isRefPending = (ref) => {
    if (!ref)
        return false;
    return !ref.current;
};
function makeAccelerateConfig(axis, options, container, target) {
    return {
        // Refs attach child-first; defer so target.current is populated
        // before scroll() reads it.
        factory: (animation) => {
            let cleanup;
            const start = () => {
                // A provided ref may be hydrated by an effect declared after
                // useScroll (or in a parent). Don't attach to the window
                // scroll in the meantime — that result gets cached and would
                // permanently mistrack. Wait until the ref resolves.
                if (isRefPending(container) || isRefPending(target)) {
                    motionDom.microtask.read(start);
                    return;
                }
                cleanup = scroll(animation, {
                    ...options,
                    axis,
                    container: container?.current || undefined,
                    target: target?.current || undefined,
                });
            };
            motionDom.microtask.read(start);
            return () => {
                motionDom.cancelMicrotask(start);
                cleanup?.();
            };
        },
        times: [0, 1],
        keyframes: [0, 1],
        ease: (v) => v,
        duration: 1,
    };
}
function canAccelerateScroll(target, offset) {
    if (typeof window === "undefined")
        return false;
    return target
        ? motionDom.supportsViewTimeline() && !!offsetToViewTimelineRange(offset)
        : motionDom.supportsScrollTimeline();
}
function useScroll({ container, target, ...options } = {}) {
    const values = index.useConstant(createScrollMotionValues);
    if (canAccelerateScroll(target, options.offset)) {
        values.scrollXProgress.accelerate = makeAccelerateConfig("x", options, container, target);
        values.scrollYProgress.accelerate = makeAccelerateConfig("y", options, container, target);
    }
    const scrollAnimation = React.useRef(null);
    const needsStart = React.useRef(false);
    const start = React.useCallback(() => {
        scrollAnimation.current = scroll((_progress, { x, y, }) => {
            values.scrollX.set(x.current);
            values.scrollXProgress.set(x.progress);
            values.scrollY.set(y.current);
            values.scrollYProgress.set(y.progress);
        }, {
            ...options,
            container: container?.current || undefined,
            target: target?.current || undefined,
        });
        return () => {
            scrollAnimation.current?.();
        };
    }, [container, target, JSON.stringify(options.offset)]);
    index.useIsomorphicLayoutEffect(() => {
        needsStart.current = false;
        if (isRefPending(container) || isRefPending(target)) {
            needsStart.current = true;
            return;
        }
        else {
            return start();
        }
    }, [start]);
    React.useEffect(() => {
        if (!needsStart.current)
            return;
        // Defer to a microtask so any sibling/parent effect that hydrates the
        // ref has a chance to run first.
        let cleanup;
        const tryStart = () => {
            const containerPending = isRefPending(container);
            const targetPending = isRefPending(target);
            motionUtils.invariant(!containerPending, "Container ref is defined but not hydrated", "use-scroll-ref");
            motionUtils.invariant(!targetPending, "Target ref is defined but not hydrated", "use-scroll-ref");
            if (!containerPending && !targetPending)
                cleanup = start();
        };
        motionDom.microtask.read(tryStart);
        return () => {
            motionDom.cancelMicrotask(tryStart);
            cleanup?.();
        };
    }, [start]);
    return values;
}

/**
 * @deprecated useElementScroll is deprecated. Convert to useScroll({ container: ref })
 */
function useElementScroll(ref) {
    if (process.env.NODE_ENV === "development") {
        motionUtils.warnOnce(false, "useElementScroll is deprecated. Convert to useScroll({ container: ref }).");
    }
    return useScroll({ container: ref });
}

/**
 * @deprecated useViewportScroll is deprecated. Convert to useScroll()
 */
function useViewportScroll() {
    if (process.env.NODE_ENV !== "production") {
        motionUtils.warnOnce(false, "useViewportScroll is deprecated. Convert to useScroll().");
    }
    return useScroll();
}

/**
 * Combine multiple motion values into a new one using a string template literal.
 *
 * ```jsx
 * import {
 *   motion,
 *   useSpring,
 *   useMotionValue,
 *   useMotionTemplate
 * } from "framer-motion"
 *
 * function Component() {
 *   const shadowX = useSpring(0)
 *   const shadowY = useMotionValue(0)
 *   const shadow = useMotionTemplate`drop-shadow(${shadowX}px ${shadowY}px 20px rgba(0,0,0,0.3))`
 *
 *   return <motion.div style={{ filter: shadow }} />
 * }
 * ```
 *
 * @public
 */
function useMotionTemplate(fragments, ...values) {
    /**
     * Create a function that will build a string from the latest motion values.
     */
    const numFragments = fragments.length;
    function buildValue() {
        let output = ``;
        for (let i = 0; i < numFragments; i++) {
            output += fragments[i];
            const value = values[i];
            if (value) {
                output += motionDom.isMotionValue(value) ? value.get() : value;
            }
        }
        return output;
    }
    return useCombineMotionValues(values.filter(motionDom.isMotionValue), buildValue);
}

function useFollowValue(source, options = {}) {
    const { isStatic } = React.useContext(index.MotionConfigContext);
    const getFromSource = () => (motionDom.isMotionValue(source) ? source.get() : source);
    // isStatic will never change, allowing early hooks return
    if (isStatic) {
        return useTransform(getFromSource);
    }
    const value = useMotionValue(getFromSource());
    React.useInsertionEffect(() => {
        return motionDom.attachFollow(value, source, options);
    }, [value, JSON.stringify(options)]);
    return value;
}

function useSpring(source, options = {}) {
    return useFollowValue(source, { type: "spring", ...options });
}

function useAnimationFrame(callback) {
    const initialTimestamp = React.useRef(0);
    const { isStatic } = React.useContext(index.MotionConfigContext);
    React.useEffect(() => {
        if (isStatic)
            return;
        const provideTimeSinceStart = ({ timestamp, delta }) => {
            if (!initialTimestamp.current)
                initialTimestamp.current = timestamp;
            callback(timestamp - initialTimestamp.current, delta);
        };
        motionDom.frame.update(provideTimeSinceStart, true);
        return () => motionDom.cancelFrame(provideTimeSinceStart);
    }, [callback]);
}

function useTime() {
    const time = useMotionValue(0);
    useAnimationFrame((t) => time.set(t));
    return time;
}

/**
 * Creates a `MotionValue` that updates when the velocity of the provided `MotionValue` changes.
 *
 * ```javascript
 * const x = useMotionValue(0)
 * const xVelocity = useVelocity(x)
 * const xAcceleration = useVelocity(xVelocity)
 * ```
 *
 * @public
 */
function useVelocity(value) {
    const velocity = useMotionValue(value.getVelocity());
    const updateVelocity = () => {
        const latest = value.getVelocity();
        velocity.set(latest);
        /**
         * If we still have velocity, schedule an update for the next frame
         * to keep checking until it is zero.
         */
        if (latest)
            motionDom.frame.update(updateVelocity);
    };
    useMotionValueEvent(value, "change", () => {
        // Schedule an update to this value at the end of the current frame.
        motionDom.frame.update(updateVelocity, false, true);
    });
    return velocity;
}

class WillChangeMotionValue extends motionDom.MotionValue {
    constructor() {
        super(...arguments);
        this.isEnabled = false;
    }
    add(name) {
        if (motionDom.transformProps.has(name) || motionDom.acceleratedValues.has(name)) {
            this.isEnabled = true;
            this.update();
        }
    }
    update() {
        this.set(this.isEnabled ? "transform" : "auto");
    }
}

function useWillChange() {
    return index.useConstant(() => new WillChangeMotionValue("auto"));
}

/**
 * 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 (
 *     <motion.div animate={{
 *       opacity: isOpen ? 1 : 0,
 *       x: isOpen ? 0 : closedX
 *     }} />
 *   )
 * }
 * ```
 *
 * @return boolean
 *
 * @public
 */
function useReducedMotion() {
    /**
     * Lazy initialisation of prefersReducedMotion
     */
    !motionDom.hasReducedMotionListener.current && motionDom.initPrefersReducedMotion();
    const [shouldReduceMotion] = React.useState(motionDom.prefersReducedMotion.current);
    if (process.env.NODE_ENV !== "production") {
        motionUtils.warnOnce(shouldReduceMotion !== true, "You have Reduced Motion enabled on your device. Animations may not appear as expected.", "reduced-motion-disabled");
    }
    /**
     * TODO See if people miss automatically updating shouldReduceMotion setting
     */
    return shouldReduceMotion;
}

function useReducedMotionConfig() {
    const reducedMotionPreference = useReducedMotion();
    const { reducedMotion } = React.useContext(index.MotionConfigContext);
    if (reducedMotion === "never") {
        return false;
    }
    else if (reducedMotion === "always") {
        return true;
    }
    else {
        return reducedMotionPreference;
    }
}

function stopAnimation(visualElement) {
    visualElement.values.forEach((value) => value.stop());
}
function setVariants(visualElement, variantLabels) {
    const reversedLabels = [...variantLabels].reverse();
    reversedLabels.forEach((key) => {
        const variant = visualElement.getVariant(key);
        variant && motionDom.setTarget(visualElement, variant);
        if (visualElement.variantChildren) {
            visualElement.variantChildren.forEach((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 {
        motionDom.setTarget(visualElement, definition);
    }
}
/**
 * @public
 */
function animationControls() {
    /**
     * Track whether the host component has mounted.
     */
    let hasMounted = false;
    /**
     * A collection of linked component animation controls.
     */
    const subscribers = new Set();
    const controls = {
        subscribe(visualElement) {
            subscribers.add(visualElement);
            return () => void subscribers.delete(visualElement);
        },
        start(definition, transitionOverride) {
            motionUtils.invariant(hasMounted, "controls.start() should only be called after a component has mounted. Consider calling within a useEffect hook.");
            const animations = [];
            subscribers.forEach((visualElement) => {
                animations.push(motionDom.animateVisualElement(visualElement, definition, {
                    transitionOverride,
                }));
            });
            return Promise.all(animations);
        },
        set(definition) {
            motionUtils.invariant(hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.");
            return subscribers.forEach((visualElement) => {
                setValues(visualElement, definition);
            });
        },
        stop() {
            subscribers.forEach((visualElement) => {
                stopAnimation(visualElement);
            });
        },
        mount() {
            hasMounted = true;
            return () => {
                hasMounted = false;
                controls.stop();
            };
        },
    };
    return controls;
}

function useAnimate() {
    const scope = index.useConstant(() => ({
        current: null, // Will be hydrated by React
        animations: [],
    }));
    const reduceMotion = useReducedMotionConfig() ?? undefined;
    const { skipAnimations } = React.useContext(index.MotionConfigContext);
    const animate = React.useMemo(() => createScopedAnimate({ scope, reduceMotion, skipAnimations }), [scope, reduceMotion, skipAnimations]);
    useUnmountEffect(() => {
        scope.animations.forEach((animation) => animation.stop());
        scope.animations.length = 0;
    });
    return [scope, animate];
}

function useAnimateMini() {
    const scope = index.useConstant(() => ({
        current: null, // Will be hydrated by React
        animations: [],
    }));
    const animate = index.useConstant(() => createScopedWaapiAnimate(scope));
    useUnmountEffect(() => {
        scope.animations.forEach((animation) => animation.stop());
    });
    return [scope, animate];
}

/**
 * Creates `LegacyAnimationControls`, which can be used to manually start, stop
 * and sequence animations on one or more components.
 *
 * The returned `LegacyAnimationControls` should be passed to the `animate` property
 * of the components you want to animate.
 *
 * These components can then be animated with the `start` method.
 *
 * ```jsx
 * import * as React from 'react'
 * import { motion, useAnimation } from 'framer-motion'
 *
 * export function MyComponent(props) {
 *    const controls = useAnimation()
 *
 *    controls.start({
 *        x: 100,
 *        transition: { duration: 0.5 },
 *    })
 *
 *    return <motion.div animate={controls} />
 * }
 * ```
 *
 * @returns Animation controller with `start` and `stop` methods
 *
 * @public
 */
function useAnimationControls() {
    const controls = index.useConstant(animationControls);
    index.useIsomorphicLayoutEffect(controls.mount, []);
    return controls;
}
const useAnimation = useAnimationControls;

function usePresenceData() {
    const context = React.useContext(index.PresenceContext);
    return context ? context.custom : undefined;
}

/**
 * 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 <div ref={ref} />
 * ```
 *
 * @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(() => {
        const element = ref.current;
        if (handler && element) {
            return motionDom.addDomEvent(element, eventName, handler, options);
        }
    }, [ref, eventName, handler, options]);
}

/**
 * Can manually trigger a drag gesture on one or more `drag`-enabled `motion` components.
 *
 * ```jsx
 * const dragControls = useDragControls()
 *
 * function startDrag(event) {
 *   dragControls.start(event, { snapToCursor: true })
 * }
 *
 * return (
 *   <>
 *     <div onPointerDown={startDrag} />
 *     <motion.div drag="x" dragControls={dragControls} />
 *   </>
 * )
 * ```
 *
 * @public
 */
class DragControls {
    constructor() {
        this.componentControls = new Set();
    }
    /**
     * Subscribe a component's internal `VisualElementDragControls` to the user-facing API.
     *
     * @internal
     */
    subscribe(controls) {
        this.componentControls.add(controls);
        return () => this.componentControls.delete(controls);
    }
    /**
     * Start a drag gesture on every `motion` component that has this set of drag controls
     * passed into it via the `dragControls` prop.
     *
     * ```jsx
     * dragControls.start(e, {
     *   snapToCursor: true
     * })
     * ```
     *
     * @param event - PointerEvent
     * @param options - Options
     *
     * @public
     */
    start(event, options) {
        this.componentControls.forEach((controls) => {
            controls.start(event.nativeEvent || event, options);
        });
    }
    /**
     * Cancels a drag gesture.
     *
     * ```jsx
     * dragControls.cancel()
     * ```
     *
     * @public
     */
    cancel() {
        this.componentControls.forEach((controls) => {
            controls.cancel();
        });
    }
    /**
     * Stops a drag gesture.
     *
     * ```jsx
     * dragControls.stop()
     * ```
     *
     * @public
     */
    stop() {
        this.componentControls.forEach((controls) => {
            controls.stop();
        });
    }
}
const createDragControls = () => new DragControls();
/**
 * Usually, dragging is initiated by pressing down on a `motion` component with a `drag` prop
 * and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we
 * might want to initiate that dragging from a different component than the draggable one.
 *
 * By creating a `dragControls` using the `useDragControls` hook, we can pass this into
 * the draggable component's `dragControls` prop. It exposes a `start` method
 * that can start dragging from pointer events on other components.
 *
 * ```jsx
 * const dragControls = useDragControls()
 *
 * function startDrag(event) {
 *   dragControls.start(event, { snapToCursor: true })
 * }
 *
 * return (
 *   <>
 *     <div onPointerDown={startDrag} />
 *     <motion.div drag="x" dragControls={dragControls} />
 *   </>
 * )
 * ```
 *
 * @public
 */
function useDragControls() {
    return index.useConstant(createDragControls);
}

/**
 * Checks if a component is a `motion` component.
 */
function isMotionComponent(component) {
    return (component !== null &&
        typeof component === "object" &&
        index.motionComponentSymbol in component);
}

/**
 * Unwraps a `motion` component and returns either a string for `motion.div` or
 * the React component for `motion(Component)`.
 *
 * If the component is not a `motion` component it returns undefined.
 */
function unwrapMotionComponent(component) {
    if (isMotionComponent(component)) {
        return component[index.motionComponentSymbol];
    }
    return undefined;
}

function useInstantLayoutTransition() {
    return startTransition;
}
function startTransition(callback) {
    if (!motionDom.rootProjectionNode.current)
        return;
    motionDom.rootProjectionNode.current.isUpdating = false;
    motionDom.rootProjectionNode.current.blockUpdate();
    callback && callback();
}

function useResetProjection() {
    const reset = React.useCallback(() => {
        const root = motionDom.rootProjectionNode.current;
        if (!root)
            return;
        root.resetTree();
    }, []);
    return reset;
}

/**
 * Cycles through a series of visual properties. Can be used to toggle between or cycle through animations. It works similar to `useState` in React. It is provided an initial array of possible states, and returns an array of two arguments.
 *
 * An index value can be passed to the returned `cycle` function to cycle to a specific index.
 *
 * ```jsx
 * import * as React from "react"
 * import { motion, useCycle } from "framer-motion"
 *
 * export const MyComponent = () => {
 *   const [x, cycleX] = useCycle(0, 50, 100)
 *
 *   return (
 *     <motion.div
 *       animate={{ x: x }}
 *       onTap={() => cycleX()}
 *      />
 *    )
 * }
 * ```
 *
 * @param items - items to cycle through
 * @returns [currentState, cycleState]
 *
 * @public
 */
function useCycle(...items) {
    const index = React.useRef(0);
    const [item, setItem] = React.useState(items[index.current]);
    const runCycle = React.useCallback((next) => {
        index.current =
            typeof next !== "number"
                ? motionUtils.wrap(0, items.length, index.current + 1)
                : next;
        setItem(items[index.current]);
    }, 
    // The array will change on each call, but by putting items.length at
    // the front of this array, we guarantee the dependency comparison will match up
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [items.length, ...items]);
    return [item, runCycle];
}

function useInView(ref, { root, margin, amount, once = false, initial = false, } = {}) {
    const [isInView, setInView] = React.useState(initial);
    React.useEffect(() => {
        if (!ref.current || (once && isInView))
            return;
        const onEnter = () => {
            setInView(true);
            return once ? undefined : () => setInView(false);
        };
        const options = {
            root: (root && root.current) || undefined,
            margin,
            amount,
        };
        return inView(ref.current, onEnter, options);
    }, [root, ref, margin, once, amount]);
    return isInView;
}

function useInstantTransition() {
    const [forceUpdate, forcedRenderCount] = useForceUpdate();
    const startInstantLayoutTransition = useInstantLayoutTransition();
    const unlockOnFrameRef = React.useRef(-1);
    React.useEffect(() => {
        /**
         * Unblock after two animation frames, otherwise this will unblock too soon.
         */
        motionDom.frame.postRender(() => motionDom.frame.postRender(() => {
            /**
             * If the callback has been called again after the effect
             * triggered this 2 frame delay, don't unblock animations. This
             * prevents the previous effect from unblocking the current
             * instant transition too soon. This becomes more likely when
             * used in conjunction with React.startTransition().
             */
            if (forcedRenderCount !== unlockOnFrameRef.current)
                return;
            motionUtils.MotionGlobalConfig.instantAnimations = false;
        }));
    }, [forcedRenderCount]);
    return (callback) => {
        startInstantLayoutTransition(() => {
            motionUtils.MotionGlobalConfig.instantAnimations = true;
            forceUpdate();
            callback();
            unlockOnFrameRef.current = forcedRenderCount + 1;
        });
    };
}
function disableInstantTransitions() {
    motionUtils.MotionGlobalConfig.instantAnimations = false;
}

function usePageInView() {
    const [isInView, setIsInView] = React.useState(true);
    React.useEffect(() => {
        const handleVisibilityChange = () => setIsInView(!document.hidden);
        if (document.hidden) {
            handleVisibilityChange();
        }
        document.addEventListener("visibilitychange", handleVisibilityChange);
        return () => {
            document.removeEventListener("visibilitychange", handleVisibilityChange);
        };
    }, []);
    return isInView;
}

/**
 * Creates a `transformPagePoint` function that accounts for SVG viewBox scaling.
 *
 * When dragging SVG elements inside an SVG with a viewBox that differs from
 * the rendered dimensions (e.g., `viewBox="0 0 100 100"` but rendered at 500x500 pixels),
 * pointer coordinates need to be transformed to match the SVG's coordinate system.
 *
 * @example
 * ```jsx
 * function App() {
 *   const svgRef = useRef<SVGSVGElement>(null)
 *
 *   return (
 *     <MotionConfig transformPagePoint={transformViewBoxPoint(svgRef)}>
 *       <svg ref={svgRef} viewBox="0 0 100 100" width={500} height={500}>
 *         <motion.rect drag width={10} height={10} />
 *       </svg>
 *     </MotionConfig>
 *   )
 * }
 * ```
 *
 * @param svgRef - A React ref to the SVG element
 * @returns A transformPagePoint function for use with MotionConfig
 *
 * @public
 */
function transformViewBoxPoint(svgRef) {
    return (point) => {
        const svg = svgRef.current;
        if (!svg) {
            return point;
        }
        // Get the viewBox attribute
        const viewBox = svg.viewBox?.baseVal;
        if (!viewBox || (viewBox.width === 0 && viewBox.height === 0)) {
            // No viewBox or empty viewBox - no transformation needed
            return point;
        }
        // Get the rendered dimensions of the SVG
        const bbox = svg.getBoundingClientRect();
        if (bbox.width === 0 || bbox.height === 0) {
            return point;
        }
        // Calculate scale factors
        const scaleX = viewBox.width / bbox.width;
        const scaleY = viewBox.height / bbox.height;
        // Get the SVG's position on the page
        const svgX = bbox.left + window.scrollX;
        const svgY = bbox.top + window.scrollY;
        // Transform the point:
        // 1. Calculate position relative to SVG
        // 2. Scale by viewBox/viewport ratio
        // 3. Add back the SVG position (but in SVG coordinates)
        return {
            x: (point.x - svgX) * scaleX + svgX,
            y: (point.y - svgY) * scaleY + svgY,
        };
    };
}

/**
 * Creates a `transformPagePoint` function that corrects pointer coordinates
 * for a parent container with CSS transforms (rotation, scale, skew).
 *
 * When dragging elements inside a transformed parent, pointer coordinates
 * need to be transformed through the inverse of the parent's transform
 * so the drag offset is in local space.
 *
 * Works with both static and continuously animating transforms.
 *
 * @example
 * ```jsx
 * function App() {
 *   const ref = useRef(null)
 *
 *   return (
 *     <motion.div ref={ref} style={{ rotate: 90 }}>
 *       <MotionConfig transformPagePoint={correctParentTransform(ref)}>
 *         <motion.div drag />
 *       </MotionConfig>
 *     </motion.div>
 *   )
 * }
 * ```
 *
 * @param parentRef - A React ref to the transformed parent element
 * @returns A transformPagePoint function for use with MotionConfig
 *
 * @public
 */
function correctParentTransform(parentRef) {
    return (point) => {
        const parent = parentRef.current;
        if (!parent)
            return point;
        const inv = getInverseMatrix(parent);
        if (!inv)
            return point;
        // Get center of rotation in page space
        const rect = parent.getBoundingClientRect();
        const cx = rect.left + window.scrollX + rect.width / 2;
        const cy = rect.top + window.scrollY + rect.height / 2;
        // Transform (point - center) through inverse, then add center back
        const dx = point.x - cx;
        const dy = point.y - cy;
        return {
            x: cx + inv.a * dx + inv.c * dy,
            y: cy + inv.b * dx + inv.d * dy,
        };
    };
}
function getInverseMatrix(element) {
    const { transform } = getComputedStyle(element);
    if (!transform || transform === "none")
        return null;
    const match = transform.match(/^matrix3d\((.*)\)$/u) ||
        transform.match(/^matrix\((.*)\)$/u);
    if (!match)
        return null;
    const v = match[1].split(",").map(Number);
    const is3d = transform.startsWith("matrix3d");
    const a = v[0], b = v[1];
    const c = is3d ? v[4] : v[2];
    const d = is3d ? v[5] : v[3];
    const det = a * d - b * c;
    if (Math.abs(det) < 1e-10)
        return null;
    return { a: d / det, b: -b / det, c: -c / det, d: a / det };
}

const appearAnimationStore = new Map();
const appearComplete = new Map();

const appearStoreId = (elementId, valueName) => {
    const key = motionDom.transformProps.has(valueName) ? "transform" : valueName;
    return `${elementId}: ${key}`;
};

function handoffOptimizedAppearAnimation(elementId, valueName, frame) {
    const storeId = appearStoreId(elementId, valueName);
    const optimisedAnimation = appearAnimationStore.get(storeId);
    if (!optimisedAnimation) {
        return null;
    }
    const { animation, startTime } = optimisedAnimation;
    function cancelAnimation() {
        window.MotionCancelOptimisedAnimation?.(elementId, valueName, frame);
    }
    /**
     * We can cancel the animation once it's finished now that we've synced
     * with Motion.
     *
     * Prefer onfinish over finished as onfinish is backwards compatible with
     * older browsers.
     */
    animation.onfinish = cancelAnimation;
    if (startTime === null || window.MotionHandoffIsComplete?.(elementId)) {
        /**
         * If the startTime is null, this animation is the Paint Ready detection animation
         * and we can cancel it immediately without handoff.
         *
         * Or if we've already handed off the animation then we're now interrupting it.
         * In which case we need to cancel it.
         */
        cancelAnimation();
        return null;
    }
    else {
        return startTime;
    }
}

/**
 * A single time to use across all animations to manually set startTime
 * and ensure they're all in sync.
 */
let startFrameTime;
/**
 * A dummy animation to detect when Chrome is ready to start
 * painting the page and hold off from triggering the real animation
 * until then. We only need one animation to detect paint ready.
 *
 * https://bugs.chromium.org/p/chromium/issues/detail?id=1406850
 */
let readyAnimation;
/**
 * Keep track of animations that were suspended vs cancelled so we
 * can easily resume them when we're done measuring layout.
 */
const suspendedAnimations = new Set();
function resumeSuspendedAnimations() {
    suspendedAnimations.forEach((data) => {
        data.animation.play();
        data.animation.startTime = data.startTime;
    });
    suspendedAnimations.clear();
}
function startOptimizedAppearAnimation(element, name, keyframes, options, onReady) {
    // Prevent optimised appear animations if Motion has already started animating.
    if (window.MotionIsMounted) {
        return;
    }
    const id = element.dataset[motionDom.optimizedAppearDataId];
    if (!id)
        return;
    window.MotionHandoffAnimation = handoffOptimizedAppearAnimation;
    const storeId = appearStoreId(id, name);
    if (!readyAnimation) {
        readyAnimation = motionDom.startWaapiAnimation(element, name, [keyframes[0], keyframes[0]], 
        /**
         * 10 secs is basically just a super-safe duration to give Chrome
         * long enough to get the animation ready.
         */
        { duration: 10000, ease: "linear" });
        appearAnimationStore.set(storeId, {
            animation: readyAnimation,
            startTime: null,
        });
        /**
         * If there's no readyAnimation then there's been no instantiation
         * of handoff animations.
         */
        window.MotionHandoffAnimation = handoffOptimizedAppearAnimation;
        window.MotionHasOptimisedAnimation = (elementId, valueName) => {
            if (!elementId)
                return false;
            /**
             * Keep a map of elementIds that have started animating. We check
             * via ID instead of Element because of hydration errors and
             * pre-hydration checks. We also actively record IDs as they start
             * animating rather than simply checking for data-appear-id as
             * this attrbute might be present but not lead to an animation, for
             * instance if the element's appear animation is on a different
             * breakpoint.
             */
            if (!valueName) {
                return appearComplete.has(elementId);
            }
            const animationId = appearStoreId(elementId, valueName);
            return Boolean(appearAnimationStore.get(animationId));
        };
        window.MotionHandoffMarkAsComplete = (elementId) => {
            if (appearComplete.has(elementId)) {
                appearComplete.set(elementId, true);
            }
        };
        window.MotionHandoffIsComplete = (elementId) => {
            return appearComplete.get(elementId) === true;
        };
        /**
         * We only need to cancel transform animations as
         * they're the ones that will interfere with the
         * layout animation measurements.
         */
        window.MotionCancelOptimisedAnimation = (elementId, valueName, frame, canResume) => {
            const animationId = appearStoreId(elementId, valueName);
            const data = appearAnimationStore.get(animationId);
            if (!data)
                return;
            if (frame && canResume === undefined) {
                /**
                 * Wait until the end of the subsequent frame to cancel the animation
                 * to ensure we don't remove the animation before the main thread has
                 * had a chance to resolve keyframes and render.
                 */
                frame.postRender(() => {
                    frame.postRender(() => {
                        data.animation.cancel();
                    });
                });
            }
            else {
                data.animation.cancel();
            }
            if (frame && canResume) {
                suspendedAnimations.add(data);
                frame.render(resumeSuspendedAnimations);
            }
            else {
                appearAnimationStore.delete(animationId);
                /**
                 * If there are no more animations left, we can remove the cancel function.
                 * This will let us know when we can stop checking for conflicting layout animations.
                 */
                if (!appearAnimationStore.size) {
                    window.MotionCancelOptimisedAnimation = undefined;
                }
            }
        };
        window.MotionCheckAppearSync = (visualElement, valueName, value) => {
            const appearId = motionDom.getOptimisedAppearId(visualElement);
            if (!appearId)
                return;
            const valueIsOptimised = window.MotionHasOptimisedAnimation?.(appearId, valueName);
            const externalAnimationValue = visualElement.props.values?.[valueName];
            if (!valueIsOptimised || !externalAnimationValue)
                return;
            const removeSyncCheck = value.on("change", (latestValue) => {
                if (externalAnimationValue.get() !== latestValue) {
                    window.MotionCancelOptimisedAnimation?.(appearId, valueName);
                    removeSyncCheck();
                }
            });
            return removeSyncCheck;
        };
    }
    const startAnimation = () => {
        readyAnimation.cancel();
        const appearAnimation = motionDom.startWaapiAnimation(element, name, keyframes, options);
        /**
         * Record the time of the first started animation. We call performance.now() once
         * here and once in handoff to ensure we're getting
         * close to a frame-locked time. This keeps all animations in sync.
         */
        if (startFrameTime === undefined) {
            startFrameTime = performance.now();
        }
        appearAnimation.startTime = startFrameTime;
        appearAnimationStore.set(storeId, {
            animation: appearAnimation,
            startTime: startFrameTime,
        });
        if (onReady)
            onReady(appearAnimation);
    };
    appearComplete.set(id, false);
    if (readyAnimation.ready) {
        readyAnimation.ready.then(startAnimation).catch(motionUtils.noop);
    }
    else {
        startAnimation();
    }
}

const createObject = () => ({});
class StateVisualElement extends motionDom.VisualElement {
    constructor() {
        super(...arguments);
        this.measureInstanceViewportBox = motionDom.createBox;
    }
    build() { }
    resetTransform() { }
    restoreTransform() { }
    removeValueFromRenderState() { }
    renderInstance() { }
    scrapeMotionValuesFromProps() {
        return createObject();
    }
    getBaseTargetFromProps() {
        return undefined;
    }
    readValueFromInstance(_state, key, options) {
        return options.initialState[key] || 0;
    }
    sortInstanceNodePosition() {
        return 0;
    }
}
const useVisualState = index.makeUseVisualState({
    scrapeMotionValuesFromProps: createObject,
    createRenderState: createObject,
});
/**
 * This is not an officially supported API and may be removed
 * on any version.
 */
function useAnimatedState(initialState) {
    const [animationState, setAnimationState] = React.useState(initialState);
    const visualState = useVisualState({}, false);
    const element = index.useConstant(() => {
        return new StateVisualElement({
            props: {
                onUpdate: (v) => {
                    setAnimationState({ ...v });
                },
            },
            visualState,
            presenceContext: null,
        }, { initialState });
    });
    React.useLayoutEffect(() => {
        element.mount({});
        return () => element.unmount();
    }, [element]);
    const startAnimation = index.useConstant(() => (animationDefinition) => {
        return motionDom.animateVisualElement(element, animationDefinition);
    });
    return [animationState, startAnimation];
}

let id = 0;
const AnimateSharedLayout = ({ children }) => {
    React__namespace.useEffect(() => {
        motionUtils.invariant(false, "AnimateSharedLayout is deprecated: https://www.framer.com/docs/guide-upgrade/##shared-layout-animations");
    }, []);
    return (jsxRuntime.jsx(LayoutGroup, { id: index.useConstant(() => `asl-${id++}`), children: children }));
};

// Keep things reasonable and avoid scale: Infinity. In practise we might need
// to add another value, opacity, that could interpolate scaleX/Y [0,0.01] => [0,1]
// to simply hide content at unreasonable scales.
const maxScale = 100000;
const invertScale = (scale) => scale > 0.001 ? 1 / scale : maxScale;
let hasWarned = false;
/**
 * Returns a `MotionValue` each for `scaleX` and `scaleY` that update with the inverse
 * of their respective parent scales.
 *
 * This is useful for undoing the distortion of content when scaling a parent component.
 *
 * By default, `useInvertedScale` will automatically fetch `scaleX` and `scaleY` from the nearest parent.
 * By passing other `MotionValue`s in as `useInvertedScale({ scaleX, scaleY })`, it will invert the output
 * of those instead.
 *
 * ```jsx
 * const MyComponent = () => {
 *   const { scaleX, scaleY } = useInvertedScale()
 *   return <motion.div style={{ scaleX, scaleY }} />
 * }
 * ```
 *
 * @deprecated
 */
function useInvertedScale(scale) {
    let parentScaleX = useMotionValue(1);
    let parentScaleY = useMotionValue(1);
    const { visualElement } = React.useContext(index.MotionContext);
    motionUtils.invariant(!!(scale || visualElement), "If no scale values are provided, useInvertedScale must be used within a child of another motion component.");
    motionUtils.warning(hasWarned, "useInvertedScale is deprecated and will be removed in 3.0. Use the layout prop instead.");
    hasWarned = true;
    if (scale) {
        parentScaleX = scale.scaleX || parentScaleX;
        parentScaleY = scale.scaleY || parentScaleY;
    }
    else if (visualElement) {
        parentScaleX = visualElement.getValue("scaleX", 1);
        parentScaleY = visualElement.getValue("scaleY", 1);
    }
    const scaleX = useTransform(parentScaleX, invertScale);
    const scaleY = useTransform(parentScaleY, invertScale);
    return { scaleX, scaleY };
}

exports.LayoutGroupContext = index.LayoutGroupContext;
exports.MotionConfigContext = index.MotionConfigContext;
exports.MotionContext = index.MotionContext;
exports.PresenceContext = index.PresenceContext;
exports.SwitchLayoutGroupContext = index.SwitchLayoutGroupContext;
exports.filterProps = index.filterProps;
exports.isBrowser = index.isBrowser;
exports.isValidMotionProp = index.isValidMotionProp;
exports.makeUseVisualState = index.makeUseVisualState;
exports.useIsomorphicLayoutEffect = index.useIsomorphicLayoutEffect;
Object.defineProperty(exports, "VisualElement", {
    enumerable: true,
    get: function () { return motionDom.VisualElement; }
});
Object.defineProperty(exports, "addScaleCorrector", {
    enumerable: true,
    get: function () { return motionDom.addScaleCorrector; }
});
Object.defineProperty(exports, "animateVisualElement", {
    enumerable: true,
    get: function () { return motionDom.animateVisualElement; }
});
Object.defineProperty(exports, "arc", {
    enumerable: true,
    get: function () { return motionDom.arc; }
});
Object.defineProperty(exports, "buildTransform", {
    enumerable: true,
    get: function () { return motionDom.buildTransform; }
});
Object.defineProperty(exports, "calcLength", {
    enumerable: true,
    get: function () { return motionDom.calcLength; }
});
Object.defineProperty(exports, "createBox", {
    enumerable: true,
    get: function () { return motionDom.createBox; }
});
Object.defineProperty(exports, "delay", {
    enumerable: true,
    get: function () { return motionDom.delay; }
});
Object.defineProperty(exports, "optimizedAppearDataAttribute", {
    enumerable: true,
    get: function () { return motionDom.optimizedAppearDataAttribute; }
});
Object.defineProperty(exports, "resolveMotionValue", {
    enumerable: true,
    get: function () { return motionDom.resolveMotionValue; }
});
Object.defineProperty(exports, "visualElementStore", {
    enumerable: true,
    get: function () { return motionDom.visualElementStore; }
});
exports.addPointerEvent = featureBundle.addPointerEvent;
exports.addPointerInfo = featureBundle.addPointerInfo;
exports.animations = featureBundle.animations;
exports.distance = featureBundle.distance;
exports.distance2D = featureBundle.distance2D;
exports.useIsPresent = featureBundle.useIsPresent;
exports.usePresence = featureBundle.usePresence;
Object.defineProperty(exports, "MotionGlobalConfig", {
    enumerable: true,
    get: function () { return motionUtils.MotionGlobalConfig; }
});
exports.AnimatePresence = AnimatePresence;
exports.AnimateSharedLayout = AnimateSharedLayout;
exports.DeprecatedLayoutGroupContext = DeprecatedLayoutGroupContext;
exports.DragControls = DragControls;
exports.LayoutGroup = LayoutGroup;
exports.LazyMotion = LazyMotion;
exports.MotionConfig = MotionConfig;
exports.PopChild = PopChild;
exports.PresenceChild = PresenceChild;
exports.Reorder = namespace;
exports.WillChangeMotionValue = WillChangeMotionValue;
exports.animate = animate;
exports.animateMini = animateMini;
exports.animationControls = animationControls;
exports.correctParentTransform = correctParentTransform;
exports.createScopedAnimate = createScopedAnimate;
exports.disableInstantTransitions = disableInstantTransitions;
exports.domAnimation = domAnimation;
exports.domMax = domMax;
exports.domMin = domMin;
exports.inView = inView;
exports.isMotionComponent = isMotionComponent;
exports.m = m;
exports.motion = motion;
exports.scroll = scroll;
exports.scrollInfo = scrollInfo;
exports.startOptimizedAppearAnimation = startOptimizedAppearAnimation;
exports.transformViewBoxPoint = transformViewBoxPoint;
exports.unwrapMotionComponent = unwrapMotionComponent;
exports.useAnimate = useAnimate;
exports.useAnimateMini = useAnimateMini;
exports.useAnimation = useAnimation;
exports.useAnimationControls = useAnimationControls;
exports.useAnimationFrame = useAnimationFrame;
exports.useComposedRefs = useComposedRefs;
exports.useCycle = useCycle;
exports.useDeprecatedAnimatedState = useAnimatedState;
exports.useDeprecatedInvertedScale = useInvertedScale;
exports.useDomEvent = useDomEvent;
exports.useDragControls = useDragControls;
exports.useElementScroll = useElementScroll;
exports.useFollowValue = useFollowValue;
exports.useForceUpdate = useForceUpdate;
exports.useInView = useInView;
exports.useInstantLayoutTransition = useInstantLayoutTransition;
exports.useInstantTransition = useInstantTransition;
exports.useMotionTemplate = useMotionTemplate;
exports.useMotionValue = useMotionValue;
exports.useMotionValueEvent = useMotionValueEvent;
exports.usePageInView = usePageInView;
exports.usePresenceData = usePresenceData;
exports.useReducedMotion = useReducedMotion;
exports.useReducedMotionConfig = useReducedMotionConfig;
exports.useResetProjection = useResetProjection;
exports.useScroll = useScroll;
exports.useSpring = useSpring;
exports.useTime = useTime;
exports.useTransform = useTransform;
exports.useUnmountEffect = useUnmountEffect;
exports.useVelocity = useVelocity;
exports.useViewportScroll = useViewportScroll;
exports.useWillChange = useWillChange;
Object.keys(motionDom).forEach(function (k) {
    if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
        enumerable: true,
        get: function () { return motionDom[k]; }
    });
});
Object.keys(motionUtils).forEach(function (k) {
    if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
        enumerable: true,
        get: function () { return motionUtils[k]; }
    });
});
//# sourceMappingURL=index.js.map
