Skip to content

Commit c571f81

Browse files
committed
fix(core): call onEnter/onExit when using useFocusContainer
1 parent 8831bc2 commit c571f81

File tree

4 files changed

+44
-24
lines changed

4 files changed

+44
-24
lines changed

packages/core/src/dialog/Dialog.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,21 @@ export const Dialog = forwardRef<HTMLDivElement, DialogProps>(
287287
const { eventHandlers, transitionOptions } = useFocusContainer({
288288
nodeRef: ref,
289289
activate: visible,
290+
onEnter(appearing) {
291+
onEnter(appearing);
292+
setChildVisible(type !== "full-page");
293+
},
290294
onEntered(appear) {
291295
onEntered(appear);
292296
// this needs to be called onEnter and onEntered just in case the
293297
// transition is disabled
294298
setChildVisible(type !== "full-page");
295299
},
296300
onEntering,
301+
onExit() {
302+
onExit();
303+
setChildVisible(false);
304+
},
297305
onExiting,
298306
onExited() {
299307
onExited();
@@ -334,14 +342,6 @@ export const Dialog = forwardRef<HTMLDivElement, DialogProps>(
334342
appear: appear && !disableTransition && !ssr,
335343
enter: enter && !disableTransition,
336344
exit: exit && !disableTransition,
337-
onEnter(appearing) {
338-
onEnter(appearing);
339-
setChildVisible(type !== "full-page");
340-
},
341-
onExit() {
342-
onExit();
343-
setChildVisible(false);
344-
},
345345
temporary,
346346
exitedHidden,
347347
disablePortal: propDisablePortal,

packages/core/src/focus/__tests__/useFocusContainer.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,29 +70,37 @@ describe("useFocusContainer", () => {
7070
TRANSITION_CONFIG.disabled = false;
7171

7272
const user = userEvent.setup();
73+
const onEnter = jest.fn();
7374
const onEntering = jest.fn();
7475
const onEntered = jest.fn();
76+
const onExit = jest.fn();
7577
const onExiting = jest.fn();
7678
const onExited = jest.fn();
7779
rmdRender(
7880
<Test
81+
onEnter={onEnter}
7982
onEntering={onEntering}
8083
onEntered={onEntered}
84+
onExit={onExit}
8185
onExiting={onExiting}
8286
onExited={onExited}
8387
/>
8488
);
8589

90+
expect(onEnter).not.toHaveBeenCalled();
8691
expect(onEntering).not.toHaveBeenCalled();
8792
expect(onEntered).not.toHaveBeenCalled();
93+
expect(onExit).not.toHaveBeenCalled();
8894
expect(onExiting).not.toHaveBeenCalled();
8995
expect(onExited).not.toHaveBeenCalled();
9096

9197
await user.click(screen.getByRole("button", { name: "Show" }));
9298
await waitFor(() => {
9399
expect(onEntering).toHaveBeenCalled();
94100
});
101+
expect(onEnter).toHaveBeenCalled();
95102
expect(onEntered).not.toHaveBeenCalled();
103+
expect(onExit).not.toHaveBeenCalled();
96104
expect(onExiting).not.toHaveBeenCalled();
97105
expect(onExited).not.toHaveBeenCalled();
98106

@@ -101,8 +109,10 @@ describe("useFocusContainer", () => {
101109
});
102110

103111
await user.click(screen.getByRole("button", { name: "Button 1" }));
112+
expect(onEnter).toHaveBeenCalled();
104113
expect(onEntering).toHaveBeenCalled();
105114
expect(onEntered).toHaveBeenCalled();
115+
expect(onExit).toHaveBeenCalled();
106116
expect(onExiting).toHaveBeenCalled();
107117
expect(onExited).not.toHaveBeenCalled();
108118

packages/core/src/focus/useFocusContainer.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,19 @@ const noop = (): void => {
3939
*/
4040
export type FocusType = "mount" | "unmount" | "keyboard";
4141

42-
/** @since 6.0.0 */
43-
export type FocusContainerTransitionCallbacks = Pick<
44-
TransitionCallbacks,
45-
"onEntering" | "onEntered" | "onExiting" | "onExited"
46-
>;
42+
/**
43+
* @since 6.0.0
44+
* @deprecated Use `TransitionCallbacks` instead.
45+
*/
46+
export type FocusContainerTransitionCallbacks = TransitionCallbacks;
4747

48-
/** @since 6.0.0 */
48+
/**
49+
* @since 6.0.0
50+
* @since 6.3.2 Fixed by extending `TransitionCallbacks` after the
51+
* `onEnteredOnce` and `onExitedOnce` support was added to CSS transitions.
52+
*/
4953
export interface FocusContainerTransitionOptions<E extends HTMLElement>
50-
extends FocusContainerTransitionCallbacks {
54+
extends TransitionCallbacks {
5155
/**
5256
* An optional ref that will be merged with the
5357
* {@link FocusContainerImplementation.nodeRef}
@@ -155,10 +159,12 @@ export function useFocusContainer<E extends HTMLElement>(
155159
const {
156160
nodeRef,
157161
activate,
158-
onEntering = noop,
159-
onEntered = noop,
160-
onExiting = noop,
161-
onExited = noop,
162+
onEnter,
163+
onEntering,
164+
onEntered,
165+
onExit,
166+
onExiting,
167+
onExited,
162168
onKeyDown = noop,
163169
programmatic = false,
164170
disableTransition = false,
@@ -181,6 +187,7 @@ export function useFocusContainer<E extends HTMLElement>(
181187
transitionOptions: {
182188
nodeRef: refCallback,
183189
...getTransitionCallbacks({
190+
onEnter,
184191
onEnterOnce: () => {
185192
const instance = ref.current;
186193
if (
@@ -205,6 +212,7 @@ export function useFocusContainer<E extends HTMLElement>(
205212
prevFocus.current?.focus();
206213
});
207214
},
215+
onExit,
208216
onExiting,
209217
onExited,
210218
disableTransition,

packages/core/src/menu/Menu.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ export const Menu = forwardRef<HTMLDivElement, LabelRequiredForA11y<MenuProps>>(
420420
break;
421421
}
422422
},
423+
onEnter,
423424
onEntering(appearing) {
424425
onEntering(appearing);
425426
entered.current = true;
@@ -430,11 +431,12 @@ export const Menu = forwardRef<HTMLDivElement, LabelRequiredForA11y<MenuProps>>(
430431
cancelUnmountFocus.current = false;
431432
animatedOnceRef.current = true;
432433
},
434+
onExit,
435+
onExiting,
433436
onExited() {
434437
onExited();
435438
entered.current = false;
436439
},
437-
onExiting,
438440
disableTransition,
439441
isFocusTypeDisabled(type) {
440442
if (role === "listbox") {
@@ -461,7 +463,6 @@ export const Menu = forwardRef<HTMLDivElement, LabelRequiredForA11y<MenuProps>>(
461463
const { ref, style, callbacks, updateStyle } = useFixedPositioning({
462464
...transitionOptions,
463465
disabled: disableFixedPositioning,
464-
onEnter,
465466
style: isSheet ? propStyle : menuStyle,
466467
fixedTo,
467468
anchor: getDefaultAnchor({
@@ -491,7 +492,6 @@ export const Menu = forwardRef<HTMLDivElement, LabelRequiredForA11y<MenuProps>>(
491492
},
492493
});
493494
const { rendered, disablePortal, elementProps } = useScaleTransition({
494-
nodeRef: ref,
495495
className: cnb(!isSheet && menuClassName, className),
496496
transitionIn: visible,
497497
vertical: !horizontal,
@@ -501,10 +501,12 @@ export const Menu = forwardRef<HTMLDivElement, LabelRequiredForA11y<MenuProps>>(
501501
appear,
502502
enter,
503503
exit,
504-
onExit,
505-
onExiting: transitionOptions.onExiting,
506504
exitedHidden: true,
505+
// merge the transition callbacks
506+
...transitionOptions,
507507
...callbacks,
508+
// but prefer the latest defined ref
509+
nodeRef: ref,
508510
});
509511
useScrollLock(visible && preventScroll);
510512

0 commit comments

Comments
 (0)