react-transition-state 2.0.1 → 2.1.0-alpha.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/README.md +2 -2
- package/dist/cjs/index.js +116 -179
- package/dist/es/hooks/useTransition.js +25 -49
- package/dist/es/hooks/useTransitionMap.js +75 -107
- package/dist/es/hooks/utils.js +18 -25
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ useEffect(() => {
|
|
|
147
147
|
| Use derived state | _Yes_ – use an `in` prop to trigger changes in a derived transition state | _No_ – there is only a single state which is triggered by a toggle function |
|
|
148
148
|
| Controlled | _No_ – <br/>Transition state is managed internally.<br/>Resort to callback events to read the internal state. | _Yes_ – <br/>Transition state is _lifted_ up into the consuming component.<br/>You have direct access to the transition state. |
|
|
149
149
|
| DOM updates | _Imperative_ – [commit changes into DOM imperatively](https://github.com/reactjs/react-transition-group/blob/5aa3fd2d7e3354a7e42505d55af605ff44f74e2e/src/CSSTransition.js#L10) to update `classes` | _Declarative_ – you declare [what the `classes` look like](https://github.com/szhsin/react-transition-state/blob/2ab44c12ac5d5283ec3bb997bfc1d5ef6dffb0ce/example/src/components/BasicExample.js#L31) and DOM updates are taken care of by `ReactDOM` |
|
|
150
|
-
| Render something in response to state updates | _Resort to side effects_ – rendering based on [state update events](https://codesandbox.io/s/react-transition-state-vs-group-p45iy?file=/src/App.js:
|
|
150
|
+
| Render something in response to state updates | _Resort to side effects_ – rendering based on [state update events](https://codesandbox.io/s/react-transition-state-vs-group-p45iy?file=/src/App.js:1010-1191) | _Pure_ – rendering based on [transition state](https://codesandbox.io/s/react-transition-state-vs-group-p45iy?file=/src/App.js:2168-2342) |
|
|
151
151
|
| Working with _styled-components_ | Your code looks like – <br/>`&.box-exit-active { opacity: 0; }`<br/>`&.box-enter-active { opacity: 1; }` | Your code looks like – <br/>`opacity: ${({ state }) => (state === 'exiting' ? '0' : '1')};` <br/> It's the way how you normally use the _styled-components_ |
|
|
152
152
|
| Bundle size | [](https://bundlephobia.com/package/react-transition-group) | ✅ [](https://bundlephobia.com/package/react-transition-state) |
|
|
153
153
|
| Dependency count | [](https://www.npmjs.com/package/react-transition-group?activeTab=dependencies) | ✅ [](https://www.npmjs.com/package/react-transition-state?activeTab=dependencies) |
|
|
@@ -178,7 +178,7 @@ function useTransition(
|
|
|
178
178
|
| `mountOnEnter` | boolean | | State will be 'unmounted' until hit enter phase for the first time. It allows you to create lazily mounted component. |
|
|
179
179
|
| `unmountOnExit` | boolean | | State will become 'unmounted' after 'exiting' finishes. It allows you to transition component out of DOM. |
|
|
180
180
|
| `timeout` | number \| <br />{ enter?: number; exit?: number; } | | Set timeout in **ms** for transitions; you can set a single value or different values for enter and exit transitions. |
|
|
181
|
-
| `
|
|
181
|
+
| `onStateChange` | (event: { current: TransitionState }) => void | | Event fired when state has changed. <br/><br/>Prefer to read state from the hook function return value directly unless you want to perform some side effects in response to state changes. <br/><br/>_Note: create an event handler with `useCallback` if you need to keep `toggle` or `endTransition` function's identity stable across re-renders._ |
|
|
182
182
|
|
|
183
183
|
#### Return value
|
|
184
184
|
|
package/dist/cjs/index.js
CHANGED
|
@@ -4,267 +4,204 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
var startOrEnd = function startOrEnd(unmounted) {
|
|
25
|
-
return unmounted ? UNMOUNTED : EXITED;
|
|
26
|
-
};
|
|
27
|
-
var getEndStatus = function getEndStatus(status, unmountOnExit) {
|
|
7
|
+
const PRE_ENTER = 0;
|
|
8
|
+
const ENTERING = 1;
|
|
9
|
+
const ENTERED = 2;
|
|
10
|
+
const PRE_EXIT = 3;
|
|
11
|
+
const EXITING = 4;
|
|
12
|
+
const EXITED = 5;
|
|
13
|
+
const UNMOUNTED = 6;
|
|
14
|
+
const STATUS = ['preEnter', 'entering', 'entered', 'preExit', 'exiting', 'exited', 'unmounted'];
|
|
15
|
+
const getState = status => ({
|
|
16
|
+
_status: status,
|
|
17
|
+
status: STATUS[status],
|
|
18
|
+
isEnter: status < PRE_EXIT,
|
|
19
|
+
isMounted: status !== UNMOUNTED,
|
|
20
|
+
isResolved: status === ENTERED || status > EXITING
|
|
21
|
+
});
|
|
22
|
+
const startOrEnd = unmounted => unmounted ? UNMOUNTED : EXITED;
|
|
23
|
+
const getEndStatus = (status, unmountOnExit) => {
|
|
28
24
|
switch (status) {
|
|
29
25
|
case ENTERING:
|
|
30
26
|
case PRE_ENTER:
|
|
31
27
|
return ENTERED;
|
|
32
|
-
|
|
33
28
|
case EXITING:
|
|
34
29
|
case PRE_EXIT:
|
|
35
30
|
return startOrEnd(unmountOnExit);
|
|
36
31
|
}
|
|
37
32
|
};
|
|
38
|
-
|
|
39
|
-
return typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
40
|
-
};
|
|
33
|
+
const getTimeout = timeout => typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
41
34
|
|
|
42
|
-
|
|
35
|
+
const updateState$1 = (status, setState, latestState, timeoutId, onChange) => {
|
|
43
36
|
clearTimeout(timeoutId.current);
|
|
44
|
-
|
|
37
|
+
const state = getState(status);
|
|
45
38
|
setState(state);
|
|
46
39
|
latestState.current = state;
|
|
47
40
|
onChange && onChange({
|
|
48
41
|
current: state
|
|
49
42
|
});
|
|
50
43
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}),
|
|
69
|
-
state = _useState[0],
|
|
70
|
-
setState = _useState[1];
|
|
71
|
-
|
|
72
|
-
var latestState = react.useRef(state);
|
|
73
|
-
var timeoutId = react.useRef();
|
|
74
|
-
|
|
75
|
-
var _getTimeout = getTimeout(timeout),
|
|
76
|
-
enterTimeout = _getTimeout[0],
|
|
77
|
-
exitTimeout = _getTimeout[1];
|
|
78
|
-
|
|
79
|
-
var endTransition = react.useCallback(function () {
|
|
80
|
-
var status = getEndStatus(latestState.current._status, unmountOnExit);
|
|
44
|
+
const useTransition = ({
|
|
45
|
+
enter = true,
|
|
46
|
+
exit = true,
|
|
47
|
+
preEnter,
|
|
48
|
+
preExit,
|
|
49
|
+
timeout,
|
|
50
|
+
initialEntered,
|
|
51
|
+
mountOnEnter,
|
|
52
|
+
unmountOnExit,
|
|
53
|
+
onStateChange: onChange
|
|
54
|
+
} = {}) => {
|
|
55
|
+
const [state, setState] = react.useState(() => getState(initialEntered ? ENTERED : startOrEnd(mountOnEnter)));
|
|
56
|
+
const latestState = react.useRef(state);
|
|
57
|
+
const timeoutId = react.useRef();
|
|
58
|
+
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
59
|
+
const endTransition = react.useCallback(() => {
|
|
60
|
+
const status = getEndStatus(latestState.current._status, unmountOnExit);
|
|
81
61
|
status && updateState$1(status, setState, latestState, timeoutId, onChange);
|
|
82
62
|
}, [onChange, unmountOnExit]);
|
|
83
|
-
|
|
84
|
-
|
|
63
|
+
const toggle = react.useCallback(toEnter => {
|
|
64
|
+
const transitState = status => {
|
|
85
65
|
updateState$1(status, setState, latestState, timeoutId, onChange);
|
|
86
|
-
|
|
87
66
|
switch (status) {
|
|
88
67
|
case ENTERING:
|
|
89
68
|
if (enterTimeout >= 0) timeoutId.current = setTimeout(endTransition, enterTimeout);
|
|
90
69
|
break;
|
|
91
|
-
|
|
92
70
|
case EXITING:
|
|
93
71
|
if (exitTimeout >= 0) timeoutId.current = setTimeout(endTransition, exitTimeout);
|
|
94
72
|
break;
|
|
95
|
-
|
|
96
73
|
case PRE_ENTER:
|
|
97
74
|
case PRE_EXIT:
|
|
98
|
-
timeoutId.current = setTimeout(
|
|
99
|
-
return transitState(status + 1);
|
|
100
|
-
}, 0);
|
|
75
|
+
timeoutId.current = setTimeout(() => transitState(status + 1), 0);
|
|
101
76
|
break;
|
|
102
77
|
}
|
|
103
78
|
};
|
|
104
|
-
|
|
105
|
-
var enterStage = latestState.current._status <= ENTERED;
|
|
79
|
+
const enterStage = latestState.current.isEnter;
|
|
106
80
|
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
107
|
-
|
|
108
81
|
if (toEnter) {
|
|
109
82
|
!enterStage && transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
110
83
|
} else {
|
|
111
84
|
enterStage && transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
112
85
|
}
|
|
113
86
|
}, [endTransition, onChange, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
114
|
-
react.useEffect(
|
|
115
|
-
return function () {
|
|
116
|
-
return clearTimeout(timeoutId.current);
|
|
117
|
-
};
|
|
118
|
-
}, []);
|
|
87
|
+
react.useEffect(() => () => clearTimeout(timeoutId.current), []);
|
|
119
88
|
return [state, toggle, endTransition];
|
|
120
89
|
};
|
|
121
90
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
91
|
+
const initialStateMap = new Map();
|
|
92
|
+
const initialConfigMap = new Map();
|
|
93
|
+
const updateState = ({
|
|
94
|
+
key,
|
|
95
|
+
status,
|
|
96
|
+
setStateMap,
|
|
97
|
+
latestStateMap,
|
|
98
|
+
timeoutId,
|
|
99
|
+
onChange
|
|
100
|
+
}) => {
|
|
132
101
|
clearTimeout(timeoutId);
|
|
133
|
-
|
|
134
|
-
|
|
102
|
+
const state = getState(status);
|
|
103
|
+
const stateMap = new Map(latestStateMap.current);
|
|
135
104
|
stateMap.set(key, state);
|
|
136
105
|
setStateMap(stateMap);
|
|
137
106
|
latestStateMap.current = stateMap;
|
|
138
107
|
onChange && onChange({
|
|
139
|
-
key
|
|
108
|
+
key,
|
|
140
109
|
current: state
|
|
141
110
|
});
|
|
142
111
|
};
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
var configMap = react.useRef(initialConfigMap);
|
|
165
|
-
|
|
166
|
-
var _getTimeout = getTimeout(timeout),
|
|
167
|
-
enterTimeout = _getTimeout[0],
|
|
168
|
-
exitTimeout = _getTimeout[1];
|
|
169
|
-
|
|
170
|
-
var setItem = react.useCallback(function (key, config) {
|
|
171
|
-
var _ref3 = config || {},
|
|
172
|
-
_ref3$initialEntered = _ref3.initialEntered,
|
|
173
|
-
_initialEntered = _ref3$initialEntered === void 0 ? initialEntered : _ref3$initialEntered;
|
|
174
|
-
|
|
175
|
-
var status = _initialEntered ? ENTERED : startOrEnd(mountOnEnter);
|
|
112
|
+
const useTransitionMap = ({
|
|
113
|
+
allowMultiple,
|
|
114
|
+
enter = true,
|
|
115
|
+
exit = true,
|
|
116
|
+
preEnter,
|
|
117
|
+
preExit,
|
|
118
|
+
timeout,
|
|
119
|
+
initialEntered,
|
|
120
|
+
mountOnEnter,
|
|
121
|
+
unmountOnExit,
|
|
122
|
+
onStateChange: onChange
|
|
123
|
+
} = {}) => {
|
|
124
|
+
const [stateMap, setStateMap] = react.useState(initialStateMap);
|
|
125
|
+
const latestStateMap = react.useRef(stateMap);
|
|
126
|
+
const configMap = react.useRef(initialConfigMap);
|
|
127
|
+
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
128
|
+
const setItem = react.useCallback((key, config) => {
|
|
129
|
+
const {
|
|
130
|
+
initialEntered: _initialEntered = initialEntered
|
|
131
|
+
} = config || {};
|
|
132
|
+
const status = _initialEntered ? ENTERED : startOrEnd(mountOnEnter);
|
|
176
133
|
updateState({
|
|
177
|
-
key
|
|
178
|
-
status
|
|
179
|
-
setStateMap
|
|
180
|
-
latestStateMap
|
|
134
|
+
key,
|
|
135
|
+
status,
|
|
136
|
+
setStateMap,
|
|
137
|
+
latestStateMap
|
|
181
138
|
});
|
|
182
139
|
configMap.current.set(key, {});
|
|
183
140
|
}, [initialEntered, mountOnEnter]);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
141
|
+
const deleteItem = react.useCallback(key => {
|
|
142
|
+
const newStateMap = new Map(latestStateMap.current);
|
|
187
143
|
if (newStateMap.delete(key)) {
|
|
188
144
|
setStateMap(newStateMap);
|
|
189
145
|
latestStateMap.current = newStateMap;
|
|
190
146
|
configMap.current.delete(key);
|
|
191
147
|
return true;
|
|
192
148
|
}
|
|
193
|
-
|
|
194
149
|
return false;
|
|
195
150
|
}, []);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
151
|
+
const endTransition = react.useCallback(key => {
|
|
152
|
+
const stateObj = latestStateMap.current.get(key);
|
|
199
153
|
if (!stateObj) {
|
|
200
|
-
process.env.NODE_ENV !== 'production' && console.error(
|
|
154
|
+
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
201
155
|
return;
|
|
202
156
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
var status = getEndStatus(stateObj._status, unmountOnExit);
|
|
157
|
+
const {
|
|
158
|
+
timeoutId
|
|
159
|
+
} = configMap.current.get(key);
|
|
160
|
+
const status = getEndStatus(stateObj._status, unmountOnExit);
|
|
208
161
|
status && updateState({
|
|
209
|
-
key
|
|
210
|
-
status
|
|
211
|
-
setStateMap
|
|
212
|
-
latestStateMap
|
|
213
|
-
timeoutId
|
|
214
|
-
onChange
|
|
162
|
+
key,
|
|
163
|
+
status,
|
|
164
|
+
setStateMap,
|
|
165
|
+
latestStateMap,
|
|
166
|
+
timeoutId,
|
|
167
|
+
onChange
|
|
215
168
|
});
|
|
216
169
|
}, [onChange, unmountOnExit]);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
170
|
+
const toggle = react.useCallback((key, toEnter) => {
|
|
171
|
+
const stateObj = latestStateMap.current.get(key);
|
|
220
172
|
if (!stateObj) {
|
|
221
|
-
process.env.NODE_ENV !== 'production' && console.error(
|
|
173
|
+
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
222
174
|
return;
|
|
223
175
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
var transitState = function transitState(status) {
|
|
176
|
+
const config = configMap.current.get(key);
|
|
177
|
+
const transitState = status => {
|
|
228
178
|
updateState({
|
|
229
|
-
key
|
|
230
|
-
status
|
|
231
|
-
setStateMap
|
|
232
|
-
latestStateMap
|
|
179
|
+
key,
|
|
180
|
+
status,
|
|
181
|
+
setStateMap,
|
|
182
|
+
latestStateMap,
|
|
233
183
|
timeoutId: config.timeoutId,
|
|
234
|
-
onChange
|
|
184
|
+
onChange
|
|
235
185
|
});
|
|
236
|
-
|
|
237
186
|
switch (status) {
|
|
238
187
|
case ENTERING:
|
|
239
|
-
if (enterTimeout >= 0) config.timeoutId = setTimeout(
|
|
240
|
-
return endTransition(key);
|
|
241
|
-
}, enterTimeout);
|
|
188
|
+
if (enterTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), enterTimeout);
|
|
242
189
|
break;
|
|
243
|
-
|
|
244
190
|
case EXITING:
|
|
245
|
-
if (exitTimeout >= 0) config.timeoutId = setTimeout(
|
|
246
|
-
return endTransition(key);
|
|
247
|
-
}, exitTimeout);
|
|
191
|
+
if (exitTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), exitTimeout);
|
|
248
192
|
break;
|
|
249
|
-
|
|
250
193
|
case PRE_ENTER:
|
|
251
194
|
case PRE_EXIT:
|
|
252
|
-
config.timeoutId = setTimeout(
|
|
253
|
-
return transitState(status + 1);
|
|
254
|
-
}, 0);
|
|
195
|
+
config.timeoutId = setTimeout(() => transitState(status + 1), 0);
|
|
255
196
|
break;
|
|
256
197
|
}
|
|
257
198
|
};
|
|
258
|
-
|
|
259
|
-
var enterStage = stateObj._status <= ENTERED;
|
|
199
|
+
const enterStage = stateObj.isEnter;
|
|
260
200
|
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
261
|
-
|
|
262
201
|
if (toEnter) {
|
|
263
202
|
if (!enterStage) {
|
|
264
203
|
transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
265
|
-
!allowMultiple && latestStateMap.current.forEach(
|
|
266
|
-
return _key !== key && toggle(_key, false);
|
|
267
|
-
});
|
|
204
|
+
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
268
205
|
}
|
|
269
206
|
} else {
|
|
270
207
|
if (enterStage) {
|
|
@@ -273,14 +210,14 @@ var useTransitionMap = function useTransitionMap(_temp) {
|
|
|
273
210
|
}
|
|
274
211
|
}, [onChange, endTransition, allowMultiple, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
275
212
|
return {
|
|
276
|
-
stateMap
|
|
277
|
-
toggle
|
|
278
|
-
endTransition
|
|
279
|
-
setItem
|
|
280
|
-
deleteItem
|
|
213
|
+
stateMap,
|
|
214
|
+
toggle,
|
|
215
|
+
endTransition,
|
|
216
|
+
setItem,
|
|
217
|
+
deleteItem
|
|
281
218
|
};
|
|
282
219
|
};
|
|
283
220
|
|
|
284
|
-
exports
|
|
221
|
+
exports.default = useTransition;
|
|
285
222
|
exports.useTransition = useTransition;
|
|
286
223
|
exports.useTransitionMap = useTransitionMap;
|
|
@@ -1,83 +1,59 @@
|
|
|
1
1
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
-
import { getState, ENTERED, startOrEnd, getTimeout, getEndStatus,
|
|
2
|
+
import { getState, ENTERED, startOrEnd, getTimeout, getEndStatus, PRE_ENTER, ENTERING, PRE_EXIT, EXITING } from './utils.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const updateState = (status, setState, latestState, timeoutId, onChange) => {
|
|
5
5
|
clearTimeout(timeoutId.current);
|
|
6
|
-
|
|
6
|
+
const state = getState(status);
|
|
7
7
|
setState(state);
|
|
8
8
|
latestState.current = state;
|
|
9
9
|
onChange && onChange({
|
|
10
10
|
current: state
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}),
|
|
31
|
-
state = _useState[0],
|
|
32
|
-
setState = _useState[1];
|
|
33
|
-
|
|
34
|
-
var latestState = useRef(state);
|
|
35
|
-
var timeoutId = useRef();
|
|
36
|
-
|
|
37
|
-
var _getTimeout = getTimeout(timeout),
|
|
38
|
-
enterTimeout = _getTimeout[0],
|
|
39
|
-
exitTimeout = _getTimeout[1];
|
|
40
|
-
|
|
41
|
-
var endTransition = useCallback(function () {
|
|
42
|
-
var status = getEndStatus(latestState.current._status, unmountOnExit);
|
|
13
|
+
const useTransition = ({
|
|
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._status, unmountOnExit);
|
|
43
30
|
status && updateState(status, setState, latestState, timeoutId, onChange);
|
|
44
31
|
}, [onChange, unmountOnExit]);
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
const toggle = useCallback(toEnter => {
|
|
33
|
+
const transitState = status => {
|
|
47
34
|
updateState(status, setState, latestState, timeoutId, onChange);
|
|
48
|
-
|
|
49
35
|
switch (status) {
|
|
50
36
|
case ENTERING:
|
|
51
37
|
if (enterTimeout >= 0) timeoutId.current = setTimeout(endTransition, enterTimeout);
|
|
52
38
|
break;
|
|
53
|
-
|
|
54
39
|
case EXITING:
|
|
55
40
|
if (exitTimeout >= 0) timeoutId.current = setTimeout(endTransition, exitTimeout);
|
|
56
41
|
break;
|
|
57
|
-
|
|
58
42
|
case PRE_ENTER:
|
|
59
43
|
case PRE_EXIT:
|
|
60
|
-
timeoutId.current = setTimeout(
|
|
61
|
-
return transitState(status + 1);
|
|
62
|
-
}, 0);
|
|
44
|
+
timeoutId.current = setTimeout(() => transitState(status + 1), 0);
|
|
63
45
|
break;
|
|
64
46
|
}
|
|
65
47
|
};
|
|
66
|
-
|
|
67
|
-
var enterStage = latestState.current._status <= ENTERED;
|
|
48
|
+
const enterStage = latestState.current.isEnter;
|
|
68
49
|
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
69
|
-
|
|
70
50
|
if (toEnter) {
|
|
71
51
|
!enterStage && transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
72
52
|
} else {
|
|
73
53
|
enterStage && transitState(exit ? preExit ? PRE_EXIT : EXITING : startOrEnd(unmountOnExit));
|
|
74
54
|
}
|
|
75
55
|
}, [endTransition, onChange, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
76
|
-
useEffect(
|
|
77
|
-
return function () {
|
|
78
|
-
return clearTimeout(timeoutId.current);
|
|
79
|
-
};
|
|
80
|
-
}, []);
|
|
56
|
+
useEffect(() => () => clearTimeout(timeoutId.current), []);
|
|
81
57
|
return [state, toggle, endTransition];
|
|
82
58
|
};
|
|
83
59
|
|
|
@@ -1,152 +1,120 @@
|
|
|
1
1
|
import { useState, useRef, useCallback } from 'react';
|
|
2
|
-
import { getTimeout, ENTERED, startOrEnd, getEndStatus,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
import { getTimeout, ENTERED, startOrEnd, getEndStatus, PRE_ENTER, ENTERING, PRE_EXIT, EXITING, getState } from './utils.js';
|
|
3
|
+
|
|
4
|
+
const initialStateMap = new Map();
|
|
5
|
+
const initialConfigMap = new Map();
|
|
6
|
+
const updateState = ({
|
|
7
|
+
key,
|
|
8
|
+
status,
|
|
9
|
+
setStateMap,
|
|
10
|
+
latestStateMap,
|
|
11
|
+
timeoutId,
|
|
12
|
+
onChange
|
|
13
|
+
}) => {
|
|
14
14
|
clearTimeout(timeoutId);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const state = getState(status);
|
|
16
|
+
const stateMap = new Map(latestStateMap.current);
|
|
17
17
|
stateMap.set(key, state);
|
|
18
18
|
setStateMap(stateMap);
|
|
19
19
|
latestStateMap.current = stateMap;
|
|
20
20
|
onChange && onChange({
|
|
21
|
-
key
|
|
21
|
+
key,
|
|
22
22
|
current: state
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
var configMap = useRef(initialConfigMap);
|
|
47
|
-
|
|
48
|
-
var _getTimeout = getTimeout(timeout),
|
|
49
|
-
enterTimeout = _getTimeout[0],
|
|
50
|
-
exitTimeout = _getTimeout[1];
|
|
51
|
-
|
|
52
|
-
var setItem = useCallback(function (key, config) {
|
|
53
|
-
var _ref3 = config || {},
|
|
54
|
-
_ref3$initialEntered = _ref3.initialEntered,
|
|
55
|
-
_initialEntered = _ref3$initialEntered === void 0 ? initialEntered : _ref3$initialEntered;
|
|
56
|
-
|
|
57
|
-
var status = _initialEntered ? ENTERED : startOrEnd(mountOnEnter);
|
|
25
|
+
const useTransitionMap = ({
|
|
26
|
+
allowMultiple,
|
|
27
|
+
enter = true,
|
|
28
|
+
exit = true,
|
|
29
|
+
preEnter,
|
|
30
|
+
preExit,
|
|
31
|
+
timeout,
|
|
32
|
+
initialEntered,
|
|
33
|
+
mountOnEnter,
|
|
34
|
+
unmountOnExit,
|
|
35
|
+
onStateChange: onChange
|
|
36
|
+
} = {}) => {
|
|
37
|
+
const [stateMap, setStateMap] = useState(initialStateMap);
|
|
38
|
+
const latestStateMap = useRef(stateMap);
|
|
39
|
+
const configMap = useRef(initialConfigMap);
|
|
40
|
+
const [enterTimeout, exitTimeout] = getTimeout(timeout);
|
|
41
|
+
const setItem = useCallback((key, config) => {
|
|
42
|
+
const {
|
|
43
|
+
initialEntered: _initialEntered = initialEntered
|
|
44
|
+
} = config || {};
|
|
45
|
+
const status = _initialEntered ? ENTERED : startOrEnd(mountOnEnter);
|
|
58
46
|
updateState({
|
|
59
|
-
key
|
|
60
|
-
status
|
|
61
|
-
setStateMap
|
|
62
|
-
latestStateMap
|
|
47
|
+
key,
|
|
48
|
+
status,
|
|
49
|
+
setStateMap,
|
|
50
|
+
latestStateMap
|
|
63
51
|
});
|
|
64
52
|
configMap.current.set(key, {});
|
|
65
53
|
}, [initialEntered, mountOnEnter]);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
const deleteItem = useCallback(key => {
|
|
55
|
+
const newStateMap = new Map(latestStateMap.current);
|
|
69
56
|
if (newStateMap.delete(key)) {
|
|
70
57
|
setStateMap(newStateMap);
|
|
71
58
|
latestStateMap.current = newStateMap;
|
|
72
59
|
configMap.current.delete(key);
|
|
73
60
|
return true;
|
|
74
61
|
}
|
|
75
|
-
|
|
76
62
|
return false;
|
|
77
63
|
}, []);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
64
|
+
const endTransition = useCallback(key => {
|
|
65
|
+
const stateObj = latestStateMap.current.get(key);
|
|
81
66
|
if (!stateObj) {
|
|
82
|
-
process.env.NODE_ENV !== 'production' && console.error(
|
|
67
|
+
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
83
68
|
return;
|
|
84
69
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
var status = getEndStatus(stateObj._status, unmountOnExit);
|
|
70
|
+
const {
|
|
71
|
+
timeoutId
|
|
72
|
+
} = configMap.current.get(key);
|
|
73
|
+
const status = getEndStatus(stateObj._status, unmountOnExit);
|
|
90
74
|
status && updateState({
|
|
91
|
-
key
|
|
92
|
-
status
|
|
93
|
-
setStateMap
|
|
94
|
-
latestStateMap
|
|
95
|
-
timeoutId
|
|
96
|
-
onChange
|
|
75
|
+
key,
|
|
76
|
+
status,
|
|
77
|
+
setStateMap,
|
|
78
|
+
latestStateMap,
|
|
79
|
+
timeoutId,
|
|
80
|
+
onChange
|
|
97
81
|
});
|
|
98
82
|
}, [onChange, unmountOnExit]);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
83
|
+
const toggle = useCallback((key, toEnter) => {
|
|
84
|
+
const stateObj = latestStateMap.current.get(key);
|
|
102
85
|
if (!stateObj) {
|
|
103
|
-
process.env.NODE_ENV !== 'production' && console.error(
|
|
86
|
+
process.env.NODE_ENV !== 'production' && console.error(`[React-Transition-State] invalid key: ${key}`);
|
|
104
87
|
return;
|
|
105
88
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
var transitState = function transitState(status) {
|
|
89
|
+
const config = configMap.current.get(key);
|
|
90
|
+
const transitState = status => {
|
|
110
91
|
updateState({
|
|
111
|
-
key
|
|
112
|
-
status
|
|
113
|
-
setStateMap
|
|
114
|
-
latestStateMap
|
|
92
|
+
key,
|
|
93
|
+
status,
|
|
94
|
+
setStateMap,
|
|
95
|
+
latestStateMap,
|
|
115
96
|
timeoutId: config.timeoutId,
|
|
116
|
-
onChange
|
|
97
|
+
onChange
|
|
117
98
|
});
|
|
118
|
-
|
|
119
99
|
switch (status) {
|
|
120
100
|
case ENTERING:
|
|
121
|
-
if (enterTimeout >= 0) config.timeoutId = setTimeout(
|
|
122
|
-
return endTransition(key);
|
|
123
|
-
}, enterTimeout);
|
|
101
|
+
if (enterTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), enterTimeout);
|
|
124
102
|
break;
|
|
125
|
-
|
|
126
103
|
case EXITING:
|
|
127
|
-
if (exitTimeout >= 0) config.timeoutId = setTimeout(
|
|
128
|
-
return endTransition(key);
|
|
129
|
-
}, exitTimeout);
|
|
104
|
+
if (exitTimeout >= 0) config.timeoutId = setTimeout(() => endTransition(key), exitTimeout);
|
|
130
105
|
break;
|
|
131
|
-
|
|
132
106
|
case PRE_ENTER:
|
|
133
107
|
case PRE_EXIT:
|
|
134
|
-
config.timeoutId = setTimeout(
|
|
135
|
-
return transitState(status + 1);
|
|
136
|
-
}, 0);
|
|
108
|
+
config.timeoutId = setTimeout(() => transitState(status + 1), 0);
|
|
137
109
|
break;
|
|
138
110
|
}
|
|
139
111
|
};
|
|
140
|
-
|
|
141
|
-
var enterStage = stateObj._status <= ENTERED;
|
|
112
|
+
const enterStage = stateObj.isEnter;
|
|
142
113
|
if (typeof toEnter !== 'boolean') toEnter = !enterStage;
|
|
143
|
-
|
|
144
114
|
if (toEnter) {
|
|
145
115
|
if (!enterStage) {
|
|
146
116
|
transitState(enter ? preEnter ? PRE_ENTER : ENTERING : ENTERED);
|
|
147
|
-
!allowMultiple && latestStateMap.current.forEach(
|
|
148
|
-
return _key !== key && toggle(_key, false);
|
|
149
|
-
});
|
|
117
|
+
!allowMultiple && latestStateMap.current.forEach((_, _key) => _key !== key && toggle(_key, false));
|
|
150
118
|
}
|
|
151
119
|
} else {
|
|
152
120
|
if (enterStage) {
|
|
@@ -155,11 +123,11 @@ var useTransitionMap = function useTransitionMap(_temp) {
|
|
|
155
123
|
}
|
|
156
124
|
}, [onChange, endTransition, allowMultiple, enter, exit, preEnter, preExit, enterTimeout, exitTimeout, unmountOnExit]);
|
|
157
125
|
return {
|
|
158
|
-
stateMap
|
|
159
|
-
toggle
|
|
160
|
-
endTransition
|
|
161
|
-
setItem
|
|
162
|
-
deleteItem
|
|
126
|
+
stateMap,
|
|
127
|
+
toggle,
|
|
128
|
+
endTransition,
|
|
129
|
+
setItem,
|
|
130
|
+
deleteItem
|
|
163
131
|
};
|
|
164
132
|
};
|
|
165
133
|
|
package/dist/es/hooks/utils.js
CHANGED
|
@@ -1,36 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
var startOrEnd = function startOrEnd(unmounted) {
|
|
19
|
-
return unmounted ? UNMOUNTED : EXITED;
|
|
20
|
-
};
|
|
21
|
-
var getEndStatus = function getEndStatus(status, unmountOnExit) {
|
|
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
|
+
_status: 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) => {
|
|
22
18
|
switch (status) {
|
|
23
19
|
case ENTERING:
|
|
24
20
|
case PRE_ENTER:
|
|
25
21
|
return ENTERED;
|
|
26
|
-
|
|
27
22
|
case EXITING:
|
|
28
23
|
case PRE_EXIT:
|
|
29
24
|
return startOrEnd(unmountOnExit);
|
|
30
25
|
}
|
|
31
26
|
};
|
|
32
|
-
|
|
33
|
-
return typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
34
|
-
};
|
|
27
|
+
const getTimeout = timeout => typeof timeout === 'object' ? [timeout.enter, timeout.exit] : [timeout, timeout];
|
|
35
28
|
|
|
36
29
|
export { ENTERED, ENTERING, EXITED, EXITING, PRE_ENTER, PRE_EXIT, STATUS, UNMOUNTED, getEndStatus, getState, getTimeout, startOrEnd };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-transition-state",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.1.0-alpha.0",
|
|
4
4
|
"description": "Zero dependency React transition state machine.",
|
|
5
5
|
"author": "Zheng Song",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,25 +41,25 @@
|
|
|
41
41
|
"react-dom": ">=16.8.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@babel/core": "^7.
|
|
45
|
-
"@babel/preset-env": "^7.
|
|
46
|
-
"@rollup/plugin-babel": "^
|
|
47
|
-
"@testing-library/react": "^13.
|
|
48
|
-
"@types/jest": "^
|
|
44
|
+
"@babel/core": "^7.20.12",
|
|
45
|
+
"@babel/preset-env": "^7.20.2",
|
|
46
|
+
"@rollup/plugin-babel": "^6.0.3",
|
|
47
|
+
"@testing-library/react": "^13.4.0",
|
|
48
|
+
"@types/jest": "^29.4.0",
|
|
49
49
|
"babel-plugin-pure-annotations": "^0.1.2",
|
|
50
50
|
"dtslint": "^4.1.6",
|
|
51
|
-
"eslint": "^8.
|
|
52
|
-
"eslint-config-prettier": "^8.
|
|
53
|
-
"eslint-plugin-jest": "^
|
|
51
|
+
"eslint": "^8.33.0",
|
|
52
|
+
"eslint-config-prettier": "^8.6.0",
|
|
53
|
+
"eslint-plugin-jest": "^27.2.1",
|
|
54
54
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
55
|
-
"jest": "^
|
|
56
|
-
"jest-environment-jsdom": "^
|
|
55
|
+
"jest": "^29.4.1",
|
|
56
|
+
"jest-environment-jsdom": "^29.4.1",
|
|
57
57
|
"npm-run-all": "^4.1.5",
|
|
58
|
-
"prettier": "^2.
|
|
58
|
+
"prettier": "^2.8.3",
|
|
59
59
|
"react": "^18.2.0",
|
|
60
60
|
"react-dom": "^18.2.0",
|
|
61
|
-
"regenerator-runtime": "^0.13.
|
|
62
|
-
"rollup": "^
|
|
63
|
-
"typescript": "^4.
|
|
61
|
+
"regenerator-runtime": "^0.13.11",
|
|
62
|
+
"rollup": "^3.14.0",
|
|
63
|
+
"typescript": "^4.9.5"
|
|
64
64
|
}
|
|
65
65
|
}
|