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.
- package/dist/cjs/index.js +762 -627
- package/dist/es/animation/use-animated-state.mjs +3 -5
- package/dist/es/animation/utils/default-transitions.mjs +1 -1
- package/dist/es/animation/utils/transitions.mjs +28 -26
- package/dist/es/components/AnimatePresence/PopChild.mjs +3 -2
- package/dist/es/components/AnimatePresence/PresenceChild.mjs +5 -2
- package/dist/es/components/AnimatePresence/use-presence.mjs +1 -1
- package/dist/es/components/LayoutGroup/index.mjs +4 -5
- package/dist/es/components/LazyMotion/index.mjs +3 -5
- package/dist/es/components/MotionConfig/index.mjs +2 -4
- package/dist/es/components/Reorder/Group.mjs +2 -4
- package/dist/es/components/Reorder/Item.mjs +6 -8
- package/dist/es/context/MotionContext/utils.mjs +3 -2
- package/dist/es/gestures/PanSession.mjs +2 -2
- package/dist/es/gestures/drag/VisualElementDragControls.mjs +16 -4
- package/dist/es/gestures/use-focus-gesture.mjs +3 -4
- package/dist/es/gestures/use-hover-gesture.mjs +4 -3
- package/dist/es/gestures/use-tap-gesture.mjs +9 -10
- package/dist/es/index.mjs +2 -1
- package/dist/es/motion/features/animations.mjs +8 -3
- package/dist/es/motion/features/definitions.mjs +1 -13
- package/dist/es/motion/features/layout/MeasureLayout.mjs +12 -6
- package/dist/es/motion/features/load-features.mjs +14 -0
- package/dist/es/motion/features/viewport/observers.mjs +4 -7
- package/dist/es/motion/features/viewport/use-viewport.mjs +8 -6
- package/dist/es/motion/index.mjs +23 -23
- package/dist/es/motion/utils/VisualElementHandler.mjs +2 -5
- package/dist/es/motion/utils/is-forced-motion-value.mjs +3 -3
- package/dist/es/motion/utils/use-motion-ref.mjs +1 -2
- package/dist/es/motion/utils/use-visual-element.mjs +14 -12
- package/dist/es/motion/utils/use-visual-state.mjs +19 -16
- package/dist/es/motion/utils/valid-prop.mjs +22 -17
- package/dist/es/projection/geometry/utils.mjs +10 -1
- package/dist/es/projection/node/HTMLProjectionNode.mjs +1 -1
- package/dist/es/projection/node/create-projection-node.mjs +62 -20
- package/dist/es/projection/use-instant-layout-transition.mjs +2 -2
- package/dist/es/render/dom/features-animation.mjs +5 -1
- package/dist/es/render/dom/features-max.mjs +6 -1
- package/dist/es/render/dom/motion.mjs +6 -1
- package/dist/es/render/dom/use-render.mjs +5 -1
- package/dist/es/render/dom/utils/camel-to-dash.mjs +1 -3
- package/dist/es/render/dom/utils/create-config.mjs +7 -2
- package/dist/es/render/dom/utils/css-variables-conversion.mjs +5 -7
- package/dist/es/render/dom/utils/unit-conversion.mjs +4 -4
- package/dist/es/render/dom/value-types/defaults.mjs +15 -3
- package/dist/es/render/dom/value-types/type-int.mjs +4 -1
- package/dist/es/render/html/config-motion.mjs +1 -1
- package/dist/es/render/html/use-props.mjs +5 -9
- package/dist/es/render/html/utils/build-styles.mjs +17 -15
- package/dist/es/render/html/utils/build-transform.mjs +8 -18
- package/dist/es/render/html/utils/transform.mjs +21 -30
- package/dist/es/render/html/visual-element.mjs +8 -9
- package/dist/es/render/index.mjs +118 -40
- package/dist/es/render/svg/use-props.mjs +5 -2
- package/dist/es/render/svg/utils/build-attrs.mjs +3 -5
- package/dist/es/render/svg/utils/create-render-state.mjs +4 -1
- package/dist/es/render/svg/visual-element.mjs +8 -4
- package/dist/es/render/utils/animation-state.mjs +12 -9
- package/dist/es/render/utils/animation.mjs +14 -8
- package/dist/es/render/utils/is-controlling-variants.mjs +22 -0
- package/dist/es/render/utils/is-variant-label.mjs +8 -0
- package/dist/es/render/utils/motion-values.mjs +3 -3
- package/dist/es/render/utils/resolve-dynamic-variants.mjs +24 -0
- package/dist/es/render/utils/resolve-variants.mjs +26 -0
- package/dist/es/render/utils/setters.mjs +12 -9
- package/dist/es/utils/reduced-motion/index.mjs +19 -0
- package/dist/es/utils/reduced-motion/state.mjs +5 -0
- package/dist/es/utils/reduced-motion/use-reduced-motion-config.mjs +19 -0
- package/dist/es/utils/reduced-motion/use-reduced-motion.mjs +43 -0
- package/dist/es/utils/transform.mjs +4 -1
- package/dist/es/utils/use-in-view.mjs +1 -2
- package/dist/es/value/index.mjs +1 -1
- package/dist/es/value/use-scroll.mjs +6 -4
- package/dist/es/value/use-spring.mjs +7 -1
- package/dist/es/value/use-will-change/index.mjs +4 -4
- package/dist/es/value/utils/is-motion-value.mjs +1 -3
- package/dist/framer-motion.dev.js +806 -670
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +60 -54
- package/dist/projection.dev.js +402 -213
- package/dist/size-rollup-dom-animation-assets.js +1 -0
- package/dist/size-rollup-dom-animation-m.js +1 -0
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max-assets.js +1 -0
- package/dist/size-rollup-dom-max.js +1 -1
- package/dist/size-rollup-m.js +1 -1
- package/dist/size-rollup-motion.js +1 -0
- package/dist/size-webpack-dom-animation.js +1 -1
- package/dist/size-webpack-dom-max.js +1 -1
- package/dist/size-webpack-m.js +1 -1
- package/dist/three-entry.d.ts +41 -22
- package/package.json +12 -8
- package/dist/es/motion/features/use-features.mjs +0 -40
- package/dist/es/motion/features/use-projection.mjs +0 -33
- package/dist/es/render/utils/variants.mjs +0 -73
- 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
|
-
|
|
17
|
-
|
|
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(
|
|
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,
|
|
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
|
-
(
|
|
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
|
|
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
|
|
91
|
-
(
|
|
90
|
+
onViewportEnter && onViewportEnter(null);
|
|
91
|
+
if (visualElement.animationState) {
|
|
92
|
+
visualElement.animationState.setActive(AnimationType.InView, true);
|
|
93
|
+
}
|
|
92
94
|
});
|
|
93
95
|
}, [shouldObserve]);
|
|
94
96
|
}
|
package/dist/es/motion/index.mjs
CHANGED
|
@@ -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 {
|
|
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
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 =
|
|
48
|
+
const projectionId = isStatic ? undefined : useProjectionId();
|
|
51
49
|
/**
|
|
52
50
|
*
|
|
53
51
|
*/
|
|
54
|
-
const visualState = useVisualState(props,
|
|
55
|
-
if (!
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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 {
|
|
2
|
+
import { transformProps } from '../../render/html/utils/transform.mjs';
|
|
3
3
|
|
|
4
4
|
function isForcedMotionValue(key, { layout, layoutId }) {
|
|
5
|
-
return (
|
|
6
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
25
|
-
blockInitialAnimation:
|
|
26
|
-
|
|
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
|
|
32
|
+
visualElement && visualElement.syncRender();
|
|
32
33
|
});
|
|
33
34
|
useEffect(() => {
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
if (visualElement && visualElement.animationState) {
|
|
36
|
+
visualElement.animationState.animateChanges();
|
|
37
|
+
}
|
|
36
38
|
});
|
|
37
|
-
useIsomorphicLayoutEffect(() => () => visualElement
|
|
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 {
|
|
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
|
-
|
|
24
|
-
|
|
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 =
|
|
36
|
-
const isVariantNode =
|
|
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
|
-
|
|
42
|
-
|
|
39
|
+
if (initial === undefined)
|
|
40
|
+
initial = context.initial;
|
|
41
|
+
if (animate === undefined)
|
|
42
|
+
animate = context.animate;
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
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
|
|
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 =
|
|
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 !==
|
|
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 =
|
|
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
|
-
|
|
538
|
-
|
|
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 =
|
|
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,
|
|
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
|
-
},
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
? (
|
|
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
|
-
?
|
|
982
|
-
|
|
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
|
|
1031
|
-
const 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 (
|
|
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 (
|
|
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
|
-
(
|
|
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 };
|