@atlaskit/top-layer 4.4.3 → 4.4.5
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/CHANGELOG.md +17 -0
- package/dist/cjs/dialog/dialog-content.js +57 -47
- package/dist/cjs/internal/use-animated-visibility.js +245 -165
- package/dist/cjs/popover/popover.js +97 -81
- package/dist/cjs/popover-surface/popover-surface.js +1 -1
- package/dist/es2019/dialog/dialog-content.js +57 -47
- package/dist/es2019/internal/use-animated-visibility.js +241 -153
- package/dist/es2019/popover/popover.js +98 -82
- package/dist/es2019/popover-surface/popover-surface.js +1 -1
- package/dist/esm/dialog/dialog-content.js +57 -47
- package/dist/esm/internal/use-animated-visibility.js +246 -166
- package/dist/esm/popover/popover.js +97 -81
- package/dist/esm/popover-surface/popover-surface.js +1 -1
- package/dist/types/dialog/types.d.ts +6 -4
- package/dist/types/internal/use-animated-visibility.d.ts +37 -50
- package/dist/types/popover/popover.d.ts +3 -1
- package/dist/types/popover/types.d.ts +12 -9
- package/package.json +3 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, useLayoutEffect,
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useReducer, useRef } from 'react';
|
|
2
2
|
import { prefersReducedMotion } from './reduced-motion';
|
|
3
3
|
function runCancellableSettlement({
|
|
4
4
|
schedule,
|
|
@@ -12,6 +12,7 @@ function runCancellableSettlement({
|
|
|
12
12
|
onSettled();
|
|
13
13
|
});
|
|
14
14
|
return () => {
|
|
15
|
+
// Prevent an interrupted or unmounted lifecycle from firing a stale callback.
|
|
15
16
|
isCancelled = true;
|
|
16
17
|
};
|
|
17
18
|
}
|
|
@@ -33,6 +34,20 @@ function runOnAnimationsSettled({
|
|
|
33
34
|
}
|
|
34
35
|
});
|
|
35
36
|
}
|
|
37
|
+
function isNativeElementOpen({
|
|
38
|
+
element
|
|
39
|
+
}) {
|
|
40
|
+
if (element instanceof HTMLDialogElement) {
|
|
41
|
+
return element.open;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Some DOM implementations throw for unsupported pseudo-classes.
|
|
45
|
+
try {
|
|
46
|
+
return element.matches(':popover-open');
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
36
51
|
|
|
37
52
|
/**
|
|
38
53
|
* Visibility lifecycle phase shared between `useAnimatedVisibility`,
|
|
@@ -45,11 +60,11 @@ function runOnAnimationsSettled({
|
|
|
45
60
|
* animation disabled the lifecycle goes directly `closed → open`.
|
|
46
61
|
* - `open`: host element is mounted and settled. No transition is
|
|
47
62
|
* playing.
|
|
48
|
-
* - `exiting`:
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* focus restoration can
|
|
63
|
+
* - `exiting`: a native close has begun but the host element remains
|
|
64
|
+
* mounted. Usually this follows `isOpen` changing to `false`, but it can
|
|
65
|
+
* also begin with a browser-initiated dismissal while controlled intent
|
|
66
|
+
* is still open. With animation disabled, this phase lasts until the
|
|
67
|
+
* browser's closed `toggle` fires so native focus restoration can finish.
|
|
53
68
|
*
|
|
54
69
|
* State machine:
|
|
55
70
|
* ```
|
|
@@ -59,41 +74,111 @@ function runOnAnimationsSettled({
|
|
|
59
74
|
* exiting → entering (reopen mid-exit, animated)
|
|
60
75
|
* exiting → open (reopen mid-handshake, non-animated)
|
|
61
76
|
* ```
|
|
62
|
-
*
|
|
63
|
-
* `phase !== 'closed'` is the canonical "host is currently in the DOM
|
|
64
|
-
* and on screen" predicate.
|
|
65
77
|
*/
|
|
66
78
|
|
|
79
|
+
function getInitialVisibilityState({
|
|
80
|
+
isOpen,
|
|
81
|
+
willAnimate
|
|
82
|
+
}) {
|
|
83
|
+
if (!isOpen) {
|
|
84
|
+
return {
|
|
85
|
+
phase: 'closed',
|
|
86
|
+
controlledIntent: 'closed'
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (willAnimate) {
|
|
90
|
+
return {
|
|
91
|
+
phase: 'entering',
|
|
92
|
+
controlledIntent: 'open'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
phase: 'open',
|
|
97
|
+
controlledIntent: 'open'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
67
101
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* Used by both `Popover` and `Dialog` to share the same animation lifecycle
|
|
71
|
-
* logic. Those components own their own show/hide mechanisms (showPopover /
|
|
72
|
-
* hidePopover vs showModal / close) and event handling - this hook only
|
|
73
|
-
* manages the relationship between `isOpen` and when children are rendered.
|
|
74
|
-
*
|
|
75
|
-
* ## Problem
|
|
102
|
+
* Applies one lifecycle event to the current visibility phase.
|
|
76
103
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
104
|
+
* Events that are stale for the current phase are ignored. This allows
|
|
105
|
+
* animation callbacks and native close events to settle safely after an
|
|
106
|
+
* interrupted lifecycle.
|
|
107
|
+
*/
|
|
108
|
+
function getNextVisibilityState(state, action) {
|
|
109
|
+
if (action.type === 'open-requested') {
|
|
110
|
+
const shouldEnter = state.phase === 'closed' || state.phase === 'exiting' && state.controlledIntent === 'closed';
|
|
111
|
+
if (shouldEnter && action.willAnimate) {
|
|
112
|
+
return {
|
|
113
|
+
phase: 'entering',
|
|
114
|
+
controlledIntent: 'open'
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (shouldEnter) {
|
|
118
|
+
return {
|
|
119
|
+
phase: 'open',
|
|
120
|
+
controlledIntent: 'open'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
...state,
|
|
125
|
+
controlledIntent: 'open'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (action.type === 'close-requested') {
|
|
129
|
+
return {
|
|
130
|
+
...state,
|
|
131
|
+
controlledIntent: 'closed'
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (action.type === 'exit-started') {
|
|
135
|
+
if (state.phase !== 'open' && state.phase !== 'entering') {
|
|
136
|
+
return state;
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
...state,
|
|
140
|
+
phase: 'exiting'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (action.type === 'entry-settled') {
|
|
144
|
+
if (state.phase !== 'entering') {
|
|
145
|
+
return state;
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
...state,
|
|
149
|
+
phase: 'open'
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (action.type === 'exit-settled') {
|
|
153
|
+
if (state.phase !== 'exiting') {
|
|
154
|
+
return state;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
...state,
|
|
158
|
+
phase: 'closed'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return state;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Coordinates controlled intent, native visibility, lifecycle phase, and host
|
|
166
|
+
* mounting around CSS exit transitions. The canonical contract is documented in
|
|
167
|
+
* `notes/architecture/animations.md#canonical-visibility-lifecycle-contract`.
|
|
80
168
|
*
|
|
81
|
-
*
|
|
169
|
+
* Used by both `Popover` and `Dialog` to share the same lifecycle logic. Those
|
|
170
|
+
* components own native event binding, show and hide commands, and
|
|
171
|
+
* component-specific event handling. This hook returns stable `onBeforeToggle`
|
|
172
|
+
* and `onToggle` callbacks that advance lifecycle phase and host mounting.
|
|
82
173
|
*
|
|
83
|
-
* The
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* while the CSS exit transition plays (or, with animation disabled,
|
|
87
|
-
* while we wait for the browser's closing `toggle` event to fire on the
|
|
88
|
-
* still-attached element):
|
|
174
|
+
* The host element is rendered while `phase !== 'closed'`. The `exiting`
|
|
175
|
+
* phase keeps it mounted until its CSS animation settles or, with animation
|
|
176
|
+
* disabled, until the browser reports that the native element has closed.
|
|
89
177
|
*
|
|
90
178
|
* ```
|
|
91
179
|
* isOpen: true ──────────────── false
|
|
92
180
|
* phase: open ──────────────── exiting ─── (exit settle) ─── closed
|
|
93
181
|
* ```
|
|
94
|
-
*
|
|
95
|
-
* Every effect dispatches on the single `phase` value instead of a
|
|
96
|
-
* cross-product of booleans.
|
|
97
182
|
*/
|
|
98
183
|
export function useAnimatedVisibility({
|
|
99
184
|
isOpen,
|
|
@@ -103,160 +188,163 @@ export function useAnimatedVisibility({
|
|
|
103
188
|
onExitFinish
|
|
104
189
|
}) {
|
|
105
190
|
const willAnimate = shouldAnimate && !prefersReducedMotion();
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
return willAnimate ? 'entering' : 'open';
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Rearm only after controlled state and the native lifecycle have both
|
|
119
|
-
// reached closed. Resetting as soon as `isOpen` becomes false can erase a
|
|
120
|
-
// closing toggle that was handled in the same React batch.
|
|
121
|
-
if (!isOpen && phase === 'closed') {
|
|
122
|
-
isNativeClosedRef.current = false;
|
|
123
|
-
}
|
|
124
|
-
if (isOpen && phase === 'closed' && !isNativeClosedRef.current) {
|
|
125
|
-
setPhase(willAnimate ? 'entering' : 'open');
|
|
126
|
-
}
|
|
127
|
-
if (!isOpen && (phase === 'open' || phase === 'entering')) {
|
|
128
|
-
// Close intent. Move to `exiting` to gate the unmount on either
|
|
129
|
-
// the exit transition (animated) or the closing toggle event
|
|
130
|
-
// (non-animated). Includes interrupted entry (`entering → exiting`).
|
|
131
|
-
setPhase('exiting');
|
|
132
|
-
}
|
|
133
|
-
if (isOpen && phase === 'exiting' && !isNativeClosedRef.current) {
|
|
134
|
-
// Reopen mid-exit. With animation, jump back to `entering` and let
|
|
135
|
-
// the entry transition restart from current visual state. Without
|
|
136
|
-
// animation, jump straight to `open` (the handshake we were waiting
|
|
137
|
-
// for is no longer relevant; the consumer wants the host visible
|
|
138
|
-
// again synchronously).
|
|
139
|
-
setPhase(willAnimate ? 'entering' : 'open');
|
|
140
|
-
}
|
|
191
|
+
const [visibilityState, dispatch] = useReducer(getNextVisibilityState, {
|
|
192
|
+
isOpen,
|
|
193
|
+
willAnimate
|
|
194
|
+
}, getInitialVisibilityState);
|
|
195
|
+
const {
|
|
196
|
+
phase,
|
|
197
|
+
controlledIntent
|
|
198
|
+
} = visibilityState;
|
|
141
199
|
|
|
142
|
-
// Keep stable refs to the latest callbacks so effects and
|
|
200
|
+
// Keep stable refs to the latest callbacks so effects and animation settlement closures
|
|
143
201
|
// always call the current callback without needing them in dependency arrays.
|
|
144
202
|
const onEnterFinishRef = useRef(onEnterFinish);
|
|
145
|
-
onEnterFinishRef.current = onEnterFinish;
|
|
146
203
|
const onExitFinishRef = useRef(onExitFinish);
|
|
147
|
-
|
|
204
|
+
const willAnimateRef = useRef(willAnimate);
|
|
205
|
+
useLayoutEffect(() => {
|
|
206
|
+
onEnterFinishRef.current = onEnterFinish;
|
|
207
|
+
onExitFinishRef.current = onExitFinish;
|
|
208
|
+
willAnimateRef.current = willAnimate;
|
|
209
|
+
}, [onEnterFinish, onExitFinish, willAnimate]);
|
|
210
|
+
|
|
211
|
+
// Synchronize controlled intent during render so opening mounts the host in
|
|
212
|
+
// the same commit. Keeping the processed intent in reducer state prevents a
|
|
213
|
+
// browser-driven exit from being mistaken for a new controlled open request.
|
|
214
|
+
if (isOpen && controlledIntent === 'closed') {
|
|
215
|
+
dispatch({
|
|
216
|
+
type: 'open-requested',
|
|
217
|
+
willAnimate
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (!isOpen && controlledIntent === 'open') {
|
|
221
|
+
dispatch({
|
|
222
|
+
type: 'close-requested'
|
|
223
|
+
});
|
|
224
|
+
}
|
|
148
225
|
|
|
149
|
-
//
|
|
226
|
+
// Entry can commit `open` before its callback because the host stays mounted.
|
|
227
|
+
// This ensures consumers observe the settled DOM rather than entering styles.
|
|
228
|
+
// Treat the phase before the initial commit as closed so an initially open host
|
|
229
|
+
// notifies consumers.
|
|
230
|
+
const prevPhaseRef = useRef('closed');
|
|
150
231
|
useEffect(() => {
|
|
151
|
-
|
|
232
|
+
const prevPhase = prevPhaseRef.current;
|
|
233
|
+
prevPhaseRef.current = phase;
|
|
234
|
+
if (prevPhase === phase) {
|
|
152
235
|
return;
|
|
153
236
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
237
|
+
if (phase === 'open') {
|
|
238
|
+
var _onEnterFinishRef$cur;
|
|
239
|
+
(_onEnterFinishRef$cur = onEnterFinishRef.current) === null || _onEnterFinishRef$cur === void 0 ? void 0 : _onEnterFinishRef$cur.call(onEnterFinishRef);
|
|
157
240
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
var _onEnterFinishRef$cur;
|
|
162
|
-
// Fire the consumer callback before transitioning phase so any
|
|
163
|
-
// state the consumer reads (refs, DOM nodes) is still attached
|
|
164
|
-
// in the same synchronous tick, regardless of React batching
|
|
165
|
-
// semantics.
|
|
166
|
-
(_onEnterFinishRef$cur = onEnterFinishRef.current) === null || _onEnterFinishRef$cur === void 0 ? void 0 : _onEnterFinishRef$cur.call(onEnterFinishRef);
|
|
167
|
-
setPhase(current => current === 'entering' ? 'open' : current);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
}, [phase, elementRef]);
|
|
241
|
+
}, [phase]);
|
|
242
|
+
const isMounted = phase !== 'closed';
|
|
243
|
+
const cancelExitSettlementRef = useRef(() => {});
|
|
171
244
|
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
245
|
+
// Exit must notify consumers before `closed` unmounts the host.
|
|
246
|
+
const settleExit = useCallback(() => {
|
|
247
|
+
var _onExitFinishRef$curr;
|
|
248
|
+
(_onExitFinishRef$curr = onExitFinishRef.current) === null || _onExitFinishRef$curr === void 0 ? void 0 : _onExitFinishRef$curr.call(onExitFinishRef);
|
|
249
|
+
dispatch({
|
|
250
|
+
type: 'exit-settled'
|
|
251
|
+
});
|
|
252
|
+
}, []);
|
|
179
253
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
254
|
+
// Primitives bind these stable callbacks to their native lifecycle events.
|
|
255
|
+
// This keeps event ownership at the primitive while the hook owns state transitions.
|
|
256
|
+
const onBeforeToggle = useCallback(event => {
|
|
257
|
+
// Any native transition supersedes a previous exit snapshot. This prevents
|
|
258
|
+
// a stale settlement from closing a host that is reopening or closing again.
|
|
259
|
+
cancelExitSettlementRef.current();
|
|
260
|
+
// Snapshot currentTarget because the DOM clears it after event dispatch.
|
|
261
|
+
const element = event.currentTarget;
|
|
262
|
+
if (event.newState === 'open' && element instanceof HTMLElement) {
|
|
263
|
+
element.removeAttribute('inert');
|
|
264
|
+
element.removeAttribute('aria-hidden');
|
|
185
265
|
}
|
|
186
|
-
|
|
266
|
+
if (event.newState === 'closed') {
|
|
267
|
+
if (element instanceof HTMLElement) {
|
|
268
|
+
// We use a microtask to let native focus restoration happen before making the element inert.
|
|
269
|
+
// The browser restores focus after beforetoggle returns, during its close steps.
|
|
270
|
+
queueMicrotask(() => {
|
|
271
|
+
// A controlled close can be interrupted by isOpen changing back to true,
|
|
272
|
+
// which reopens the element before this microtask runs.
|
|
273
|
+
if (isNativeElementOpen({
|
|
274
|
+
element
|
|
275
|
+
})) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
187
278
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
279
|
+
// Exit animations keep closed content rendered, so make it non-interactive and hide it from assistive technology.
|
|
280
|
+
element.setAttribute('inert', '');
|
|
281
|
+
// Tooling does not consistently treat inert content as hidden, even though the browser does.
|
|
282
|
+
element.setAttribute('aria-hidden', 'true');
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
dispatch({
|
|
286
|
+
type: 'exit-started'
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}, []);
|
|
290
|
+
const onToggle = useCallback(event => {
|
|
291
|
+
if (event.newState !== 'closed') {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (!willAnimateRef.current) {
|
|
295
|
+
cancelExitSettlementRef.current = runCancellableSettlement({
|
|
296
|
+
schedule: queueMicrotask,
|
|
297
|
+
onSettled: settleExit
|
|
298
|
+
});
|
|
192
299
|
return;
|
|
193
300
|
}
|
|
194
301
|
const element = elementRef.current;
|
|
195
302
|
if (!element) {
|
|
196
303
|
return;
|
|
197
304
|
}
|
|
198
|
-
|
|
305
|
+
|
|
306
|
+
// The closed `toggle` is task-queued after synchronous `beforetoggle`.
|
|
307
|
+
// Snapshot here so the exiting phase styles have committed and the list
|
|
308
|
+
// represents the animations that actually govern exit settlement.
|
|
309
|
+
cancelExitSettlementRef.current = runOnAnimationsSettled({
|
|
199
310
|
element,
|
|
200
|
-
onSettled:
|
|
201
|
-
var _onExitFinishRef$curr;
|
|
202
|
-
// Fire the consumer callback before transitioning phase to
|
|
203
|
-
// `closed`. The phase change drives the host element unmount,
|
|
204
|
-
// and consumers expect to be able to read the element (or a
|
|
205
|
-
// forwarded ref to it) inside `onExitFinish`. Doing this in
|
|
206
|
-
// the safe order avoids relying on React's automatic batching
|
|
207
|
-
// to keep the element attached across the callback.
|
|
208
|
-
(_onExitFinishRef$curr = onExitFinishRef.current) === null || _onExitFinishRef$curr === void 0 ? void 0 : _onExitFinishRef$curr.call(onExitFinishRef);
|
|
209
|
-
setPhase(current => current === 'exiting' ? 'closed' : current);
|
|
210
|
-
}
|
|
311
|
+
onSettled: settleExit
|
|
211
312
|
});
|
|
212
|
-
}, [
|
|
313
|
+
}, [elementRef, settleExit]);
|
|
314
|
+
useLayoutEffect(() => () => {
|
|
315
|
+
// Prevent a pending animation or microtask from notifying after unmount.
|
|
316
|
+
cancelExitSettlementRef.current();
|
|
317
|
+
}, []);
|
|
213
318
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
setPhase('closed');
|
|
319
|
+
// Entry settlement only removes entering styles. Its callback runs after the
|
|
320
|
+
// resulting `open` commit in the effect above.
|
|
321
|
+
useEffect(function settleEntry() {
|
|
322
|
+
if (phase !== 'entering') {
|
|
323
|
+
return;
|
|
220
324
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
325
|
+
if (!willAnimate) {
|
|
326
|
+
dispatch({
|
|
327
|
+
type: 'entry-settled'
|
|
328
|
+
});
|
|
225
329
|
return;
|
|
226
330
|
}
|
|
227
|
-
|
|
331
|
+
const element = elementRef.current;
|
|
332
|
+
if (!element) {
|
|
228
333
|
return;
|
|
229
334
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return 'closed';
|
|
335
|
+
return runOnAnimationsSettled({
|
|
336
|
+
element,
|
|
337
|
+
onSettled() {
|
|
338
|
+
dispatch({
|
|
339
|
+
type: 'entry-settled'
|
|
340
|
+
});
|
|
237
341
|
}
|
|
238
|
-
return current;
|
|
239
342
|
});
|
|
240
|
-
}, [willAnimate]);
|
|
241
|
-
|
|
242
|
-
// Non-animated exit callback. There are no animations to wait for, so fire
|
|
243
|
-
// `onExitFinish` on the transition into `exiting` (the unmount itself
|
|
244
|
-
// is gated by the closing toggle handshake above).
|
|
245
|
-
const prevPhaseForExitRef = useRef('closed');
|
|
246
|
-
useEffect(() => {
|
|
247
|
-
const prevPhase = prevPhaseForExitRef.current;
|
|
248
|
-
prevPhaseForExitRef.current = phase;
|
|
249
|
-
|
|
250
|
-
// Only fire on the non-animated transition into `exiting`. The
|
|
251
|
-
// animated path's `exiting → closed` settle already fires
|
|
252
|
-
// `onExitFinish` from `runOnAnimationsSettled`.
|
|
253
|
-
if (prevPhase !== 'exiting' && phase === 'exiting' && !willAnimate) {
|
|
254
|
-
var _onExitFinishRef$curr2;
|
|
255
|
-
(_onExitFinishRef$curr2 = onExitFinishRef.current) === null || _onExitFinishRef$curr2 === void 0 ? void 0 : _onExitFinishRef$curr2.call(onExitFinishRef);
|
|
256
|
-
}
|
|
257
|
-
}, [phase, willAnimate]);
|
|
343
|
+
}, [phase, willAnimate, elementRef]);
|
|
258
344
|
return {
|
|
259
345
|
phase,
|
|
346
|
+
isMounted,
|
|
347
|
+
onBeforeToggle,
|
|
260
348
|
onToggle
|
|
261
349
|
};
|
|
262
350
|
}
|