securityos/node_modules/framer-motion/dist/es/motion/index.mjs

80 lines
4.0 KiB
JavaScript
Raw Permalink Normal View History

2024-09-06 15:32:35 +00:00
import * as React from 'react';
import { forwardRef, useContext } from 'react';
import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
import { MotionContext } from '../context/MotionContext/index.mjs';
import { useVisualElement } from './utils/use-visual-element.mjs';
import { useMotionRef } from './utils/use-motion-ref.mjs';
import { useCreateMotionContext } from '../context/MotionContext/create.mjs';
import { loadFeatures } from './features/load-features.mjs';
import { isBrowser } from '../utils/is-browser.mjs';
import { LayoutGroupContext } from '../context/LayoutGroupContext.mjs';
import { LazyContext } from '../context/LazyContext.mjs';
import { SwitchLayoutGroupContext } from '../context/SwitchLayoutGroupContext.mjs';
import { motionComponentSymbol } from './utils/symbol.mjs';
/**
* 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({ preloadedFeatures, createVisualElement, useRender, useVisualState, Component, }) {
preloadedFeatures && loadFeatures(preloadedFeatures);
function MotionComponent(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 = {
...useContext(MotionConfigContext),
...props,
layoutId: useLayoutId(props),
};
const { isStatic } = configAndProps;
const context = useCreateMotionContext(props);
const visualState = useVisualState(props, isStatic);
if (!isStatic && isBrowser) {
/**
* Create a VisualElement for this component. A VisualElement provides a common
* interface to renderer-specific APIs (ie DOM/Three.js etc) as well as
* providing a way of rendering to these APIs outside of the React render loop
* for more performant animations and interactions
*/
context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement);
/**
* Load Motion gesture and animation features. These are rendered as renderless
* components so each feature can optionally make use of React lifecycle methods.
*/
const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext);
const isStrict = useContext(LazyContext).strict;
if (context.visualElement) {
MeasureLayout = context.visualElement.loadFeatures(
// Note: Pass the full new combined props to correctly re-render dynamic feature components.
configAndProps, isStrict, preloadedFeatures, initialLayoutGroupConfig);
}
}
/**
* The mount order and hierarchy is specific to ensure our element ref
* is hydrated by the time features fire their effects.
*/
return (React.createElement(MotionContext.Provider, { value: context },
MeasureLayout && context.visualElement ? (React.createElement(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null,
useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, context.visualElement)));
}
const ForwardRefComponent = forwardRef(MotionComponent);
ForwardRefComponent[motionComponentSymbol] = Component;
return ForwardRefComponent;
}
function useLayoutId({ layoutId }) {
const layoutGroupId = useContext(LayoutGroupContext).id;
return layoutGroupId && layoutId !== undefined
? layoutGroupId + "-" + layoutId
: layoutId;
}
export { createMotionComponent };