framer-motion 7.1.2 → 7.2.0
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 +84 -10
- package/dist/es/components/AnimatePresence/PopChild.mjs +70 -0
- package/dist/es/components/AnimatePresence/PresenceChild.mjs +5 -1
- package/dist/es/components/AnimatePresence/index.mjs +13 -7
- package/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/value/index.mjs +1 -1
- package/dist/framer-motion.dev.js +84 -10
- package/dist/framer-motion.js +1 -1
- package/dist/index.d.ts +17 -3
- package/dist/projection.dev.js +2 -2
- package/dist/size-rollup-dom-animation.js +1 -1
- package/dist/size-rollup-dom-max.js +1 -1
- package/package.json +2 -2
package/dist/cjs/index.js
CHANGED
|
@@ -2376,7 +2376,7 @@ class MotionValue {
|
|
|
2376
2376
|
* This will be replaced by the build step with the latest version number.
|
|
2377
2377
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
2378
2378
|
*/
|
|
2379
|
-
this.version = "7.
|
|
2379
|
+
this.version = "7.2.0";
|
|
2380
2380
|
/**
|
|
2381
2381
|
* Duration, in milliseconds, since last updating frame.
|
|
2382
2382
|
*
|
|
@@ -4282,7 +4282,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
4282
4282
|
* and warn against mismatches.
|
|
4283
4283
|
*/
|
|
4284
4284
|
if (process.env.NODE_ENV === "development") {
|
|
4285
|
-
warnOnce(nextValue.version === "7.
|
|
4285
|
+
warnOnce(nextValue.version === "7.2.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.2.0 may not work as expected.`);
|
|
4286
4286
|
}
|
|
4287
4287
|
}
|
|
4288
4288
|
else if (isMotionValue(prevValue)) {
|
|
@@ -6968,7 +6968,73 @@ function useForceUpdate() {
|
|
|
6968
6968
|
return [deferredForceRender, forcedRenderCount];
|
|
6969
6969
|
}
|
|
6970
6970
|
|
|
6971
|
-
|
|
6971
|
+
/**
|
|
6972
|
+
* Measurement functionality has to be within a separate component
|
|
6973
|
+
* to leverage snapshot lifecycle.
|
|
6974
|
+
*/
|
|
6975
|
+
class PopChildMeasure extends React__namespace.Component {
|
|
6976
|
+
getSnapshotBeforeUpdate(prevProps) {
|
|
6977
|
+
const element = this.props.childRef.current;
|
|
6978
|
+
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
6979
|
+
const size = this.props.sizeRef.current;
|
|
6980
|
+
size.height = element.offsetHeight || 0;
|
|
6981
|
+
size.width = element.offsetWidth || 0;
|
|
6982
|
+
size.top = element.offsetTop;
|
|
6983
|
+
size.left = element.offsetLeft;
|
|
6984
|
+
}
|
|
6985
|
+
return null;
|
|
6986
|
+
}
|
|
6987
|
+
/**
|
|
6988
|
+
* Required with getSnapshotBeforeUpdate to stop React complaining.
|
|
6989
|
+
*/
|
|
6990
|
+
componentDidUpdate() { }
|
|
6991
|
+
render() {
|
|
6992
|
+
return this.props.children;
|
|
6993
|
+
}
|
|
6994
|
+
}
|
|
6995
|
+
function PopChild({ children, isPresent }) {
|
|
6996
|
+
const id = React.useId();
|
|
6997
|
+
const ref = React.useRef(null);
|
|
6998
|
+
const size = React.useRef({
|
|
6999
|
+
width: 0,
|
|
7000
|
+
height: 0,
|
|
7001
|
+
top: 0,
|
|
7002
|
+
left: 0,
|
|
7003
|
+
});
|
|
7004
|
+
/**
|
|
7005
|
+
* We create and inject a style block so we can apply this explicit
|
|
7006
|
+
* sizing in a non-destructive manner by just deleting the style block.
|
|
7007
|
+
*
|
|
7008
|
+
* We can't apply size via render as the measurement happens
|
|
7009
|
+
* in getSnapshotBeforeUpdate (post-render), likewise if we apply the
|
|
7010
|
+
* styles directly on the DOM node, we might be overwriting
|
|
7011
|
+
* styles set via the style prop.
|
|
7012
|
+
*/
|
|
7013
|
+
React.useInsertionEffect(() => {
|
|
7014
|
+
var _a;
|
|
7015
|
+
const { width, height, top, left } = size.current;
|
|
7016
|
+
if (isPresent || !ref.current || !width || !height)
|
|
7017
|
+
return;
|
|
7018
|
+
ref.current.dataset.motionPopId = id;
|
|
7019
|
+
const style = document.createElement("style");
|
|
7020
|
+
document.head.appendChild(style);
|
|
7021
|
+
(_a = style.sheet) === null || _a === void 0 ? void 0 : _a.insertRule(`
|
|
7022
|
+
[data-motion-pop-id="${id}"] {
|
|
7023
|
+
position: absolute !important;
|
|
7024
|
+
width: ${width}px !important;
|
|
7025
|
+
height: ${height}px !important;
|
|
7026
|
+
top: ${top}px !important;
|
|
7027
|
+
left: ${left}px !important;
|
|
7028
|
+
}
|
|
7029
|
+
`);
|
|
7030
|
+
return () => {
|
|
7031
|
+
document.head.removeChild(style);
|
|
7032
|
+
};
|
|
7033
|
+
}, [isPresent]);
|
|
7034
|
+
return (React__namespace.createElement(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size }, React__namespace.cloneElement(children, { ref })));
|
|
7035
|
+
}
|
|
7036
|
+
|
|
7037
|
+
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, }) => {
|
|
6972
7038
|
const presenceChildren = useConstant(newChildrenMap);
|
|
6973
7039
|
const id = React.useId();
|
|
6974
7040
|
const context = React.useMemo(() => ({
|
|
@@ -7005,6 +7071,9 @@ const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, p
|
|
|
7005
7071
|
React__namespace.useEffect(() => {
|
|
7006
7072
|
!isPresent && !presenceChildren.size && (onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete());
|
|
7007
7073
|
}, [isPresent]);
|
|
7074
|
+
if (mode === "popLayout") {
|
|
7075
|
+
children = React__namespace.createElement(PopChild, { isPresent: isPresent }, children);
|
|
7076
|
+
}
|
|
7008
7077
|
return (React__namespace.createElement(PresenceContext.Provider, { value: context }, children));
|
|
7009
7078
|
};
|
|
7010
7079
|
function newChildrenMap() {
|
|
@@ -7060,7 +7129,12 @@ function onlyElements(children) {
|
|
|
7060
7129
|
*
|
|
7061
7130
|
* @public
|
|
7062
7131
|
*/
|
|
7063
|
-
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, }) => {
|
|
7132
|
+
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, mode = "sync", }) => {
|
|
7133
|
+
// Support deprecated exitBeforeEnter prop
|
|
7134
|
+
if (exitBeforeEnter) {
|
|
7135
|
+
mode = "wait";
|
|
7136
|
+
warnOnce(false, "Replace exitBeforeEnter with mode='wait'");
|
|
7137
|
+
}
|
|
7064
7138
|
// We want to force a re-render once all exiting animations have finished. We
|
|
7065
7139
|
// either use a local forceRender function, or one from a parent context if it exists.
|
|
7066
7140
|
let [forceRender] = useForceUpdate();
|
|
@@ -7091,7 +7165,7 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
7091
7165
|
exiting.clear();
|
|
7092
7166
|
});
|
|
7093
7167
|
if (isInitialRender.current) {
|
|
7094
|
-
return (React__namespace.createElement(React__namespace.Fragment, null, childrenToRender.map((child) => (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout }, child)))));
|
|
7168
|
+
return (React__namespace.createElement(React__namespace.Fragment, null, childrenToRender.map((child) => (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child)))));
|
|
7095
7169
|
}
|
|
7096
7170
|
// If this is a subsequent render, deal with entering and exiting children
|
|
7097
7171
|
childrenToRender = [...childrenToRender];
|
|
@@ -7109,7 +7183,7 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
7109
7183
|
}
|
|
7110
7184
|
// If we currently have exiting children, and we're deferring rendering incoming children
|
|
7111
7185
|
// until after all current children have exiting, empty the childrenToRender array
|
|
7112
|
-
if (
|
|
7186
|
+
if (mode === "wait" && exiting.size) {
|
|
7113
7187
|
childrenToRender = [];
|
|
7114
7188
|
}
|
|
7115
7189
|
// Loop through all currently exiting components and clone them to overwrite `animate`
|
|
@@ -7137,18 +7211,18 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
7137
7211
|
onExitComplete && onExitComplete();
|
|
7138
7212
|
}
|
|
7139
7213
|
};
|
|
7140
|
-
childrenToRender.splice(insertionIndex, 0, React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
7214
|
+
childrenToRender.splice(insertionIndex, 0, React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
7141
7215
|
});
|
|
7142
7216
|
// Add `MotionContext` even to children that don't need it to ensure we're rendering
|
|
7143
7217
|
// the same tree between renders
|
|
7144
7218
|
childrenToRender = childrenToRender.map((child) => {
|
|
7145
7219
|
const key = child.key;
|
|
7146
|
-
return exiting.has(key) ? (child) : (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
7220
|
+
return exiting.has(key) ? (child) : (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
7147
7221
|
});
|
|
7148
7222
|
if (env !== "production" &&
|
|
7149
|
-
|
|
7223
|
+
mode === "wait" &&
|
|
7150
7224
|
childrenToRender.length > 1) {
|
|
7151
|
-
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its
|
|
7225
|
+
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
|
|
7152
7226
|
}
|
|
7153
7227
|
return (React__namespace.createElement(React__namespace.Fragment, null, exiting.size
|
|
7154
7228
|
? childrenToRender
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useId, useRef, useInsertionEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Measurement functionality has to be within a separate component
|
|
6
|
+
* to leverage snapshot lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
class PopChildMeasure extends React.Component {
|
|
9
|
+
getSnapshotBeforeUpdate(prevProps) {
|
|
10
|
+
const element = this.props.childRef.current;
|
|
11
|
+
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
12
|
+
const size = this.props.sizeRef.current;
|
|
13
|
+
size.height = element.offsetHeight || 0;
|
|
14
|
+
size.width = element.offsetWidth || 0;
|
|
15
|
+
size.top = element.offsetTop;
|
|
16
|
+
size.left = element.offsetLeft;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Required with getSnapshotBeforeUpdate to stop React complaining.
|
|
22
|
+
*/
|
|
23
|
+
componentDidUpdate() { }
|
|
24
|
+
render() {
|
|
25
|
+
return this.props.children;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function PopChild({ children, isPresent }) {
|
|
29
|
+
const id = useId();
|
|
30
|
+
const ref = useRef(null);
|
|
31
|
+
const size = useRef({
|
|
32
|
+
width: 0,
|
|
33
|
+
height: 0,
|
|
34
|
+
top: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* We create and inject a style block so we can apply this explicit
|
|
39
|
+
* sizing in a non-destructive manner by just deleting the style block.
|
|
40
|
+
*
|
|
41
|
+
* We can't apply size via render as the measurement happens
|
|
42
|
+
* in getSnapshotBeforeUpdate (post-render), likewise if we apply the
|
|
43
|
+
* styles directly on the DOM node, we might be overwriting
|
|
44
|
+
* styles set via the style prop.
|
|
45
|
+
*/
|
|
46
|
+
useInsertionEffect(() => {
|
|
47
|
+
var _a;
|
|
48
|
+
const { width, height, top, left } = size.current;
|
|
49
|
+
if (isPresent || !ref.current || !width || !height)
|
|
50
|
+
return;
|
|
51
|
+
ref.current.dataset.motionPopId = id;
|
|
52
|
+
const style = document.createElement("style");
|
|
53
|
+
document.head.appendChild(style);
|
|
54
|
+
(_a = style.sheet) === null || _a === void 0 ? void 0 : _a.insertRule(`
|
|
55
|
+
[data-motion-pop-id="${id}"] {
|
|
56
|
+
position: absolute !important;
|
|
57
|
+
width: ${width}px !important;
|
|
58
|
+
height: ${height}px !important;
|
|
59
|
+
top: ${top}px !important;
|
|
60
|
+
left: ${left}px !important;
|
|
61
|
+
}
|
|
62
|
+
`);
|
|
63
|
+
return () => {
|
|
64
|
+
document.head.removeChild(style);
|
|
65
|
+
};
|
|
66
|
+
}, [isPresent]);
|
|
67
|
+
return (React.createElement(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size }, React.cloneElement(children, { ref })));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { PopChild };
|
|
@@ -2,8 +2,9 @@ import * as React from 'react';
|
|
|
2
2
|
import { useId, useMemo } from 'react';
|
|
3
3
|
import { PresenceContext } from '../../context/PresenceContext.mjs';
|
|
4
4
|
import { useConstant } from '../../utils/use-constant.mjs';
|
|
5
|
+
import { PopChild } from './PopChild.mjs';
|
|
5
6
|
|
|
6
|
-
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, }) => {
|
|
7
|
+
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, }) => {
|
|
7
8
|
const presenceChildren = useConstant(newChildrenMap);
|
|
8
9
|
const id = useId();
|
|
9
10
|
const context = useMemo(() => ({
|
|
@@ -40,6 +41,9 @@ const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, p
|
|
|
40
41
|
React.useEffect(() => {
|
|
41
42
|
!isPresent && !presenceChildren.size && (onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete());
|
|
42
43
|
}, [isPresent]);
|
|
44
|
+
if (mode === "popLayout") {
|
|
45
|
+
children = React.createElement(PopChild, { isPresent: isPresent }, children);
|
|
46
|
+
}
|
|
43
47
|
return (React.createElement(PresenceContext.Provider, { value: context }, children));
|
|
44
48
|
};
|
|
45
49
|
function newChildrenMap() {
|
|
@@ -7,6 +7,7 @@ import { PresenceChild } from './PresenceChild.mjs';
|
|
|
7
7
|
import { LayoutGroupContext } from '../../context/LayoutGroupContext.mjs';
|
|
8
8
|
import { useIsomorphicLayoutEffect } from '../../utils/use-isomorphic-effect.mjs';
|
|
9
9
|
import { useUnmountEffect } from '../../utils/use-unmount-effect.mjs';
|
|
10
|
+
import { warnOnce } from '../../utils/warn-once.mjs';
|
|
10
11
|
|
|
11
12
|
const getChildKey = (child) => child.key || "";
|
|
12
13
|
function updateChildLookup(children, allChildren) {
|
|
@@ -57,7 +58,12 @@ function onlyElements(children) {
|
|
|
57
58
|
*
|
|
58
59
|
* @public
|
|
59
60
|
*/
|
|
60
|
-
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, }) => {
|
|
61
|
+
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, mode = "sync", }) => {
|
|
62
|
+
// Support deprecated exitBeforeEnter prop
|
|
63
|
+
if (exitBeforeEnter) {
|
|
64
|
+
mode = "wait";
|
|
65
|
+
warnOnce(false, "Replace exitBeforeEnter with mode='wait'");
|
|
66
|
+
}
|
|
61
67
|
// We want to force a re-render once all exiting animations have finished. We
|
|
62
68
|
// either use a local forceRender function, or one from a parent context if it exists.
|
|
63
69
|
let [forceRender] = useForceUpdate();
|
|
@@ -88,7 +94,7 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
88
94
|
exiting.clear();
|
|
89
95
|
});
|
|
90
96
|
if (isInitialRender.current) {
|
|
91
|
-
return (React.createElement(React.Fragment, null, childrenToRender.map((child) => (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout }, child)))));
|
|
97
|
+
return (React.createElement(React.Fragment, null, childrenToRender.map((child) => (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child)))));
|
|
92
98
|
}
|
|
93
99
|
// If this is a subsequent render, deal with entering and exiting children
|
|
94
100
|
childrenToRender = [...childrenToRender];
|
|
@@ -106,7 +112,7 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
106
112
|
}
|
|
107
113
|
// If we currently have exiting children, and we're deferring rendering incoming children
|
|
108
114
|
// until after all current children have exiting, empty the childrenToRender array
|
|
109
|
-
if (
|
|
115
|
+
if (mode === "wait" && exiting.size) {
|
|
110
116
|
childrenToRender = [];
|
|
111
117
|
}
|
|
112
118
|
// Loop through all currently exiting components and clone them to overwrite `animate`
|
|
@@ -134,18 +140,18 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exi
|
|
|
134
140
|
onExitComplete && onExitComplete();
|
|
135
141
|
}
|
|
136
142
|
};
|
|
137
|
-
childrenToRender.splice(insertionIndex, 0, React.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
143
|
+
childrenToRender.splice(insertionIndex, 0, React.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
138
144
|
});
|
|
139
145
|
// Add `MotionContext` even to children that don't need it to ensure we're rendering
|
|
140
146
|
// the same tree between renders
|
|
141
147
|
childrenToRender = childrenToRender.map((child) => {
|
|
142
148
|
const key = child.key;
|
|
143
|
-
return exiting.has(key) ? (child) : (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
149
|
+
return exiting.has(key) ? (child) : (React.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
144
150
|
});
|
|
145
151
|
if (env !== "production" &&
|
|
146
|
-
|
|
152
|
+
mode === "wait" &&
|
|
147
153
|
childrenToRender.length > 1) {
|
|
148
|
-
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its
|
|
154
|
+
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
|
|
149
155
|
}
|
|
150
156
|
return (React.createElement(React.Fragment, null, exiting.size
|
|
151
157
|
? childrenToRender
|
|
@@ -23,7 +23,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
23
23
|
* and warn against mismatches.
|
|
24
24
|
*/
|
|
25
25
|
if (process.env.NODE_ENV === "development") {
|
|
26
|
-
warnOnce(nextValue.version === "7.
|
|
26
|
+
warnOnce(nextValue.version === "7.2.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.2.0 may not work as expected.`);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
else if (isMotionValue(prevValue)) {
|
package/dist/es/value/index.mjs
CHANGED
|
@@ -24,7 +24,7 @@ class MotionValue {
|
|
|
24
24
|
* This will be replaced by the build step with the latest version number.
|
|
25
25
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
26
26
|
*/
|
|
27
|
-
this.version = "7.
|
|
27
|
+
this.version = "7.2.0";
|
|
28
28
|
/**
|
|
29
29
|
* Duration, in milliseconds, since last updating frame.
|
|
30
30
|
*
|
|
@@ -3543,7 +3543,7 @@
|
|
|
3543
3543
|
* This will be replaced by the build step with the latest version number.
|
|
3544
3544
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
3545
3545
|
*/
|
|
3546
|
-
this.version = "7.
|
|
3546
|
+
this.version = "7.2.0";
|
|
3547
3547
|
/**
|
|
3548
3548
|
* Duration, in milliseconds, since last updating frame.
|
|
3549
3549
|
*
|
|
@@ -5449,7 +5449,7 @@
|
|
|
5449
5449
|
* and warn against mismatches.
|
|
5450
5450
|
*/
|
|
5451
5451
|
{
|
|
5452
|
-
warnOnce(nextValue.version === "7.
|
|
5452
|
+
warnOnce(nextValue.version === "7.2.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.2.0 may not work as expected.`);
|
|
5453
5453
|
}
|
|
5454
5454
|
}
|
|
5455
5455
|
else if (isMotionValue(prevValue)) {
|
|
@@ -8135,7 +8135,73 @@
|
|
|
8135
8135
|
return [deferredForceRender, forcedRenderCount];
|
|
8136
8136
|
}
|
|
8137
8137
|
|
|
8138
|
-
|
|
8138
|
+
/**
|
|
8139
|
+
* Measurement functionality has to be within a separate component
|
|
8140
|
+
* to leverage snapshot lifecycle.
|
|
8141
|
+
*/
|
|
8142
|
+
class PopChildMeasure extends React__namespace.Component {
|
|
8143
|
+
getSnapshotBeforeUpdate(prevProps) {
|
|
8144
|
+
const element = this.props.childRef.current;
|
|
8145
|
+
if (element && prevProps.isPresent && !this.props.isPresent) {
|
|
8146
|
+
const size = this.props.sizeRef.current;
|
|
8147
|
+
size.height = element.offsetHeight || 0;
|
|
8148
|
+
size.width = element.offsetWidth || 0;
|
|
8149
|
+
size.top = element.offsetTop;
|
|
8150
|
+
size.left = element.offsetLeft;
|
|
8151
|
+
}
|
|
8152
|
+
return null;
|
|
8153
|
+
}
|
|
8154
|
+
/**
|
|
8155
|
+
* Required with getSnapshotBeforeUpdate to stop React complaining.
|
|
8156
|
+
*/
|
|
8157
|
+
componentDidUpdate() { }
|
|
8158
|
+
render() {
|
|
8159
|
+
return this.props.children;
|
|
8160
|
+
}
|
|
8161
|
+
}
|
|
8162
|
+
function PopChild({ children, isPresent }) {
|
|
8163
|
+
const id = React.useId();
|
|
8164
|
+
const ref = React.useRef(null);
|
|
8165
|
+
const size = React.useRef({
|
|
8166
|
+
width: 0,
|
|
8167
|
+
height: 0,
|
|
8168
|
+
top: 0,
|
|
8169
|
+
left: 0,
|
|
8170
|
+
});
|
|
8171
|
+
/**
|
|
8172
|
+
* We create and inject a style block so we can apply this explicit
|
|
8173
|
+
* sizing in a non-destructive manner by just deleting the style block.
|
|
8174
|
+
*
|
|
8175
|
+
* We can't apply size via render as the measurement happens
|
|
8176
|
+
* in getSnapshotBeforeUpdate (post-render), likewise if we apply the
|
|
8177
|
+
* styles directly on the DOM node, we might be overwriting
|
|
8178
|
+
* styles set via the style prop.
|
|
8179
|
+
*/
|
|
8180
|
+
React.useInsertionEffect(() => {
|
|
8181
|
+
var _a;
|
|
8182
|
+
const { width, height, top, left } = size.current;
|
|
8183
|
+
if (isPresent || !ref.current || !width || !height)
|
|
8184
|
+
return;
|
|
8185
|
+
ref.current.dataset.motionPopId = id;
|
|
8186
|
+
const style = document.createElement("style");
|
|
8187
|
+
document.head.appendChild(style);
|
|
8188
|
+
(_a = style.sheet) === null || _a === void 0 ? void 0 : _a.insertRule(`
|
|
8189
|
+
[data-motion-pop-id="${id}"] {
|
|
8190
|
+
position: absolute !important;
|
|
8191
|
+
width: ${width}px !important;
|
|
8192
|
+
height: ${height}px !important;
|
|
8193
|
+
top: ${top}px !important;
|
|
8194
|
+
left: ${left}px !important;
|
|
8195
|
+
}
|
|
8196
|
+
`);
|
|
8197
|
+
return () => {
|
|
8198
|
+
document.head.removeChild(style);
|
|
8199
|
+
};
|
|
8200
|
+
}, [isPresent]);
|
|
8201
|
+
return (React__namespace.createElement(PopChildMeasure, { isPresent: isPresent, childRef: ref, sizeRef: size }, React__namespace.cloneElement(children, { ref })));
|
|
8202
|
+
}
|
|
8203
|
+
|
|
8204
|
+
const PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode, }) => {
|
|
8139
8205
|
const presenceChildren = useConstant(newChildrenMap);
|
|
8140
8206
|
const id = React.useId();
|
|
8141
8207
|
const context = React.useMemo(() => ({
|
|
@@ -8172,6 +8238,9 @@
|
|
|
8172
8238
|
React__namespace.useEffect(() => {
|
|
8173
8239
|
!isPresent && !presenceChildren.size && (onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete());
|
|
8174
8240
|
}, [isPresent]);
|
|
8241
|
+
if (mode === "popLayout") {
|
|
8242
|
+
children = React__namespace.createElement(PopChild, { isPresent: isPresent }, children);
|
|
8243
|
+
}
|
|
8175
8244
|
return (React__namespace.createElement(PresenceContext.Provider, { value: context }, children));
|
|
8176
8245
|
};
|
|
8177
8246
|
function newChildrenMap() {
|
|
@@ -8227,7 +8296,12 @@
|
|
|
8227
8296
|
*
|
|
8228
8297
|
* @public
|
|
8229
8298
|
*/
|
|
8230
|
-
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, }) => {
|
|
8299
|
+
const AnimatePresence = ({ children, custom, initial = true, onExitComplete, exitBeforeEnter, presenceAffectsLayout = true, mode = "sync", }) => {
|
|
8300
|
+
// Support deprecated exitBeforeEnter prop
|
|
8301
|
+
if (exitBeforeEnter) {
|
|
8302
|
+
mode = "wait";
|
|
8303
|
+
warnOnce(false, "Replace exitBeforeEnter with mode='wait'");
|
|
8304
|
+
}
|
|
8231
8305
|
// We want to force a re-render once all exiting animations have finished. We
|
|
8232
8306
|
// either use a local forceRender function, or one from a parent context if it exists.
|
|
8233
8307
|
let [forceRender] = useForceUpdate();
|
|
@@ -8258,7 +8332,7 @@
|
|
|
8258
8332
|
exiting.clear();
|
|
8259
8333
|
});
|
|
8260
8334
|
if (isInitialRender.current) {
|
|
8261
|
-
return (React__namespace.createElement(React__namespace.Fragment, null, childrenToRender.map((child) => (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout }, child)))));
|
|
8335
|
+
return (React__namespace.createElement(React__namespace.Fragment, null, childrenToRender.map((child) => (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, initial: initial ? undefined : false, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child)))));
|
|
8262
8336
|
}
|
|
8263
8337
|
// If this is a subsequent render, deal with entering and exiting children
|
|
8264
8338
|
childrenToRender = [...childrenToRender];
|
|
@@ -8276,7 +8350,7 @@
|
|
|
8276
8350
|
}
|
|
8277
8351
|
// If we currently have exiting children, and we're deferring rendering incoming children
|
|
8278
8352
|
// until after all current children have exiting, empty the childrenToRender array
|
|
8279
|
-
if (
|
|
8353
|
+
if (mode === "wait" && exiting.size) {
|
|
8280
8354
|
childrenToRender = [];
|
|
8281
8355
|
}
|
|
8282
8356
|
// Loop through all currently exiting components and clone them to overwrite `animate`
|
|
@@ -8304,18 +8378,18 @@
|
|
|
8304
8378
|
onExitComplete && onExitComplete();
|
|
8305
8379
|
}
|
|
8306
8380
|
};
|
|
8307
|
-
childrenToRender.splice(insertionIndex, 0, React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
8381
|
+
childrenToRender.splice(insertionIndex, 0, React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: false, onExitComplete: onExit, custom: custom, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
8308
8382
|
});
|
|
8309
8383
|
// Add `MotionContext` even to children that don't need it to ensure we're rendering
|
|
8310
8384
|
// the same tree between renders
|
|
8311
8385
|
childrenToRender = childrenToRender.map((child) => {
|
|
8312
8386
|
const key = child.key;
|
|
8313
|
-
return exiting.has(key) ? (child) : (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout }, child));
|
|
8387
|
+
return exiting.has(key) ? (child) : (React__namespace.createElement(PresenceChild, { key: getChildKey(child), isPresent: true, presenceAffectsLayout: presenceAffectsLayout, mode: mode }, child));
|
|
8314
8388
|
});
|
|
8315
8389
|
if (env !== "production" &&
|
|
8316
|
-
|
|
8390
|
+
mode === "wait" &&
|
|
8317
8391
|
childrenToRender.length > 1) {
|
|
8318
|
-
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its
|
|
8392
|
+
console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`);
|
|
8319
8393
|
}
|
|
8320
8394
|
return (React__namespace.createElement(React__namespace.Fragment, null, exiting.size
|
|
8321
8395
|
? childrenToRender
|