framer-motion 12.23.28 → 12.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client.js +1 -1
- package/dist/cjs/dom.js +15 -0
- package/dist/cjs/dom.js.map +1 -1
- package/dist/cjs/{feature-bundle-Dt2VtvSZ.js → feature-bundle-DRMwxyzS.js} +45 -13
- package/dist/cjs/feature-bundle-DRMwxyzS.js.map +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/m.js +29 -11
- package/dist/cjs/m.js.map +1 -1
- package/dist/dom-mini.js +1 -1
- package/dist/dom.js +1 -1
- package/dist/es/components/Reorder/Group.mjs.map +1 -1
- package/dist/es/components/Reorder/Item.mjs.map +1 -1
- package/dist/es/gestures/drag/index.mjs +10 -0
- package/dist/es/gestures/drag/index.mjs.map +1 -1
- package/dist/es/motion/index.mjs +10 -6
- package/dist/es/motion/index.mjs.map +1 -1
- package/dist/es/motion/utils/use-visual-element.mjs +2 -1
- package/dist/es/motion/utils/use-visual-element.mjs.map +1 -1
- package/dist/es/render/dom/create-visual-element.mjs +5 -1
- package/dist/es/render/dom/create-visual-element.mjs.map +1 -1
- package/dist/es/render/dom/use-render.mjs +2 -4
- package/dist/es/render/dom/use-render.mjs.map +1 -1
- package/dist/es/render/svg/utils/build-attrs.mjs +15 -0
- package/dist/es/render/svg/utils/build-attrs.mjs.map +1 -1
- package/dist/framer-motion.dev.js +82 -34
- package/dist/framer-motion.js +1 -1
- package/dist/m.d.ts +8 -0
- package/dist/mini.js +1 -1
- package/dist/size-rollup-animate.js +1 -1
- package/dist/size-rollup-animate.js.map +1 -1
- package/dist/size-rollup-dom-animation-assets.js +1 -1
- package/dist/size-rollup-dom-animation-m.js +1 -1
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max-assets.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-m.js +1 -1
- package/dist/size-rollup-m.js.map +1 -1
- package/dist/size-rollup-motion.js +1 -1
- package/dist/size-rollup-motion.js.map +1 -1
- package/dist/size-rollup-scroll.js.map +1 -1
- package/dist/size-rollup-waapi-animate.js +1 -1
- package/dist/size-rollup-waapi-animate.js.map +1 -1
- package/dist/types/client.d.ts +1 -1
- package/dist/types/index.d.ts +13 -5
- package/dist/{types.d-C8SDx5n-.d.ts → types.d-a9pt5qxk.d.ts} +5 -0
- package/package.json +3 -3
- package/dist/cjs/feature-bundle-Dt2VtvSZ.js.map +0 -1
package/dist/es/motion/index.mjs
CHANGED
|
@@ -27,11 +27,15 @@ import { useVisualElement } from './utils/use-visual-element.mjs';
|
|
|
27
27
|
* Alongside this is a config option which provides a way of rendering the provided
|
|
28
28
|
* component "offline", or outside the React render cycle.
|
|
29
29
|
*/
|
|
30
|
-
function createMotionComponent(Component, { forwardMotionProps = false } = {}, preloadedFeatures, createVisualElement) {
|
|
30
|
+
function createMotionComponent(Component, { forwardMotionProps = false, type } = {}, preloadedFeatures, createVisualElement) {
|
|
31
31
|
preloadedFeatures && loadFeatures(preloadedFeatures);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Determine whether to use SVG or HTML rendering based on:
|
|
34
|
+
* 1. Explicit `type` option (highest priority)
|
|
35
|
+
* 2. Auto-detection via `isSVGComponent`
|
|
36
|
+
*/
|
|
37
|
+
const isSVG = type ? type === "svg" : isSVGComponent(Component);
|
|
38
|
+
const useVisualState = isSVG ? useSVGVisualState : useHTMLVisualState;
|
|
35
39
|
function MotionDOMComponent(props, externalRef) {
|
|
36
40
|
/**
|
|
37
41
|
* If we need to measure the element we load this functionality in a
|
|
@@ -56,13 +60,13 @@ function createMotionComponent(Component, { forwardMotionProps = false } = {}, p
|
|
|
56
60
|
* providing a way of rendering to these APIs outside of the React render loop
|
|
57
61
|
* for more performant animations and interactions
|
|
58
62
|
*/
|
|
59
|
-
context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode);
|
|
63
|
+
context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode, isSVG);
|
|
60
64
|
}
|
|
61
65
|
/**
|
|
62
66
|
* The mount order and hierarchy is specific to ensure our element ref
|
|
63
67
|
* is hydrated by the time features fire their effects.
|
|
64
68
|
*/
|
|
65
|
-
return (jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps)] }));
|
|
69
|
+
return (jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps, isSVG)] }));
|
|
66
70
|
}
|
|
67
71
|
MotionDOMComponent.displayName = `motion.${typeof Component === "string"
|
|
68
72
|
? Component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../../src/motion/index.tsx"],"sourcesContent":["\"use client\"\n\nimport { invariant, warning } from \"motion-utils\"\nimport * as React from \"react\"\nimport { forwardRef, useContext } from \"react\"\nimport { LayoutGroupContext } from \"../context/LayoutGroupContext\"\nimport { LazyContext } from \"../context/LazyContext\"\nimport { MotionConfigContext } from \"../context/MotionConfigContext\"\nimport { MotionContext } from \"../context/MotionContext\"\nimport { useCreateMotionContext } from \"../context/MotionContext/create\"\nimport { DOMMotionComponents } from \"../render/dom/types\"\nimport { useRender } from \"../render/dom/use-render\"\nimport { isSVGComponent } from \"../render/dom/utils/is-svg-component\"\nimport { HTMLRenderState } from \"../render/html/types\"\nimport { useHTMLVisualState } from \"../render/html/use-html-visual-state\"\nimport { SVGRenderState } from \"../render/svg/types\"\nimport { useSVGVisualState } from \"../render/svg/use-svg-visual-state\"\nimport { CreateVisualElement } from \"../render/types\"\nimport { isBrowser } from \"../utils/is-browser\"\nimport { featureDefinitions } from \"./features/definitions\"\nimport { loadFeatures } from \"./features/load-features\"\nimport { FeatureBundle, FeaturePackages } from \"./features/types\"\nimport { MotionProps } from \"./types\"\nimport { motionComponentSymbol } from \"./utils/symbol\"\nimport { useMotionRef } from \"./utils/use-motion-ref\"\nimport { useVisualElement } from \"./utils/use-visual-element\"\n\nexport interface MotionComponentConfig<\n TagName extends keyof DOMMotionComponents | string = \"div\"\n> {\n preloadedFeatures?: FeatureBundle\n createVisualElement?: CreateVisualElement\n Component: TagName | React.ComponentType<React.PropsWithChildren<unknown>>\n forwardMotionProps?: boolean\n}\n\nexport type MotionComponentProps<Props> = {\n [K in Exclude<keyof Props, keyof MotionProps>]?: Props[K]\n} & MotionProps\n\nexport type MotionComponent<T, P> = T extends keyof DOMMotionComponents\n ? DOMMotionComponents[T]\n : React.ComponentType<\n Omit<MotionComponentProps<P>, \"children\"> & {\n children?: \"children\" extends keyof P\n ? P[\"children\"] | MotionComponentProps<P>[\"children\"]\n : MotionComponentProps<P>[\"children\"]\n }\n >\n\nexport interface MotionComponentOptions {\n forwardMotionProps?: boolean\n}\n\n/**\n * Create a `motion` component.\n *\n * This function accepts a Component argument, which can be either a string (ie \"div\"\n * for `motion.div`), or an actual React component.\n *\n * Alongside this is a config option which provides a way of rendering the provided\n * component \"offline\", or outside the React render cycle.\n */\nexport function createMotionComponent<\n Props,\n TagName extends keyof DOMMotionComponents | string = \"div\"\n>(\n Component: TagName | string | React.ComponentType<Props>,\n { forwardMotionProps = false }: MotionComponentOptions = {},\n preloadedFeatures?: FeaturePackages,\n createVisualElement?: CreateVisualElement<Props, TagName>\n) {\n preloadedFeatures && loadFeatures(preloadedFeatures)\n\n const
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../../src/motion/index.tsx"],"sourcesContent":["\"use client\"\n\nimport { invariant, warning } from \"motion-utils\"\nimport * as React from \"react\"\nimport { forwardRef, useContext } from \"react\"\nimport { LayoutGroupContext } from \"../context/LayoutGroupContext\"\nimport { LazyContext } from \"../context/LazyContext\"\nimport { MotionConfigContext } from \"../context/MotionConfigContext\"\nimport { MotionContext } from \"../context/MotionContext\"\nimport { useCreateMotionContext } from \"../context/MotionContext/create\"\nimport { DOMMotionComponents } from \"../render/dom/types\"\nimport { useRender } from \"../render/dom/use-render\"\nimport { isSVGComponent } from \"../render/dom/utils/is-svg-component\"\nimport { HTMLRenderState } from \"../render/html/types\"\nimport { useHTMLVisualState } from \"../render/html/use-html-visual-state\"\nimport { SVGRenderState } from \"../render/svg/types\"\nimport { useSVGVisualState } from \"../render/svg/use-svg-visual-state\"\nimport { CreateVisualElement } from \"../render/types\"\nimport { isBrowser } from \"../utils/is-browser\"\nimport { featureDefinitions } from \"./features/definitions\"\nimport { loadFeatures } from \"./features/load-features\"\nimport { FeatureBundle, FeaturePackages } from \"./features/types\"\nimport { MotionProps } from \"./types\"\nimport { motionComponentSymbol } from \"./utils/symbol\"\nimport { useMotionRef } from \"./utils/use-motion-ref\"\nimport { useVisualElement } from \"./utils/use-visual-element\"\n\nexport interface MotionComponentConfig<\n TagName extends keyof DOMMotionComponents | string = \"div\"\n> {\n preloadedFeatures?: FeatureBundle\n createVisualElement?: CreateVisualElement\n Component: TagName | React.ComponentType<React.PropsWithChildren<unknown>>\n forwardMotionProps?: boolean\n}\n\nexport type MotionComponentProps<Props> = {\n [K in Exclude<keyof Props, keyof MotionProps>]?: Props[K]\n} & MotionProps\n\nexport type MotionComponent<T, P> = T extends keyof DOMMotionComponents\n ? DOMMotionComponents[T]\n : React.ComponentType<\n Omit<MotionComponentProps<P>, \"children\"> & {\n children?: \"children\" extends keyof P\n ? P[\"children\"] | MotionComponentProps<P>[\"children\"]\n : MotionComponentProps<P>[\"children\"]\n }\n >\n\nexport interface MotionComponentOptions {\n forwardMotionProps?: boolean\n /**\n * Specify whether the component renders an HTML or SVG element.\n * This is useful when wrapping custom SVG components that need\n * SVG-specific attribute handling (like viewBox animation).\n * By default, Motion auto-detects based on the component name,\n * but custom React components are always treated as HTML.\n */\n type?: \"html\" | \"svg\"\n}\n\n/**\n * Create a `motion` component.\n *\n * This function accepts a Component argument, which can be either a string (ie \"div\"\n * for `motion.div`), or an actual React component.\n *\n * Alongside this is a config option which provides a way of rendering the provided\n * component \"offline\", or outside the React render cycle.\n */\nexport function createMotionComponent<\n Props,\n TagName extends keyof DOMMotionComponents | string = \"div\"\n>(\n Component: TagName | string | React.ComponentType<Props>,\n { forwardMotionProps = false, type }: MotionComponentOptions = {},\n preloadedFeatures?: FeaturePackages,\n createVisualElement?: CreateVisualElement<Props, TagName>\n) {\n preloadedFeatures && loadFeatures(preloadedFeatures)\n\n /**\n * Determine whether to use SVG or HTML rendering based on:\n * 1. Explicit `type` option (highest priority)\n * 2. Auto-detection via `isSVGComponent`\n */\n const isSVG = type ? type === \"svg\" : isSVGComponent(Component)\n const useVisualState = isSVG ? useSVGVisualState : useHTMLVisualState\n\n function MotionDOMComponent(\n props: MotionComponentProps<Props>,\n externalRef?: React.Ref<HTMLElement | SVGElement>\n ) {\n /**\n * If we need to measure the element we load this functionality in a\n * separate class component in order to gain access to getSnapshotBeforeUpdate.\n */\n let MeasureLayout: undefined | React.ComponentType<MotionProps>\n\n const configAndProps = {\n ...useContext(MotionConfigContext),\n ...props,\n layoutId: useLayoutId(props),\n }\n\n const { isStatic } = configAndProps\n\n const context = useCreateMotionContext<HTMLElement | SVGElement>(props)\n\n const visualState = useVisualState(props, isStatic)\n\n if (!isStatic && isBrowser) {\n useStrictMode(configAndProps, preloadedFeatures)\n\n const layoutProjection = getProjectionFunctionality(configAndProps)\n MeasureLayout = layoutProjection.MeasureLayout\n\n /**\n * Create a VisualElement for this component. A VisualElement provides a common\n * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as\n * providing a way of rendering to these APIs outside of the React render loop\n * for more performant animations and interactions\n */\n context.visualElement = useVisualElement(\n Component,\n visualState,\n configAndProps,\n createVisualElement,\n layoutProjection.ProjectionNode,\n isSVG\n )\n }\n\n /**\n * The mount order and hierarchy is specific to ensure our element ref\n * is hydrated by the time features fire their effects.\n */\n return (\n <MotionContext.Provider value={context}>\n {MeasureLayout && context.visualElement ? (\n <MeasureLayout\n visualElement={context.visualElement}\n {...configAndProps}\n />\n ) : null}\n {useRender<Props, TagName>(\n Component,\n props,\n useMotionRef<\n HTMLElement | SVGElement,\n HTMLRenderState | SVGRenderState\n >(visualState, context.visualElement, externalRef),\n visualState,\n isStatic,\n forwardMotionProps,\n isSVG\n )}\n </MotionContext.Provider>\n )\n }\n\n MotionDOMComponent.displayName = `motion.${\n typeof Component === \"string\"\n ? Component\n : `create(${Component.displayName ?? Component.name ?? \"\"})`\n }`\n\n const ForwardRefMotionComponent = forwardRef(MotionDOMComponent as any)\n ;(ForwardRefMotionComponent as any)[motionComponentSymbol] = Component\n\n return ForwardRefMotionComponent as MotionComponent<TagName, Props>\n}\n\nfunction useLayoutId({ layoutId }: MotionProps) {\n const layoutGroupId = useContext(LayoutGroupContext).id\n return layoutGroupId && layoutId !== undefined\n ? layoutGroupId + \"-\" + layoutId\n : layoutId\n}\n\nfunction useStrictMode(\n configAndProps: MotionProps,\n preloadedFeatures?: FeaturePackages\n) {\n const isStrict = useContext(LazyContext).strict\n\n /**\n * If we're in development mode, check to make sure we're not rendering a motion component\n * as a child of LazyMotion, as this will break the file-size benefits of using it.\n */\n if (\n process.env.NODE_ENV !== \"production\" &&\n preloadedFeatures &&\n isStrict\n ) {\n const strictMessage =\n \"You have rendered a `motion` component within a `LazyMotion` component. This will break tree shaking. Import and render a `m` component instead.\"\n configAndProps.ignoreStrict\n ? warning(false, strictMessage, \"lazy-strict-mode\")\n : invariant(false, strictMessage, \"lazy-strict-mode\")\n }\n}\n\nfunction getProjectionFunctionality(props: MotionProps) {\n const { drag, layout } = featureDefinitions\n\n if (!drag && !layout) return {}\n\n const combined = { ...drag, ...layout }\n\n return {\n MeasureLayout:\n drag?.isEnabled(props) || layout?.isEnabled(props)\n ? combined.MeasureLayout\n : undefined,\n ProjectionNode: combined.ProjectionNode,\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8DA;;;;;;;;AAQG;;AAUC;AAEA;;;;AAIG;AACH;;AAGA;AAII;;;AAGG;AACH;AAEA;;AAEI;AACA;;AAGJ;AAEA;;AAIA;AACI;AAEA;AACA;AAEA;;;;;AAKG;AACH;;AAUJ;;;AAGG;AACH;;AAwBJ;AAEQ;AACA;AAGR;AACE;AAEF;AACJ;AAEA;;AAEI;AACI;;AAER;AAEA;;AAMI;;;AAGG;AACH;;AAGI;;AAIA;;;;AAIR;AAEA;AACI;AAEA;AAAsB;;;AAKlB;;AAGQ;;;AAGhB;;"}
|
|
@@ -9,7 +9,7 @@ import { SwitchLayoutGroupContext } from '../../context/SwitchLayoutGroupContext
|
|
|
9
9
|
import { isRefObject } from '../../utils/is-ref-object.mjs';
|
|
10
10
|
import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
|
|
11
11
|
|
|
12
|
-
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor) {
|
|
12
|
+
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor, isSVG) {
|
|
13
13
|
const { visualElement: parent } = useContext(MotionContext);
|
|
14
14
|
const lazyContext = useContext(LazyContext);
|
|
15
15
|
const presenceContext = useContext(PresenceContext);
|
|
@@ -31,6 +31,7 @@ function useVisualElement(Component, visualState, props, createVisualElement, Pr
|
|
|
31
31
|
? presenceContext.initial === false
|
|
32
32
|
: false,
|
|
33
33
|
reducedMotionConfig,
|
|
34
|
+
isSVG,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
const visualElement = visualElementRef.current;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-visual-element.mjs","sources":["../../../../src/motion/utils/use-visual-element.ts"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { useContext, useEffect, useInsertionEffect, useRef } from \"react\"\nimport { optimizedAppearDataAttribute } from \"../../animation/optimized-appear/data-id\"\nimport { LazyContext } from \"../../context/LazyContext\"\nimport { MotionConfigContext } from \"../../context/MotionConfigContext\"\nimport { MotionContext } from \"../../context/MotionContext\"\nimport { PresenceContext } from \"../../context/PresenceContext\"\nimport {\n InitialPromotionConfig,\n SwitchLayoutGroupContext,\n} from \"../../context/SwitchLayoutGroupContext\"\nimport { MotionProps } from \"../../motion/types\"\nimport { IProjectionNode } from \"../../projection/node/types\"\nimport { DOMMotionComponents } from \"../../render/dom/types\"\nimport { HTMLRenderState } from \"../../render/html/types\"\nimport { SVGRenderState } from \"../../render/svg/types\"\nimport { CreateVisualElement } from \"../../render/types\"\nimport type { VisualElement } from \"../../render/VisualElement\"\nimport { isRefObject } from \"../../utils/is-ref-object\"\nimport { useIsomorphicLayoutEffect } from \"../../utils/use-isomorphic-effect\"\nimport { VisualState } from \"./use-visual-state\"\n\nexport function useVisualElement<\n Props,\n TagName extends keyof DOMMotionComponents | string\n>(\n Component: TagName | string | React.ComponentType<Props>,\n visualState:\n | VisualState<SVGElement, SVGRenderState>\n | VisualState<HTMLElement, HTMLRenderState>,\n props: MotionProps & Partial<MotionConfigContext>,\n createVisualElement?: CreateVisualElement<Props, TagName>,\n ProjectionNodeConstructor?: any\n): VisualElement<HTMLElement | SVGElement> | undefined {\n const { visualElement: parent } = useContext(MotionContext)\n const lazyContext = useContext(LazyContext)\n const presenceContext = useContext(PresenceContext)\n const reducedMotionConfig = useContext(MotionConfigContext).reducedMotion\n\n const visualElementRef = useRef<VisualElement<\n HTMLElement | SVGElement\n > | null>(null)\n\n /**\n * If we haven't preloaded a renderer, check to see if we have one lazy-loaded\n */\n createVisualElement =\n createVisualElement ||\n (lazyContext.renderer as CreateVisualElement<Props, TagName>)\n\n if (!visualElementRef.current && createVisualElement) {\n visualElementRef.current = createVisualElement(Component, {\n visualState,\n parent,\n props,\n presenceContext,\n blockInitialAnimation: presenceContext\n ? presenceContext.initial === false\n : false,\n reducedMotionConfig,\n })\n }\n\n const visualElement = visualElementRef.current\n\n /**\n * Load Motion gesture and animation features. These are rendered as renderless\n * components so each feature can optionally make use of React lifecycle methods.\n */\n const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext)\n\n if (\n visualElement &&\n !visualElement.projection &&\n ProjectionNodeConstructor &&\n (visualElement.type === \"html\" || visualElement.type === \"svg\")\n ) {\n createProjectionNode(\n visualElementRef.current!,\n props,\n ProjectionNodeConstructor,\n initialLayoutGroupConfig\n )\n }\n\n const isMounted = useRef(false)\n useInsertionEffect(() => {\n /**\n * Check the component has already mounted before calling\n * `update` unnecessarily. This ensures we skip the initial update.\n */\n if (visualElement && isMounted.current) {\n visualElement.update(props, presenceContext)\n }\n })\n\n /**\n * Cache this value as we want to know whether HandoffAppearAnimations\n * was present on initial render - it will be deleted after this.\n */\n const optimisedAppearId =\n props[optimizedAppearDataAttribute as keyof typeof props]\n const wantsHandoff = useRef(\n Boolean(optimisedAppearId) &&\n !window.MotionHandoffIsComplete?.(optimisedAppearId) &&\n window.MotionHasOptimisedAnimation?.(optimisedAppearId)\n )\n\n useIsomorphicLayoutEffect(() => {\n if (!visualElement) return\n\n isMounted.current = true\n window.MotionIsMounted = true\n\n visualElement.updateFeatures()\n visualElement.scheduleRenderMicrotask()\n\n /**\n * Ideally this function would always run in a useEffect.\n *\n * However, if we have optimised appear animations to handoff from,\n * it needs to happen synchronously to ensure there's no flash of\n * incorrect styles in the event of a hydration error.\n *\n * So if we detect a situtation where optimised appear animations\n * are running, we use useLayoutEffect to trigger animations.\n */\n if (wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges()\n }\n })\n\n useEffect(() => {\n if (!visualElement) return\n\n if (!wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges()\n }\n\n if (wantsHandoff.current) {\n // This ensures all future calls to animateChanges() in this component will run in useEffect\n queueMicrotask(() => {\n window.MotionHandoffMarkAsComplete?.(optimisedAppearId)\n })\n\n wantsHandoff.current = false\n }\n\n /**\n * Now we've finished triggering animations for this element we\n * can wipe the enteringChildren set for the next render.\n */\n visualElement.enteringChildren = undefined\n })\n\n return visualElement!\n}\n\nfunction createProjectionNode(\n visualElement: VisualElement<any>,\n props: MotionProps,\n ProjectionNodeConstructor: any,\n initialPromotionConfig?: InitialPromotionConfig\n) {\n const {\n layoutId,\n layout,\n drag,\n dragConstraints,\n layoutScroll,\n layoutRoot,\n layoutCrossfade,\n } = props\n\n visualElement.projection = new ProjectionNodeConstructor(\n visualElement.latestValues,\n props[\"data-framer-portal-id\"]\n ? undefined\n : getClosestProjectingNode(visualElement.parent)\n ) as IProjectionNode\n\n visualElement.projection.setOptions({\n layoutId,\n layout,\n alwaysMeasureLayout:\n Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)),\n visualElement,\n /**\n * TODO: Update options in an effect. This could be tricky as it'll be too late\n * to update by the time layout animations run.\n * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,\n * ensuring it gets called if there's no potential layout animations.\n *\n */\n animationType: typeof layout === \"string\" ? layout : \"both\",\n initialPromotionConfig,\n crossfade: layoutCrossfade,\n layoutScroll,\n layoutRoot,\n })\n}\n\nfunction getClosestProjectingNode(\n visualElement?: VisualElement<\n unknown,\n unknown,\n { allowProjection?: boolean }\n >\n): IProjectionNode | undefined {\n if (!visualElement) return undefined\n\n return visualElement.options.allowProjection !== false\n ? visualElement.projection\n : getClosestProjectingNode(visualElement.parent)\n}\n"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"use-visual-element.mjs","sources":["../../../../src/motion/utils/use-visual-element.ts"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { useContext, useEffect, useInsertionEffect, useRef } from \"react\"\nimport { optimizedAppearDataAttribute } from \"../../animation/optimized-appear/data-id\"\nimport { LazyContext } from \"../../context/LazyContext\"\nimport { MotionConfigContext } from \"../../context/MotionConfigContext\"\nimport { MotionContext } from \"../../context/MotionContext\"\nimport { PresenceContext } from \"../../context/PresenceContext\"\nimport {\n InitialPromotionConfig,\n SwitchLayoutGroupContext,\n} from \"../../context/SwitchLayoutGroupContext\"\nimport { MotionProps } from \"../../motion/types\"\nimport { IProjectionNode } from \"../../projection/node/types\"\nimport { DOMMotionComponents } from \"../../render/dom/types\"\nimport { HTMLRenderState } from \"../../render/html/types\"\nimport { SVGRenderState } from \"../../render/svg/types\"\nimport { CreateVisualElement } from \"../../render/types\"\nimport type { VisualElement } from \"../../render/VisualElement\"\nimport { isRefObject } from \"../../utils/is-ref-object\"\nimport { useIsomorphicLayoutEffect } from \"../../utils/use-isomorphic-effect\"\nimport { VisualState } from \"./use-visual-state\"\n\nexport function useVisualElement<\n Props,\n TagName extends keyof DOMMotionComponents | string\n>(\n Component: TagName | string | React.ComponentType<Props>,\n visualState:\n | VisualState<SVGElement, SVGRenderState>\n | VisualState<HTMLElement, HTMLRenderState>,\n props: MotionProps & Partial<MotionConfigContext>,\n createVisualElement?: CreateVisualElement<Props, TagName>,\n ProjectionNodeConstructor?: any,\n isSVG?: boolean\n): VisualElement<HTMLElement | SVGElement> | undefined {\n const { visualElement: parent } = useContext(MotionContext)\n const lazyContext = useContext(LazyContext)\n const presenceContext = useContext(PresenceContext)\n const reducedMotionConfig = useContext(MotionConfigContext).reducedMotion\n\n const visualElementRef = useRef<VisualElement<\n HTMLElement | SVGElement\n > | null>(null)\n\n /**\n * If we haven't preloaded a renderer, check to see if we have one lazy-loaded\n */\n createVisualElement =\n createVisualElement ||\n (lazyContext.renderer as CreateVisualElement<Props, TagName>)\n\n if (!visualElementRef.current && createVisualElement) {\n visualElementRef.current = createVisualElement(Component, {\n visualState,\n parent,\n props,\n presenceContext,\n blockInitialAnimation: presenceContext\n ? presenceContext.initial === false\n : false,\n reducedMotionConfig,\n isSVG,\n })\n }\n\n const visualElement = visualElementRef.current\n\n /**\n * Load Motion gesture and animation features. These are rendered as renderless\n * components so each feature can optionally make use of React lifecycle methods.\n */\n const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext)\n\n if (\n visualElement &&\n !visualElement.projection &&\n ProjectionNodeConstructor &&\n (visualElement.type === \"html\" || visualElement.type === \"svg\")\n ) {\n createProjectionNode(\n visualElementRef.current!,\n props,\n ProjectionNodeConstructor,\n initialLayoutGroupConfig\n )\n }\n\n const isMounted = useRef(false)\n useInsertionEffect(() => {\n /**\n * Check the component has already mounted before calling\n * `update` unnecessarily. This ensures we skip the initial update.\n */\n if (visualElement && isMounted.current) {\n visualElement.update(props, presenceContext)\n }\n })\n\n /**\n * Cache this value as we want to know whether HandoffAppearAnimations\n * was present on initial render - it will be deleted after this.\n */\n const optimisedAppearId =\n props[optimizedAppearDataAttribute as keyof typeof props]\n const wantsHandoff = useRef(\n Boolean(optimisedAppearId) &&\n !window.MotionHandoffIsComplete?.(optimisedAppearId) &&\n window.MotionHasOptimisedAnimation?.(optimisedAppearId)\n )\n\n useIsomorphicLayoutEffect(() => {\n if (!visualElement) return\n\n isMounted.current = true\n window.MotionIsMounted = true\n\n visualElement.updateFeatures()\n visualElement.scheduleRenderMicrotask()\n\n /**\n * Ideally this function would always run in a useEffect.\n *\n * However, if we have optimised appear animations to handoff from,\n * it needs to happen synchronously to ensure there's no flash of\n * incorrect styles in the event of a hydration error.\n *\n * So if we detect a situtation where optimised appear animations\n * are running, we use useLayoutEffect to trigger animations.\n */\n if (wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges()\n }\n })\n\n useEffect(() => {\n if (!visualElement) return\n\n if (!wantsHandoff.current && visualElement.animationState) {\n visualElement.animationState.animateChanges()\n }\n\n if (wantsHandoff.current) {\n // This ensures all future calls to animateChanges() in this component will run in useEffect\n queueMicrotask(() => {\n window.MotionHandoffMarkAsComplete?.(optimisedAppearId)\n })\n\n wantsHandoff.current = false\n }\n\n /**\n * Now we've finished triggering animations for this element we\n * can wipe the enteringChildren set for the next render.\n */\n visualElement.enteringChildren = undefined\n })\n\n return visualElement!\n}\n\nfunction createProjectionNode(\n visualElement: VisualElement<any>,\n props: MotionProps,\n ProjectionNodeConstructor: any,\n initialPromotionConfig?: InitialPromotionConfig\n) {\n const {\n layoutId,\n layout,\n drag,\n dragConstraints,\n layoutScroll,\n layoutRoot,\n layoutCrossfade,\n } = props\n\n visualElement.projection = new ProjectionNodeConstructor(\n visualElement.latestValues,\n props[\"data-framer-portal-id\"]\n ? undefined\n : getClosestProjectingNode(visualElement.parent)\n ) as IProjectionNode\n\n visualElement.projection.setOptions({\n layoutId,\n layout,\n alwaysMeasureLayout:\n Boolean(drag) || (dragConstraints && isRefObject(dragConstraints)),\n visualElement,\n /**\n * TODO: Update options in an effect. This could be tricky as it'll be too late\n * to update by the time layout animations run.\n * We also need to fix this safeToRemove by linking it up to the one returned by usePresence,\n * ensuring it gets called if there's no potential layout animations.\n *\n */\n animationType: typeof layout === \"string\" ? layout : \"both\",\n initialPromotionConfig,\n crossfade: layoutCrossfade,\n layoutScroll,\n layoutRoot,\n })\n}\n\nfunction getClosestProjectingNode(\n visualElement?: VisualElement<\n unknown,\n unknown,\n { allowProjection?: boolean }\n >\n): IProjectionNode | undefined {\n if (!visualElement) return undefined\n\n return visualElement.options.allowProjection !== false\n ? visualElement.projection\n : getClosestProjectingNode(visualElement.parent)\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAwBgB;;AAcZ;AACA;;AAGA;AAIA;;AAEG;;;;AAKH;AACI;;;;;AAKI;AACI;AACA;;;AAGP;;AAGL;AAEA;;;AAGG;AACH;AAEA;;;AAII;;;AAUJ;;AAEI;;;AAGG;AACH;AACI;;AAER;AAEA;;;AAGG;AACH;AAEA;AAEQ;AACA;;AAIJ;;AAEA;AACA;;;AAKA;;;;;;;;;AASG;;AAEC;;AAER;;AAGI;;;AAGI;;AAGJ;;;AAGQ;AACJ;AAEA;;AAGJ;;;AAGG;AACH;AACJ;AAEA;AACJ;AAEA;AAMI;AAUA;AAGQ;;AAIR;;;AAGI;;AAGA;;;;;;AAMG;AACH;;AAEA;;;AAGH;AACL;AAEA;AAOI;AAAoB;AAEpB;;AAEI;AACR;;"}
|
|
@@ -4,7 +4,11 @@ import { SVGVisualElement } from '../svg/SVGVisualElement.mjs';
|
|
|
4
4
|
import { isSVGComponent } from './utils/is-svg-component.mjs';
|
|
5
5
|
|
|
6
6
|
const createDomVisualElement = (Component, options) => {
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Use explicit isSVG override if provided, otherwise auto-detect
|
|
9
|
+
*/
|
|
10
|
+
const isSVG = options.isSVG ?? isSVGComponent(Component);
|
|
11
|
+
return isSVG
|
|
8
12
|
? new SVGVisualElement(options)
|
|
9
13
|
: new HTMLVisualElement(options, {
|
|
10
14
|
allowProjection: Component !== Fragment,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-visual-element.mjs","sources":["../../../../src/render/dom/create-visual-element.ts"],"sourcesContent":["import { ComponentType, Fragment } from \"react\"\nimport { HTMLVisualElement } from \"../html/HTMLVisualElement\"\nimport { SVGVisualElement } from \"../svg/SVGVisualElement\"\nimport { CreateVisualElement, VisualElementOptions } from \"../types\"\nimport { isSVGComponent } from \"./utils/is-svg-component\"\n\nexport const createDomVisualElement: CreateVisualElement = (\n Component: string | ComponentType<React.PropsWithChildren<unknown>>,\n options: VisualElementOptions<HTMLElement | SVGElement>\n) => {\n
|
|
1
|
+
{"version":3,"file":"create-visual-element.mjs","sources":["../../../../src/render/dom/create-visual-element.ts"],"sourcesContent":["import { ComponentType, Fragment } from \"react\"\nimport { HTMLVisualElement } from \"../html/HTMLVisualElement\"\nimport { SVGVisualElement } from \"../svg/SVGVisualElement\"\nimport { CreateVisualElement, VisualElementOptions } from \"../types\"\nimport { isSVGComponent } from \"./utils/is-svg-component\"\n\nexport const createDomVisualElement: CreateVisualElement = (\n Component: string | ComponentType<React.PropsWithChildren<unknown>>,\n options: VisualElementOptions<HTMLElement | SVGElement>\n) => {\n /**\n * Use explicit isSVG override if provided, otherwise auto-detect\n */\n const isSVG = options.isSVG ?? isSVGComponent(Component)\n\n return isSVG\n ? new SVGVisualElement(options)\n : new HTMLVisualElement(options, {\n allowProjection: Component !== Fragment,\n })\n}\n"],"names":[],"mappings":";;;;;MAMa,sBAAsB,GAAwB,CACvD,SAAmE,EACnE,OAAuD,KACvD;AACA;;AAEG;IACH,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC,SAAS,CAAC,CAAA;AAExD,IAAA,OAAO,KAAK;AACR,UAAE,IAAI,gBAAgB,CAAC,OAAO,CAAC;AAC/B,UAAE,IAAI,iBAAiB,CAAC,OAAO,EAAE;YAC3B,eAAe,EAAE,SAAS,KAAK,QAAQ;AAC1C,SAAA,CAAC,CAAA;AACZ;;;;"}
|
|
@@ -6,10 +6,8 @@ import { useSVGProps } from '../svg/use-props.mjs';
|
|
|
6
6
|
import { filterProps } from './utils/filter-props.mjs';
|
|
7
7
|
import { isSVGComponent } from './utils/is-svg-component.mjs';
|
|
8
8
|
|
|
9
|
-
function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMotionProps = false) {
|
|
10
|
-
const useVisualProps = isSVGComponent(Component)
|
|
11
|
-
? useSVGProps
|
|
12
|
-
: useHTMLProps;
|
|
9
|
+
function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMotionProps = false, isSVG) {
|
|
10
|
+
const useVisualProps = (isSVG ?? isSVGComponent(Component)) ? useSVGProps : useHTMLProps;
|
|
13
11
|
const visualProps = useVisualProps(props, latestValues, isStatic, Component);
|
|
14
12
|
const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
|
|
15
13
|
const elementProps = Component !== Fragment ? { ...filteredProps, ...visualProps, ref } : {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-render.mjs","sources":["../../../../src/render/dom/use-render.ts"],"sourcesContent":["\"use client\"\n\nimport { isMotionValue } from \"motion-dom\"\nimport { Fragment, createElement, useMemo } from \"react\"\nimport { MotionProps } from \"../../motion/types\"\nimport { VisualState } from \"../../motion/utils/use-visual-state\"\nimport { HTMLRenderState } from \"../html/types\"\nimport { useHTMLProps } from \"../html/use-props\"\nimport { SVGRenderState } from \"../svg/types\"\nimport { useSVGProps } from \"../svg/use-props\"\nimport { DOMMotionComponents } from \"./types\"\nimport { filterProps } from \"./utils/filter-props\"\nimport { isSVGComponent } from \"./utils/is-svg-component\"\n\nexport function useRender<\n Props = {},\n TagName extends keyof DOMMotionComponents | string = \"div\"\n>(\n Component: TagName | string | React.ComponentType<Props>,\n props: MotionProps,\n ref: React.Ref<HTMLElement | SVGElement>,\n {\n latestValues,\n }: VisualState<HTMLElement | SVGElement, HTMLRenderState | SVGRenderState>,\n isStatic: boolean,\n forwardMotionProps: boolean = false\n) {\n const useVisualProps
|
|
1
|
+
{"version":3,"file":"use-render.mjs","sources":["../../../../src/render/dom/use-render.ts"],"sourcesContent":["\"use client\"\n\nimport { isMotionValue } from \"motion-dom\"\nimport { Fragment, createElement, useMemo } from \"react\"\nimport { MotionProps } from \"../../motion/types\"\nimport { VisualState } from \"../../motion/utils/use-visual-state\"\nimport { HTMLRenderState } from \"../html/types\"\nimport { useHTMLProps } from \"../html/use-props\"\nimport { SVGRenderState } from \"../svg/types\"\nimport { useSVGProps } from \"../svg/use-props\"\nimport { DOMMotionComponents } from \"./types\"\nimport { filterProps } from \"./utils/filter-props\"\nimport { isSVGComponent } from \"./utils/is-svg-component\"\n\nexport function useRender<\n Props = {},\n TagName extends keyof DOMMotionComponents | string = \"div\"\n>(\n Component: TagName | string | React.ComponentType<Props>,\n props: MotionProps,\n ref: React.Ref<HTMLElement | SVGElement>,\n {\n latestValues,\n }: VisualState<HTMLElement | SVGElement, HTMLRenderState | SVGRenderState>,\n isStatic: boolean,\n forwardMotionProps: boolean = false,\n isSVG?: boolean\n) {\n const useVisualProps =\n (isSVG ?? isSVGComponent(Component)) ? useSVGProps : useHTMLProps\n\n const visualProps = useVisualProps(\n props as any,\n latestValues,\n isStatic,\n Component as any\n )\n const filteredProps = filterProps(\n props,\n typeof Component === \"string\",\n forwardMotionProps\n )\n const elementProps =\n Component !== Fragment ? { ...filteredProps, ...visualProps, ref } : {}\n\n /**\n * If component has been handed a motion value as its child,\n * memoise its initial value and render that. Subsequent updates\n * will be handled by the onChange handler\n */\n const { children } = props\n const renderedChildren = useMemo(\n () => (isMotionValue(children) ? children.get() : children),\n [children]\n )\n\n return createElement<any>(Component, {\n ...elementProps,\n children: renderedChildren,\n })\n}\n"],"names":[],"mappings":";;;;;;;;;AA4BI;AAGA;AAMA;;AAQA;;;;AAIG;AACH;AACA;;AAMI;AACA;AACH;AACL;;"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { buildHTMLStyles } from '../../html/utils/build-styles.mjs';
|
|
2
2
|
import { buildSVGPath } from './path.mjs';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* CSS Motion Path properties that should remain as CSS styles on SVG elements.
|
|
6
|
+
*/
|
|
7
|
+
const cssMotionPathProperties = [
|
|
8
|
+
"offsetDistance",
|
|
9
|
+
"offsetPath",
|
|
10
|
+
"offsetRotate",
|
|
11
|
+
"offsetAnchor",
|
|
12
|
+
];
|
|
4
13
|
/**
|
|
5
14
|
* Build SVG visual attributes, like cx and style.transform
|
|
6
15
|
*/
|
|
@@ -41,6 +50,12 @@ function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing
|
|
|
41
50
|
style.transformBox = styleProp?.transformBox ?? "fill-box";
|
|
42
51
|
delete attrs.transformBox;
|
|
43
52
|
}
|
|
53
|
+
for (const key of cssMotionPathProperties) {
|
|
54
|
+
if (attrs[key] !== undefined) {
|
|
55
|
+
style[key] = attrs[key];
|
|
56
|
+
delete attrs[key];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
44
59
|
// Render attrX/attrY/attrScale as attributes
|
|
45
60
|
if (attrX !== undefined)
|
|
46
61
|
attrs.x = attrX;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-attrs.mjs","sources":["../../../../../src/render/svg/utils/build-attrs.ts"],"sourcesContent":["import { MotionProps } from \"../../../motion/types\"\nimport { buildHTMLStyles } from \"../../html/utils/build-styles\"\nimport { ResolvedValues } from \"../../types\"\nimport { SVGRenderState } from \"../types\"\nimport { buildSVGPath } from \"./path\"\n\n/**\n * Build SVG visual attributes, like cx and style.transform\n */\nexport function buildSVGAttrs(\n state: SVGRenderState,\n {\n attrX,\n attrY,\n attrScale,\n pathLength,\n pathSpacing = 1,\n pathOffset = 0,\n // This is object creation, which we try to avoid per-frame.\n ...latest\n }: ResolvedValues,\n isSVGTag: boolean,\n transformTemplate?: MotionProps[\"transformTemplate\"],\n styleProp?: MotionProps[\"style\"]\n) {\n buildHTMLStyles(state, latest, transformTemplate)\n\n /**\n * For svg tags we just want to make sure viewBox is animatable and treat all the styles\n * as normal HTML tags.\n */\n if (isSVGTag) {\n if (state.style.viewBox) {\n state.attrs.viewBox = state.style.viewBox\n }\n return\n }\n\n state.attrs = state.style\n state.style = {}\n const { attrs, style } = state\n\n /**\n * However, we apply transforms as CSS transforms.\n * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.\n */\n if (attrs.transform) {\n style.transform = attrs.transform\n delete attrs.transform\n }\n if (style.transform || attrs.transformOrigin) {\n style.transformOrigin = attrs.transformOrigin ?? \"50% 50%\"\n delete attrs.transformOrigin\n }\n\n if (style.transform) {\n /**\n * SVG's element transform-origin uses its own median as a reference.\n * Therefore, transformBox becomes a fill-box\n */\n style.transformBox = (styleProp?.transformBox as string) ?? \"fill-box\"\n delete attrs.transformBox\n }\n\n // Render attrX/attrY/attrScale as attributes\n if (attrX !== undefined) attrs.x = attrX\n if (attrY !== undefined) attrs.y = attrY\n if (attrScale !== undefined) attrs.scale = attrScale\n\n // Build SVG path if one has been defined\n if (pathLength !== undefined) {\n buildSVGPath(\n attrs,\n pathLength as number,\n pathSpacing as number,\n pathOffset as number,\n false\n )\n }\n}\n"],"names":[],"mappings":";;;AAMA;;AAEG;AACG,SAAU,aAAa,CACzB,KAAqB,EACrB,EACI,KAAK,EACL,KAAK,EACL,SAAS,EACT,UAAU,EACV,WAAW,GAAG,CAAC,EACf,UAAU,GAAG,CAAC;AACd;AACA,GAAG,MAAM,EACI,EACjB,QAAiB,EACjB,iBAAoD,EACpD,SAAgC,EAAA;AAEhC,IAAA,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAA;AAEjD;;;AAGG;IACH,IAAI,QAAQ,EAAE;AACV,QAAA,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;YACrB,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAA;SAC5C;QACD,OAAM;KACT;AAED,IAAA,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;AACzB,IAAA,KAAK,CAAC,KAAK,GAAG,EAAE,CAAA;AAChB,IAAA,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;AAE9B;;;AAGG;AACH,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB,QAAA,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;QACjC,OAAO,KAAK,CAAC,SAAS,CAAA;KACzB;IACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,eAAe,EAAE;QAC1C,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,IAAI,SAAS,CAAA;QAC1D,OAAO,KAAK,CAAC,eAAe,CAAA;KAC/B;AAED,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB;;;AAGG;QACH,KAAK,CAAC,YAAY,GAAI,SAAS,EAAE,YAAuB,IAAI,UAAU,CAAA;QACtE,OAAO,KAAK,CAAC,YAAY,CAAA;KAC5B;;IAGD,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK,CAAA;IACxC,IAAI,SAAS,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;;AAGpD,IAAA,IAAI,UAAU,KAAK,SAAS,EAAE;QAC1B,YAAY,CACR,KAAK,EACL,UAAoB,EACpB,WAAqB,EACrB,UAAoB,EACpB,KAAK,CACR,CAAA;KACJ;AACL;;;;"}
|
|
1
|
+
{"version":3,"file":"build-attrs.mjs","sources":["../../../../../src/render/svg/utils/build-attrs.ts"],"sourcesContent":["import { MotionProps } from \"../../../motion/types\"\nimport { buildHTMLStyles } from \"../../html/utils/build-styles\"\nimport { ResolvedValues } from \"../../types\"\nimport { SVGRenderState } from \"../types\"\nimport { buildSVGPath } from \"./path\"\n\n/**\n * CSS Motion Path properties that should remain as CSS styles on SVG elements.\n */\nconst cssMotionPathProperties = [\n \"offsetDistance\",\n \"offsetPath\",\n \"offsetRotate\",\n \"offsetAnchor\",\n]\n\n/**\n * Build SVG visual attributes, like cx and style.transform\n */\nexport function buildSVGAttrs(\n state: SVGRenderState,\n {\n attrX,\n attrY,\n attrScale,\n pathLength,\n pathSpacing = 1,\n pathOffset = 0,\n // This is object creation, which we try to avoid per-frame.\n ...latest\n }: ResolvedValues,\n isSVGTag: boolean,\n transformTemplate?: MotionProps[\"transformTemplate\"],\n styleProp?: MotionProps[\"style\"]\n) {\n buildHTMLStyles(state, latest, transformTemplate)\n\n /**\n * For svg tags we just want to make sure viewBox is animatable and treat all the styles\n * as normal HTML tags.\n */\n if (isSVGTag) {\n if (state.style.viewBox) {\n state.attrs.viewBox = state.style.viewBox\n }\n return\n }\n\n state.attrs = state.style\n state.style = {}\n const { attrs, style } = state\n\n /**\n * However, we apply transforms as CSS transforms.\n * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.\n */\n if (attrs.transform) {\n style.transform = attrs.transform\n delete attrs.transform\n }\n if (style.transform || attrs.transformOrigin) {\n style.transformOrigin = attrs.transformOrigin ?? \"50% 50%\"\n delete attrs.transformOrigin\n }\n\n if (style.transform) {\n /**\n * SVG's element transform-origin uses its own median as a reference.\n * Therefore, transformBox becomes a fill-box\n */\n style.transformBox = (styleProp?.transformBox as string) ?? \"fill-box\"\n delete attrs.transformBox\n }\n\n for (const key of cssMotionPathProperties) {\n if (attrs[key] !== undefined) {\n style[key] = attrs[key]\n delete attrs[key]\n }\n }\n\n // Render attrX/attrY/attrScale as attributes\n if (attrX !== undefined) attrs.x = attrX\n if (attrY !== undefined) attrs.y = attrY\n if (attrScale !== undefined) attrs.scale = attrScale\n\n // Build SVG path if one has been defined\n if (pathLength !== undefined) {\n buildSVGPath(\n attrs,\n pathLength as number,\n pathSpacing as number,\n pathOffset as number,\n false\n )\n }\n}\n"],"names":[],"mappings":";;;AAMA;;AAEG;AACH,MAAM,uBAAuB,GAAG;IAC5B,gBAAgB;IAChB,YAAY;IACZ,cAAc;IACd,cAAc;CACjB,CAAA;AAED;;AAEG;AACG,SAAU,aAAa,CACzB,KAAqB,EACrB,EACI,KAAK,EACL,KAAK,EACL,SAAS,EACT,UAAU,EACV,WAAW,GAAG,CAAC,EACf,UAAU,GAAG,CAAC;AACd;AACA,GAAG,MAAM,EACI,EACjB,QAAiB,EACjB,iBAAoD,EACpD,SAAgC,EAAA;AAEhC,IAAA,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAA;AAEjD;;;AAGG;IACH,IAAI,QAAQ,EAAE;AACV,QAAA,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE;YACrB,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAA;SAC5C;QACD,OAAM;KACT;AAED,IAAA,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;AACzB,IAAA,KAAK,CAAC,KAAK,GAAG,EAAE,CAAA;AAChB,IAAA,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;AAE9B;;;AAGG;AACH,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB,QAAA,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAA;QACjC,OAAO,KAAK,CAAC,SAAS,CAAA;KACzB;IACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,eAAe,EAAE;QAC1C,KAAK,CAAC,eAAe,GAAG,KAAK,CAAC,eAAe,IAAI,SAAS,CAAA;QAC1D,OAAO,KAAK,CAAC,eAAe,CAAA;KAC/B;AAED,IAAA,IAAI,KAAK,CAAC,SAAS,EAAE;AACjB;;;AAGG;QACH,KAAK,CAAC,YAAY,GAAI,SAAS,EAAE,YAAuB,IAAI,UAAU,CAAA;QACtE,OAAO,KAAK,CAAC,YAAY,CAAA;KAC5B;AAED,IAAA,KAAK,MAAM,GAAG,IAAI,uBAAuB,EAAE;AACvC,QAAA,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;YAC1B,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AACvB,YAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAA;SACpB;KACJ;;IAGD,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,CAAC,GAAG,KAAK,CAAA;IACxC,IAAI,SAAS,KAAK,SAAS;AAAE,QAAA,KAAK,CAAC,KAAK,GAAG,SAAS,CAAA;;AAGpD,IAAA,IAAI,UAAU,KAAK,SAAS,EAAE;QAC1B,YAAY,CACR,KAAK,EACL,UAAoB,EACpB,WAAqB,EACrB,UAAoB,EACpB,KAAK,CACR,CAAA;KACJ;AACL;;;;"}
|
|
@@ -606,17 +606,6 @@
|
|
|
606
606
|
return singleCssVariableRegex.test(value.split("/*")[0].trim());
|
|
607
607
|
};
|
|
608
608
|
const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
|
|
609
|
-
/**
|
|
610
|
-
* Check if a value contains a CSS variable anywhere (e.g. inside calc()).
|
|
611
|
-
* Unlike isCSSVariableToken which checks if the value IS a var() token,
|
|
612
|
-
* this checks if the value CONTAINS var() somewhere in the string.
|
|
613
|
-
*/
|
|
614
|
-
function containsCSSVariable(value) {
|
|
615
|
-
if (typeof value !== "string")
|
|
616
|
-
return false;
|
|
617
|
-
// Strip comments to avoid false positives
|
|
618
|
-
return value.split("/*")[0].includes("var(--");
|
|
619
|
-
}
|
|
620
609
|
|
|
621
610
|
const number = {
|
|
622
611
|
test: (v) => typeof v === "number",
|
|
@@ -3190,17 +3179,36 @@
|
|
|
3190
3179
|
right: px,
|
|
3191
3180
|
bottom: px,
|
|
3192
3181
|
left: px,
|
|
3182
|
+
inset: px,
|
|
3183
|
+
insetBlock: px,
|
|
3184
|
+
insetBlockStart: px,
|
|
3185
|
+
insetBlockEnd: px,
|
|
3186
|
+
insetInline: px,
|
|
3187
|
+
insetInlineStart: px,
|
|
3188
|
+
insetInlineEnd: px,
|
|
3193
3189
|
// Spacing props
|
|
3194
3190
|
padding: px,
|
|
3195
3191
|
paddingTop: px,
|
|
3196
3192
|
paddingRight: px,
|
|
3197
3193
|
paddingBottom: px,
|
|
3198
3194
|
paddingLeft: px,
|
|
3195
|
+
paddingBlock: px,
|
|
3196
|
+
paddingBlockStart: px,
|
|
3197
|
+
paddingBlockEnd: px,
|
|
3198
|
+
paddingInline: px,
|
|
3199
|
+
paddingInlineStart: px,
|
|
3200
|
+
paddingInlineEnd: px,
|
|
3199
3201
|
margin: px,
|
|
3200
3202
|
marginTop: px,
|
|
3201
3203
|
marginRight: px,
|
|
3202
3204
|
marginBottom: px,
|
|
3203
3205
|
marginLeft: px,
|
|
3206
|
+
marginBlock: px,
|
|
3207
|
+
marginBlockStart: px,
|
|
3208
|
+
marginBlockEnd: px,
|
|
3209
|
+
marginInline: px,
|
|
3210
|
+
marginInlineStart: px,
|
|
3211
|
+
marginInlineEnd: px,
|
|
3204
3212
|
// Misc
|
|
3205
3213
|
backgroundPositionX: px,
|
|
3206
3214
|
backgroundPositionY: px,
|
|
@@ -3318,16 +3326,6 @@
|
|
|
3318
3326
|
const [origin, target] = unresolvedKeyframes;
|
|
3319
3327
|
const originType = findDimensionValueType(origin);
|
|
3320
3328
|
const targetType = findDimensionValueType(target);
|
|
3321
|
-
/**
|
|
3322
|
-
* If one keyframe contains embedded CSS variables (e.g. in calc()) and the other
|
|
3323
|
-
* doesn't, we need to measure to convert to pixels. This handles GitHub issue #3410.
|
|
3324
|
-
*/
|
|
3325
|
-
const originHasVar = containsCSSVariable(origin);
|
|
3326
|
-
const targetHasVar = containsCSSVariable(target);
|
|
3327
|
-
if (originHasVar !== targetHasVar && positionalValues[name]) {
|
|
3328
|
-
this.needsMeasurement = true;
|
|
3329
|
-
return;
|
|
3330
|
-
}
|
|
3331
3329
|
/**
|
|
3332
3330
|
* Either we don't recognise these value types or we can animate between them.
|
|
3333
3331
|
*/
|
|
@@ -3426,17 +3424,36 @@
|
|
|
3426
3424
|
"right",
|
|
3427
3425
|
"bottom",
|
|
3428
3426
|
"left",
|
|
3427
|
+
"inset",
|
|
3428
|
+
"insetBlock",
|
|
3429
|
+
"insetBlockStart",
|
|
3430
|
+
"insetBlockEnd",
|
|
3431
|
+
"insetInline",
|
|
3432
|
+
"insetInlineStart",
|
|
3433
|
+
"insetInlineEnd",
|
|
3429
3434
|
// Spacing props
|
|
3430
3435
|
"padding",
|
|
3431
3436
|
"paddingTop",
|
|
3432
3437
|
"paddingRight",
|
|
3433
3438
|
"paddingBottom",
|
|
3434
3439
|
"paddingLeft",
|
|
3440
|
+
"paddingBlock",
|
|
3441
|
+
"paddingBlockStart",
|
|
3442
|
+
"paddingBlockEnd",
|
|
3443
|
+
"paddingInline",
|
|
3444
|
+
"paddingInlineStart",
|
|
3445
|
+
"paddingInlineEnd",
|
|
3435
3446
|
"margin",
|
|
3436
3447
|
"marginTop",
|
|
3437
3448
|
"marginRight",
|
|
3438
3449
|
"marginBottom",
|
|
3439
3450
|
"marginLeft",
|
|
3451
|
+
"marginBlock",
|
|
3452
|
+
"marginBlockStart",
|
|
3453
|
+
"marginBlockEnd",
|
|
3454
|
+
"marginInline",
|
|
3455
|
+
"marginInlineStart",
|
|
3456
|
+
"marginInlineEnd",
|
|
3440
3457
|
// Misc
|
|
3441
3458
|
"backgroundPositionX",
|
|
3442
3459
|
"backgroundPositionY",
|
|
@@ -9248,6 +9265,15 @@
|
|
|
9248
9265
|
attrs[keys.array] = `${pathLength} ${pathSpacing}`;
|
|
9249
9266
|
}
|
|
9250
9267
|
|
|
9268
|
+
/**
|
|
9269
|
+
* CSS Motion Path properties that should remain as CSS styles on SVG elements.
|
|
9270
|
+
*/
|
|
9271
|
+
const cssMotionPathProperties = [
|
|
9272
|
+
"offsetDistance",
|
|
9273
|
+
"offsetPath",
|
|
9274
|
+
"offsetRotate",
|
|
9275
|
+
"offsetAnchor",
|
|
9276
|
+
];
|
|
9251
9277
|
/**
|
|
9252
9278
|
* Build SVG visual attributes, like cx and style.transform
|
|
9253
9279
|
*/
|
|
@@ -9288,6 +9314,12 @@
|
|
|
9288
9314
|
style.transformBox = styleProp?.transformBox ?? "fill-box";
|
|
9289
9315
|
delete attrs.transformBox;
|
|
9290
9316
|
}
|
|
9317
|
+
for (const key of cssMotionPathProperties) {
|
|
9318
|
+
if (attrs[key] !== undefined) {
|
|
9319
|
+
style[key] = attrs[key];
|
|
9320
|
+
delete attrs[key];
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9291
9323
|
// Render attrX/attrY/attrScale as attributes
|
|
9292
9324
|
if (attrX !== undefined)
|
|
9293
9325
|
attrs.x = attrX;
|
|
@@ -9446,7 +9478,11 @@
|
|
|
9446
9478
|
}
|
|
9447
9479
|
|
|
9448
9480
|
const createDomVisualElement = (Component, options) => {
|
|
9449
|
-
|
|
9481
|
+
/**
|
|
9482
|
+
* Use explicit isSVG override if provided, otherwise auto-detect
|
|
9483
|
+
*/
|
|
9484
|
+
const isSVG = options.isSVG ?? isSVGComponent(Component);
|
|
9485
|
+
return isSVG
|
|
9450
9486
|
? new SVGVisualElement(options)
|
|
9451
9487
|
: new HTMLVisualElement(options, {
|
|
9452
9488
|
allowProjection: Component !== React$1.Fragment,
|
|
@@ -9555,10 +9591,8 @@
|
|
|
9555
9591
|
return visualProps;
|
|
9556
9592
|
}
|
|
9557
9593
|
|
|
9558
|
-
function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMotionProps = false) {
|
|
9559
|
-
const useVisualProps = isSVGComponent(Component)
|
|
9560
|
-
? useSVGProps
|
|
9561
|
-
: useHTMLProps;
|
|
9594
|
+
function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMotionProps = false, isSVG) {
|
|
9595
|
+
const useVisualProps = (isSVG ?? isSVGComponent(Component)) ? useSVGProps : useHTMLProps;
|
|
9562
9596
|
const visualProps = useVisualProps(props, latestValues, isStatic, Component);
|
|
9563
9597
|
const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
|
|
9564
9598
|
const elementProps = Component !== React$1.Fragment ? { ...filteredProps, ...visualProps, ref } : {};
|
|
@@ -9700,7 +9734,7 @@
|
|
|
9700
9734
|
*/
|
|
9701
9735
|
const SwitchLayoutGroupContext = React$1.createContext({});
|
|
9702
9736
|
|
|
9703
|
-
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor) {
|
|
9737
|
+
function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor, isSVG) {
|
|
9704
9738
|
const { visualElement: parent } = React$1.useContext(MotionContext);
|
|
9705
9739
|
const lazyContext = React$1.useContext(LazyContext);
|
|
9706
9740
|
const presenceContext = React$1.useContext(PresenceContext);
|
|
@@ -9722,6 +9756,7 @@
|
|
|
9722
9756
|
? presenceContext.initial === false
|
|
9723
9757
|
: false,
|
|
9724
9758
|
reducedMotionConfig,
|
|
9759
|
+
isSVG,
|
|
9725
9760
|
});
|
|
9726
9761
|
}
|
|
9727
9762
|
const visualElement = visualElementRef.current;
|
|
@@ -9837,11 +9872,15 @@
|
|
|
9837
9872
|
* Alongside this is a config option which provides a way of rendering the provided
|
|
9838
9873
|
* component "offline", or outside the React render cycle.
|
|
9839
9874
|
*/
|
|
9840
|
-
function createMotionComponent(Component, { forwardMotionProps = false } = {}, preloadedFeatures, createVisualElement) {
|
|
9875
|
+
function createMotionComponent(Component, { forwardMotionProps = false, type } = {}, preloadedFeatures, createVisualElement) {
|
|
9841
9876
|
preloadedFeatures && loadFeatures(preloadedFeatures);
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9877
|
+
/**
|
|
9878
|
+
* Determine whether to use SVG or HTML rendering based on:
|
|
9879
|
+
* 1. Explicit `type` option (highest priority)
|
|
9880
|
+
* 2. Auto-detection via `isSVGComponent`
|
|
9881
|
+
*/
|
|
9882
|
+
const isSVG = type ? type === "svg" : isSVGComponent(Component);
|
|
9883
|
+
const useVisualState = isSVG ? useSVGVisualState : useHTMLVisualState;
|
|
9845
9884
|
function MotionDOMComponent(props, externalRef) {
|
|
9846
9885
|
/**
|
|
9847
9886
|
* If we need to measure the element we load this functionality in a
|
|
@@ -9866,13 +9905,13 @@
|
|
|
9866
9905
|
* providing a way of rendering to these APIs outside of the React render loop
|
|
9867
9906
|
* for more performant animations and interactions
|
|
9868
9907
|
*/
|
|
9869
|
-
context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode);
|
|
9908
|
+
context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement, layoutProjection.ProjectionNode, isSVG);
|
|
9870
9909
|
}
|
|
9871
9910
|
/**
|
|
9872
9911
|
* The mount order and hierarchy is specific to ensure our element ref
|
|
9873
9912
|
* is hydrated by the time features fire their effects.
|
|
9874
9913
|
*/
|
|
9875
|
-
return (jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps)] }));
|
|
9914
|
+
return (jsxs(MotionContext.Provider, { value: context, children: [MeasureLayout && context.visualElement ? (jsx(MeasureLayout, { visualElement: context.visualElement, ...configAndProps })) : null, useRender(Component, props, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, forwardMotionProps, isSVG)] }));
|
|
9876
9915
|
}
|
|
9877
9916
|
MotionDOMComponent.displayName = `motion.${typeof Component === "string"
|
|
9878
9917
|
? Component
|
|
@@ -11444,6 +11483,16 @@
|
|
|
11444
11483
|
}
|
|
11445
11484
|
this.removeListeners = this.controls.addListeners() || noop;
|
|
11446
11485
|
}
|
|
11486
|
+
update() {
|
|
11487
|
+
const { dragControls } = this.node.getProps();
|
|
11488
|
+
const { dragControls: prevDragControls } = this.node.prevProps || {};
|
|
11489
|
+
if (dragControls !== prevDragControls) {
|
|
11490
|
+
this.removeGroupControls();
|
|
11491
|
+
if (dragControls) {
|
|
11492
|
+
this.removeGroupControls = dragControls.subscribe(this.controls);
|
|
11493
|
+
}
|
|
11494
|
+
}
|
|
11495
|
+
}
|
|
11447
11496
|
unmount() {
|
|
11448
11497
|
this.removeGroupControls();
|
|
11449
11498
|
this.removeListeners();
|
|
@@ -14242,7 +14291,6 @@
|
|
|
14242
14291
|
exports.collectMotionValues = collectMotionValues;
|
|
14243
14292
|
exports.color = color;
|
|
14244
14293
|
exports.complex = complex;
|
|
14245
|
-
exports.containsCSSVariable = containsCSSVariable;
|
|
14246
14294
|
exports.convertOffsetToTimes = convertOffsetToTimes;
|
|
14247
14295
|
exports.createBox = createBox;
|
|
14248
14296
|
exports.createGeneratorEasing = createGeneratorEasing;
|