framer-motion 12.23.15 → 12.23.18

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var featureBundle = require('./feature-bundle-DzuUB-G1.js');
5
+ var featureBundle = require('./feature-bundle-pqhrS3ID.js');
6
6
  require('react');
7
7
  require('motion-dom');
8
8
  require('motion-utils');
package/dist/cjs/dom.js CHANGED
@@ -1838,13 +1838,22 @@ function createScopedAnimate(scope) {
1838
1838
  */
1839
1839
  function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options) {
1840
1840
  let animations = [];
1841
+ let animationOnComplete;
1841
1842
  if (isSequence(subjectOrSequence)) {
1842
1843
  animations = animateSequence(subjectOrSequence, optionsOrKeyframes, scope);
1843
1844
  }
1844
1845
  else {
1845
- animations = animateSubject(subjectOrSequence, optionsOrKeyframes, options, scope);
1846
+ // Extract top-level onComplete so it doesn't get applied per-value
1847
+ const { onComplete, ...rest } = options || {};
1848
+ if (typeof onComplete === "function") {
1849
+ animationOnComplete = onComplete;
1850
+ }
1851
+ animations = animateSubject(subjectOrSequence, optionsOrKeyframes, rest, scope);
1846
1852
  }
1847
1853
  const animation = new motionDom.GroupAnimationWithThen(animations);
1854
+ if (animationOnComplete) {
1855
+ animation.finished.then(animationOnComplete);
1856
+ }
1848
1857
  if (scope) {
1849
1858
  scope.animations.push(animation);
1850
1859
  animation.finished.then(() => {
@@ -5,6 +5,25 @@ var motionDom = require('motion-dom');
5
5
  var motionUtils = require('motion-utils');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
+ function _interopNamespaceDefault(e) {
9
+ var n = Object.create(null);
10
+ if (e) {
11
+ Object.keys(e).forEach(function (k) {
12
+ if (k !== 'default') {
13
+ var d = Object.getOwnPropertyDescriptor(e, k);
14
+ Object.defineProperty(n, k, d.get ? d : {
15
+ enumerable: true,
16
+ get: function () { return e[k]; }
17
+ });
18
+ }
19
+ });
20
+ }
21
+ n.default = e;
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
26
+
8
27
  const LayoutGroupContext = React.createContext({});
9
28
 
10
29
  /**
@@ -4069,16 +4088,22 @@ function isRefObject(ref) {
4069
4088
  * external ref and VisualElement.
4070
4089
  */
4071
4090
  function useMotionRef(visualState, visualElement, externalRef) {
4091
+ const currentInstanceRef = React__namespace.useRef(null);
4072
4092
  return React.useCallback((instance) => {
4073
- if (instance) {
4074
- visualState.onMount && visualState.onMount(instance);
4075
- }
4076
- if (visualElement) {
4093
+ const prevInstance = currentInstanceRef.current;
4094
+ currentInstanceRef.current = instance;
4095
+ // Only run mount/unmount logic when the instance actually changes
4096
+ if (instance !== prevInstance) {
4077
4097
  if (instance) {
4078
- visualElement.mount(instance);
4098
+ visualState.onMount && visualState.onMount(instance);
4079
4099
  }
4080
- else {
4081
- visualElement.unmount();
4100
+ if (visualElement) {
4101
+ if (instance) {
4102
+ visualElement.mount(instance);
4103
+ }
4104
+ else {
4105
+ visualElement.unmount();
4106
+ }
4082
4107
  }
4083
4108
  }
4084
4109
  if (externalRef) {
@@ -4094,7 +4119,7 @@ function useMotionRef(visualState, visualElement, externalRef) {
4094
4119
  * Include externalRef in dependencies to ensure the callback updates
4095
4120
  * when the ref changes, allowing proper ref forwarding.
4096
4121
  */
4097
- [visualElement]);
4122
+ [visualElement, externalRef]);
4098
4123
  }
4099
4124
 
4100
4125
  /**
package/dist/cjs/index.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var React = require('react');
7
- var featureBundle = require('./feature-bundle-DzuUB-G1.js');
7
+ var featureBundle = require('./feature-bundle-pqhrS3ID.js');
8
8
  var motionDom = require('motion-dom');
9
9
  var motionUtils = require('motion-utils');
10
10
 
@@ -27,6 +27,60 @@ function _interopNamespaceDefault(e) {
27
27
 
28
28
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
29
29
 
30
+ /**
31
+ * Set a given ref to a given value
32
+ * This utility takes care of different types of refs: callback refs and RefObject(s)
33
+ */
34
+ function setRef(ref, value) {
35
+ if (typeof ref === "function") {
36
+ return ref(value);
37
+ }
38
+ else if (ref !== null && ref !== undefined) {
39
+ ref.current = value;
40
+ }
41
+ }
42
+ /**
43
+ * A utility to compose multiple refs together
44
+ * Accepts callback refs and RefObject(s)
45
+ */
46
+ function composeRefs(...refs) {
47
+ return (node) => {
48
+ let hasCleanup = false;
49
+ const cleanups = refs.map((ref) => {
50
+ const cleanup = setRef(ref, node);
51
+ if (!hasCleanup && typeof cleanup === "function") {
52
+ hasCleanup = true;
53
+ }
54
+ return cleanup;
55
+ });
56
+ // React <19 will log an error to the console if a callback ref returns a
57
+ // value. We don't use ref cleanups internally so this will only happen if a
58
+ // user's ref callback returns a value, which we only expect if they are
59
+ // using the cleanup functionality added in React 19.
60
+ if (hasCleanup) {
61
+ return () => {
62
+ for (let i = 0; i < cleanups.length; i++) {
63
+ const cleanup = cleanups[i];
64
+ if (typeof cleanup === "function") {
65
+ cleanup();
66
+ }
67
+ else {
68
+ setRef(refs[i], null);
69
+ }
70
+ }
71
+ };
72
+ }
73
+ };
74
+ }
75
+ /**
76
+ * A custom hook that composes multiple refs
77
+ * Accepts callback refs and RefObject(s)
78
+ */
79
+ function useComposedRefs(...refs) {
80
+ // eslint-disable-next-line react-hooks/exhaustive-deps
81
+ return React__namespace.useCallback(composeRefs(...refs), refs);
82
+ }
83
+
30
84
  /**
31
85
  * Measurement functionality has to be within a separate component
32
86
  * to leverage snapshot lifecycle.
@@ -67,6 +121,7 @@ function PopChild({ children, isPresent, anchorX, root }) {
67
121
  right: 0,
68
122
  });
69
123
  const { nonce } = React.useContext(featureBundle.MotionConfigContext);
124
+ const composedRef = useComposedRefs(ref, children?.ref);
70
125
  /**
71
126
  * We create and inject a style block so we can apply this explicit
72
127
  * sizing in a non-destructive manner by just deleting the style block.
@@ -104,7 +159,7 @@ function PopChild({ children, isPresent, anchorX, root }) {
104
159
  }
105
160
  };
106
161
  }, [isPresent]);
107
- return (jsxRuntime.jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React__namespace.cloneElement(children, { ref }) }));
162
+ return (jsxRuntime.jsx(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size, children: React__namespace.cloneElement(children, { ref: composedRef }) }));
108
163
  }
109
164
 
110
165
  const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, anchorX, root }) => {
@@ -1219,13 +1274,22 @@ function createScopedAnimate(scope) {
1219
1274
  */
1220
1275
  function scopedAnimate(subjectOrSequence, optionsOrKeyframes, options) {
1221
1276
  let animations = [];
1277
+ let animationOnComplete;
1222
1278
  if (isSequence(subjectOrSequence)) {
1223
1279
  animations = animateSequence(subjectOrSequence, optionsOrKeyframes, scope);
1224
1280
  }
1225
1281
  else {
1226
- animations = animateSubject(subjectOrSequence, optionsOrKeyframes, options, scope);
1282
+ // Extract top-level onComplete so it doesn't get applied per-value
1283
+ const { onComplete, ...rest } = options || {};
1284
+ if (typeof onComplete === "function") {
1285
+ animationOnComplete = onComplete;
1286
+ }
1287
+ animations = animateSubject(subjectOrSequence, optionsOrKeyframes, rest, scope);
1227
1288
  }
1228
1289
  const animation = new motionDom.GroupAnimationWithThen(animations);
1290
+ if (animationOnComplete) {
1291
+ animation.finished.then(animationOnComplete);
1292
+ }
1229
1293
  if (scope) {
1230
1294
  scope.animations.push(animation);
1231
1295
  animation.finished.then(() => {
package/dist/cjs/m.js CHANGED
@@ -4,23 +4,42 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var motionUtils = require('motion-utils');
7
- var react = require('react');
7
+ var React = require('react');
8
8
  var motionDom = require('motion-dom');
9
9
 
10
- const LayoutGroupContext = react.createContext({});
10
+ function _interopNamespaceDefault(e) {
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
11
28
 
12
- const LazyContext = react.createContext({ strict: false });
29
+ const LayoutGroupContext = React.createContext({});
30
+
31
+ const LazyContext = React.createContext({ strict: false });
13
32
 
14
33
  /**
15
34
  * @public
16
35
  */
17
- const MotionConfigContext = react.createContext({
36
+ const MotionConfigContext = React.createContext({
18
37
  transformPagePoint: (p) => p,
19
38
  isStatic: false,
20
39
  reducedMotion: "never",
21
40
  });
22
41
 
23
- const MotionContext = /* @__PURE__ */ react.createContext({});
42
+ const MotionContext = /* @__PURE__ */ React.createContext({});
24
43
 
25
44
  function isAnimationControls(v) {
26
45
  return (v !== null &&
@@ -68,8 +87,8 @@ function getCurrentTreeVariants(props, context) {
68
87
  }
69
88
 
70
89
  function useCreateMotionContext(props) {
71
- const { initial, animate } = getCurrentTreeVariants(props, react.useContext(MotionContext));
72
- return react.useMemo(() => ({ initial, animate }), [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate)]);
90
+ const { initial, animate } = getCurrentTreeVariants(props, React.useContext(MotionContext));
91
+ return React.useMemo(() => ({ initial, animate }), [variantLabelsAsDependency(initial), variantLabelsAsDependency(animate)]);
73
92
  }
74
93
  function variantLabelsAsDependency(prop) {
75
94
  return Array.isArray(prop) ? prop.join(" ") : prop;
@@ -214,7 +233,7 @@ function copyRawValuesOnly(target, source, props) {
214
233
  }
215
234
  }
216
235
  function useInitialMotionValues({ transformTemplate }, visualState) {
217
- return react.useMemo(() => {
236
+ return React.useMemo(() => {
218
237
  const state = createHtmlRenderState();
219
238
  buildHTMLStyles(state, visualState, transformTemplate);
220
239
  return Object.assign({}, state.vars, state.style);
@@ -346,7 +365,7 @@ const createSvgRenderState = () => ({
346
365
  const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
347
366
 
348
367
  function useSVGProps(props, visualState, _isStatic, Component) {
349
- const visualProps = react.useMemo(() => {
368
+ const visualProps = React.useMemo(() => {
350
369
  const state = createSvgRenderState();
351
370
  buildSVGAttrs(state, visualState, isSVGTag(Component), props.transformTemplate, props.style);
352
371
  return {
@@ -539,15 +558,15 @@ function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMo
539
558
  : useHTMLProps;
540
559
  const visualProps = useVisualProps(props, latestValues, isStatic, Component);
541
560
  const filteredProps = filterProps(props, typeof Component === "string", forwardMotionProps);
542
- const elementProps = Component !== react.Fragment ? { ...filteredProps, ...visualProps, ref } : {};
561
+ const elementProps = Component !== React.Fragment ? { ...filteredProps, ...visualProps, ref } : {};
543
562
  /**
544
563
  * If component has been handed a motion value as its child,
545
564
  * memoise its initial value and render that. Subsequent updates
546
565
  * will be handled by the onChange handler
547
566
  */
548
567
  const { children } = props;
549
- const renderedChildren = react.useMemo(() => (motionDom.isMotionValue(children) ? children.get() : children), [children]);
550
- return react.createElement(Component, {
568
+ const renderedChildren = React.useMemo(() => (motionDom.isMotionValue(children) ? children.get() : children), [children]);
569
+ return React.createElement(Component, {
551
570
  ...elementProps,
552
571
  children: renderedChildren,
553
572
  });
@@ -557,7 +576,7 @@ function useRender(Component, props, ref, { latestValues, }, isStatic, forwardMo
557
576
  * @public
558
577
  */
559
578
  const PresenceContext =
560
- /* @__PURE__ */ react.createContext(null);
579
+ /* @__PURE__ */ React.createContext(null);
561
580
 
562
581
  function getValueState(visualElement) {
563
582
  const state = [{}, {}];
@@ -598,7 +617,7 @@ function resolveVariantFromProps(props, definition, custom, visualElement) {
598
617
  * you can ensure that initialisers don't execute twice or more.
599
618
  */
600
619
  function useConstant(init) {
601
- const ref = react.useRef(null);
620
+ const ref = React.useRef(null);
602
621
  if (ref.current === null) {
603
622
  ref.current = init();
604
623
  }
@@ -677,8 +696,8 @@ function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
677
696
  return values;
678
697
  }
679
698
  const makeUseVisualState = (config) => (props, isStatic) => {
680
- const context = react.useContext(MotionContext);
681
- const presenceContext = react.useContext(PresenceContext);
699
+ const context = React.useContext(MotionContext);
700
+ const presenceContext = React.useContext(PresenceContext);
682
701
  const make = () => makeState(config, props, context, presenceContext);
683
702
  return isStatic ? make() : useConstant(make);
684
703
  };
@@ -764,16 +783,22 @@ function isRefObject(ref) {
764
783
  * external ref and VisualElement.
765
784
  */
766
785
  function useMotionRef(visualState, visualElement, externalRef) {
767
- return react.useCallback((instance) => {
768
- if (instance) {
769
- visualState.onMount && visualState.onMount(instance);
770
- }
771
- if (visualElement) {
786
+ const currentInstanceRef = React__namespace.useRef(null);
787
+ return React.useCallback((instance) => {
788
+ const prevInstance = currentInstanceRef.current;
789
+ currentInstanceRef.current = instance;
790
+ // Only run mount/unmount logic when the instance actually changes
791
+ if (instance !== prevInstance) {
772
792
  if (instance) {
773
- visualElement.mount(instance);
793
+ visualState.onMount && visualState.onMount(instance);
774
794
  }
775
- else {
776
- visualElement.unmount();
795
+ if (visualElement) {
796
+ if (instance) {
797
+ visualElement.mount(instance);
798
+ }
799
+ else {
800
+ visualElement.unmount();
801
+ }
777
802
  }
778
803
  }
779
804
  if (externalRef) {
@@ -789,7 +814,7 @@ function useMotionRef(visualState, visualElement, externalRef) {
789
814
  * Include externalRef in dependencies to ensure the callback updates
790
815
  * when the ref changes, allowing proper ref forwarding.
791
816
  */
792
- [visualElement]);
817
+ [visualElement, externalRef]);
793
818
  }
794
819
 
795
820
  /**
@@ -803,16 +828,16 @@ const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId
803
828
  /**
804
829
  * Internal, exported only for usage in Framer
805
830
  */
806
- const SwitchLayoutGroupContext = react.createContext({});
831
+ const SwitchLayoutGroupContext = React.createContext({});
807
832
 
808
- const useIsomorphicLayoutEffect = isBrowser ? react.useLayoutEffect : react.useEffect;
833
+ const useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect;
809
834
 
810
835
  function useVisualElement(Component, visualState, props, createVisualElement, ProjectionNodeConstructor) {
811
- const { visualElement: parent } = react.useContext(MotionContext);
812
- const lazyContext = react.useContext(LazyContext);
813
- const presenceContext = react.useContext(PresenceContext);
814
- const reducedMotionConfig = react.useContext(MotionConfigContext).reducedMotion;
815
- const visualElementRef = react.useRef(null);
836
+ const { visualElement: parent } = React.useContext(MotionContext);
837
+ const lazyContext = React.useContext(LazyContext);
838
+ const presenceContext = React.useContext(PresenceContext);
839
+ const reducedMotionConfig = React.useContext(MotionConfigContext).reducedMotion;
840
+ const visualElementRef = React.useRef(null);
816
841
  /**
817
842
  * If we haven't preloaded a renderer, check to see if we have one lazy-loaded
818
843
  */
@@ -836,15 +861,15 @@ function useVisualElement(Component, visualState, props, createVisualElement, Pr
836
861
  * Load Motion gesture and animation features. These are rendered as renderless
837
862
  * components so each feature can optionally make use of React lifecycle methods.
838
863
  */
839
- const initialLayoutGroupConfig = react.useContext(SwitchLayoutGroupContext);
864
+ const initialLayoutGroupConfig = React.useContext(SwitchLayoutGroupContext);
840
865
  if (visualElement &&
841
866
  !visualElement.projection &&
842
867
  ProjectionNodeConstructor &&
843
868
  (visualElement.type === "html" || visualElement.type === "svg")) {
844
869
  createProjectionNode(visualElementRef.current, props, ProjectionNodeConstructor, initialLayoutGroupConfig);
845
870
  }
846
- const isMounted = react.useRef(false);
847
- react.useInsertionEffect(() => {
871
+ const isMounted = React.useRef(false);
872
+ React.useInsertionEffect(() => {
848
873
  /**
849
874
  * Check the component has already mounted before calling
850
875
  * `update` unnecessarily. This ensures we skip the initial update.
@@ -858,7 +883,7 @@ function useVisualElement(Component, visualState, props, createVisualElement, Pr
858
883
  * was present on initial render - it will be deleted after this.
859
884
  */
860
885
  const optimisedAppearId = props[optimizedAppearDataAttribute];
861
- const wantsHandoff = react.useRef(Boolean(optimisedAppearId) &&
886
+ const wantsHandoff = React.useRef(Boolean(optimisedAppearId) &&
862
887
  !window.MotionHandoffIsComplete?.(optimisedAppearId) &&
863
888
  window.MotionHasOptimisedAnimation?.(optimisedAppearId));
864
889
  useIsomorphicLayoutEffect(() => {
@@ -882,7 +907,7 @@ function useVisualElement(Component, visualState, props, createVisualElement, Pr
882
907
  visualElement.animationState.animateChanges();
883
908
  }
884
909
  });
885
- react.useEffect(() => {
910
+ React.useEffect(() => {
886
911
  if (!visualElement)
887
912
  return;
888
913
  if (!wantsHandoff.current && visualElement.animationState) {
@@ -955,7 +980,7 @@ function createMotionComponent(Component, { forwardMotionProps = false } = {}, p
955
980
  */
956
981
  let MeasureLayout;
957
982
  const configAndProps = {
958
- ...react.useContext(MotionConfigContext),
983
+ ...React.useContext(MotionConfigContext),
959
984
  ...props,
960
985
  layoutId: useLayoutId(props),
961
986
  };
@@ -983,18 +1008,18 @@ function createMotionComponent(Component, { forwardMotionProps = false } = {}, p
983
1008
  MotionDOMComponent.displayName = `motion.${typeof Component === "string"
984
1009
  ? Component
985
1010
  : `create(${Component.displayName ?? Component.name ?? ""})`}`;
986
- const ForwardRefMotionComponent = react.forwardRef(MotionDOMComponent);
1011
+ const ForwardRefMotionComponent = React.forwardRef(MotionDOMComponent);
987
1012
  ForwardRefMotionComponent[motionComponentSymbol] = Component;
988
1013
  return ForwardRefMotionComponent;
989
1014
  }
990
1015
  function useLayoutId({ layoutId }) {
991
- const layoutGroupId = react.useContext(LayoutGroupContext).id;
1016
+ const layoutGroupId = React.useContext(LayoutGroupContext).id;
992
1017
  return layoutGroupId && layoutId !== undefined
993
1018
  ? layoutGroupId + "-" + layoutId
994
1019
  : layoutId;
995
1020
  }
996
1021
  function useStrictMode(configAndProps, preloadedFeatures) {
997
- const isStrict = react.useContext(LazyContext).strict;
1022
+ const isStrict = React.useContext(LazyContext).strict;
998
1023
  /**
999
1024
  * If we're in development mode, check to make sure we're not rendering a motion component
1000
1025
  * as a child of LazyMotion, as this will break the file-size benefits of using it.