Skip to content

Commit 3baedee

Browse files
committed
fix: close submenus on root Escape
1 parent 5e2a3e2 commit 3baedee

3 files changed

Lines changed: 37 additions & 1 deletion

File tree

src/Menu.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,12 @@ const Menu = React.forwardRef<MenuRef, MenuProps>((props, ref) => {
506506
onInternalOpenChange(key, nextOpen);
507507
};
508508

509+
const triggerAccessibilityClose = () => {
510+
if (mergedOpenKeys.length) {
511+
triggerOpenKeys(EMPTY_LIST, true);
512+
}
513+
};
514+
509515
const onInternalKeyDown = useAccessibility(
510516
internalMode,
511517
mergedActiveKey,
@@ -518,6 +524,7 @@ const Menu = React.forwardRef<MenuRef, MenuProps>((props, ref) => {
518524

519525
setMergedActiveKey,
520526
triggerAccessibilityOpen,
527+
triggerAccessibilityClose,
521528

522529
onKeyDown,
523530
);

src/hooks/useAccessibility.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ export function useAccessibility<T extends HTMLElement>(
174174

175175
triggerActiveKey: (key: string) => void,
176176
triggerAccessibilityOpen: (key: string, open?: boolean) => void,
177+
triggerAccessibilityClose: () => void,
177178

178179
originOnKeyDown?: React.KeyboardEventHandler<T>,
179180
): React.KeyboardEventHandler<T> {
@@ -196,6 +197,12 @@ export function useAccessibility<T extends HTMLElement>(
196197
return e => {
197198
const { which } = e;
198199

200+
if (which === ESC && mode !== 'inline' && e.target === containerRef.current) {
201+
triggerAccessibilityClose();
202+
originOnKeyDown?.(e);
203+
return;
204+
}
205+
199206
if ([...ArrowKeys, ENTER, ESC, HOME, END].includes(which)) {
200207
const keys = getKeys();
201208

tests/SubMenu.spec.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable no-undef */
22
import { act, fireEvent, render } from '@testing-library/react';
3-
import { resetWarned } from '@rc-component/util';
3+
import { KeyCode, resetWarned } from '@rc-component/util';
44
import React from 'react';
55
import Menu, { MenuItem, SubMenu } from '../src';
66
import { isActive, last } from './util';
@@ -203,6 +203,28 @@ describe('SubMenu', () => {
203203
});
204204
expect(container.querySelector('.rc-menu-submenu-open')).toBeFalsy();
205205
});
206+
207+
it('closes open submenus when Escape is pressed on the root menu', () => {
208+
const onOpenChange = jest.fn();
209+
const { container } = render(
210+
createMenu({
211+
triggerSubMenuAction: 'click',
212+
onOpenChange,
213+
}),
214+
);
215+
216+
fireEvent.click(container.querySelector('.rc-menu-submenu-title'));
217+
runAllTimer();
218+
expect(container.querySelector('.rc-menu-submenu-open')).toBeTruthy();
219+
220+
const rootMenu = container.querySelector<HTMLElement>('.rc-menu-root');
221+
rootMenu.focus();
222+
fireEvent.keyDown(rootMenu, { keyCode: KeyCode.ESC, which: KeyCode.ESC });
223+
runAllTimer();
224+
225+
expect(onOpenChange).toHaveBeenLastCalledWith([]);
226+
expect(container.querySelector('.rc-menu-submenu-open')).toBeFalsy();
227+
});
206228
});
207229

208230
it('fires openChange event', () => {

0 commit comments

Comments
 (0)