Skip to content

Commit 4242acd

Browse files
authored
feat: menu ref support focus (#442)
1 parent bd99d30 commit 4242acd

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

src/Menu.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
SelectInfo,
1616
RenderIconType,
1717
ItemType,
18+
MenuRef,
1819
} from './interface';
1920
import MenuItem from './MenuItem';
2021
import { parseItems } from './utils/nodeUtil';
@@ -28,7 +29,7 @@ import { PathRegisterContext, PathUserContext } from './context/PathContext';
2829
import useKeyRecords, { OVERFLOW_KEY } from './hooks/useKeyRecords';
2930
import { IdContext } from './context/IdContext';
3031
import PrivateContext from './context/PrivateContext';
31-
import { composeRef } from 'rc-util/lib/ref';
32+
import { useImperativeHandle } from 'react';
3233

3334
/**
3435
* Menu modify after refactor:
@@ -149,7 +150,7 @@ interface LegacyMenuProps extends MenuProps {
149150
openAnimation?: string;
150151
}
151152

152-
const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
153+
const Menu = React.forwardRef<MenuRef, MenuProps>((props, ref) => {
153154
const {
154155
prefixCls = 'rc-menu',
155156
style,
@@ -232,7 +233,13 @@ const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
232233
const [mounted, setMounted] = React.useState(false);
233234

234235
const containerRef = React.useRef<HTMLUListElement>();
235-
const mergedRef = composeRef(containerRef, ref);
236+
237+
useImperativeHandle(ref, () => ({
238+
list: containerRef.current,
239+
focus: (options?: FocusOptions) => {
240+
containerRef.current?.focus(options);
241+
},
242+
}));
236243

237244
const uuid = useUUID(id);
238245

@@ -498,7 +505,7 @@ const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
498505
const container = (
499506
<Overflow
500507
id={id}
501-
ref={mergedRef as any}
508+
ref={containerRef as any}
502509
prefixCls={`${prefixCls}-overflow`}
503510
component="ul"
504511
itemComponent={MenuItem}

src/interface.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,8 @@ export type SelectEventHandler = (info: SelectInfo) => void;
116116

117117
// ========================== Click ==========================
118118
export type MenuClickEventHandler = (info: MenuInfo) => void;
119+
120+
export type MenuRef = {
121+
focus: (options?: FocusOptions) => void;
122+
list: HTMLUListElement;
123+
};

tests/Menu.spec.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -650,14 +650,27 @@ describe('Menu', () => {
650650

651651
it('should support ref', () => {
652652
const menuRef = React.createRef();
653+
const wrapper = mount(
654+
<Menu ref={menuRef}>
655+
<MenuItem key="light">Light</MenuItem>
656+
</Menu>,
657+
);
653658

654-
mount(
659+
expect(menuRef.current?.list).toBe(wrapper.find('ul').first().getDOMNode());
660+
});
661+
662+
it('should support focus through ref', () => {
663+
const menuRef = React.createRef();
664+
const wrapper = mount(
655665
<Menu ref={menuRef}>
656666
<MenuItem key="light">Light</MenuItem>
657667
</Menu>,
658668
);
669+
menuRef.current?.focus();
659670

660-
expect(menuRef.current).toBeTruthy();
671+
expect(document.activeElement).toBe(
672+
wrapper.find('ul').first().getDOMNode(),
673+
);
661674
});
662675
});
663676
/* eslint-enable */

0 commit comments

Comments
 (0)