BOC v1.0: RS256 auth, Ledger integration, Prometheus metrics, CI/CD, backup
This commit is contained in:
+802
@@ -0,0 +1,802 @@
|
||||
'use strict';
|
||||
|
||||
var jsxRuntime = require('react/jsx-runtime');
|
||||
var motionUtils = require('motion-utils');
|
||||
var React = require('react');
|
||||
var motionDom = require('motion-dom');
|
||||
|
||||
const LayoutGroupContext = React.createContext({});
|
||||
|
||||
/**
|
||||
* Creates a constant value over the lifecycle of a component.
|
||||
*
|
||||
* Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
|
||||
* a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
|
||||
* you can ensure that initialisers don't execute twice or more.
|
||||
*/
|
||||
function useConstant(init) {
|
||||
const ref = React.useRef(null);
|
||||
if (ref.current === null) {
|
||||
ref.current = init();
|
||||
}
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
const isBrowser = typeof window !== "undefined";
|
||||
|
||||
const useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
const PresenceContext =
|
||||
/* @__PURE__ */ React.createContext(null);
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
const MotionConfigContext = React.createContext({
|
||||
transformPagePoint: (p) => p,
|
||||
isStatic: false,
|
||||
reducedMotion: "never",
|
||||
});
|
||||
|
||||
const LazyContext = React.createContext({ strict: false });
|
||||
|
||||
const featureProps = {
|
||||
animation: [
|
||||
"animate",
|
||||
"variants",
|
||||
"whileHover",
|
||||
"whileTap",
|
||||
"exit",
|
||||
"whileInView",
|
||||
"whileFocus",
|
||||
"whileDrag",
|
||||
],
|
||||
exit: ["exit"],
|
||||
drag: ["drag", "dragControls"],
|
||||
focus: ["whileFocus"],
|
||||
hover: ["whileHover", "onHoverStart", "onHoverEnd"],
|
||||
tap: ["whileTap", "onTap", "onTapStart", "onTapCancel"],
|
||||
pan: ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"],
|
||||
inView: ["whileInView", "onViewportEnter", "onViewportLeave"],
|
||||
layout: ["layout", "layoutId"],
|
||||
};
|
||||
let isInitialized = false;
|
||||
/**
|
||||
* Initialize feature definitions with isEnabled checks.
|
||||
* This must be called before any motion components are rendered.
|
||||
*/
|
||||
function initFeatureDefinitions() {
|
||||
if (isInitialized)
|
||||
return;
|
||||
const initialFeatureDefinitions = {};
|
||||
for (const key in featureProps) {
|
||||
initialFeatureDefinitions[key] = {
|
||||
isEnabled: (props) => featureProps[key].some((name) => !!props[name]),
|
||||
};
|
||||
}
|
||||
motionDom.setFeatureDefinitions(initialFeatureDefinitions);
|
||||
isInitialized = true;
|
||||
}
|
||||
/**
|
||||
* Get the current feature definitions, initializing if needed.
|
||||
*/
|
||||
function getInitializedFeatureDefinitions() {
|
||||
initFeatureDefinitions();
|
||||
return motionDom.getFeatureDefinitions();
|
||||
}
|
||||
|
||||
function loadFeatures(features) {
|
||||
const featureDefinitions = getInitializedFeatureDefinitions();
|
||||
for (const key in features) {
|
||||
featureDefinitions[key] = {
|
||||
...featureDefinitions[key],
|
||||
...features[key],
|
||||
};
|
||||
}
|
||||
motionDom.setFeatureDefinitions(featureDefinitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all valid MotionProps.
|
||||
*
|
||||
* @privateRemarks
|
||||
* This doesn't throw if a `MotionProp` name is missing - it should.
|
||||
*/
|
||||
const validMotionProps = new Set([
|
||||
"animate",
|
||||
"exit",
|
||||
"variants",
|
||||
"initial",
|
||||
"style",
|
||||
"values",
|
||||
"variants",
|
||||
"transition",
|
||||
"transformTemplate",
|
||||
"custom",
|
||||
"inherit",
|
||||
"onBeforeLayoutMeasure",
|
||||
"onAnimationStart",
|
||||
"onAnimationComplete",
|
||||
"onUpdate",
|
||||
"onDragStart",
|
||||
"onDrag",
|
||||
"onDragEnd",
|
||||
"onMeasureDragConstraints",
|
||||
"onDirectionLock",
|
||||
"onDragTransitionEnd",
|
||||
"_dragX",
|
||||
"_dragY",
|
||||
"onHoverStart",
|
||||
"onHoverEnd",
|
||||
"onViewportEnter",
|
||||
"onViewportLeave",
|
||||
"globalTapTarget",
|
||||
"propagate",
|
||||
"ignoreStrict",
|
||||
"viewport",
|
||||
]);
|
||||
/**
|
||||
* Check whether a prop name is a valid `MotionProp` key.
|
||||
*
|
||||
* @param key - Name of the property to check
|
||||
* @returns `true` is key is a valid `MotionProp`.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
function isValidMotionProp(key) {
|
||||
return (key.startsWith("while") ||
|
||||
(key.startsWith("drag") && key !== "draggable") ||
|
||||
key.startsWith("layout") ||
|
||||
key.startsWith("onTap") ||
|
||||
key.startsWith("onPan") ||
|
||||
key.startsWith("onLayout") ||
|
||||
validMotionProps.has(key));
|
||||
}
|
||||
|
||||
let shouldForward = (key) => !isValidMotionProp(key);
|
||||
function loadExternalIsValidProp(isValidProp) {
|
||||
if (typeof isValidProp !== "function")
|
||||
return;
|
||||
// Explicitly filter our events
|
||||
shouldForward = (key) => key.startsWith("on") ? !isValidMotionProp(key) : isValidProp(key);
|
||||
}
|
||||
/**
|
||||
* Emotion and Styled Components both allow users to pass through arbitrary props to their components
|
||||
* to dynamically generate CSS. They both use the `@emotion/is-prop-valid` package to determine which
|
||||
* of these should be passed to the underlying DOM node.
|
||||
*
|
||||
* However, when styling a Motion component `styled(motion.div)`, both packages pass through *all* props
|
||||
* as it's seen as an arbitrary component rather than a DOM node. Motion only allows arbitrary props
|
||||
* passed through the `custom` prop so it doesn't *need* the payload or computational overhead of
|
||||
* `@emotion/is-prop-valid`, however to fix this problem we need to use it.
|
||||
*
|
||||
* By making it an optionalDependency we can offer this functionality only in the situations where it's
|
||||
* actually required.
|
||||
*/
|
||||
try {
|
||||
/**
|
||||
* We attempt to import this package but require won't be defined in esm environments, in that case
|
||||
* isPropValid will have to be provided via `MotionContext`. In a 6.0.0 this should probably be removed
|
||||
* in favour of explicit injection.
|
||||
*
|
||||
* String concatenation prevents bundlers like webpack (e.g. Storybook)
|
||||
* from statically resolving this optional dependency at build time.
|
||||
*/
|
||||
const emotionPkg = "@emotion/is-prop-" + "valid";
|
||||
loadExternalIsValidProp(require(emotionPkg).default);
|
||||
}
|
||||
catch {
|
||||
// We don't need to actually do anything here - the fallback is the existing `isPropValid`.
|
||||
}
|
||||
function filterProps(props, isDom, forwardMotionProps) {
|
||||
const filteredProps = {};
|
||||
for (const key in props) {
|
||||
/**
|
||||
* values is considered a valid prop by Emotion, so if it's present
|
||||
* this will be rendered out to the DOM unless explicitly filtered.
|
||||
*
|
||||
* We check the type as it could be used with the `feColorMatrix`
|
||||
* element, which we support.
|
||||
*/
|
||||
if (key === "values" && typeof props.values === "object")
|
||||
continue;
|
||||
if (motionDom.isMotionValue(props[key]))
|
||||
continue;
|
||||
if (shouldForward(key) ||
|
||||
(forwardMotionProps === true && isValidMotionProp(key)) ||
|
||||
(!isDom && !isValidMotionProp(key)) ||
|
||||
// If trying to use native HTML drag events, forward drag listeners
|
||||
(props["draggable"] &&
|
||||
key.startsWith("onDrag"))) {
|
||||
filteredProps[key] =
|
||||
props[key];
|
||||
}
|
||||
}
|
||||
return filteredProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* We keep these listed separately as we use the lowercase tag names as part
|
||||
* of the runtime bundle to detect SVG components
|
||||
*/
|
||||
const lowercaseSVGElements = [
|
||||
"animate",
|
||||
"circle",
|
||||
"defs",
|
||||
"desc",
|
||||
"ellipse",
|
||||
"g",
|
||||
"image",
|
||||
"line",
|
||||
"filter",
|
||||
"marker",
|
||||
"mask",
|
||||
"metadata",
|
||||
"path",
|
||||
"pattern",
|
||||
"polygon",
|
||||
"polyline",
|
||||
"rect",
|
||||
"stop",
|
||||
"switch",
|
||||
"symbol",
|
||||
"svg",
|
||||
"text",
|
||||
"tspan",
|
||||
"use",
|
||||
"view",
|
||||
];
|
||||
|
||||
function isSVGComponent(Component) {
|
||||
if (
|
||||
/**
|
||||
* If it's not a string, it's a custom React component. Currently we only support
|
||||
* HTML custom React components.
|
||||
*/
|
||||
typeof Component !== "string" ||
|
||||
/**
|
||||
* If it contains a dash, the element is a custom HTML webcomponent.
|
||||
*/
|
||||
Component.includes("-")) {
|
||||
return false;
|
||||
}
|
||||
else if (
|
||||
/**
|
||||
* If it's in our list of lowercase SVG tags, it's an SVG component
|
||||
*/
|
||||
lowercaseSVGElements.indexOf(Component) > -1 ||
|
||||
/**
|
||||
* If it contains a capital letter, it's an SVG component
|
||||
*/
|
||||
/[A-Z]/u.test(Component)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const MotionContext = /* @__PURE__ */ React.createContext({});
|
||||
|
||||
function getCurrentTreeVariants(props, context) {
|
||||
if (motionDom.isControllingVariants(props)) {
|
||||
const { initial, animate } = props;
|
||||
return {
|
||||
initial: initial === false || motionDom.isVariantLabel(initial)
|
||||
? initial
|
||||
: undefined,
|
||||
animate: motionDom.isVariantLabel(animate) ? animate : undefined,
|
||||
};
|
||||
}
|
||||
return props.inherit !== false ? context : {};
|
||||
}
|
||||
|
||||
function useCreateMotionContext(props) {
|
||||
const { initial, animate } = getCurrentTreeVariants(props, React.useContext(MotionContext));
|
||||
return React.useMemo(() => ({ initial, animate }), [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate)]);
|
||||
}
|
||||
function variantLabelsAsDependency(prop) {
|
||||
return Array.isArray(prop) ? prop.join(" ") : prop;
|
||||
}
|
||||
|
||||
const createHtmlRenderState = () => ({
|
||||
style: {},
|
||||
transform: {},
|
||||
transformOrigin: {},
|
||||
vars: {},
|
||||
});
|
||||
|
||||
function copyRawValuesOnly(target, source, props) {
|
||||
for (const key in source) {
|
||||
if (!motionDom.isMotionValue(source[key]) && !motionDom.isForcedMotionValue(key, props)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
function useInitialMotionValues({ transformTemplate }, visualState) {
|
||||
return React.useMemo(() => {
|
||||
const state = createHtmlRenderState();
|
||||
motionDom.buildHTMLStyles(state, visualState, transformTemplate);
|
||||
return Object.assign({}, state.vars, state.style);
|
||||
}, [visualState]);
|
||||
}
|
||||
function useStyle(props, visualState) {
|
||||
const styleProp = props.style || {};
|
||||
const style = {};
|
||||
/**
|
||||
* Copy non-Motion Values straight into style
|
||||
*/
|
||||
copyRawValuesOnly(style, styleProp, props);
|
||||
Object.assign(style, useInitialMotionValues(props, visualState));
|
||||
return style;
|
||||
}
|
||||
function useHTMLProps(props, visualState) {
|
||||
// The `any` isn't ideal but it is the type of createElement props argument
|
||||
const htmlProps = {};
|
||||
const style = useStyle(props, visualState);
|
||||
if (props.drag && props.dragListener !== false) {
|
||||
// Disable the ghost element when a user drags
|
||||
htmlProps.draggable = false;
|
||||
// Disable text selection
|
||||
style.userSelect =
|
||||
style.WebkitUserSelect =
|
||||
style.WebkitTouchCallout =
|
||||
"none";
|
||||
// Disable scrolling on the draggable direction
|
||||
style.touchAction =
|
||||
props.drag === true
|
||||
? "none"
|
||||
: `pan-${props.drag === "x" ? "y" : "x"}`;
|
||||
}
|
||||
if (props.tabIndex === undefined &&
|
||||
(props.onTap || props.onTapStart || props.whileTap)) {
|
||||
htmlProps.tabIndex = 0;
|
||||
}
|
||||
htmlProps.style = style;
|
||||
return htmlProps;
|
||||
}
|
||||
|
||||
const createSvgRenderState = () => ({
|
||||
...createHtmlRenderState(),
|
||||
attrs: {},
|
||||
});
|
||||
|
||||
function useSVGProps(props, visualState, _isStatic, Component) {
|
||||
const visualProps = React.useMemo(() => {
|
||||
const state = createSvgRenderState();
|
||||
motionDom.buildSVGAttrs(state, visualState, motionDom.isSVGTag(Component), props.transformTemplate, props.style);
|
||||
return {
|
||||
...state.attrs,
|
||||
style: { ...state.style },
|
||||
};
|
||||
}, [visualState]);
|
||||
if (props.style) {
|
||||
const rawStyles = {};
|
||||
copyRawValuesOnly(rawStyles, props.style, props);
|
||||
visualProps.style = { ...rawStyles, ...visualProps.style };
|
||||
}
|
||||
return visualProps;
|
||||
}
|
||||
|
||||
function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMotionProps = false, isSVG) {
|
||||
const useVisualProps = (isSVG ?? isSVGComponent(Component)) ? useSVGProps : useHTMLProps;
|
||||
const visualProps = useVisualProps(props, latestValues, isStatic, Component);
|
||||
const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
|
||||
const elementProps = Component !== React.Fragment ? { ...filteredProps, ...visualProps, ref } : {};
|
||||
/**
|
||||
* If component has been handed a motion value as its child,
|
||||
* memoise its initial value and render that. Subsequent updates
|
||||
* will be handled by the onChange handler
|
||||
*/
|
||||
const { children } = props;
|
||||
const renderedChildren = React.useMemo(() => (motionDom.isMotionValue(children) ? children.get() : children), [children]);
|
||||
return React.createElement(Component, {
|
||||
...elementProps,
|
||||
children: renderedChildren,
|
||||
});
|
||||
}
|
||||
|
||||
function makeState({ scrapeMotionValuesFromProps, createRenderState, }, props, context, presenceContext) {
|
||||
const state = {
|
||||
latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
|
||||
renderState: createRenderState(),
|
||||
};
|
||||
return state;
|
||||
}
|
||||
function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
|
||||
const values = {};
|
||||
const motionValues = scrapeMotionValues(props, {});
|
||||
for (const key in motionValues) {
|
||||
values[key] = motionDom.resolveMotionValue(motionValues[key]);
|
||||
}
|
||||
let { initial, animate } = props;
|
||||
const isControllingVariants = motionDom.isControllingVariants(props);
|
||||
const isVariantNode = motionDom.isVariantNode(props);
|
||||
if (context &&
|
||||
isVariantNode &&
|
||||
!isControllingVariants &&
|
||||
props.inherit !== false) {
|
||||
if (initial === undefined)
|
||||
initial = context.initial;
|
||||
if (animate === undefined)
|
||||
animate = context.animate;
|
||||
}
|
||||
let isInitialAnimationBlocked = presenceContext
|
||||
? presenceContext.initial === false
|
||||
: false;
|
||||
isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
|
||||
const variantToSet = isInitialAnimationBlocked ? animate : initial;
|
||||
if (variantToSet &&
|
||||
typeof variantToSet !== "boolean" &&
|
||||
!motionDom.isAnimationControls(variantToSet)) {
|
||||
const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const resolved = motionDom.resolveVariantFromProps(props, list[i]);
|
||||
if (resolved) {
|
||||
const { transitionEnd, transition, ...target } = resolved;
|
||||
for (const key in target) {
|
||||
let valueTarget = target[key];
|
||||
if (Array.isArray(valueTarget)) {
|
||||
/**
|
||||
* Take final keyframe if the initial animation is blocked because
|
||||
* we want to initialise at the end of that blocked animation.
|
||||
*/
|
||||
const index = isInitialAnimationBlocked
|
||||
? valueTarget.length - 1
|
||||
: 0;
|
||||
valueTarget = valueTarget[index];
|
||||
}
|
||||
if (valueTarget !== null) {
|
||||
values[key] = valueTarget;
|
||||
}
|
||||
}
|
||||
for (const key in transitionEnd) {
|
||||
values[key] = transitionEnd[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
const makeUseVisualState = (config) => (props, isStatic) => {
|
||||
const context = React.useContext(MotionContext);
|
||||
const presenceContext = React.useContext(PresenceContext);
|
||||
const make = () => makeState(config, props, context, presenceContext);
|
||||
return isStatic ? make() : useConstant(make);
|
||||
};
|
||||
|
||||
const useHTMLVisualState = /*@__PURE__*/ makeUseVisualState({
|
||||
scrapeMotionValuesFromProps: motionDom.scrapeHTMLMotionValuesFromProps,
|
||||
createRenderState: createHtmlRenderState,
|
||||
});
|
||||
|
||||
const useSVGVisualState = /*@__PURE__*/ makeUseVisualState({
|
||||
scrapeMotionValuesFromProps: motionDom.scrapeSVGMotionValuesFromProps,
|
||||
createRenderState: createSvgRenderState,
|
||||
});
|
||||
|
||||
const motionComponentSymbol = Symbol.for("motionComponentSymbol");
|
||||
|
||||
/**
|
||||
* Creates a ref function that, when called, hydrates the provided
|
||||
* external ref and VisualElement.
|
||||
*/
|
||||
function useMotionRef(visualState, visualElement, externalRef) {
|
||||
/**
|
||||
* Store externalRef in a ref to avoid including it in the useCallback
|
||||
* dependency array. Including externalRef in dependencies causes issues
|
||||
* with libraries like Radix UI that create new callback refs on each render
|
||||
* when using asChild - this would cause the callback to be recreated,
|
||||
* triggering element remounts and breaking AnimatePresence exit animations.
|
||||
*/
|
||||
const externalRefContainer = React.useRef(externalRef);
|
||||
React.useInsertionEffect(() => {
|
||||
externalRefContainer.current = externalRef;
|
||||
});
|
||||
// Store cleanup function returned by callback refs (React 19 feature)
|
||||
const refCleanup = React.useRef(null);
|
||||
return React.useCallback((instance) => {
|
||||
if (instance) {
|
||||
visualState.onMount?.(instance);
|
||||
}
|
||||
if (visualElement) {
|
||||
instance ? visualElement.mount(instance) : visualElement.unmount();
|
||||
}
|
||||
const ref = externalRefContainer.current;
|
||||
if (typeof ref === "function") {
|
||||
if (instance) {
|
||||
const cleanup = ref(instance);
|
||||
if (typeof cleanup === "function") {
|
||||
refCleanup.current = cleanup;
|
||||
}
|
||||
}
|
||||
else if (refCleanup.current) {
|
||||
refCleanup.current();
|
||||
refCleanup.current = null;
|
||||
}
|
||||
else {
|
||||
ref(instance);
|
||||
}
|
||||
}
|
||||
else if (ref) {
|
||||
ref.current = instance;
|
||||
}
|
||||
}, [visualElement]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, exported only for usage in Framer
|
||||
*/
|
||||
const SwitchLayoutGroupContext = React.createContext({});
|
||||
|
||||
function isRefObject(ref) {
|
||||
return (ref &&
|
||||
typeof ref === "object" &&
|
||||
Object.prototype.hasOwnProperty.call(ref, "current"));
|
||||
}
|
||||
|
||||
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor, isSVG) {
|
||||
const { visualElement: parent } = React.useContext(MotionContext);
|
||||
const lazyContext = React.useContext(LazyContext);
|
||||
const presenceContext = React.useContext(PresenceContext);
|
||||
const motionConfig = React.useContext(MotionConfigContext);
|
||||
const reducedMotionConfig = motionConfig.reducedMotion;
|
||||
const skipAnimations = motionConfig.skipAnimations;
|
||||
const visualElementRef = React.useRef(null);
|
||||
/**
|
||||
* Track whether the component has been through React's commit phase.
|
||||
* Used to detect when LazyMotion features load after the component has mounted.
|
||||
*/
|
||||
const hasMountedOnce = React.useRef(false);
|
||||
/**
|
||||
* If we haven't preloaded a renderer, check to see if we have one lazy-loaded
|
||||
*/
|
||||
createVisualElement =
|
||||
createVisualElement ||
|
||||
lazyContext.renderer;
|
||||
if (!visualElementRef.current && createVisualElement) {
|
||||
visualElementRef.current = createVisualElement(Component, {
|
||||
visualState,
|
||||
parent,
|
||||
props,
|
||||
presenceContext,
|
||||
blockInitialAnimation: presenceContext
|
||||
? presenceContext.initial === false
|
||||
: false,
|
||||
reducedMotionConfig,
|
||||
skipAnimations,
|
||||
isSVG,
|
||||
});
|
||||
/**
|
||||
* If the component has already mounted before features loaded (e.g. via
|
||||
* LazyMotion with async feature loading), we need to force the initial
|
||||
* animation to run. Otherwise state changes that occurred before features
|
||||
* loaded will be lost and the element will snap to its final state.
|
||||
*/
|
||||
if (hasMountedOnce.current && visualElementRef.current) {
|
||||
visualElementRef.current.manuallyAnimateOnMount = true;
|
||||
}
|
||||
}
|
||||
const visualElement = visualElementRef.current;
|
||||
/**
|
||||
* 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 = React.useContext(SwitchLayoutGroupContext);
|
||||
if (visualElement &&
|
||||
!visualElement.projection &&
|
||||
ProjectionNodeConstructor &&
|
||||
(visualElement.type === "html" || visualElement.type === "svg")) {
|
||||
createProjectionNode(visualElementRef.current, props, ProjectionNodeConstructor, initialLayoutGroupConfig);
|
||||
}
|
||||
const isMounted = React.useRef(false);
|
||||
React.useInsertionEffect(() => {
|
||||
/**
|
||||
* Check the component has already mounted before calling
|
||||
* `update` unnecessarily. This ensures we skip the initial update.
|
||||
*/
|
||||
if (visualElement && isMounted.current) {
|
||||
visualElement.update(props, presenceContext);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Cache this value as we want to know whether HandoffAppearAnimations
|
||||
* was present on initial render - it will be deleted after this.
|
||||
*/
|
||||
const optimisedAppearId = props[motionDom.optimizedAppearDataAttribute];
|
||||
const wantsHandoff = React.useRef(Boolean(optimisedAppearId) &&
|
||||
typeof window !== "undefined" &&
|
||||
!window.MotionHandoffIsComplete?.(optimisedAppearId) &&
|
||||
window.MotionHasOptimisedAnimation?.(optimisedAppearId));
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
/**
|
||||
* Track that this component has mounted. This is used to detect when
|
||||
* LazyMotion features load after the component has already committed.
|
||||
*/
|
||||
hasMountedOnce.current = true;
|
||||
if (!visualElement)
|
||||
return;
|
||||
isMounted.current = true;
|
||||
window.MotionIsMounted = true;
|
||||
visualElement.updateFeatures();
|
||||
visualElement.scheduleRenderMicrotask();
|
||||
/**
|
||||
* Ideally this function would always run in a useEffect.
|
||||
*
|
||||
* However, if we have optimised appear animations to handoff from,
|
||||
* it needs to happen synchronously to ensure there's no flash of
|
||||
* incorrect styles in the event of a hydration error.
|
||||
*
|
||||
* So if we detect a situtation where optimised appear animations
|
||||
* are running, we use useLayoutEffect to trigger animations.
|
||||
*/
|
||||
if (wantsHandoff.current && visualElement.animationState) {
|
||||
visualElement.animationState.animateChanges();
|
||||
}
|
||||
});
|
||||
React.useEffect(() => {
|
||||
if (!visualElement)
|
||||
return;
|
||||
if (!wantsHandoff.current && visualElement.animationState) {
|
||||
visualElement.animationState.animateChanges();
|
||||
}
|
||||
if (wantsHandoff.current) {
|
||||
// This ensures all future calls to animateChanges() in this component will run in useEffect
|
||||
queueMicrotask(() => {
|
||||
window.MotionHandoffMarkAsComplete?.(optimisedAppearId);
|
||||
});
|
||||
wantsHandoff.current = false;
|
||||
}
|
||||
/**
|
||||
* Now we've finished triggering animations for this element we
|
||||
* can wipe the enteringChildren set for the next render.
|
||||
*/
|
||||
visualElement.enteringChildren = undefined;
|
||||
});
|
||||
return visualElement;
|
||||
}
|
||||
function createProjectionNode(visualElement, props, ProjectionNodeConstructor, initialPromotionConfig) {
|
||||
const { layoutId, layout, drag, dragConstraints, layoutScroll, layoutRoot, layoutAnchor, layoutCrossfade, } = props;
|
||||
visualElement.projection = new ProjectionNodeConstructor(visualElement.latestValues, props["data-framer-portal-id"]
|
||||
? undefined
|
||||
: getClosestProjectingNode(visualElement.parent));
|
||||
visualElement.projection.setOptions({
|
||||
layoutId,
|
||||
layout,
|
||||
alwaysMeasureLayout: Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)),
|
||||
visualElement,
|
||||
/**
|
||||
* TODO: Update options in an effect. This could be tricky as it'll be too late
|
||||
* to update by the time layout animations run.
|
||||
* We also need to fix this safeToRemove by linking it up to the one returned by usePresence,
|
||||
* ensuring it gets called if there's no potential layout animations.
|
||||
*
|
||||
*/
|
||||
animationType: typeof layout === "string" ? layout : "both",
|
||||
initialPromotionConfig,
|
||||
crossfade: layoutCrossfade,
|
||||
layoutScroll,
|
||||
layoutRoot,
|
||||
layoutAnchor,
|
||||
});
|
||||
}
|
||||
function getClosestProjectingNode(visualElement) {
|
||||
if (!visualElement)
|
||||
return undefined;
|
||||
return visualElement.options.allowProjection !== false
|
||||
? visualElement.projection
|
||||
: getClosestProjectingNode(visualElement.parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(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(Component);
|
||||
const useVisualState = isSVG ? useSVGVisualState : 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),
|
||||
...props,
|
||||
layoutId: useLayoutId(props),
|
||||
};
|
||||
const { isStatic } = configAndProps;
|
||||
const context = 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(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(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsxRuntime.jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, 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[motionComponentSymbol] = Component;
|
||||
return ForwardRefMotionComponent;
|
||||
}
|
||||
function useLayoutId({ layoutId }) {
|
||||
const layoutGroupId = React.useContext(LayoutGroupContext).id;
|
||||
return layoutGroupId && layoutId !== undefined
|
||||
? layoutGroupId + "-" + layoutId
|
||||
: layoutId;
|
||||
}
|
||||
function useStrictMode(configAndProps, preloadedFeatures) {
|
||||
const isStrict = React.useContext(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
|
||||
? motionUtils.warning(false, strictMessage, "lazy-strict-mode")
|
||||
: motionUtils.invariant(false, strictMessage, "lazy-strict-mode");
|
||||
}
|
||||
}
|
||||
function getProjectionFunctionality(props) {
|
||||
const featureDefinitions = 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.LayoutGroupContext = LayoutGroupContext;
|
||||
exports.LazyContext = LazyContext;
|
||||
exports.MotionConfigContext = MotionConfigContext;
|
||||
exports.MotionContext = MotionContext;
|
||||
exports.PresenceContext = PresenceContext;
|
||||
exports.SwitchLayoutGroupContext = SwitchLayoutGroupContext;
|
||||
exports.createMotionComponent = createMotionComponent;
|
||||
exports.filterProps = filterProps;
|
||||
exports.isBrowser = isBrowser;
|
||||
exports.isRefObject = isRefObject;
|
||||
exports.isSVGComponent = isSVGComponent;
|
||||
exports.isValidMotionProp = isValidMotionProp;
|
||||
exports.loadExternalIsValidProp = loadExternalIsValidProp;
|
||||
exports.loadFeatures = loadFeatures;
|
||||
exports.makeUseVisualState = makeUseVisualState;
|
||||
exports.motionComponentSymbol = motionComponentSymbol;
|
||||
exports.useConstant = useConstant;
|
||||
exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
|
||||
//# sourceMappingURL=index-6W16WHlG.js.map
|
||||
Reference in New Issue
Block a user