framer-motion 7.2.0 → 7.3.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.
Files changed (96) hide show
  1. package/dist/cjs/index.js +762 -627
  2. package/dist/es/animation/use-animated-state.mjs +3 -5
  3. package/dist/es/animation/utils/default-transitions.mjs +1 -1
  4. package/dist/es/animation/utils/transitions.mjs +28 -26
  5. package/dist/es/components/AnimatePresence/PopChild.mjs +3 -2
  6. package/dist/es/components/AnimatePresence/PresenceChild.mjs +5 -2
  7. package/dist/es/components/AnimatePresence/use-presence.mjs +1 -1
  8. package/dist/es/components/LayoutGroup/index.mjs +4 -5
  9. package/dist/es/components/LazyMotion/index.mjs +3 -5
  10. package/dist/es/components/MotionConfig/index.mjs +2 -4
  11. package/dist/es/components/Reorder/Group.mjs +2 -4
  12. package/dist/es/components/Reorder/Item.mjs +6 -8
  13. package/dist/es/context/MotionContext/utils.mjs +3 -2
  14. package/dist/es/gestures/PanSession.mjs +2 -2
  15. package/dist/es/gestures/drag/VisualElementDragControls.mjs +16 -4
  16. package/dist/es/gestures/use-focus-gesture.mjs +3 -4
  17. package/dist/es/gestures/use-hover-gesture.mjs +4 -3
  18. package/dist/es/gestures/use-tap-gesture.mjs +9 -10
  19. package/dist/es/index.mjs +2 -1
  20. package/dist/es/motion/features/animations.mjs +8 -3
  21. package/dist/es/motion/features/definitions.mjs +1 -13
  22. package/dist/es/motion/features/layout/MeasureLayout.mjs +12 -6
  23. package/dist/es/motion/features/load-features.mjs +14 -0
  24. package/dist/es/motion/features/viewport/observers.mjs +4 -7
  25. package/dist/es/motion/features/viewport/use-viewport.mjs +8 -6
  26. package/dist/es/motion/index.mjs +23 -23
  27. package/dist/es/motion/utils/VisualElementHandler.mjs +2 -5
  28. package/dist/es/motion/utils/is-forced-motion-value.mjs +3 -3
  29. package/dist/es/motion/utils/use-motion-ref.mjs +1 -2
  30. package/dist/es/motion/utils/use-visual-element.mjs +14 -12
  31. package/dist/es/motion/utils/use-visual-state.mjs +19 -16
  32. package/dist/es/motion/utils/valid-prop.mjs +22 -17
  33. package/dist/es/projection/geometry/utils.mjs +10 -1
  34. package/dist/es/projection/node/HTMLProjectionNode.mjs +1 -1
  35. package/dist/es/projection/node/create-projection-node.mjs +62 -20
  36. package/dist/es/projection/use-instant-layout-transition.mjs +2 -2
  37. package/dist/es/render/dom/features-animation.mjs +5 -1
  38. package/dist/es/render/dom/features-max.mjs +6 -1
  39. package/dist/es/render/dom/motion.mjs +6 -1
  40. package/dist/es/render/dom/use-render.mjs +5 -1
  41. package/dist/es/render/dom/utils/camel-to-dash.mjs +1 -3
  42. package/dist/es/render/dom/utils/create-config.mjs +7 -2
  43. package/dist/es/render/dom/utils/css-variables-conversion.mjs +5 -7
  44. package/dist/es/render/dom/utils/unit-conversion.mjs +4 -4
  45. package/dist/es/render/dom/value-types/defaults.mjs +15 -3
  46. package/dist/es/render/dom/value-types/type-int.mjs +4 -1
  47. package/dist/es/render/html/config-motion.mjs +1 -1
  48. package/dist/es/render/html/use-props.mjs +5 -9
  49. package/dist/es/render/html/utils/build-styles.mjs +17 -15
  50. package/dist/es/render/html/utils/build-transform.mjs +8 -18
  51. package/dist/es/render/html/utils/transform.mjs +21 -30
  52. package/dist/es/render/html/visual-element.mjs +8 -9
  53. package/dist/es/render/index.mjs +118 -40
  54. package/dist/es/render/svg/use-props.mjs +5 -2
  55. package/dist/es/render/svg/utils/build-attrs.mjs +3 -5
  56. package/dist/es/render/svg/utils/create-render-state.mjs +4 -1
  57. package/dist/es/render/svg/visual-element.mjs +8 -4
  58. package/dist/es/render/utils/animation-state.mjs +12 -9
  59. package/dist/es/render/utils/animation.mjs +14 -8
  60. package/dist/es/render/utils/is-controlling-variants.mjs +22 -0
  61. package/dist/es/render/utils/is-variant-label.mjs +8 -0
  62. package/dist/es/render/utils/motion-values.mjs +3 -3
  63. package/dist/es/render/utils/resolve-dynamic-variants.mjs +24 -0
  64. package/dist/es/render/utils/resolve-variants.mjs +26 -0
  65. package/dist/es/render/utils/setters.mjs +12 -9
  66. package/dist/es/utils/reduced-motion/index.mjs +19 -0
  67. package/dist/es/utils/reduced-motion/state.mjs +5 -0
  68. package/dist/es/utils/reduced-motion/use-reduced-motion-config.mjs +19 -0
  69. package/dist/es/utils/reduced-motion/use-reduced-motion.mjs +43 -0
  70. package/dist/es/utils/transform.mjs +4 -1
  71. package/dist/es/utils/use-in-view.mjs +1 -2
  72. package/dist/es/value/index.mjs +1 -1
  73. package/dist/es/value/use-scroll.mjs +6 -4
  74. package/dist/es/value/use-spring.mjs +7 -1
  75. package/dist/es/value/use-will-change/index.mjs +4 -4
  76. package/dist/es/value/utils/is-motion-value.mjs +1 -3
  77. package/dist/framer-motion.dev.js +806 -670
  78. package/dist/framer-motion.js +1 -1
  79. package/dist/index.d.ts +60 -54
  80. package/dist/projection.dev.js +402 -213
  81. package/dist/size-rollup-dom-animation-assets.js +1 -0
  82. package/dist/size-rollup-dom-animation-m.js +1 -0
  83. package/dist/size-rollup-dom-animation.js +1 -1
  84. package/dist/size-rollup-dom-max-assets.js +1 -0
  85. package/dist/size-rollup-dom-max.js +1 -1
  86. package/dist/size-rollup-m.js +1 -1
  87. package/dist/size-rollup-motion.js +1 -0
  88. package/dist/size-webpack-dom-animation.js +1 -1
  89. package/dist/size-webpack-dom-max.js +1 -1
  90. package/dist/size-webpack-m.js +1 -1
  91. package/dist/three-entry.d.ts +41 -22
  92. package/package.json +12 -8
  93. package/dist/es/motion/features/use-features.mjs +0 -40
  94. package/dist/es/motion/features/use-projection.mjs +0 -33
  95. package/dist/es/render/utils/variants.mjs +0 -73
  96. package/dist/es/utils/use-reduced-motion.mjs +0 -73
@@ -1,5 +1,3 @@
1
- import { __rest } from 'tslib';
2
-
3
1
  /**
4
2
  * Map an IntersectionHandler callback to an element. We only ever make one handler for one
5
3
  * element, so even though these handlers might all be triggered by different
@@ -13,14 +11,13 @@ const observerCallbacks = new WeakMap();
13
11
  */
14
12
  const observers = new WeakMap();
15
13
  const fireObserverCallback = (entry) => {
16
- var _a;
17
- (_a = observerCallbacks.get(entry.target)) === null || _a === void 0 ? void 0 : _a(entry);
14
+ const callback = observerCallbacks.get(entry.target);
15
+ callback && callback(entry);
18
16
  };
19
17
  const fireAllObserverCallbacks = (entries) => {
20
18
  entries.forEach(fireObserverCallback);
21
19
  };
22
- function initIntersectionObserver(_a) {
23
- var { root } = _a, options = __rest(_a, ["root"]);
20
+ function initIntersectionObserver({ root, ...options }) {
24
21
  const lookupRoot = root || document;
25
22
  /**
26
23
  * If we don't have an observer lookup map for this root, create one.
@@ -35,7 +32,7 @@ function initIntersectionObserver(_a) {
35
32
  * create one.
36
33
  */
37
34
  if (!rootObservers[key]) {
38
- rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, Object.assign({ root }, options));
35
+ rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, { root, ...options });
39
36
  }
40
37
  return rootObservers[key];
41
38
  }
@@ -31,7 +31,6 @@ function useIntersectionObserver(shouldObserve, state, visualElement, { root, ma
31
31
  threshold: typeof amount === "number" ? amount : thresholdNames[amount],
32
32
  };
33
33
  const intersectionCallback = (entry) => {
34
- var _a;
35
34
  const { isIntersecting } = entry;
36
35
  /**
37
36
  * If there's been no change in the viewport state, early return.
@@ -49,7 +48,9 @@ function useIntersectionObserver(shouldObserve, state, visualElement, { root, ma
49
48
  else if (isIntersecting) {
50
49
  state.hasEnteredView = true;
51
50
  }
52
- (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(AnimationType.InView, isIntersecting);
51
+ if (visualElement.animationState) {
52
+ visualElement.animationState.setActive(AnimationType.InView, isIntersecting);
53
+ }
53
54
  /**
54
55
  * Use the latest committed props rather than the ones in scope
55
56
  * when this observer is created
@@ -58,7 +59,7 @@ function useIntersectionObserver(shouldObserve, state, visualElement, { root, ma
58
59
  const callback = isIntersecting
59
60
  ? props.onViewportEnter
60
61
  : props.onViewportLeave;
61
- callback === null || callback === void 0 ? void 0 : callback(entry);
62
+ callback && callback(entry);
62
63
  };
63
64
  return observeIntersection(visualElement.getInstance(), options, intersectionCallback);
64
65
  }, [shouldObserve, root, rootMargin, amount]);
@@ -84,11 +85,12 @@ function useMissingIntersectionObserver(shouldObserve, state, visualElement, { f
84
85
  * is preferred to changing the behaviour of the animation state.
85
86
  */
86
87
  requestAnimationFrame(() => {
87
- var _a;
88
88
  state.hasEnteredView = true;
89
89
  const { onViewportEnter } = visualElement.getProps();
90
- onViewportEnter === null || onViewportEnter === void 0 ? void 0 : onViewportEnter(null);
91
- (_a = visualElement.animationState) === null || _a === void 0 ? void 0 : _a.setActive(AnimationType.InView, true);
90
+ onViewportEnter && onViewportEnter(null);
91
+ if (visualElement.animationState) {
92
+ visualElement.animationState.setActive(AnimationType.InView, true);
93
+ }
92
94
  });
93
95
  }, [shouldObserve]);
94
96
  }
@@ -1,17 +1,18 @@
1
1
  import * as React from 'react';
2
2
  import { forwardRef, useContext } from 'react';
3
- import { useFeatures } from './features/use-features.mjs';
4
3
  import { MotionConfigContext } from '../context/MotionConfigContext.mjs';
5
4
  import { MotionContext } from '../context/MotionContext/index.mjs';
6
5
  import { useVisualElement } from './utils/use-visual-element.mjs';
7
6
  import { useMotionRef } from './utils/use-motion-ref.mjs';
8
7
  import { useCreateMotionContext } from '../context/MotionContext/create.mjs';
9
- import { loadFeatures, featureDefinitions } from './features/definitions.mjs';
8
+ import { featureDefinitions } from './features/definitions.mjs';
9
+ import { loadFeatures } from './features/load-features.mjs';
10
10
  import { isBrowser } from '../utils/is-browser.mjs';
11
11
  import { useProjectionId } from '../projection/node/id.mjs';
12
12
  import { LayoutGroupContext } from '../context/LayoutGroupContext.mjs';
13
- import { useProjection } from './features/use-projection.mjs';
14
13
  import { VisualElementHandler } from './utils/VisualElementHandler.mjs';
14
+ import { LazyContext } from '../context/LazyContext.mjs';
15
+ import { SwitchLayoutGroupContext } from '../context/SwitchLayoutGroupContext.mjs';
15
16
 
16
17
  /**
17
18
  * Create a `motion` component.
@@ -25,15 +26,12 @@ import { VisualElementHandler } from './utils/VisualElementHandler.mjs';
25
26
  function createMotionComponent({ preloadedFeatures, createVisualElement, projectionNodeConstructor, useRender, useVisualState, Component, }) {
26
27
  preloadedFeatures && loadFeatures(preloadedFeatures);
27
28
  function MotionComponent(props, externalRef) {
28
- const layoutId = useLayoutId(props);
29
- props = Object.assign(Object.assign({}, props), { layoutId });
30
- /**
31
- * If we're rendering in a static environment, we only visually update the component
32
- * as a result of a React-rerender rather than interactions or animations. This
33
- * means we don't need to load additional memory structures like VisualElement,
34
- * or any gesture/animation features.
35
- */
36
- const config = useContext(MotionConfigContext);
29
+ const configAndProps = {
30
+ ...useContext(MotionConfigContext),
31
+ ...props,
32
+ layoutId: useLayoutId(props),
33
+ };
34
+ const { isStatic } = configAndProps;
37
35
  let features = null;
38
36
  const context = useCreateMotionContext(props);
39
37
  /**
@@ -47,40 +45,42 @@ function createMotionComponent({ preloadedFeatures, createVisualElement, project
47
45
  * shared element transitions however. Perhaps for those we could revert to a root node
48
46
  * that gets forceRendered and layout animations are triggered on its layout effect.
49
47
  */
50
- const projectionId = config.isStatic ? undefined : useProjectionId();
48
+ const projectionId = isStatic ? undefined : useProjectionId();
51
49
  /**
52
50
  *
53
51
  */
54
- const visualState = useVisualState(props, config.isStatic);
55
- if (!config.isStatic && isBrowser) {
52
+ const visualState = useVisualState(props, isStatic);
53
+ if (!isStatic && isBrowser) {
56
54
  /**
57
55
  * Create a VisualElement for this component. A VisualElement provides a common
58
56
  * interface to renderer-specific APIs (ie DOM/Three.js etc) as well as
59
57
  * providing a way of rendering to these APIs outside of the React render loop
60
58
  * for more performant animations and interactions
61
59
  */
62
- context.visualElement = useVisualElement(Component, visualState, Object.assign(Object.assign({}, config), props), createVisualElement);
63
- useProjection(projectionId, props, context.visualElement, projectionNodeConstructor ||
64
- featureDefinitions.projectionNodeConstructor);
60
+ context.visualElement = useVisualElement(Component, visualState, configAndProps, createVisualElement);
65
61
  /**
66
62
  * Load Motion gesture and animation features. These are rendered as renderless
67
63
  * components so each feature can optionally make use of React lifecycle methods.
68
64
  */
69
- features = useFeatures(props, context.visualElement, preloadedFeatures);
65
+ const lazyStrictMode = useContext(LazyContext).strict;
66
+ const initialLayoutGroupConfig = useContext(SwitchLayoutGroupContext);
67
+ if (context.visualElement) {
68
+ features = context.visualElement.loadFeatures(props, lazyStrictMode, preloadedFeatures, projectionId, projectionNodeConstructor ||
69
+ featureDefinitions.projectionNodeConstructor, initialLayoutGroupConfig);
70
+ }
70
71
  }
71
72
  /**
72
73
  * The mount order and hierarchy is specific to ensure our element ref
73
74
  * is hydrated by the time features fire their effects.
74
75
  */
75
- return (React.createElement(VisualElementHandler, { visualElement: context.visualElement, props: Object.assign(Object.assign({}, config), props) },
76
+ return (React.createElement(VisualElementHandler, { visualElement: context.visualElement, props: configAndProps },
76
77
  features,
77
- React.createElement(MotionContext.Provider, { value: context }, useRender(Component, props, projectionId, useMotionRef(visualState, context.visualElement, externalRef), visualState, config.isStatic, context.visualElement))));
78
+ React.createElement(MotionContext.Provider, { value: context }, useRender(Component, props, projectionId, useMotionRef(visualState, context.visualElement, externalRef), visualState, isStatic, context.visualElement))));
78
79
  }
79
80
  return forwardRef(MotionComponent);
80
81
  }
81
82
  function useLayoutId({ layoutId }) {
82
- var _a;
83
- const layoutGroupId = (_a = useContext(LayoutGroupContext)) === null || _a === void 0 ? void 0 : _a.id;
83
+ const layoutGroupId = useContext(LayoutGroupContext).id;
84
84
  return layoutGroupId && layoutId !== undefined
85
85
  ? layoutGroupId + "-" + layoutId
86
86
  : layoutId;
@@ -5,15 +5,12 @@ class VisualElementHandler extends React__default.Component {
5
5
  * Update visual element props as soon as we know this update is going to be commited.
6
6
  */
7
7
  getSnapshotBeforeUpdate() {
8
- this.updateProps();
9
- return null;
10
- }
11
- componentDidUpdate() { }
12
- updateProps() {
13
8
  const { visualElement, props } = this.props;
14
9
  if (visualElement)
15
10
  visualElement.setProps(props);
11
+ return null;
16
12
  }
13
+ componentDidUpdate() { }
17
14
  render() {
18
15
  return this.props.children;
19
16
  }
@@ -1,9 +1,9 @@
1
1
  import { scaleCorrectors } from '../../projection/styles/scale-correction.mjs';
2
- import { isTransformProp, isTransformOriginProp } from '../../render/html/utils/transform.mjs';
2
+ import { transformProps } from '../../render/html/utils/transform.mjs';
3
3
 
4
4
  function isForcedMotionValue(key, { layout, layoutId }) {
5
- return (isTransformProp(key) ||
6
- isTransformOriginProp(key) ||
5
+ return (transformProps.has(key) ||
6
+ key.startsWith("origin") ||
7
7
  ((layout || layoutId !== undefined) &&
8
8
  (!!scaleCorrectors[key] || key === "opacity")));
9
9
  }
@@ -7,8 +7,7 @@ import { isRefObject } from '../../utils/is-ref-object.mjs';
7
7
  */
8
8
  function useMotionRef(visualState, visualElement, externalRef) {
9
9
  return useCallback((instance) => {
10
- var _a;
11
- instance && ((_a = visualState.mount) === null || _a === void 0 ? void 0 : _a.call(visualState, instance));
10
+ instance && visualState.mount && visualState.mount(instance);
12
11
  if (visualElement) {
13
12
  instance
14
13
  ? visualElement.mount(instance)
@@ -3,38 +3,40 @@ import { PresenceContext } from '../../context/PresenceContext.mjs';
3
3
  import { useVisualElementContext } from '../../context/MotionContext/index.mjs';
4
4
  import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
5
5
  import { LazyContext } from '../../context/LazyContext.mjs';
6
- import { useReducedMotionConfig } from '../../utils/use-reduced-motion.mjs';
6
+ import { MotionConfigContext } from '../../context/MotionConfigContext.mjs';
7
7
 
8
8
  function useVisualElement(Component, visualState, props, createVisualElement) {
9
- const lazyContext = useContext(LazyContext);
10
9
  const parent = useVisualElementContext();
10
+ const lazyContext = useContext(LazyContext);
11
11
  const presenceContext = useContext(PresenceContext);
12
- const shouldReduceMotion = useReducedMotionConfig();
12
+ const reducedMotionConfig = useContext(MotionConfigContext).reducedMotion;
13
13
  const visualElementRef = useRef(undefined);
14
14
  /**
15
15
  * If we haven't preloaded a renderer, check to see if we have one lazy-loaded
16
16
  */
17
- if (!createVisualElement)
18
- createVisualElement = lazyContext.renderer;
17
+ createVisualElement = createVisualElement || lazyContext.renderer;
19
18
  if (!visualElementRef.current && createVisualElement) {
20
19
  visualElementRef.current = createVisualElement(Component, {
21
20
  visualState,
22
21
  parent,
23
22
  props,
24
- presenceId: presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.id,
25
- blockInitialAnimation: (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) === false,
26
- shouldReduceMotion,
23
+ presenceId: presenceContext ? presenceContext.id : undefined,
24
+ blockInitialAnimation: presenceContext
25
+ ? presenceContext.initial === false
26
+ : false,
27
+ reducedMotionConfig,
27
28
  });
28
29
  }
29
30
  const visualElement = visualElementRef.current;
30
31
  useIsomorphicLayoutEffect(() => {
31
- visualElement === null || visualElement === void 0 ? void 0 : visualElement.syncRender();
32
+ visualElement && visualElement.syncRender();
32
33
  });
33
34
  useEffect(() => {
34
- var _a;
35
- (_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.animationState) === null || _a === void 0 ? void 0 : _a.animateChanges();
35
+ if (visualElement && visualElement.animationState) {
36
+ visualElement.animationState.animateChanges();
37
+ }
36
38
  });
37
- useIsomorphicLayoutEffect(() => () => visualElement === null || visualElement === void 0 ? void 0 : visualElement.notifyUnmount(), []);
39
+ useIsomorphicLayoutEffect(() => () => visualElement && visualElement.notifyUnmount(), []);
38
40
  return visualElement;
39
41
  }
40
42
 
@@ -1,11 +1,11 @@
1
- import { __rest } from 'tslib';
2
1
  import { useContext } from 'react';
3
2
  import { isAnimationControls } from '../../animation/utils/is-animation-controls.mjs';
4
3
  import { PresenceContext } from '../../context/PresenceContext.mjs';
5
- import { checkIfControllingVariants, checkIfVariantNode, resolveVariantFromProps } from '../../render/utils/variants.mjs';
4
+ import { resolveVariantFromProps } from '../../render/utils/resolve-variants.mjs';
6
5
  import { useConstant } from '../../utils/use-constant.mjs';
7
6
  import { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';
8
7
  import { MotionContext } from '../../context/MotionContext/index.mjs';
8
+ import { isControllingVariants, isVariantNode } from '../../render/utils/is-controlling-variants.mjs';
9
9
 
10
10
  function makeState({ scrapeMotionValuesFromProps, createRenderState, onMount, }, props, context, presenceContext) {
11
11
  const state = {
@@ -20,29 +20,32 @@ function makeState({ scrapeMotionValuesFromProps, createRenderState, onMount, },
20
20
  const makeUseVisualState = (config) => (props, isStatic) => {
21
21
  const context = useContext(MotionContext);
22
22
  const presenceContext = useContext(PresenceContext);
23
- return isStatic
24
- ? makeState(config, props, context, presenceContext)
25
- : useConstant(() => makeState(config, props, context, presenceContext));
23
+ const make = () => makeState(config, props, context, presenceContext);
24
+ return isStatic ? make() : useConstant(make);
26
25
  };
27
26
  function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
28
27
  const values = {};
29
- const blockInitialAnimation = (presenceContext === null || presenceContext === void 0 ? void 0 : presenceContext.initial) === false;
30
28
  const motionValues = scrapeMotionValues(props);
31
29
  for (const key in motionValues) {
32
30
  values[key] = resolveMotionValue(motionValues[key]);
33
31
  }
34
32
  let { initial, animate } = props;
35
- const isControllingVariants = checkIfControllingVariants(props);
36
- const isVariantNode = checkIfVariantNode(props);
33
+ const isControllingVariants$1 = isControllingVariants(props);
34
+ const isVariantNode$1 = isVariantNode(props);
37
35
  if (context &&
38
- isVariantNode &&
39
- !isControllingVariants &&
36
+ isVariantNode$1 &&
37
+ !isControllingVariants$1 &&
40
38
  props.inherit !== false) {
41
- initial !== null && initial !== void 0 ? initial : (initial = context.initial);
42
- animate !== null && animate !== void 0 ? animate : (animate = context.animate);
39
+ if (initial === undefined)
40
+ initial = context.initial;
41
+ if (animate === undefined)
42
+ animate = context.animate;
43
43
  }
44
- const initialAnimationIsBlocked = blockInitialAnimation || initial === false;
45
- const variantToSet = initialAnimationIsBlocked ? animate : initial;
44
+ let isInitialAnimationBlocked = presenceContext
45
+ ? presenceContext.initial === false
46
+ : false;
47
+ isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
48
+ const variantToSet = isInitialAnimationBlocked ? animate : initial;
46
49
  if (variantToSet &&
47
50
  typeof variantToSet !== "boolean" &&
48
51
  !isAnimationControls(variantToSet)) {
@@ -51,7 +54,7 @@ function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
51
54
  const resolved = resolveVariantFromProps(props, definition);
52
55
  if (!resolved)
53
56
  return;
54
- const { transitionEnd, transition } = resolved, target = __rest(resolved, ["transitionEnd", "transition"]);
57
+ const { transitionEnd, transition, ...target } = resolved;
55
58
  for (const key in target) {
56
59
  let valueTarget = target[key];
57
60
  if (Array.isArray(valueTarget)) {
@@ -59,7 +62,7 @@ function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
59
62
  * Take final keyframe if the initial animation is blocked because
60
63
  * we want to initialise at the end of that blocked animation.
61
64
  */
62
- const index = initialAnimationIsBlocked
65
+ const index = isInitialAnimationBlocked
63
66
  ? valueTarget.length - 1
64
67
  : 0;
65
68
  valueTarget = valueTarget[index];
@@ -1,3 +1,21 @@
1
+ const animationProps = [
2
+ "animate",
3
+ "exit",
4
+ "variants",
5
+ "whileHover",
6
+ "whileTap",
7
+ "whileFocus",
8
+ "whileDrag",
9
+ "whileInView",
10
+ ];
11
+ const tapProps = ["whileTap", "onTap", "onTapStart", "onTapCancel"];
12
+ const panProps = ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"];
13
+ const inViewProps = [
14
+ "whileInView",
15
+ "onViewportEnter",
16
+ "onViewportLeave",
17
+ "viewport",
18
+ ];
1
19
  /**
2
20
  * A list of all valid MotionProps.
3
21
  *
@@ -6,8 +24,6 @@
6
24
  */
7
25
  const validMotionProps = new Set([
8
26
  "initial",
9
- "animate",
10
- "exit",
11
27
  "style",
12
28
  "variants",
13
29
  "transition",
@@ -43,24 +59,13 @@ const validMotionProps = new Set([
43
59
  "dragMomentum",
44
60
  "dragPropagation",
45
61
  "dragTransition",
46
- "whileDrag",
47
- "onPan",
48
- "onPanStart",
49
- "onPanEnd",
50
- "onPanSessionStart",
51
- "onTap",
52
- "onTapStart",
53
- "onTapCancel",
54
62
  "onHoverStart",
55
63
  "onHoverEnd",
56
- "whileFocus",
57
- "whileTap",
58
- "whileHover",
59
- "whileInView",
60
- "onViewportEnter",
61
- "onViewportLeave",
62
- "viewport",
63
64
  "layoutScroll",
65
+ ...inViewProps,
66
+ ...tapProps,
67
+ ...animationProps,
68
+ ...panProps,
64
69
  ]);
65
70
  /**
66
71
  * Check whether a prop name is a valid `MotionProp` key.
@@ -1,3 +1,6 @@
1
+ import { distance } from 'popmotion';
2
+ import { calcLength } from './delta-calc.mjs';
3
+
1
4
  function isAxisDeltaZero(delta) {
2
5
  return delta.translate === 0 && delta.scale === 1;
3
6
  }
@@ -10,5 +13,11 @@ function boxEquals(a, b) {
10
13
  a.y.min === b.y.min &&
11
14
  a.y.max === b.y.max);
12
15
  }
16
+ function aspectRatio(box) {
17
+ return calcLength(box.x) / calcLength(box.y);
18
+ }
19
+ function isCloseTo(a, b, max = 0.01) {
20
+ return distance(a, b) <= max;
21
+ }
13
22
 
14
- export { boxEquals, isDeltaZero };
23
+ export { aspectRatio, boxEquals, isCloseTo, isDeltaZero };
@@ -19,7 +19,7 @@ const HTMLProjectionNode = createProjectionNode({
19
19
  return rootProjectionNode.current;
20
20
  },
21
21
  resetTransform: (instance, value) => {
22
- instance.style.transform = value !== null && value !== void 0 ? value : "none";
22
+ instance.style.transform = value !== undefined ? value : "none";
23
23
  },
24
24
  checkIsScrollRoot: (instance) => Boolean(window.getComputedStyle(instance).position === "fixed"),
25
25
  });
@@ -9,17 +9,17 @@ import { calcRelativePosition, calcRelativeBox, calcBoxDelta, calcLength } from
9
9
  import { removeBoxTransforms } from '../geometry/delta-remove.mjs';
10
10
  import { createBox, createDelta } from '../geometry/models.mjs';
11
11
  import { getValueTransition } from '../../animation/utils/transitions.mjs';
12
- import { boxEquals, isDeltaZero } from '../geometry/utils.mjs';
12
+ import { boxEquals, isDeltaZero, isCloseTo, aspectRatio } from '../geometry/utils.mjs';
13
13
  import { NodeStack } from '../shared/stack.mjs';
14
14
  import { scaleCorrectors } from '../styles/scale-correction.mjs';
15
15
  import { buildProjectionTransform } from '../styles/transform.mjs';
16
16
  import { eachAxis } from '../utils/each-axis.mjs';
17
17
  import { hasTransform, hasScale } from '../utils/has-transform.mjs';
18
- import { transformAxes } from '../../render/html/utils/transform.mjs';
19
18
  import { FlatTree } from '../../render/utils/flat-tree.mjs';
20
19
  import { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';
21
20
  import { globalProjectionState } from './state.mjs';
22
21
 
22
+ const transformAxes = ["", "X", "Y", "Z"];
23
23
  /**
24
24
  * We use 1000 as the animation target as 0-1000 maps better to pixels than 0-1
25
25
  * which has a noticeable difference in spring animations
@@ -211,7 +211,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
211
211
  this.resumingFrom.resumingFrom = undefined;
212
212
  }
213
213
  this.setAnimationOrigin(delta, hasOnlyRelativeTargetChanged);
214
- const animationOptions = Object.assign(Object.assign({}, getValueTransition(layoutTransition, "layout")), { onPlay: onLayoutAnimationStart, onComplete: onLayoutAnimationComplete });
214
+ const animationOptions = {
215
+ ...getValueTransition(layoutTransition, "layout"),
216
+ onPlay: onLayoutAnimationStart,
217
+ onComplete: onLayoutAnimationComplete,
218
+ };
215
219
  if (visualElement.shouldReduceMotion) {
216
220
  animationOptions.delay = 0;
217
221
  animationOptions.type = false;
@@ -534,8 +538,11 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
534
538
  this.root.scheduleUpdateProjection();
535
539
  }
536
540
  setOptions(options) {
537
- var _a;
538
- this.options = Object.assign(Object.assign(Object.assign({}, this.options), options), { crossfade: (_a = options.crossfade) !== null && _a !== void 0 ? _a : true });
541
+ this.options = {
542
+ ...this.options,
543
+ ...options,
544
+ crossfade: options.crossfade !== undefined ? options.crossfade : true,
545
+ };
539
546
  }
540
547
  clearMeasurements() {
541
548
  this.scroll = undefined;
@@ -717,7 +724,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
717
724
  var _a;
718
725
  const snapshot = this.snapshot;
719
726
  const snapshotLatestValues = (snapshot === null || snapshot === void 0 ? void 0 : snapshot.latestValues) || {};
720
- const mixedValues = Object.assign({}, this.latestValues);
727
+ const mixedValues = { ...this.latestValues };
721
728
  const targetDelta = createDelta();
722
729
  this.relativeTarget = this.relativeTargetOrigin = undefined;
723
730
  this.attemptToResolveRelativeTarget = !hasOnlyRelativeTargetChanged;
@@ -770,15 +777,19 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
770
777
  */
771
778
  this.pendingAnimation = sync.update(() => {
772
779
  globalProjectionState.hasAnimatedSinceResize = true;
773
- this.currentAnimation = animate(0, animationTarget, Object.assign(Object.assign({}, options), { onUpdate: (latest) => {
780
+ this.currentAnimation = animate(0, animationTarget, {
781
+ ...options,
782
+ onUpdate: (latest) => {
774
783
  var _a;
775
784
  this.mixTargetDelta(latest);
776
785
  (_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, latest);
777
- }, onComplete: () => {
786
+ },
787
+ onComplete: () => {
778
788
  var _a;
779
789
  (_a = options.onComplete) === null || _a === void 0 ? void 0 : _a.call(options);
780
790
  this.completeAnimation();
781
- } }));
791
+ },
792
+ });
782
793
  if (this.resumingFrom) {
783
794
  this.resumingFrom.currentAnimation = this.currentAnimation;
784
795
  }
@@ -807,9 +818,27 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
807
818
  this.completeAnimation();
808
819
  }
809
820
  applyTransformsToTarget() {
810
- const { targetWithTransforms, target, layout, latestValues } = this.getLead();
821
+ const lead = this.getLead();
822
+ let { targetWithTransforms, target, layout, latestValues } = lead;
811
823
  if (!targetWithTransforms || !target || !layout)
812
824
  return;
825
+ /**
826
+ * If we're only animating position, and this element isn't the lead element,
827
+ * then instead of projecting into the lead box we instead want to calculate
828
+ * a new target that aligns the two boxes but maintains the layout shape.
829
+ */
830
+ if (this !== lead &&
831
+ this.layout &&
832
+ layout &&
833
+ shouldAnimatePositionOnly(this.options.animationType, this.layout.actual, layout.actual)) {
834
+ target = this.target || createBox();
835
+ const xLength = calcLength(this.layout.actual.x);
836
+ target.x.min = lead.target.x.min;
837
+ target.x.max = target.x.min + xLength;
838
+ const yLength = calcLength(this.layout.actual.y);
839
+ target.y.min = lead.target.y.min;
840
+ target.y.max = target.y.min + yLength;
841
+ }
813
842
  copyBoxInto(targetWithTransforms, target);
814
843
  /**
815
844
  * Apply the latest user-set transforms to the targetBox to produce the targetBoxFinal.
@@ -913,7 +942,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
913
942
  visualElement.scheduleRender();
914
943
  }
915
944
  getProjectionStyles(styleProp = {}) {
916
- var _a, _b, _c, _d, _e, _f;
945
+ var _a, _b, _c;
917
946
  // TODO: Return lifecycle-persistent object
918
947
  const styles = {};
919
948
  if (!this.instance || this.isSVG)
@@ -939,7 +968,10 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
939
968
  if (!this.projectionDelta || !this.layout || !lead.target) {
940
969
  const emptyStyles = {};
941
970
  if (this.options.layoutId) {
942
- emptyStyles.opacity = (_b = this.latestValues.opacity) !== null && _b !== void 0 ? _b : 1;
971
+ emptyStyles.opacity =
972
+ this.latestValues.opacity !== undefined
973
+ ? this.latestValues.opacity
974
+ : 1;
943
975
  emptyStyles.pointerEvents =
944
976
  resolveMotionValue(styleProp.pointerEvents) || "";
945
977
  }
@@ -966,7 +998,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
966
998
  */
967
999
  styles.opacity =
968
1000
  lead === this
969
- ? (_d = (_c = valuesToRender.opacity) !== null && _c !== void 0 ? _c : this.latestValues.opacity) !== null && _d !== void 0 ? _d : 1
1001
+ ? (_c = (_b = valuesToRender.opacity) !== null && _b !== void 0 ? _b : this.latestValues.opacity) !== null && _c !== void 0 ? _c : 1
970
1002
  : this.preserveOpacity
971
1003
  ? this.latestValues.opacity
972
1004
  : valuesToRender.opacityExit;
@@ -978,8 +1010,12 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
978
1010
  */
979
1011
  styles.opacity =
980
1012
  lead === this
981
- ? (_e = valuesToRender.opacity) !== null && _e !== void 0 ? _e : ""
982
- : (_f = valuesToRender.opacityExit) !== null && _f !== void 0 ? _f : 0;
1013
+ ? valuesToRender.opacity !== undefined
1014
+ ? valuesToRender.opacity
1015
+ : ""
1016
+ : valuesToRender.opacityExit !== undefined
1017
+ ? valuesToRender.opacityExit
1018
+ : 0;
983
1019
  }
984
1020
  /**
985
1021
  * Apply scale correction
@@ -1027,16 +1063,17 @@ function updateLayout(node) {
1027
1063
  node.updateLayout();
1028
1064
  }
1029
1065
  function notifyLayoutUpdate(node) {
1030
- var _a, _b, _c, _d;
1031
- const snapshot = (_b = (_a = node.resumeFrom) === null || _a === void 0 ? void 0 : _a.snapshot) !== null && _b !== void 0 ? _b : node.snapshot;
1066
+ var _a, _b, _c;
1067
+ const snapshot = ((_a = node.resumeFrom) === null || _a === void 0 ? void 0 : _a.snapshot) || node.snapshot;
1032
1068
  if (node.isLead() &&
1033
1069
  node.layout &&
1034
1070
  snapshot &&
1035
1071
  node.hasListeners("didUpdate")) {
1036
1072
  const { actual: layout, measured: measuredLayout } = node.layout;
1073
+ const { animationType } = node.options;
1037
1074
  // TODO Maybe we want to also resize the layout snapshot so we don't trigger
1038
1075
  // animations for instance if layout="size" and an element has only changed position
1039
- if (node.options.animationType === "size") {
1076
+ if (animationType === "size") {
1040
1077
  eachAxis((axis) => {
1041
1078
  const axisSnapshot = snapshot.isShared
1042
1079
  ? snapshot.measured[axis]
@@ -1046,7 +1083,7 @@ function notifyLayoutUpdate(node) {
1046
1083
  axisSnapshot.max = axisSnapshot.min + length;
1047
1084
  });
1048
1085
  }
1049
- else if (node.options.animationType === "position") {
1086
+ else if (shouldAnimatePositionOnly(animationType, snapshot.layout, layout)) {
1050
1087
  eachAxis((axis) => {
1051
1088
  const axisSnapshot = snapshot.isShared
1052
1089
  ? snapshot.measured[axis]
@@ -1095,7 +1132,7 @@ function notifyLayoutUpdate(node) {
1095
1132
  });
1096
1133
  }
1097
1134
  else if (node.isLead()) {
1098
- (_d = (_c = node.options).onExitComplete) === null || _d === void 0 ? void 0 : _d.call(_c);
1135
+ (_c = (_b = node.options).onExitComplete) === null || _c === void 0 ? void 0 : _c.call(_b);
1099
1136
  }
1100
1137
  /**
1101
1138
  * Clearing transition
@@ -1179,5 +1216,10 @@ function roundBox(box) {
1179
1216
  roundAxis(box.x);
1180
1217
  roundAxis(box.y);
1181
1218
  }
1219
+ function shouldAnimatePositionOnly(animationType, snapshot, layout) {
1220
+ return (animationType === "position" ||
1221
+ (animationType === "preserve-aspect" &&
1222
+ !isCloseTo(aspectRatio(snapshot), aspectRatio(layout))));
1223
+ }
1182
1224
 
1183
1225
  export { createProjectionNode, mixAxis, mixAxisDelta, mixBox };