From 4d4a6ad200a0fabce8e56c3de5c2ab75fa24faa1 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Fri, 6 May 2022 18:59:35 +0800 Subject: [PATCH] feat: focus item when focusing menu (#464) * feat: focus item when focusing menu * chore: update snapshot * feat: focus active child * fix: index > -1 * fix: use querySelecor instead --- src/Menu.tsx | 24 ++++++++++++++++-------- src/interface.ts | 4 ++++ tests/Menu.spec.js | 18 ++++++++++++++++-- tests/__snapshots__/SubMenu.spec.js.snap | 2 +- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/Menu.tsx b/src/Menu.tsx index 37bcb9c0..2f1bf9fb 100644 --- a/src/Menu.tsx +++ b/src/Menu.tsx @@ -27,7 +27,7 @@ import useAccessibility from './hooks/useAccessibility'; import useUUID from './hooks/useUUID'; import { PathRegisterContext, PathUserContext } from './context/PathContext'; import useKeyRecords, { OVERFLOW_KEY } from './hooks/useKeyRecords'; -import { IdContext } from './context/IdContext'; +import { getMenuId, IdContext } from './context/IdContext'; import PrivateContext from './context/PrivateContext'; import { useImperativeHandle } from 'react'; @@ -235,13 +235,6 @@ const Menu = React.forwardRef((props, ref) => { const containerRef = React.useRef(); - useImperativeHandle(ref, () => ({ - list: containerRef.current, - focus: (options?: FocusOptions) => { - containerRef.current?.focus(options); - }, - })); - const uuid = useUUID(id); const isRtl = direction === 'rtl'; @@ -360,6 +353,21 @@ const Menu = React.forwardRef((props, ref) => { setMergedActiveKey(undefined); }); + useImperativeHandle(ref, () => ({ + list: containerRef.current, + focus: options => { + const shouldFocusKey = + mergedActiveKey ?? childList.find(node => !node.props.disabled)?.key; + if (shouldFocusKey) { + containerRef.current + ?.querySelector( + `li[data-menu-id='${getMenuId(uuid, shouldFocusKey as string)}']`, + ) + ?.focus?.(options); + } + }, + })); + // ======================== Select ======================== // >>>>> Select keys const [mergedSelectKeys, setMergedSelectKeys] = useMergedState( diff --git a/src/interface.ts b/src/interface.ts index ef74ae8a..2158e64c 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -120,6 +120,10 @@ export type SelectEventHandler = (info: SelectInfo) => void; export type MenuClickEventHandler = (info: MenuInfo) => void; export type MenuRef = { + /** + * Focus active child if any, or the first child which is not disabled will be focused. + * @param options + */ focus: (options?: FocusOptions) => void; list: HTMLUListElement; }; diff --git a/tests/Menu.spec.js b/tests/Menu.spec.js index d5e2d047..eb45d2df 100644 --- a/tests/Menu.spec.js +++ b/tests/Menu.spec.js @@ -663,14 +663,28 @@ describe('Menu', () => { const menuRef = React.createRef(); const wrapper = mount( + + Disabled child + Light , ); menuRef.current?.focus(); - expect(document.activeElement).toBe( - wrapper.find('ul').first().getDOMNode(), + expect(document.activeElement).toBe(wrapper.find('li').last().getDOMNode()); + }); + + it('should focus active item through ref', () => { + const menuRef = React.createRef(); + const wrapper = mount( + + Light + Cat + , ); + menuRef.current?.focus(); + + expect(document.activeElement).toBe(wrapper.find('li').last().getDOMNode()); }); }); /* eslint-enable */ diff --git a/tests/__snapshots__/SubMenu.spec.js.snap b/tests/__snapshots__/SubMenu.spec.js.snap index 11f7aaed..ffa2739d 100644 --- a/tests/__snapshots__/SubMenu.spec.js.snap +++ b/tests/__snapshots__/SubMenu.spec.js.snap @@ -84,7 +84,7 @@ Array [