react-transition-state 2.3.0 → 2.3.2
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.cjs +8 -9
- package/dist/cjs/useTransitionMap.cjs +105 -0
- package/dist/cjs/useTransitionState.cjs +61 -0
- package/dist/cjs/utils.cjs +54 -0
- package/dist/esm/index.mjs +6 -2
- package/dist/esm/useTransitionMap.mjs +103 -0
- package/dist/esm/useTransitionState.mjs +59 -0
- package/dist/esm/utils.mjs +41 -0
- package/package.json +29 -35
- package/types/index.d.ts +8 -60
- package/types/types.d.ts +42 -0
- package/types/useTransitionMap.d.ts +3 -0
- package/types/useTransitionState.d.ts +2 -0
- package/types/utils.d.ts +22 -0
- package/dist/cjs/hooks/useTransitionMap.cjs +0 -113
- package/dist/cjs/hooks/useTransitionState.cjs +0 -62
- package/dist/cjs/hooks/utils.cjs +0 -47
- package/dist/esm/hooks/useTransitionMap.mjs +0 -111
- package/dist/esm/hooks/useTransitionState.mjs +0 -60
- package/dist/esm/hooks/utils.mjs +0 -33
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
|
|
1
2
|
'use strict';
|
|
3
|
+
'use client';
|
|
2
4
|
|
|
3
5
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
6
|
+
const require_useTransitionState = require('./useTransitionState.cjs');
|
|
7
|
+
const require_useTransitionMap = require('./useTransitionMap.cjs');
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
exports.default = useTransitionState.useTransitionState;
|
|
11
|
-
exports.useTransition = useTransitionState.useTransitionState;
|
|
12
|
-
exports.useTransitionState = useTransitionState.useTransitionState;
|
|
13
|
-
exports.useTransitionMap = useTransitionMap.useTransitionMap;
|
|
9
|
+
exports.default = require_useTransitionState.useTransitionState;
|
|
10
|
+
exports.useTransition = require_useTransitionState.useTransitionState;
|
|
11
|
+
exports.useTransitionMap = require_useTransitionMap.useTransitionMap;
|
|
12
|
+
exports.useTransitionState = require_useTransitionState.useTransitionState;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
const require_utils = require('./utils.cjs');
|
|
4
|
+
let react = require("react");
|
|
5
|
+
|
|
6
|
+
//#region src/useTransitionMap.ts
|
|
7
|
+
const updateState = (key, status, setStateMap, latestStateMap, timeoutId, onChange) => {
|
|
8
|
+
clearTimeout(timeoutId);
|
|
9
|
+
const state = require_utils.getState(status);
|
|
10
|
+
const stateMap = new Map(latestStateMap.current);
|
|
11
|
+
stateMap.set(key, state);
|
|
12
|
+
setStateMap(stateMap);
|
|
13
|
+
latestStateMap.current = stateMap;
|
|
14
|
+
onChange && onChange({
|
|
15
|
+
key,
|
|
16
|
+
current: state
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const useTransitionMap = ({ allowMultiple, enter = true, exit = true, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange } = {}) => {
|
|
20
|
+
const [stateMap, setStateMap] = (0, react.useState)(/* @__PURE__ */ new Map());
|
|
21
|
+
const latestStateMap = (0, react.useRef)(stateMap);
|
|
22
|
+
const configMap = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
23
|
+
const [enterTimeout, exitTimeout] = require_utils.getTimeout(timeout);
|
|
24
|
+
const setItem = (0, react.useCallback)((key, options) => {
|
|
25
|
+
const { initialEntered: _initialEntered = initialEntered } = options || {};
|
|
26
|
+
updateState(key, _initialEntered ? require_utils.ENTERED : require_utils.startOrEnd(mountOnEnter), setStateMap, latestStateMap);
|
|
27
|
+
configMap.current.set(key, {});
|
|
28
|
+
}, [initialEntered, mountOnEnter]);
|
|
29
|
+
const deleteItem = (0, react.useCallback)((key) => {
|
|
30
|
+
const newStateMap = new Map(latestStateMap.current);
|
|
31
|
+
if (newStateMap.delete(key)) {
|
|
32
|
+
setStateMap(newStateMap);
|
|
33
|
+
latestStateMap.current = newStateMap;
|
|
34
|
+
configMap.current.delete(key);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}, []);
|
|
39
|
+
const endTransition = (0, react.useCallback)((key) => {
|
|
40
|
+
const stateObj = latestStateMap.current.get(key);
|
|
41
|
+
if (!stateObj) {
|
|
42
|
+
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call endTransition: invalid key — ${key}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const { timeoutId } = configMap.current.get(key);
|
|
46
|
+
const status = require_utils.getEndStatus(stateObj._s, unmountOnExit);
|
|
47
|
+
status && updateState(key, status, setStateMap, latestStateMap, timeoutId, onChange);
|
|
48
|
+
}, [onChange, unmountOnExit]);
|
|
49
|
+
const toggle = (0, react.useCallback)((key, toEnter) => {
|
|
50
|
+
const stateObj = latestStateMap.current.get(key);
|
|
51
|
+
if (!stateObj) {
|
|
52
|
+
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call toggle: invalid key — ${key}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const config = configMap.current.get(key);
|
|
56
|
+
const transitState = (status) => {
|
|
57
|
+
updateState(key, status, setStateMap, latestStateMap, config.timeoutId, onChange);
|
|
58
|
+
switch (status) {
|
|
59
|
+
case require_utils.ENTERING:
|
|
60
|
+
if (enterTimeout >= 0) config.timeoutId = require_utils._setTimeout(() => endTransition(key), enterTimeout);
|
|
61
|
+
break;
|
|
62
|
+
case require_utils.EXITING:
|
|
63
|
+
if (exitTimeout >= 0) config.timeoutId = require_utils._setTimeout(() => endTransition(key), exitTimeout);
|
|
64
|
+
break;
|
|
65
|
+
case require_utils.PRE_ENTER:
|
|
66
|
+
case require_utils.PRE_EXIT:
|
|
67
|
+
config.timeoutId = require_utils.nextTick(transitState, status);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const enterStage = stateObj.isEnter;
|
|
72
|
+
if (typeof toEnter !== "boolean") toEnter = !enterStage;
|
|
73
|
+
if (toEnter) {
|
|
74
|
+
if (!enterStage) {
|
|
75
|
+
transitState(enter ? preEnter ? require_utils.PRE_ENTER : require_utils.ENTERING : require_utils.ENTERED);
|
|
76
|
+
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
77
|
+
}
|
|
78
|
+
} else if (enterStage) transitState(exit ? preExit ? require_utils.PRE_EXIT : require_utils.EXITING : require_utils.startOrEnd(unmountOnExit));
|
|
79
|
+
}, [
|
|
80
|
+
onChange,
|
|
81
|
+
endTransition,
|
|
82
|
+
allowMultiple,
|
|
83
|
+
enter,
|
|
84
|
+
exit,
|
|
85
|
+
preEnter,
|
|
86
|
+
preExit,
|
|
87
|
+
enterTimeout,
|
|
88
|
+
exitTimeout,
|
|
89
|
+
unmountOnExit
|
|
90
|
+
]);
|
|
91
|
+
return {
|
|
92
|
+
stateMap,
|
|
93
|
+
toggle,
|
|
94
|
+
toggleAll: (0, react.useCallback)((toEnter) => {
|
|
95
|
+
if (!allowMultiple && toEnter !== false) return;
|
|
96
|
+
for (const key of latestStateMap.current.keys()) toggle(key, toEnter);
|
|
97
|
+
}, [allowMultiple, toggle]),
|
|
98
|
+
endTransition,
|
|
99
|
+
setItem,
|
|
100
|
+
deleteItem
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
exports.useTransitionMap = useTransitionMap;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
const require_utils = require('./utils.cjs');
|
|
4
|
+
let react = require("react");
|
|
5
|
+
|
|
6
|
+
//#region src/useTransitionState.ts
|
|
7
|
+
const updateState = (status, setState, latestState, timeoutId, onChange) => {
|
|
8
|
+
clearTimeout(timeoutId.current);
|
|
9
|
+
const state = require_utils.getState(status);
|
|
10
|
+
setState(state);
|
|
11
|
+
latestState.current = state;
|
|
12
|
+
onChange && onChange({ current: state });
|
|
13
|
+
};
|
|
14
|
+
const useTransitionState = ({ enter = true, exit = true, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange } = {}) => {
|
|
15
|
+
const [state, setState] = (0, react.useState)(() => require_utils.getState(initialEntered ? require_utils.ENTERED : require_utils.startOrEnd(mountOnEnter)));
|
|
16
|
+
const latestState = (0, react.useRef)(state);
|
|
17
|
+
const timeoutId = (0, react.useRef)(0);
|
|
18
|
+
const [enterTimeout, exitTimeout] = require_utils.getTimeout(timeout);
|
|
19
|
+
const endTransition = (0, react.useCallback)(() => {
|
|
20
|
+
const status = require_utils.getEndStatus(latestState.current._s, unmountOnExit);
|
|
21
|
+
status && updateState(status, setState, latestState, timeoutId, onChange);
|
|
22
|
+
}, [onChange, unmountOnExit]);
|
|
23
|
+
return [
|
|
24
|
+
state,
|
|
25
|
+
(0, react.useCallback)((toEnter) => {
|
|
26
|
+
const transitState = (status) => {
|
|
27
|
+
updateState(status, setState, latestState, timeoutId, onChange);
|
|
28
|
+
switch (status) {
|
|
29
|
+
case require_utils.ENTERING:
|
|
30
|
+
if (enterTimeout >= 0) timeoutId.current = require_utils._setTimeout(endTransition, enterTimeout);
|
|
31
|
+
break;
|
|
32
|
+
case require_utils.EXITING:
|
|
33
|
+
if (exitTimeout >= 0) timeoutId.current = require_utils._setTimeout(endTransition, exitTimeout);
|
|
34
|
+
break;
|
|
35
|
+
case require_utils.PRE_ENTER:
|
|
36
|
+
case require_utils.PRE_EXIT:
|
|
37
|
+
timeoutId.current = require_utils.nextTick(transitState, status);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const enterStage = latestState.current.isEnter;
|
|
42
|
+
if (typeof toEnter !== "boolean") toEnter = !enterStage;
|
|
43
|
+
if (toEnter) !enterStage && transitState(enter ? preEnter ? require_utils.PRE_ENTER : require_utils.ENTERING : require_utils.ENTERED);
|
|
44
|
+
else enterStage && transitState(exit ? preExit ? require_utils.PRE_EXIT : require_utils.EXITING : require_utils.startOrEnd(unmountOnExit));
|
|
45
|
+
}, [
|
|
46
|
+
endTransition,
|
|
47
|
+
onChange,
|
|
48
|
+
enter,
|
|
49
|
+
exit,
|
|
50
|
+
preEnter,
|
|
51
|
+
preExit,
|
|
52
|
+
enterTimeout,
|
|
53
|
+
exitTimeout,
|
|
54
|
+
unmountOnExit
|
|
55
|
+
]),
|
|
56
|
+
endTransition
|
|
57
|
+
];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
exports.useTransitionState = useTransitionState;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
//#region src/utils.ts
|
|
5
|
+
const PRE_ENTER = 0;
|
|
6
|
+
const ENTERING = 1;
|
|
7
|
+
const ENTERED = 2;
|
|
8
|
+
const PRE_EXIT = 3;
|
|
9
|
+
const EXITING = 4;
|
|
10
|
+
const EXITED = 5;
|
|
11
|
+
const UNMOUNTED = 6;
|
|
12
|
+
const STATUS = [
|
|
13
|
+
"preEnter",
|
|
14
|
+
"entering",
|
|
15
|
+
"entered",
|
|
16
|
+
"preExit",
|
|
17
|
+
"exiting",
|
|
18
|
+
"exited",
|
|
19
|
+
"unmounted"
|
|
20
|
+
];
|
|
21
|
+
const getState = (status) => ({
|
|
22
|
+
_s: status,
|
|
23
|
+
status: STATUS[status],
|
|
24
|
+
isEnter: status < PRE_EXIT,
|
|
25
|
+
isMounted: status !== UNMOUNTED,
|
|
26
|
+
isResolved: status === ENTERED || status > EXITING
|
|
27
|
+
});
|
|
28
|
+
const startOrEnd = (unmounted) => unmounted ? UNMOUNTED : EXITED;
|
|
29
|
+
const getEndStatus = (status, unmountOnExit) => {
|
|
30
|
+
switch (status) {
|
|
31
|
+
case ENTERING:
|
|
32
|
+
case PRE_ENTER: return ENTERED;
|
|
33
|
+
case EXITING:
|
|
34
|
+
case PRE_EXIT: return startOrEnd(unmountOnExit);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const getTimeout = (timeout) => typeof timeout === "object" ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
38
|
+
const _setTimeout = setTimeout;
|
|
39
|
+
const nextTick = (transitState, status) => _setTimeout(() => {
|
|
40
|
+
isNaN(document.body.offsetTop) || transitState(status + 1);
|
|
41
|
+
}, 0);
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
exports.ENTERED = ENTERED;
|
|
45
|
+
exports.ENTERING = ENTERING;
|
|
46
|
+
exports.EXITING = EXITING;
|
|
47
|
+
exports.PRE_ENTER = PRE_ENTER;
|
|
48
|
+
exports.PRE_EXIT = PRE_EXIT;
|
|
49
|
+
exports._setTimeout = _setTimeout;
|
|
50
|
+
exports.getEndStatus = getEndStatus;
|
|
51
|
+
exports.getState = getState;
|
|
52
|
+
exports.getTimeout = getTimeout;
|
|
53
|
+
exports.nextTick = nextTick;
|
|
54
|
+
exports.startOrEnd = startOrEnd;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useTransitionState } from "./useTransitionState.mjs";
|
|
4
|
+
import { useTransitionMap } from "./useTransitionMap.mjs";
|
|
5
|
+
|
|
6
|
+
export { useTransitionState as default, useTransitionState as useTransition, useTransitionMap, useTransitionState };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { ENTERED, ENTERING, EXITING, PRE_ENTER, PRE_EXIT, _setTimeout, getEndStatus, getState, getTimeout, nextTick, startOrEnd } from "./utils.mjs";
|
|
2
|
+
import { useCallback, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/useTransitionMap.ts
|
|
5
|
+
const updateState = (key, status, setStateMap, latestStateMap, timeoutId, onChange) => {
|
|
6
|
+
clearTimeout(timeoutId);
|
|
7
|
+
const state = getState(status);
|
|
8
|
+
const stateMap = new Map(latestStateMap.current);
|
|
9
|
+
stateMap.set(key, state);
|
|
10
|
+
setStateMap(stateMap);
|
|
11
|
+
latestStateMap.current = stateMap;
|
|
12
|
+
onChange && onChange({
|
|
13
|
+
key,
|
|
14
|
+
current: state
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
const useTransitionMap = ({ allowMultiple, enter = true, exit = true, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange } = {}) => {
|
|
18
|
+
const [stateMap, setStateMap] = useState(/* @__PURE__ */ new Map());
|
|
19
|
+
const latestStateMap = useRef(stateMap);
|
|
20
|
+
const configMap = useRef(/* @__PURE__ */ new Map());
|
|
21
|
+
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
22
|
+
const setItem = useCallback((key, options) => {
|
|
23
|
+
const { initialEntered: _initialEntered = initialEntered } = options || {};
|
|
24
|
+
updateState(key, _initialEntered ? ENTERED : startOrEnd(mountOnEnter), setStateMap, latestStateMap);
|
|
25
|
+
configMap.current.set(key, {});
|
|
26
|
+
}, [initialEntered, mountOnEnter]);
|
|
27
|
+
const deleteItem = useCallback((key) => {
|
|
28
|
+
const newStateMap = new Map(latestStateMap.current);
|
|
29
|
+
if (newStateMap.delete(key)) {
|
|
30
|
+
setStateMap(newStateMap);
|
|
31
|
+
latestStateMap.current = newStateMap;
|
|
32
|
+
configMap.current.delete(key);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}, []);
|
|
37
|
+
const endTransition = useCallback((key) => {
|
|
38
|
+
const stateObj = latestStateMap.current.get(key);
|
|
39
|
+
if (!stateObj) {
|
|
40
|
+
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call endTransition: invalid key — ${key}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const { timeoutId } = configMap.current.get(key);
|
|
44
|
+
const status = getEndStatus(stateObj._s, unmountOnExit);
|
|
45
|
+
status && updateState(key, status, setStateMap, latestStateMap, timeoutId, onChange);
|
|
46
|
+
}, [onChange, unmountOnExit]);
|
|
47
|
+
const toggle = useCallback((key, toEnter) => {
|
|
48
|
+
const stateObj = latestStateMap.current.get(key);
|
|
49
|
+
if (!stateObj) {
|
|
50
|
+
if (process.env.NODE_ENV !== "production") console.error(`[React-Transition-State] cannot call toggle: invalid key — ${key}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const config = configMap.current.get(key);
|
|
54
|
+
const transitState = (status) => {
|
|
55
|
+
updateState(key, status, setStateMap, latestStateMap, config.timeoutId, onChange);
|
|
56
|
+
switch (status) {
|
|
57
|
+
case ENTERING:
|
|
58
|
+
if (enterTimeout >= 0) config.timeoutId = _setTimeout(() => endTransition(key), enterTimeout);
|
|
59
|
+
break;
|
|
60
|
+
case EXITING:
|
|
61
|
+
if (exitTimeout >= 0) config.timeoutId = _setTimeout(() => endTransition(key), exitTimeout);
|
|
62
|
+
break;
|
|
63
|
+
case PRE_ENTER:
|
|
64
|
+
case PRE_EXIT:
|
|
65
|
+
config.timeoutId = nextTick(transitState, status);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const enterStage = stateObj.isEnter;
|
|
70
|
+
if (typeof toEnter !== "boolean") toEnter = !enterStage;
|
|
71
|
+
if (toEnter) {
|
|
72
|
+
if (!enterStage) {
|
|
73
|
+
transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
74
|
+
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
75
|
+
}
|
|
76
|
+
} else if (enterStage) transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
77
|
+
}, [
|
|
78
|
+
onChange,
|
|
79
|
+
endTransition,
|
|
80
|
+
allowMultiple,
|
|
81
|
+
enter,
|
|
82
|
+
exit,
|
|
83
|
+
preEnter,
|
|
84
|
+
preExit,
|
|
85
|
+
enterTimeout,
|
|
86
|
+
exitTimeout,
|
|
87
|
+
unmountOnExit
|
|
88
|
+
]);
|
|
89
|
+
return {
|
|
90
|
+
stateMap,
|
|
91
|
+
toggle,
|
|
92
|
+
toggleAll: useCallback((toEnter) => {
|
|
93
|
+
if (!allowMultiple && toEnter !== false) return;
|
|
94
|
+
for (const key of latestStateMap.current.keys()) toggle(key, toEnter);
|
|
95
|
+
}, [allowMultiple, toggle]),
|
|
96
|
+
endTransition,
|
|
97
|
+
setItem,
|
|
98
|
+
deleteItem
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
export { useTransitionMap };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ENTERED, ENTERING, EXITING, PRE_ENTER, PRE_EXIT, _setTimeout, getEndStatus, getState, getTimeout, nextTick, startOrEnd } from "./utils.mjs";
|
|
2
|
+
import { useCallback, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/useTransitionState.ts
|
|
5
|
+
const updateState = (status, setState, latestState, timeoutId, onChange) => {
|
|
6
|
+
clearTimeout(timeoutId.current);
|
|
7
|
+
const state = getState(status);
|
|
8
|
+
setState(state);
|
|
9
|
+
latestState.current = state;
|
|
10
|
+
onChange && onChange({ current: state });
|
|
11
|
+
};
|
|
12
|
+
const useTransitionState = ({ enter = true, exit = true, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange } = {}) => {
|
|
13
|
+
const [state, setState] = useState(() => getState(initialEntered ? ENTERED : startOrEnd(mountOnEnter)));
|
|
14
|
+
const latestState = useRef(state);
|
|
15
|
+
const timeoutId = useRef(0);
|
|
16
|
+
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
17
|
+
const endTransition = useCallback(() => {
|
|
18
|
+
const status = getEndStatus(latestState.current._s, unmountOnExit);
|
|
19
|
+
status && updateState(status, setState, latestState, timeoutId, onChange);
|
|
20
|
+
}, [onChange, unmountOnExit]);
|
|
21
|
+
return [
|
|
22
|
+
state,
|
|
23
|
+
useCallback((toEnter) => {
|
|
24
|
+
const transitState = (status) => {
|
|
25
|
+
updateState(status, setState, latestState, timeoutId, onChange);
|
|
26
|
+
switch (status) {
|
|
27
|
+
case ENTERING:
|
|
28
|
+
if (enterTimeout >= 0) timeoutId.current = _setTimeout(endTransition, enterTimeout);
|
|
29
|
+
break;
|
|
30
|
+
case EXITING:
|
|
31
|
+
if (exitTimeout >= 0) timeoutId.current = _setTimeout(endTransition, exitTimeout);
|
|
32
|
+
break;
|
|
33
|
+
case PRE_ENTER:
|
|
34
|
+
case PRE_EXIT:
|
|
35
|
+
timeoutId.current = nextTick(transitState, status);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const enterStage = latestState.current.isEnter;
|
|
40
|
+
if (typeof toEnter !== "boolean") toEnter = !enterStage;
|
|
41
|
+
if (toEnter) !enterStage && transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
42
|
+
else enterStage && transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
43
|
+
}, [
|
|
44
|
+
endTransition,
|
|
45
|
+
onChange,
|
|
46
|
+
enter,
|
|
47
|
+
exit,
|
|
48
|
+
preEnter,
|
|
49
|
+
preExit,
|
|
50
|
+
enterTimeout,
|
|
51
|
+
exitTimeout,
|
|
52
|
+
unmountOnExit
|
|
53
|
+
]),
|
|
54
|
+
endTransition
|
|
55
|
+
];
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { useTransitionState };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
const PRE_ENTER = 0;
|
|
3
|
+
const ENTERING = 1;
|
|
4
|
+
const ENTERED = 2;
|
|
5
|
+
const PRE_EXIT = 3;
|
|
6
|
+
const EXITING = 4;
|
|
7
|
+
const EXITED = 5;
|
|
8
|
+
const UNMOUNTED = 6;
|
|
9
|
+
const STATUS = [
|
|
10
|
+
"preEnter",
|
|
11
|
+
"entering",
|
|
12
|
+
"entered",
|
|
13
|
+
"preExit",
|
|
14
|
+
"exiting",
|
|
15
|
+
"exited",
|
|
16
|
+
"unmounted"
|
|
17
|
+
];
|
|
18
|
+
const getState = (status) => ({
|
|
19
|
+
_s: status,
|
|
20
|
+
status: STATUS[status],
|
|
21
|
+
isEnter: status < PRE_EXIT,
|
|
22
|
+
isMounted: status !== UNMOUNTED,
|
|
23
|
+
isResolved: status === ENTERED || status > EXITING
|
|
24
|
+
});
|
|
25
|
+
const startOrEnd = (unmounted) => unmounted ? UNMOUNTED : EXITED;
|
|
26
|
+
const getEndStatus = (status, unmountOnExit) => {
|
|
27
|
+
switch (status) {
|
|
28
|
+
case ENTERING:
|
|
29
|
+
case PRE_ENTER: return ENTERED;
|
|
30
|
+
case EXITING:
|
|
31
|
+
case PRE_EXIT: return startOrEnd(unmountOnExit);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const getTimeout = (timeout) => typeof timeout === "object" ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
35
|
+
const _setTimeout = setTimeout;
|
|
36
|
+
const nextTick = (transitState, status) => _setTimeout(() => {
|
|
37
|
+
isNaN(document.body.offsetTop) || transitState(status + 1);
|
|
38
|
+
}, 0);
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ENTERED, ENTERING, EXITING, PRE_ENTER, PRE_EXIT, _setTimeout, getEndStatus, getState, getTimeout, nextTick, startOrEnd };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-transition-state",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
4
4
|
"description": "Zero dependency React transition state machine.",
|
|
5
5
|
"author": "Zheng Song",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"files": [
|
|
17
17
|
"dist/",
|
|
18
|
-
"types
|
|
18
|
+
"types/"
|
|
19
19
|
],
|
|
20
20
|
"keywords": [
|
|
21
21
|
"react",
|
|
@@ -26,17 +26,16 @@
|
|
|
26
26
|
"state machine"
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"bundle": "
|
|
32
|
-
"test": "
|
|
33
|
-
"
|
|
34
|
-
"types": "cd types && tsc",
|
|
29
|
+
"clean": "rm -Rf dist/ types/",
|
|
30
|
+
"start": "rolldown -w -c",
|
|
31
|
+
"bundle": "rolldown -c",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"tc": "tsc",
|
|
35
34
|
"lint": "eslint .",
|
|
36
|
-
"lint:fix": "eslint --fix .",
|
|
37
35
|
"pret": "prettier -c .",
|
|
38
36
|
"pret:fix": "prettier -w .",
|
|
39
|
-
"
|
|
37
|
+
"prepare": "rm -Rf types/__tests__",
|
|
38
|
+
"build": "run-s pret clean tc lint bundle"
|
|
40
39
|
},
|
|
41
40
|
"exports": {
|
|
42
41
|
".": {
|
|
@@ -51,31 +50,26 @@
|
|
|
51
50
|
"react-dom": ">=16.8.0"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"
|
|
60
|
-
"eslint": "^
|
|
61
|
-
"eslint-
|
|
62
|
-
"eslint-plugin-
|
|
63
|
-
"eslint-plugin-react": "^
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"globals": "^15.14.0",
|
|
67
|
-
"jest": "^29.7.0",
|
|
68
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
53
|
+
"@testing-library/react": "^16.3.1",
|
|
54
|
+
"@types/node": "^25.0.3",
|
|
55
|
+
"@types/react": "^19.2.7",
|
|
56
|
+
"@vitest/coverage-istanbul": "^4.0.16",
|
|
57
|
+
"@vitest/eslint-plugin": "^1.6.4",
|
|
58
|
+
"eslint": "^9.39.2",
|
|
59
|
+
"eslint-config-prettier": "^10.1.8",
|
|
60
|
+
"eslint-plugin-react": "^7.37.5",
|
|
61
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
62
|
+
"eslint-plugin-react-hooks-addons": "^0.5.0",
|
|
63
|
+
"globals": "^16.5.0",
|
|
64
|
+
"jsdom": "^27.4.0",
|
|
69
65
|
"npm-run-all": "^4.1.5",
|
|
70
|
-
"prettier": "^3.4
|
|
71
|
-
"react": "^19",
|
|
72
|
-
"react-dom": "^19",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"
|
|
78
|
-
"tr46": "^4"
|
|
79
|
-
}
|
|
66
|
+
"prettier": "^3.7.4",
|
|
67
|
+
"react": "^19.2.3",
|
|
68
|
+
"react-dom": "^19.2.3",
|
|
69
|
+
"rolldown": "^1.0.0-beta.57",
|
|
70
|
+
"rollup-plugin-add-directive": "^1.0.0",
|
|
71
|
+
"typescript": "^5.9.3",
|
|
72
|
+
"typescript-eslint": "^8.51.0",
|
|
73
|
+
"vitest": "^4.0.16"
|
|
80
74
|
}
|
|
81
75
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,63 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
| 'exited'
|
|
8
|
-
| 'unmounted';
|
|
9
|
-
|
|
10
|
-
export type TransitionState = Readonly<{
|
|
11
|
-
status: TransitionStatus;
|
|
12
|
-
isMounted: boolean;
|
|
13
|
-
isEnter: boolean;
|
|
14
|
-
isResolved: boolean;
|
|
15
|
-
}>;
|
|
16
|
-
|
|
17
|
-
export interface TransitionOptions {
|
|
18
|
-
initialEntered?: boolean;
|
|
19
|
-
mountOnEnter?: boolean;
|
|
20
|
-
unmountOnExit?: boolean;
|
|
21
|
-
preEnter?: boolean;
|
|
22
|
-
preExit?: boolean;
|
|
23
|
-
enter?: boolean;
|
|
24
|
-
exit?: boolean;
|
|
25
|
-
timeout?: number | { enter?: number; exit?: number };
|
|
26
|
-
onStateChange?: (event: { current: TransitionState }) => void;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface TransitionItemOptions {
|
|
30
|
-
initialEntered?: boolean;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface TransitionMapOptions<K> extends Omit<TransitionOptions, 'onStateChange'> {
|
|
34
|
-
allowMultiple?: boolean;
|
|
35
|
-
onStateChange?: (event: { key: K; current: TransitionState }) => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type TransitionResult = [TransitionState, (toEnter?: boolean) => void, () => void];
|
|
39
|
-
|
|
40
|
-
export interface TransitionMapResult<K> {
|
|
41
|
-
stateMap: ReadonlyMap<K, TransitionState>;
|
|
42
|
-
toggle: (key: K, toEnter?: boolean) => void;
|
|
43
|
-
toggleAll: (toEnter?: boolean) => void;
|
|
44
|
-
endTransition: (key: K) => void;
|
|
45
|
-
setItem: (key: K, options?: TransitionItemOptions) => void;
|
|
46
|
-
deleteItem: (key: K) => boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const useTransitionState: (options?: TransitionOptions) => TransitionResult;
|
|
50
|
-
|
|
51
|
-
export const useTransitionMap: <K>(options?: TransitionMapOptions<K>) => TransitionMapResult<K>;
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
/**
|
|
55
|
-
* @deprecated The `useTransition` alias will be removed in v3.0.0. Use `useTransitionState` instead.
|
|
56
|
-
*/
|
|
57
|
-
useTransitionState as useTransition
|
|
58
|
-
};
|
|
59
|
-
|
|
1
|
+
export * from './types';
|
|
2
|
+
export { useTransitionState,
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated The `useTransition` alias will be removed in v3.0.0. Use `useTransitionState` instead.
|
|
5
|
+
*/
|
|
6
|
+
useTransitionState as useTransition,
|
|
60
7
|
/**
|
|
61
8
|
* @deprecated The default export will be removed in v3.0.0. Use the named export `useTransitionState` instead.
|
|
62
9
|
*/
|
|
63
|
-
|
|
10
|
+
useTransitionState as default } from './useTransitionState';
|
|
11
|
+
export { useTransitionMap } from './useTransitionMap';
|
package/types/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type TransitionStatus = 'preEnter' | 'entering' | 'entered' | 'preExit' | 'exiting' | 'exited' | 'unmounted';
|
|
2
|
+
export type TransitionState = Readonly<{
|
|
3
|
+
status: TransitionStatus;
|
|
4
|
+
isMounted: boolean;
|
|
5
|
+
isEnter: boolean;
|
|
6
|
+
isResolved: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
export interface TransitionOptions {
|
|
9
|
+
initialEntered?: boolean;
|
|
10
|
+
mountOnEnter?: boolean;
|
|
11
|
+
unmountOnExit?: boolean;
|
|
12
|
+
preEnter?: boolean;
|
|
13
|
+
preExit?: boolean;
|
|
14
|
+
enter?: boolean;
|
|
15
|
+
exit?: boolean;
|
|
16
|
+
timeout?: number | {
|
|
17
|
+
enter?: number;
|
|
18
|
+
exit?: number;
|
|
19
|
+
};
|
|
20
|
+
onStateChange?: (event: {
|
|
21
|
+
current: TransitionState;
|
|
22
|
+
}) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface TransitionItemOptions {
|
|
25
|
+
initialEntered?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface TransitionMapOptions<TKey> extends Omit<TransitionOptions, 'onStateChange'> {
|
|
28
|
+
allowMultiple?: boolean;
|
|
29
|
+
onStateChange?: (event: {
|
|
30
|
+
key: TKey;
|
|
31
|
+
current: TransitionState;
|
|
32
|
+
}) => void;
|
|
33
|
+
}
|
|
34
|
+
export type TransitionResult = [TransitionState, (toEnter?: boolean) => void, () => void];
|
|
35
|
+
export interface TransitionMapResult<TKey> {
|
|
36
|
+
stateMap: ReadonlyMap<TKey, TransitionState>;
|
|
37
|
+
toggle: (key: TKey, toEnter?: boolean) => void;
|
|
38
|
+
toggleAll: (toEnter?: boolean) => void;
|
|
39
|
+
endTransition: (key: TKey) => void;
|
|
40
|
+
setItem: (key: TKey, options?: TransitionItemOptions) => void;
|
|
41
|
+
deleteItem: (key: TKey) => boolean;
|
|
42
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { TransitionMapOptions, TransitionMapResult } from './types';
|
|
2
|
+
declare const useTransitionMap: <TKey>({ allowMultiple, enter, exit, preEnter, preExit, timeout, initialEntered, mountOnEnter, unmountOnExit, onStateChange: onChange }?: TransitionMapOptions<TKey>) => TransitionMapResult<TKey>;
|
|
3
|
+
export { useTransitionMap };
|
package/types/utils.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { TransitionOptions, TransitionState } from './types';
|
|
2
|
+
export declare const PRE_ENTER = 0;
|
|
3
|
+
export declare const ENTERING = 1;
|
|
4
|
+
export declare const ENTERED = 2;
|
|
5
|
+
export declare const PRE_EXIT = 3;
|
|
6
|
+
export declare const EXITING = 4;
|
|
7
|
+
export declare const EXITED = 5;
|
|
8
|
+
export declare const UNMOUNTED = 6;
|
|
9
|
+
/** @internal [INTERNAL ONLY – DO NOT USE] */
|
|
10
|
+
export type Status = typeof PRE_ENTER | typeof ENTERING | typeof ENTERED | typeof PRE_EXIT | typeof EXITING | typeof EXITED | typeof UNMOUNTED;
|
|
11
|
+
/** @internal [INTERNAL ONLY – DO NOT USE] */
|
|
12
|
+
export type State = {
|
|
13
|
+
_s: Status;
|
|
14
|
+
} & TransitionState;
|
|
15
|
+
export declare const STATUS: readonly ["preEnter", "entering", "entered", "preExit", "exiting", "exited", "unmounted"];
|
|
16
|
+
export declare const getState: (status: Status) => State;
|
|
17
|
+
export declare const startOrEnd: (unmounted: boolean | undefined) => 5 | 6;
|
|
18
|
+
export declare const getEndStatus: (status: Status, unmountOnExit: boolean | undefined) => 2 | 5 | 6 | undefined;
|
|
19
|
+
export declare const getTimeout: (timeout: TransitionOptions["timeout"]) => (number | undefined)[];
|
|
20
|
+
declare const _setTimeout: typeof window.setTimeout;
|
|
21
|
+
export { _setTimeout as setTimeout };
|
|
22
|
+
export declare const nextTick: (transitState: (status: Status) => void, status: Status) => number;
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var react = require('react');
|
|
4
|
-
var utils = require('./utils.cjs');
|
|
5
|
-
|
|
6
|
-
const updateState = (key, status, setStateMap, latestStateMap, timeoutId, onChange) => {
|
|
7
|
-
clearTimeout(timeoutId);
|
|
8
|
-
const state = utils.getState(status);
|
|
9
|
-
const stateMap = new Map(latestStateMap.current);
|
|
10
|
-
stateMap.set(key, state);
|
|
11
|
-
setStateMap(stateMap);
|
|
12
|
-
latestStateMap.current = stateMap;
|
|
13
|
-
onChange && onChange({
|
|
14
|
-
key,
|
|
15
|
-
current: state
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
const useTransitionMap = ({
|
|
19
|
-
allowMultiple,
|
|
20
|
-
enter = true,
|
|
21
|
-
exit = true,
|
|
22
|
-
preEnter,
|
|
23
|
-
preExit,
|
|
24
|
-
timeout,
|
|
25
|
-
initialEntered,
|
|
26
|
-
mountOnEnter,
|
|
27
|
-
unmountOnExit,
|
|
28
|
-
onStateChange: onChange
|
|
29
|
-
} = {}) => {
|
|
30
|
-
const [stateMap, setStateMap] = react.useState(new Map());
|
|
31
|
-
const latestStateMap = react.useRef(stateMap);
|
|
32
|
-
const configMap = react.useRef(new Map());
|
|
33
|
-
const [enterTimeout, exitTimeout] = utils.getTimeout(timeout);
|
|
34
|
-
const setItem = react.useCallback((key, config) => {
|
|
35
|
-
const {
|
|
36
|
-
initialEntered: _initialEntered = initialEntered
|
|
37
|
-
} = config || {};
|
|
38
|
-
const status = _initialEntered ? utils.ENTERED : utils.startOrEnd(mountOnEnter);
|
|
39
|
-
updateState(key, status, setStateMap, latestStateMap);
|
|
40
|
-
configMap.current.set(key, {});
|
|
41
|
-
}, [initialEntered, mountOnEnter]);
|
|
42
|
-
const deleteItem = react.useCallback(key => {
|
|
43
|
-
const newStateMap = new Map(latestStateMap.current);
|
|
44
|
-
if (newStateMap.delete(key)) {
|
|
45
|
-
setStateMap(newStateMap);
|
|
46
|
-
latestStateMap.current = newStateMap;
|
|
47
|
-
configMap.current.delete(key);
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}, []);
|
|
52
|
-
const endTransition = react.useCallback(key => {
|
|
53
|
-
const stateObj = latestStateMap.current.get(key);
|
|
54
|
-
if (!stateObj) {
|
|
55
|
-
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const {
|
|
59
|
-
timeoutId
|
|
60
|
-
} = configMap.current.get(key);
|
|
61
|
-
const status = utils.getEndStatus(stateObj._s, unmountOnExit);
|
|
62
|
-
status && updateState(key, status, setStateMap, latestStateMap, timeoutId, onChange);
|
|
63
|
-
}, [onChange, unmountOnExit]);
|
|
64
|
-
const toggle = react.useCallback((key, toEnter) => {
|
|
65
|
-
const stateObj = latestStateMap.current.get(key);
|
|
66
|
-
if (!stateObj) {
|
|
67
|
-
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const config = configMap.current.get(key);
|
|
71
|
-
const transitState = status => {
|
|
72
|
-
updateState(key, status, setStateMap, latestStateMap, config.timeoutId, onChange);
|
|
73
|
-
switch (status) {
|
|
74
|
-
case utils.ENTERING:
|
|
75
|
-
if (enterTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), enterTimeout);
|
|
76
|
-
break;
|
|
77
|
-
case utils.EXITING:
|
|
78
|
-
if (exitTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), exitTimeout);
|
|
79
|
-
break;
|
|
80
|
-
case utils.PRE_ENTER:
|
|
81
|
-
case utils.PRE_EXIT:
|
|
82
|
-
config.timeoutId = utils.nextTick(transitState, status);
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
const enterStage = stateObj.isEnter;
|
|
87
|
-
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
88
|
-
if (toEnter) {
|
|
89
|
-
if (!enterStage) {
|
|
90
|
-
transitState(enter ? preEnter ? utils.PRE_ENTER : utils.ENTERING : utils.ENTERED);
|
|
91
|
-
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
if (enterStage) {
|
|
95
|
-
transitState(exit ? preExit ? utils.PRE_EXIT : utils.EXITING : utils.startOrEnd(unmountOnExit));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}, [onChange, endTransition, allowMultiple, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
99
|
-
const toggleAll = react.useCallback(toEnter => {
|
|
100
|
-
if (!allowMultiple && toEnter !== false) return;
|
|
101
|
-
for (const key of latestStateMap.current.keys()) toggle(key, toEnter);
|
|
102
|
-
}, [allowMultiple, toggle]);
|
|
103
|
-
return {
|
|
104
|
-
stateMap,
|
|
105
|
-
toggle,
|
|
106
|
-
toggleAll,
|
|
107
|
-
endTransition,
|
|
108
|
-
setItem,
|
|
109
|
-
deleteItem
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
exports.useTransitionMap = useTransitionMap;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var react = require('react');
|
|
4
|
-
var utils = require('./utils.cjs');
|
|
5
|
-
|
|
6
|
-
const updateState = (status, setState, latestState, timeoutId, onChange) => {
|
|
7
|
-
clearTimeout(timeoutId.current);
|
|
8
|
-
const state = utils.getState(status);
|
|
9
|
-
setState(state);
|
|
10
|
-
latestState.current = state;
|
|
11
|
-
onChange && onChange({
|
|
12
|
-
current: state
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
const useTransitionState = ({
|
|
16
|
-
enter = true,
|
|
17
|
-
exit = true,
|
|
18
|
-
preEnter,
|
|
19
|
-
preExit,
|
|
20
|
-
timeout,
|
|
21
|
-
initialEntered,
|
|
22
|
-
mountOnEnter,
|
|
23
|
-
unmountOnExit,
|
|
24
|
-
onStateChange: onChange
|
|
25
|
-
} = {}) => {
|
|
26
|
-
const [state, setState] = react.useState(() => utils.getState(initialEntered ? utils.ENTERED : utils.startOrEnd(mountOnEnter)));
|
|
27
|
-
const latestState = react.useRef(state);
|
|
28
|
-
const timeoutId = react.useRef();
|
|
29
|
-
const [enterTimeout, exitTimeout] = utils.getTimeout(timeout);
|
|
30
|
-
const endTransition = react.useCallback(() => {
|
|
31
|
-
const status = utils.getEndStatus(latestState.current._s, unmountOnExit);
|
|
32
|
-
status && updateState(status, setState, latestState, timeoutId, onChange);
|
|
33
|
-
}, [onChange, unmountOnExit]);
|
|
34
|
-
const toggle = react.useCallback(toEnter => {
|
|
35
|
-
const transitState = status => {
|
|
36
|
-
updateState(status, setState, latestState, timeoutId, onChange);
|
|
37
|
-
switch (status) {
|
|
38
|
-
case utils.ENTERING:
|
|
39
|
-
if (enterTimeout >= 0) timeoutId.current = setTimeout(endTransition, enterTimeout);
|
|
40
|
-
break;
|
|
41
|
-
case utils.EXITING:
|
|
42
|
-
if (exitTimeout >= 0) timeoutId.current = setTimeout(endTransition, exitTimeout);
|
|
43
|
-
break;
|
|
44
|
-
case utils.PRE_ENTER:
|
|
45
|
-
case utils.PRE_EXIT:
|
|
46
|
-
timeoutId.current = utils.nextTick(transitState, status);
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
const enterStage = latestState.current.isEnter;
|
|
51
|
-
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
52
|
-
if (toEnter) {
|
|
53
|
-
!enterStage && transitState(enter ? preEnter ? utils.PRE_ENTER : utils.ENTERING : utils.ENTERED);
|
|
54
|
-
} else {
|
|
55
|
-
enterStage && transitState(exit ? preExit ? utils.PRE_EXIT : utils.EXITING : utils.startOrEnd(unmountOnExit));
|
|
56
|
-
}
|
|
57
|
-
}, [endTransition, onChange, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
58
|
-
react.useEffect(() => () => clearTimeout(timeoutId.current), []);
|
|
59
|
-
return [state, toggle, endTransition];
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
exports.useTransitionState = useTransitionState;
|
package/dist/cjs/hooks/utils.cjs
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const PRE_ENTER = 0;
|
|
4
|
-
const ENTERING = 1;
|
|
5
|
-
const ENTERED = 2;
|
|
6
|
-
const PRE_EXIT = 3;
|
|
7
|
-
const EXITING = 4;
|
|
8
|
-
const EXITED = 5;
|
|
9
|
-
const UNMOUNTED = 6;
|
|
10
|
-
const STATUS = ['preEnter', 'entering', 'entered', 'preExit', 'exiting', 'exited', 'unmounted'];
|
|
11
|
-
const getState = status => ({
|
|
12
|
-
_s: status,
|
|
13
|
-
status: STATUS[status],
|
|
14
|
-
isEnter: status < PRE_EXIT,
|
|
15
|
-
isMounted: status !== UNMOUNTED,
|
|
16
|
-
isResolved: status === ENTERED || status > EXITING
|
|
17
|
-
});
|
|
18
|
-
const startOrEnd = unmounted => unmounted ? UNMOUNTED : EXITED;
|
|
19
|
-
const getEndStatus = (status, unmountOnExit) => {
|
|
20
|
-
switch (status) {
|
|
21
|
-
case ENTERING:
|
|
22
|
-
case PRE_ENTER:
|
|
23
|
-
return ENTERED;
|
|
24
|
-
case EXITING:
|
|
25
|
-
case PRE_EXIT:
|
|
26
|
-
return startOrEnd(unmountOnExit);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
const getTimeout = timeout => typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
30
|
-
const nextTick = (transitState, status) => setTimeout(() => {
|
|
31
|
-
// Reading document.body.offsetTop can force browser to repaint before transition to the next state
|
|
32
|
-
isNaN(document.body.offsetTop) || transitState(status + 1);
|
|
33
|
-
}, 0);
|
|
34
|
-
|
|
35
|
-
exports.ENTERED = ENTERED;
|
|
36
|
-
exports.ENTERING = ENTERING;
|
|
37
|
-
exports.EXITED = EXITED;
|
|
38
|
-
exports.EXITING = EXITING;
|
|
39
|
-
exports.PRE_ENTER = PRE_ENTER;
|
|
40
|
-
exports.PRE_EXIT = PRE_EXIT;
|
|
41
|
-
exports.STATUS = STATUS;
|
|
42
|
-
exports.UNMOUNTED = UNMOUNTED;
|
|
43
|
-
exports.getEndStatus = getEndStatus;
|
|
44
|
-
exports.getState = getState;
|
|
45
|
-
exports.getTimeout = getTimeout;
|
|
46
|
-
exports.nextTick = nextTick;
|
|
47
|
-
exports.startOrEnd = startOrEnd;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { getTimeout, getEndStatus, PRE_EXIT, nextTick, PRE_ENTER, EXITING, ENTERING, ENTERED, startOrEnd, getState } from './utils.mjs';
|
|
3
|
-
|
|
4
|
-
const updateState = (key, status, setStateMap, latestStateMap, timeoutId, onChange) => {
|
|
5
|
-
clearTimeout(timeoutId);
|
|
6
|
-
const state = getState(status);
|
|
7
|
-
const stateMap = new Map(latestStateMap.current);
|
|
8
|
-
stateMap.set(key, state);
|
|
9
|
-
setStateMap(stateMap);
|
|
10
|
-
latestStateMap.current = stateMap;
|
|
11
|
-
onChange && onChange({
|
|
12
|
-
key,
|
|
13
|
-
current: state
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
const useTransitionMap = ({
|
|
17
|
-
allowMultiple,
|
|
18
|
-
enter = true,
|
|
19
|
-
exit = true,
|
|
20
|
-
preEnter,
|
|
21
|
-
preExit,
|
|
22
|
-
timeout,
|
|
23
|
-
initialEntered,
|
|
24
|
-
mountOnEnter,
|
|
25
|
-
unmountOnExit,
|
|
26
|
-
onStateChange: onChange
|
|
27
|
-
} = {}) => {
|
|
28
|
-
const [stateMap, setStateMap] = useState(new Map());
|
|
29
|
-
const latestStateMap = useRef(stateMap);
|
|
30
|
-
const configMap = useRef(new Map());
|
|
31
|
-
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
32
|
-
const setItem = useCallback((key, config) => {
|
|
33
|
-
const {
|
|
34
|
-
initialEntered: _initialEntered = initialEntered
|
|
35
|
-
} = config || {};
|
|
36
|
-
const status = _initialEntered ? ENTERED : startOrEnd(mountOnEnter);
|
|
37
|
-
updateState(key, status, setStateMap, latestStateMap);
|
|
38
|
-
configMap.current.set(key, {});
|
|
39
|
-
}, [initialEntered, mountOnEnter]);
|
|
40
|
-
const deleteItem = useCallback(key => {
|
|
41
|
-
const newStateMap = new Map(latestStateMap.current);
|
|
42
|
-
if (newStateMap.delete(key)) {
|
|
43
|
-
setStateMap(newStateMap);
|
|
44
|
-
latestStateMap.current = newStateMap;
|
|
45
|
-
configMap.current.delete(key);
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
return false;
|
|
49
|
-
}, []);
|
|
50
|
-
const endTransition = useCallback(key => {
|
|
51
|
-
const stateObj = latestStateMap.current.get(key);
|
|
52
|
-
if (!stateObj) {
|
|
53
|
-
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
const {
|
|
57
|
-
timeoutId
|
|
58
|
-
} = configMap.current.get(key);
|
|
59
|
-
const status = getEndStatus(stateObj._s, unmountOnExit);
|
|
60
|
-
status && updateState(key, status, setStateMap, latestStateMap, timeoutId, onChange);
|
|
61
|
-
}, [onChange, unmountOnExit]);
|
|
62
|
-
const toggle = useCallback((key, toEnter) => {
|
|
63
|
-
const stateObj = latestStateMap.current.get(key);
|
|
64
|
-
if (!stateObj) {
|
|
65
|
-
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const config = configMap.current.get(key);
|
|
69
|
-
const transitState = status => {
|
|
70
|
-
updateState(key, status, setStateMap, latestStateMap, config.timeoutId, onChange);
|
|
71
|
-
switch (status) {
|
|
72
|
-
case ENTERING:
|
|
73
|
-
if (enterTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), enterTimeout);
|
|
74
|
-
break;
|
|
75
|
-
case EXITING:
|
|
76
|
-
if (exitTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), exitTimeout);
|
|
77
|
-
break;
|
|
78
|
-
case PRE_ENTER:
|
|
79
|
-
case PRE_EXIT:
|
|
80
|
-
config.timeoutId = nextTick(transitState, status);
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
const enterStage = stateObj.isEnter;
|
|
85
|
-
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
86
|
-
if (toEnter) {
|
|
87
|
-
if (!enterStage) {
|
|
88
|
-
transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
89
|
-
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
90
|
-
}
|
|
91
|
-
} else {
|
|
92
|
-
if (enterStage) {
|
|
93
|
-
transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}, [onChange, endTransition, allowMultiple, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
97
|
-
const toggleAll = useCallback(toEnter => {
|
|
98
|
-
if (!allowMultiple && toEnter !== false) return;
|
|
99
|
-
for (const key of latestStateMap.current.keys()) toggle(key, toEnter);
|
|
100
|
-
}, [allowMultiple, toggle]);
|
|
101
|
-
return {
|
|
102
|
-
stateMap,
|
|
103
|
-
toggle,
|
|
104
|
-
toggleAll,
|
|
105
|
-
endTransition,
|
|
106
|
-
setItem,
|
|
107
|
-
deleteItem
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export { useTransitionMap };
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
-
import { getState, ENTERED, startOrEnd, getTimeout, getEndStatus, PRE_EXIT, nextTick, PRE_ENTER, EXITING, ENTERING } from './utils.mjs';
|
|
3
|
-
|
|
4
|
-
const updateState = (status, setState, latestState, timeoutId, onChange) => {
|
|
5
|
-
clearTimeout(timeoutId.current);
|
|
6
|
-
const state = getState(status);
|
|
7
|
-
setState(state);
|
|
8
|
-
latestState.current = state;
|
|
9
|
-
onChange && onChange({
|
|
10
|
-
current: state
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
const useTransitionState = ({
|
|
14
|
-
enter = true,
|
|
15
|
-
exit = true,
|
|
16
|
-
preEnter,
|
|
17
|
-
preExit,
|
|
18
|
-
timeout,
|
|
19
|
-
initialEntered,
|
|
20
|
-
mountOnEnter,
|
|
21
|
-
unmountOnExit,
|
|
22
|
-
onStateChange: onChange
|
|
23
|
-
} = {}) => {
|
|
24
|
-
const [state, setState] = useState(() => getState(initialEntered ? ENTERED : startOrEnd(mountOnEnter)));
|
|
25
|
-
const latestState = useRef(state);
|
|
26
|
-
const timeoutId = useRef();
|
|
27
|
-
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
28
|
-
const endTransition = useCallback(() => {
|
|
29
|
-
const status = getEndStatus(latestState.current._s, unmountOnExit);
|
|
30
|
-
status && updateState(status, setState, latestState, timeoutId, onChange);
|
|
31
|
-
}, [onChange, unmountOnExit]);
|
|
32
|
-
const toggle = useCallback(toEnter => {
|
|
33
|
-
const transitState = status => {
|
|
34
|
-
updateState(status, setState, latestState, timeoutId, onChange);
|
|
35
|
-
switch (status) {
|
|
36
|
-
case ENTERING:
|
|
37
|
-
if (enterTimeout >= 0) timeoutId.current = setTimeout(endTransition, enterTimeout);
|
|
38
|
-
break;
|
|
39
|
-
case EXITING:
|
|
40
|
-
if (exitTimeout >= 0) timeoutId.current = setTimeout(endTransition, exitTimeout);
|
|
41
|
-
break;
|
|
42
|
-
case PRE_ENTER:
|
|
43
|
-
case PRE_EXIT:
|
|
44
|
-
timeoutId.current = nextTick(transitState, status);
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
const enterStage = latestState.current.isEnter;
|
|
49
|
-
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
50
|
-
if (toEnter) {
|
|
51
|
-
!enterStage && transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
52
|
-
} else {
|
|
53
|
-
enterStage && transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
54
|
-
}
|
|
55
|
-
}, [endTransition, onChange, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
56
|
-
useEffect(() => () => clearTimeout(timeoutId.current), []);
|
|
57
|
-
return [state, toggle, endTransition];
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export { useTransitionState };
|
package/dist/esm/hooks/utils.mjs
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const PRE_ENTER = 0;
|
|
2
|
-
const ENTERING = 1;
|
|
3
|
-
const ENTERED = 2;
|
|
4
|
-
const PRE_EXIT = 3;
|
|
5
|
-
const EXITING = 4;
|
|
6
|
-
const EXITED = 5;
|
|
7
|
-
const UNMOUNTED = 6;
|
|
8
|
-
const STATUS = ['preEnter', 'entering', 'entered', 'preExit', 'exiting', 'exited', 'unmounted'];
|
|
9
|
-
const getState = status => ({
|
|
10
|
-
_s: status,
|
|
11
|
-
status: STATUS[status],
|
|
12
|
-
isEnter: status < PRE_EXIT,
|
|
13
|
-
isMounted: status !== UNMOUNTED,
|
|
14
|
-
isResolved: status === ENTERED || status > EXITING
|
|
15
|
-
});
|
|
16
|
-
const startOrEnd = unmounted => unmounted ? UNMOUNTED : EXITED;
|
|
17
|
-
const getEndStatus = (status, unmountOnExit) => {
|
|
18
|
-
switch (status) {
|
|
19
|
-
case ENTERING:
|
|
20
|
-
case PRE_ENTER:
|
|
21
|
-
return ENTERED;
|
|
22
|
-
case EXITING:
|
|
23
|
-
case PRE_EXIT:
|
|
24
|
-
return startOrEnd(unmountOnExit);
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
const getTimeout = timeout => typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
28
|
-
const nextTick = (transitState, status) => setTimeout(() => {
|
|
29
|
-
// Reading document.body.offsetTop can force browser to repaint before transition to the next state
|
|
30
|
-
isNaN(document.body.offsetTop) || transitState(status + 1);
|
|
31
|
-
}, 0);
|
|
32
|
-
|
|
33
|
-
export { ENTERED, ENTERING, EXITED, EXITING, PRE_ENTER, PRE_EXIT, STATUS, UNMOUNTED, getEndStatus, getState, getTimeout, nextTick, startOrEnd };
|