"use client";
'use strict';

var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var LayoutGroupContext = require('../context/LayoutGroupContext.js');
var LazyContext = require('../context/LazyContext.js');
var MotionConfigContext = require('../context/MotionConfigContext.js');
var index = require('../context/MotionContext/index.js');
var create = require('../context/MotionContext/create.js');
var useRender = require('../render/dom/use-render.js');
var isSvgComponent = require('../render/dom/utils/is-svg-component.js');
var useHtmlVisualState = require('../render/html/use-html-visual-state.js');
var useSvgVisualState = require('../render/svg/use-svg-visual-state.js');
var definitions = require('./features/definitions.js');
var loadFeatures = require('./features/load-features.js');
var symbol = require('./utils/symbol.js');
var useMotionRef = require('./utils/use-motion-ref.js');
var useVisualElement = require('./utils/use-visual-element.js');
var errors = require('../../../../../../motion-utils@12.36.0/node_modules/motion-utils/dist/es/errors.js');

/**
 * Create a `motion` component.
 *
 * This function accepts a Component argument, which can be either a string (ie "div"
 * for `motion.div`), or an actual React component.
 *
 * Alongside this is a config option which provides a way of rendering the provided
 * component "offline", or outside the React render cycle.
 */
function createMotionComponent(Component, { forwardMotionProps = false, type } = {}, preloadedFeatures, createVisualElement) {
    preloadedFeatures && loadFeatures.loadFeatures(preloadedFeatures);
    /**
     * Determine whether to use SVG or HTML rendering based on:
     * 1. Explicit `type` option (highest priority)
     * 2. Auto-detection via `isSVGComponent`
     */
    const isSVG = type ? type === "svg" : isSvgComponent.isSVGComponent(Component);
    const useVisualState = isSVG ? useSvgVisualState.useSVGVisualState : useHtmlVisualState.useHTMLVisualState;
    function MotionDOMComponent(props, externalRef) {
        /**
         * If we need to measure the element we load this functionality in a
         * separate class component in order to gain access to getSnapshotBeforeUpdate.
         */
        let MeasureLayout;
        const configAndProps = {
            ...React.useContext(MotionConfigContext.MotionConfigContext),
            ...props,
            layoutId: useLayoutId(props),
        };
        const { isStatic } = configAndProps;
        const context = create.useCreateMotionContext(props);
        const visualState = useVisualState(props, isStatic);
        if (!isStatic && typeof window !== "undefined") {
            useStrictMode(configAndProps, preloadedFeatures);
            const layoutProjection = getProjectionFunctionality(configAndProps);
            MeasureLayout = layoutProjection.MeasureLayout;
            /**
             * Create a VisualElement for this component. A VisualElement provides a common
             * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as
             * providing a way of rendering to these APIs outside of the React render loop
             * for more performant animations and interactions
             */
            context.visualElement = useVisualElement.useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode, isSVG);
        }
        /**
         * The mount order and hierarchy is specific to ensure our element ref
         * is hydrated by the time features fire their effects.
         */
        return (jsxRuntime.jsxs(index.MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsxRuntime.jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender.useRender(Component, props, useMotionRef.useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps, isSVG)] }));
    }
    MotionDOMComponent.displayName = `motion.${typeof Component === "string"
        ? Component
        : `create(${Component.displayName ?? Component.name ?? ""})`}`;
    const ForwardRefMotionComponent = React.forwardRef(MotionDOMComponent);
    ForwardRefMotionComponent[symbol.motionComponentSymbol] = Component;
    return ForwardRefMotionComponent;
}
function useLayoutId({ layoutId }) {
    const layoutGroupId = React.useContext(LayoutGroupContext.LayoutGroupContext).id;
    return layoutGroupId && layoutId !== undefined
        ? layoutGroupId + "-" + layoutId
        : layoutId;
}
function useStrictMode(configAndProps, preloadedFeatures) {
    const isStrict = React.useContext(LazyContext.LazyContext).strict;
    /**
     * If we're in development mode, check to make sure we're not rendering a motion component
     * as a child of LazyMotion, as this will break the file-size benefits of using it.
     */
    if (process.env.NODE_ENV !== "production" &&
        preloadedFeatures &&
        isStrict) {
        const strictMessage = "You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.";
        configAndProps.ignoreStrict
            ? errors.warning(false, strictMessage, "lazy-strict-mode")
            : errors.invariant(false, strictMessage, "lazy-strict-mode");
    }
}
function getProjectionFunctionality(props) {
    const featureDefinitions = definitions.getInitializedFeatureDefinitions();
    const { drag, layout } = featureDefinitions;
    if (!drag && !layout)
        return {};
    const combined = { ...drag, ...layout };
    return {
        MeasureLayout: drag?.isEnabled(props) || layout?.isEnabled(props)
            ? combined.MeasureLayout
            : undefined,
        ProjectionNode: combined.ProjectionNode,
    };
}

exports.createMotionComponent = createMotionComponent;
