@tamagui/animate-presence 2.0.0-rc.9 → 2.1.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/AnimatePresence.cjs +112 -91
- package/dist/cjs/AnimatePresence.native.js +127 -106
- package/dist/cjs/AnimatePresence.native.js.map +1 -1
- package/dist/cjs/LayoutGroupContext.cjs +24 -22
- package/dist/cjs/LayoutGroupContext.native.js +26 -24
- package/dist/cjs/LayoutGroupContext.native.js.map +1 -1
- package/dist/cjs/PresenceChild.cjs +58 -45
- package/dist/cjs/PresenceChild.native.js +103 -91
- package/dist/cjs/PresenceChild.native.js.map +1 -1
- package/dist/cjs/index.cjs +7 -5
- package/dist/cjs/index.native.js +7 -5
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/types.cjs +7 -5
- package/dist/cjs/types.native.js +7 -5
- package/dist/cjs/types.native.js.map +1 -1
- package/dist/esm/AnimatePresence.mjs +96 -77
- package/dist/esm/AnimatePresence.mjs.map +1 -1
- package/dist/esm/AnimatePresence.native.js +111 -92
- package/dist/esm/AnimatePresence.native.js.map +1 -1
- package/dist/esm/PresenceChild.mjs +29 -18
- package/dist/esm/PresenceChild.mjs.map +1 -1
- package/dist/esm/PresenceChild.native.js +60 -50
- package/dist/esm/PresenceChild.native.js.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -6
- package/package.json +10 -9
- package/src/AnimatePresence.tsx +150 -143
- package/src/types.ts +10 -9
- package/types/AnimatePresence.d.ts.map +1 -1
- package/types/types.d.ts +9 -9
- package/types/types.d.ts.map +1 -1
- package/dist/cjs/AnimatePresence.js +0 -121
- package/dist/cjs/AnimatePresence.js.map +0 -6
- package/dist/cjs/LayoutGroupContext.js +0 -30
- package/dist/cjs/LayoutGroupContext.js.map +0 -6
- package/dist/cjs/PresenceChild.js +0 -77
- package/dist/cjs/PresenceChild.js.map +0 -6
- package/dist/cjs/index.js +0 -18
- package/dist/cjs/index.js.map +0 -6
- package/dist/cjs/types.js +0 -14
- package/dist/cjs/types.js.map +0 -6
- package/dist/esm/AnimatePresence.js +0 -110
- package/dist/esm/AnimatePresence.js.map +0 -6
- package/dist/esm/LayoutGroupContext.js +0 -6
- package/dist/esm/LayoutGroupContext.js.map +0 -6
- package/dist/esm/PresenceChild.js +0 -57
- package/dist/esm/PresenceChild.js.map +0 -6
- package/dist/esm/types.js +0 -1
- package/dist/esm/types.js.map +0 -6
|
@@ -5,69 +5,79 @@ import * as React from "react";
|
|
|
5
5
|
import { useId } from "react";
|
|
6
6
|
var PresenceChild = /* @__PURE__ */React.memo(function (param) {
|
|
7
7
|
var {
|
|
8
|
-
|
|
8
|
+
children,
|
|
9
|
+
initial,
|
|
10
|
+
isPresent,
|
|
11
|
+
onExitComplete,
|
|
12
|
+
exitVariant,
|
|
13
|
+
enterVariant,
|
|
14
|
+
enterExitVariant,
|
|
15
|
+
presenceAffectsLayout,
|
|
16
|
+
custom
|
|
17
|
+
} = param;
|
|
18
|
+
var presenceChildren = useConstant(newChildrenMap);
|
|
19
|
+
var id = useId() || "";
|
|
20
|
+
var context = React.useMemo(function () {
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
9
23
|
initial,
|
|
10
24
|
isPresent,
|
|
11
|
-
|
|
25
|
+
custom,
|
|
12
26
|
exitVariant,
|
|
13
27
|
enterVariant,
|
|
14
28
|
enterExitVariant,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
var _iteratorNormalCompletion = !0,
|
|
32
|
-
_didIteratorError = !1,
|
|
33
|
-
_iteratorError = void 0;
|
|
29
|
+
onExitComplete: function () {
|
|
30
|
+
presenceChildren.set(id, true);
|
|
31
|
+
var _iteratorNormalCompletion = true,
|
|
32
|
+
_didIteratorError = false,
|
|
33
|
+
_iteratorError = void 0;
|
|
34
|
+
try {
|
|
35
|
+
for (var _iterator = presenceChildren.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
36
|
+
var isComplete = _step.value;
|
|
37
|
+
if (!isComplete) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
_didIteratorError = true;
|
|
43
|
+
_iteratorError = err;
|
|
44
|
+
} finally {
|
|
34
45
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!isComplete) return;
|
|
46
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
47
|
+
_iterator.return();
|
|
38
48
|
}
|
|
39
|
-
} catch (err) {
|
|
40
|
-
_didIteratorError = !0, _iteratorError = err;
|
|
41
49
|
} finally {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
} finally {
|
|
45
|
-
if (_didIteratorError) throw _iteratorError;
|
|
50
|
+
if (_didIteratorError) {
|
|
51
|
+
throw _iteratorError;
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
|
-
onExitComplete?.();
|
|
49
|
-
},
|
|
50
|
-
register: function () {
|
|
51
|
-
return presenceChildren.set(id, !1), function () {
|
|
52
|
-
return presenceChildren.delete(id);
|
|
53
|
-
};
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete();
|
|
56
|
+
},
|
|
57
|
+
register: function () {
|
|
58
|
+
presenceChildren.set(id, false);
|
|
59
|
+
return function () {
|
|
60
|
+
return presenceChildren.delete(id);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* If the presence of a child affects the layout of the components around it,
|
|
67
|
+
* we want to make a new context value to ensure they get re-rendered
|
|
68
|
+
* so they can detect that layout change.
|
|
69
|
+
*/
|
|
70
|
+
// @ts-expect-error its ok
|
|
71
|
+
presenceAffectsLayout ? void 0 : [isPresent, exitVariant, enterVariant]);
|
|
72
|
+
React.useMemo(function () {
|
|
65
73
|
presenceChildren.forEach(function (_, key) {
|
|
66
|
-
return presenceChildren.set(key,
|
|
74
|
+
return presenceChildren.set(key, false);
|
|
67
75
|
});
|
|
68
|
-
}, [isPresent])
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
}, [isPresent]);
|
|
77
|
+
React.useEffect(function () {
|
|
78
|
+
!isPresent && !presenceChildren.size && (onExitComplete === null || onExitComplete === void 0 ? void 0 : onExitComplete());
|
|
79
|
+
}, [isPresent]);
|
|
80
|
+
return /* @__PURE__ */_jsx(PresenceContext.Provider, {
|
|
71
81
|
value: context,
|
|
72
82
|
children
|
|
73
83
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["jsx","_jsx","useConstant","PresenceContext","React","useId","PresenceChild","memo","param","children","initial","isPresent","onExitComplete","exitVariant","enterVariant","enterExitVariant","presenceAffectsLayout","custom","presenceChildren","newChildrenMap","id","context","useMemo","set","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","values","Symbol","iterator","_step","next","done","isComplete","value","err","return","register","delete"],"sources":["../../src/PresenceChild.tsx"],"sourcesContent":[null],"mappings":"AAAA,SAASA,GAAA,IAAAC,IAAA,QAAmB;AAC5B,SAASC,WAAA,+BAAuB;AAEhC,SAAAC,eAAuB;AACvB,YAASC,KAAA,MAAa;AA+EX,SAAAC,KAAA;AA9DJ,IAAAC,aAAM,kBAAsBF,KAAA,CAAAG,IAAA,WAAAC,KAAA;EACjC,IAAC;
|
|
1
|
+
{"version":3,"names":["jsx","_jsx","useConstant","PresenceContext","React","useId","PresenceChild","memo","param","children","initial","isPresent","onExitComplete","exitVariant","enterVariant","enterExitVariant","presenceAffectsLayout","custom","presenceChildren","newChildrenMap","id","context","useMemo","set","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","values","Symbol","iterator","_step","next","done","isComplete","value","err","return","register","delete"],"sources":["../../src/PresenceChild.tsx"],"sourcesContent":[null],"mappings":"AAAA,SAASA,GAAA,IAAAC,IAAA,QAAmB;AAC5B,SAASC,WAAA,+BAAuB;AAEhC,SAAAC,eAAuB;AACvB,YAASC,KAAA,MAAa;AA+EX,SAAAC,KAAA;AA9DJ,IAAAC,aAAM,kBAAsBF,KAAA,CAAAG,IAAA,WAAAC,KAAA;EACjC,IAAC;IAAAC,QAAA;IAAAC,OAAA;IAAAC,SAAA;IAAAC,cAAA;IAAAC,WAAA;IAAAC,YAAA;IAAAC,gBAAA;IAAAC,qBAAA;IAAAC;EAAA,IAAAT,KAAA;EAAA,IACCU,gBAAA,GAAAhB,WAAA,CAAAiB,cAAA;EAAA,IACAC,EAAA,GAAAf,KAAA;EAAA,IACAgB,OAAA,GAAAjB,KAAA,CAAAkB,OAAA,CACA;IACA;MACAF,EAAA;MACAV,OAAA;MACAC,SAAA;MACAM,MAAA;MACwBJ,WAAA;MACxBC,YAAM;MACNC,gBAAiB;MAEjBH,cAAgB,WAAAA,CAAA,EAAM;QACpBM,gBAA4B,CAAAK,GAAA,CAAAH,EAAA;QAC1B,IAAAI,yBAAO;UAAAC,iBAAA;UAAAC,cAAA;QACL;UACA,SAAAC,SAAA,GAAAT,gBAAA,CAAAU,MAAA,GAAAC,MAAA,CAAAC,QAAA,KAAAC,KAAA,IAAAP,yBAAA,IAAAO,KAAA,GAAAJ,SAAA,CAAAK,IAAA,IAAAC,IAAA,GAAAT,yBAAA;YACA,IAAAU,UAAA,GAAAH,KAAA,CAAAI,KAAA;YACA,KAAAD,UAAA;cACA;YACA;UACA;QACA,SAAAE,GAAA;UACEX,iBAAiB,OAAI;UACrBC,cAAW,GAAAU,GAAA;QACT,UAAK;UACH;YACF,KAAAZ,yBAAA,IAAAG,SAAA,CAAAU,MAAA;cACFV,SAAA,CAAAU,MAAA;YACA;UACF;YACA,IAAAZ,iBAAgB;cACd,MAAAC,cAAqB;YACrB;UACF;QACF;QACFd,cAAA,aAAAA,cAAA,uBAAAA,cAAA;MAAA;MAAA0B,QAAA,WAAAA,CAAA;QAAApB,gBAAA,CAAAK,GAAA,CAAAH,EAAA;QAAA;UAAA,OAAAF,gBAAA,CAAAqB,MAAA,CAAAnB,EAAA;QAAA;MAQA;IACF;EAEA;EACE;AAAqE;AAOvE;AACE;AAAyD;EAG3D;EACFJ,qBAAA,aACFL,SAAA,EAEAE,WAAS,EACPC,YAAO,C","ignoreList":[]}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from "./AnimatePresence";
|
|
1
|
+
export * from "./AnimatePresence.mjs";
|
|
2
2
|
export * from "@tamagui/use-presence";
|
|
3
|
-
export * from "./types";
|
|
4
|
-
export * from "./PresenceChild";
|
|
3
|
+
export * from "./types.mjs";
|
|
4
|
+
export * from "./PresenceChild.mjs";
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/index.ts"],
|
|
4
|
-
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
|
1
|
+
{"version":3,"names":[],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/animate-presence",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"gitHead": "a49cc7ea6b93ba384e77a4880ae48ac4a5635c14",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"source": "src/index.ts",
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
".": {
|
|
22
22
|
"types": "./types/index.d.ts",
|
|
23
23
|
"react-native": "./dist/esm/index.native.js",
|
|
24
|
+
"browser": "./dist/esm/index.mjs",
|
|
24
25
|
"module": "./dist/esm/index.mjs",
|
|
25
26
|
"import": "./dist/esm/index.mjs",
|
|
26
27
|
"require": "./dist/cjs/index.cjs",
|
|
27
|
-
"default": "./dist/
|
|
28
|
+
"default": "./dist/esm/index.mjs"
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
@@ -37,15 +38,15 @@
|
|
|
37
38
|
"clean:build": "tamagui-build clean:build"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@tamagui/constants": "2.
|
|
41
|
-
"@tamagui/helpers": "2.
|
|
42
|
-
"@tamagui/use-constant": "2.
|
|
43
|
-
"@tamagui/use-force-update": "2.
|
|
44
|
-
"@tamagui/use-presence": "2.
|
|
45
|
-
"@tamagui/web": "2.
|
|
41
|
+
"@tamagui/constants": "2.1.0",
|
|
42
|
+
"@tamagui/helpers": "2.1.0",
|
|
43
|
+
"@tamagui/use-constant": "2.1.0",
|
|
44
|
+
"@tamagui/use-force-update": "2.1.0",
|
|
45
|
+
"@tamagui/use-presence": "2.1.0",
|
|
46
|
+
"@tamagui/web": "2.1.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
|
-
"@tamagui/build": "2.
|
|
49
|
+
"@tamagui/build": "2.1.0",
|
|
49
50
|
"react": ">=19"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
package/src/AnimatePresence.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useInsertionEffect } from 'react'
|
|
2
|
+
import { useConstant } from '@tamagui/use-constant'
|
|
2
3
|
import { useForceUpdate } from '@tamagui/use-force-update'
|
|
3
4
|
import type { FunctionComponent, PropsWithChildren, ReactElement, ReactNode } from 'react'
|
|
4
|
-
import { Children,
|
|
5
|
+
import { Children, isValidElement, useContext, useMemo, useRef, useState } from 'react'
|
|
5
6
|
import { LayoutGroupContext } from './LayoutGroupContext'
|
|
6
7
|
import { PresenceChild } from './PresenceChild'
|
|
7
8
|
import type { AnimatePresenceProps } from './types'
|
|
@@ -24,16 +25,6 @@ const getChildKey = (child: ReactElement<any>): ComponentKey => {
|
|
|
24
25
|
)
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function updateChildLookup(
|
|
28
|
-
children: ReactElement<any>[],
|
|
29
|
-
allChildren: Map<ComponentKey, ReactElement<any>>
|
|
30
|
-
) {
|
|
31
|
-
children.forEach((child) => {
|
|
32
|
-
const key = getChildKey(child)
|
|
33
|
-
allChildren.set(key, child)
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
28
|
function onlyElements(children: ReactNode): ReactElement<any>[] {
|
|
38
29
|
const filtered: ReactElement<any>[] = []
|
|
39
30
|
// We use forEach here instead of map as map mutates the component key by preprending `.$`
|
|
@@ -53,158 +44,174 @@ export const AnimatePresence: FunctionComponent<
|
|
|
53
44
|
initial = true,
|
|
54
45
|
onExitComplete,
|
|
55
46
|
exitBeforeEnter,
|
|
47
|
+
mode,
|
|
56
48
|
presenceAffectsLayout = true,
|
|
57
49
|
custom,
|
|
58
50
|
passThrough,
|
|
59
51
|
}) => {
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// we play onMount animations or not.
|
|
52
|
+
// Determine effective mode: mode prop takes precedence, then exitBeforeEnter for backwards compatibility
|
|
53
|
+
const effectiveMode = mode ?? (exitBeforeEnter ? 'wait' : 'sync')
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Filter any children that aren't ReactElements. We can only track components
|
|
57
|
+
* between renders with a props.key.
|
|
58
|
+
* IMPORTANT: useMemo ensures reference stability for the comparison below
|
|
59
|
+
*/
|
|
60
|
+
const presentChildren = useMemo(() => onlyElements(children), [children])
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Track the keys of the currently rendered children.
|
|
64
|
+
*/
|
|
65
|
+
const presentKeys = presentChildren.map(getChildKey)
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* If `initial={false}` we only want to pass this to components in the first render.
|
|
69
|
+
*/
|
|
79
70
|
const isInitialRender = useRef(true)
|
|
80
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Freeze custom prop for exiting children so direction doesn't reverse mid-exit.
|
|
74
|
+
*/
|
|
75
|
+
const frozenCustomRef = useRef(new Map<ComponentKey, any>())
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A ref containing the currently present children. When all exit animations
|
|
79
|
+
* are complete, we use this to re-render with the latest children *committed*
|
|
80
|
+
* rather than the latest children *rendered*.
|
|
81
|
+
*/
|
|
82
|
+
const pendingPresentChildren = useRef(presentChildren)
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Track which exiting children have finished animating out.
|
|
86
|
+
*/
|
|
87
|
+
const exitComplete = useConstant(() => new Map<ComponentKey, boolean>())
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Save children to render as React state. To ensure this component is concurrent-safe,
|
|
91
|
+
* we check for exiting children via an effect.
|
|
92
|
+
*/
|
|
93
|
+
const [diffedChildren, setDiffedChildren] = useState(presentChildren)
|
|
94
|
+
const [renderedChildren, setRenderedChildren] = useState(presentChildren)
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* If we've been provided a forceRender function by the LayoutGroupContext,
|
|
98
|
+
* we can use it to force a re-render amongst all surrounding components once
|
|
99
|
+
* all components have finished animating out.
|
|
100
|
+
*/
|
|
101
|
+
const forceRender = useContext(LayoutGroupContext).forceRender ?? useForceUpdate()
|
|
102
|
+
|
|
81
103
|
if (passThrough) {
|
|
82
|
-
// match structure returned below
|
|
83
104
|
return <>{children}</>
|
|
84
105
|
}
|
|
85
106
|
|
|
86
|
-
|
|
107
|
+
// useInsertionEffect runs before ALL useLayoutEffects (including children's)
|
|
108
|
+
// this ensures pendingPresentChildren and exitComplete are set before
|
|
109
|
+
// animation drivers call sendExitComplete() in their layout effects
|
|
110
|
+
// (critical for immediate completions like animateOnly=[])
|
|
111
|
+
useInsertionEffect(() => {
|
|
87
112
|
isInitialRender.current = false
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
{child}
|
|
105
|
-
</PresenceChild>
|
|
106
|
-
))}
|
|
107
|
-
</>
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
let childrenToRender = [...filteredChildren]
|
|
112
|
-
|
|
113
|
-
// Diff the keys of the currently-present and target children to update our
|
|
114
|
-
// exiting list.
|
|
115
|
-
const presentKeys = presentChildren.current.map(getChildKey)
|
|
116
|
-
const targetKeys = filteredChildren.map(getChildKey)
|
|
117
|
-
|
|
118
|
-
// Diff the present children with our target children and mark those that are exiting
|
|
119
|
-
const numPresent = presentKeys.length
|
|
120
|
-
for (let i = 0; i < numPresent; i++) {
|
|
121
|
-
const key = presentKeys[i]
|
|
122
|
-
if (targetKeys.indexOf(key) === -1) {
|
|
123
|
-
exiting.add(key)
|
|
124
|
-
} else {
|
|
125
|
-
// In case this key has re-entered, remove from the exiting list
|
|
126
|
-
exiting.delete(key)
|
|
113
|
+
pendingPresentChildren.current = presentChildren
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Update complete status of exiting children.
|
|
117
|
+
*/
|
|
118
|
+
for (let i = 0; i < renderedChildren.length; i++) {
|
|
119
|
+
const key = getChildKey(renderedChildren[i])
|
|
120
|
+
|
|
121
|
+
if (!presentKeys.includes(key)) {
|
|
122
|
+
if (exitComplete.get(key) !== true) {
|
|
123
|
+
exitComplete.set(key, false)
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
exitComplete.delete(key)
|
|
127
|
+
frozenCustomRef.current.delete(key)
|
|
128
|
+
}
|
|
127
129
|
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const onExit = () => {
|
|
148
|
-
allChildren.delete(key)
|
|
149
|
-
exiting.delete(key)
|
|
150
|
-
const removeIndex = presentChildren.current.findIndex(
|
|
151
|
-
(presentChild) => presentChild.key === key
|
|
152
|
-
)
|
|
153
|
-
presentChildren.current.splice(removeIndex, 1)
|
|
154
|
-
|
|
155
|
-
if (!exiting.size) {
|
|
156
|
-
presentChildren.current = filteredChildren
|
|
157
|
-
forceRender()
|
|
158
|
-
onExitComplete?.()
|
|
130
|
+
}, [renderedChildren, presentKeys.length, presentKeys.join('-')])
|
|
131
|
+
|
|
132
|
+
if (presentChildren !== diffedChildren) {
|
|
133
|
+
let nextChildren = [...presentChildren]
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Loop through all the currently rendered components and decide which
|
|
137
|
+
* are exiting.
|
|
138
|
+
*/
|
|
139
|
+
for (let i = 0; i < renderedChildren.length; i++) {
|
|
140
|
+
const child = renderedChildren[i]
|
|
141
|
+
const key = getChildKey(child)
|
|
142
|
+
|
|
143
|
+
if (!presentKeys.includes(key)) {
|
|
144
|
+
nextChildren.splice(i, 0, child)
|
|
145
|
+
// freeze custom at the moment of exit so direction doesn't reverse
|
|
146
|
+
if (!frozenCustomRef.current.has(key)) {
|
|
147
|
+
frozenCustomRef.current.set(key, custom)
|
|
148
|
+
}
|
|
159
149
|
}
|
|
160
150
|
}
|
|
161
151
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
enterExitVariant={enterExitVariant}
|
|
169
|
-
enterVariant={enterVariant}
|
|
170
|
-
exitVariant={exitVariant}
|
|
171
|
-
custom={custom}
|
|
172
|
-
>
|
|
173
|
-
{child}
|
|
174
|
-
</PresenceChild>
|
|
152
|
+
/**
|
|
153
|
+
* If we're in "wait" mode, and we have exiting children, we want to
|
|
154
|
+
* only render these until they've all exited.
|
|
155
|
+
*/
|
|
156
|
+
const exitingChildren = renderedChildren.filter(
|
|
157
|
+
(child) => !presentKeys.includes(getChildKey(child))
|
|
175
158
|
)
|
|
159
|
+
if (effectiveMode === 'wait' && exitingChildren.length) {
|
|
160
|
+
nextChildren = exitingChildren
|
|
161
|
+
}
|
|
176
162
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// Add `MotionContext` even to children that don't need it to ensure we're rendering
|
|
181
|
-
// the same tree between renders
|
|
182
|
-
childrenToRender = childrenToRender.map((child) => {
|
|
183
|
-
const key = child.key as ComponentKey
|
|
184
|
-
return exiting.has(key) ? (
|
|
185
|
-
child
|
|
186
|
-
) : (
|
|
187
|
-
<PresenceChild
|
|
188
|
-
key={getChildKey(child)}
|
|
189
|
-
isPresent
|
|
190
|
-
exitVariant={exitVariant}
|
|
191
|
-
enterVariant={enterVariant}
|
|
192
|
-
enterExitVariant={enterExitVariant}
|
|
193
|
-
presenceAffectsLayout={presenceAffectsLayout}
|
|
194
|
-
custom={custom}
|
|
195
|
-
>
|
|
196
|
-
{child}
|
|
197
|
-
</PresenceChild>
|
|
198
|
-
)
|
|
199
|
-
})
|
|
163
|
+
setRenderedChildren(onlyElements(nextChildren))
|
|
164
|
+
setDiffedChildren(presentChildren)
|
|
200
165
|
|
|
201
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Early return to ensure once we've set state with the latest diffed
|
|
168
|
+
* children, we can immediately re-render.
|
|
169
|
+
*/
|
|
170
|
+
return null
|
|
171
|
+
}
|
|
202
172
|
|
|
203
173
|
return (
|
|
204
174
|
<>
|
|
205
|
-
{
|
|
206
|
-
|
|
207
|
-
|
|
175
|
+
{renderedChildren.map((child) => {
|
|
176
|
+
const key = getChildKey(child)
|
|
177
|
+
const isPresent =
|
|
178
|
+
presentChildren === renderedChildren || presentKeys.includes(key)
|
|
179
|
+
|
|
180
|
+
const onExit = () => {
|
|
181
|
+
if (exitComplete.has(key)) {
|
|
182
|
+
exitComplete.set(key, true)
|
|
183
|
+
} else {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let isEveryExitComplete = true
|
|
188
|
+
exitComplete.forEach((isExitComplete) => {
|
|
189
|
+
if (!isExitComplete) isEveryExitComplete = false
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
if (isEveryExitComplete) {
|
|
193
|
+
forceRender?.()
|
|
194
|
+
setRenderedChildren(pendingPresentChildren.current)
|
|
195
|
+
onExitComplete?.()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return (
|
|
200
|
+
<PresenceChild
|
|
201
|
+
key={key}
|
|
202
|
+
isPresent={isPresent}
|
|
203
|
+
initial={!isInitialRender.current || initial ? undefined : false}
|
|
204
|
+
custom={isPresent ? custom : (frozenCustomRef.current.get(key) ?? custom)}
|
|
205
|
+
presenceAffectsLayout={presenceAffectsLayout}
|
|
206
|
+
enterExitVariant={enterExitVariant}
|
|
207
|
+
enterVariant={enterVariant}
|
|
208
|
+
exitVariant={exitVariant}
|
|
209
|
+
onExitComplete={isPresent ? undefined : onExit}
|
|
210
|
+
>
|
|
211
|
+
{child}
|
|
212
|
+
</PresenceChild>
|
|
213
|
+
)
|
|
214
|
+
})}
|
|
208
215
|
</>
|
|
209
216
|
)
|
|
210
217
|
}
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,15 @@ export type VariantLabels = string | string[]
|
|
|
14
14
|
* @public
|
|
15
15
|
*/
|
|
16
16
|
export interface AnimatePresenceProps {
|
|
17
|
+
/**
|
|
18
|
+
* Determines how to handle entering and exiting elements.
|
|
19
|
+
* - "sync": Default. Elements animate in and out simultaneously.
|
|
20
|
+
* - "wait": Wait for exit to finish before entering.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
mode?: 'sync' | 'wait'
|
|
25
|
+
|
|
17
26
|
/**
|
|
18
27
|
* By passing `initial={false}`, `AnimatePresence` will disable any initial animations on children
|
|
19
28
|
* that are present when the component is first rendered.
|
|
@@ -66,15 +75,7 @@ export interface AnimatePresenceProps {
|
|
|
66
75
|
* If set to `true`, `AnimatePresence` will only render one component at a time. The exiting component
|
|
67
76
|
* will finish its exit animation before the entering component is rendered.
|
|
68
77
|
*
|
|
69
|
-
*
|
|
70
|
-
* const MyComponent = ({ currentItem }) => (
|
|
71
|
-
* <AnimatePresence exitBeforeEnter>
|
|
72
|
-
* <motion.div key={currentItem} exit={{ opacity: 0 }} />
|
|
73
|
-
* </AnimatePresence>
|
|
74
|
-
* )
|
|
75
|
-
* ```
|
|
76
|
-
*
|
|
77
|
-
* @beta
|
|
78
|
+
* @deprecated Use `mode="wait"` instead.
|
|
78
79
|
*/
|
|
79
80
|
exitBeforeEnter?: boolean
|
|
80
81
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimatePresence.d.ts","sourceRoot":"","sources":["../src/AnimatePresence.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AnimatePresence.d.ts","sourceRoot":"","sources":["../src/AnimatePresence.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAA2B,MAAM,OAAO,CAAA;AAI1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AA6BnD,eAAO,MAAM,eAAe,EAAE,iBAAiB,CAC7C,iBAAiB,CAAC,oBAAoB,CAAC,CAmLxC,CAAA"}
|
package/types/types.d.ts
CHANGED
|
@@ -11,6 +11,14 @@ export type VariantLabels = string | string[];
|
|
|
11
11
|
* @public
|
|
12
12
|
*/
|
|
13
13
|
export interface AnimatePresenceProps {
|
|
14
|
+
/**
|
|
15
|
+
* Determines how to handle entering and exiting elements.
|
|
16
|
+
* - "sync": Default. Elements animate in and out simultaneously.
|
|
17
|
+
* - "wait": Wait for exit to finish before entering.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
mode?: 'sync' | 'wait';
|
|
14
22
|
/**
|
|
15
23
|
* By passing `initial={false}`, `AnimatePresence` will disable any initial animations on children
|
|
16
24
|
* that are present when the component is first rendered.
|
|
@@ -60,15 +68,7 @@ export interface AnimatePresenceProps {
|
|
|
60
68
|
* If set to `true`, `AnimatePresence` will only render one component at a time. The exiting component
|
|
61
69
|
* will finish its exit animation before the entering component is rendered.
|
|
62
70
|
*
|
|
63
|
-
*
|
|
64
|
-
* const MyComponent = ({ currentItem }) => (
|
|
65
|
-
* <AnimatePresence exitBeforeEnter>
|
|
66
|
-
* <motion.div key={currentItem} exit={{ opacity: 0 }} />
|
|
67
|
-
* </AnimatePresence>
|
|
68
|
-
* )
|
|
69
|
-
* ```
|
|
70
|
-
*
|
|
71
|
-
* @beta
|
|
71
|
+
* @deprecated Use `mode="wait"` instead.
|
|
72
72
|
*/
|
|
73
73
|
exitBeforeEnter?: boolean;
|
|
74
74
|
/**
|
package/types/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,IAAI,CAAA;IACP,CAAC,EAAE,IAAI,CAAA;CACR;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;AAE7C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAE3B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,GAAG;IAClB,CAAC,EAAE,IAAI,CAAA;IACP,CAAC,EAAE,IAAI,CAAA;CACR;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;AAE7C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAEtB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAE3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;;;;OAKG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAE/B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAE3B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAE5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAEhC,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB"}
|