diff --git a/README.md b/README.md
index ba1c37b5..965659c9 100644
--- a/README.md
+++ b/README.md
@@ -135,13 +135,13 @@ ReactDOM.render(
| onSelect |
- function({key:String, item:ReactComponent, domEvent:Event, selectedKeys:String[]}) |
+ function({key:String, item:ReactComponent, domEvent:Event, selectedKeys:String[], info:{item:MenuItemInfo}}) |
|
called when select a menu item |
| onClick |
- function({key:String, item:ReactComponent, domEvent:Event, keyPath: String[]}) |
+ function({key:String, item:ReactComponent, domEvent:Event, keyPath: String[], info:{item:MenuItemInfo}}) |
|
called when click a menu item |
diff --git a/src/MenuItem.tsx b/src/MenuItem.tsx
index 3405fae6..024d755c 100644
--- a/src/MenuItem.tsx
+++ b/src/MenuItem.tsx
@@ -12,7 +12,7 @@ import PrivateContext from './context/PrivateContext';
import useActive from './hooks/useActive';
import useDirectionStyle from './hooks/useDirectionStyle';
import Icon from './Icon';
-import type { MenuInfo, MenuItemType } from './interface';
+import type { MenuInfo, MenuItemInfo, MenuItemType } from './interface';
import { warnItemProp } from './utils/warnUtil';
export interface MenuItemProps
@@ -32,6 +32,9 @@ export interface MenuItemProps
/** @deprecated No place to use this. Should remove */
attribute?: Record;
+
+ /** @private Origin item config from items prop */
+ info?: { item: MenuItemInfo };
}
// Since Menu event provide the `info.item` which point to the MenuItem node instance.
@@ -77,6 +80,7 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
disabled,
itemIcon,
children,
+ info: propsInfo,
// Aria
role,
@@ -133,12 +137,21 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
const getEventInfo = (
e: React.MouseEvent | React.KeyboardEvent,
): MenuInfo => {
+ // If propsInfo exists (items mode), use it; otherwise build from props (children mode)
+ const infoItem: MenuItemInfo = propsInfo?.item || {
+ key: eventKey || '',
+ label: children,
+ itemIcon,
+ extra: props.extra,
+ };
+
return {
key: eventKey,
// Note: For legacy code is reversed which not like other antd component
keyPath: [...connectedKeys].reverse(),
item: legacyMenuItemRef.current,
domEvent: e,
+ info: propsInfo || { item: infoItem },
};
};
diff --git a/src/interface.ts b/src/interface.ts
index 683f6d87..ac7a62ac 100644
--- a/src/interface.ts
+++ b/src/interface.ts
@@ -63,6 +63,14 @@ export interface MenuItemType extends ItemSharedProps {
onClick?: MenuClickEventHandler;
}
+/** Info item type passed to onSelect/onClick callbacks, excluding event handlers */
+export type MenuItemInfo = {
+ label?: React.ReactNode;
+ itemIcon?: RenderIconType;
+ extra?: React.ReactNode;
+ key: React.Key;
+};
+
export interface MenuItemGroupType extends ItemSharedProps {
type: 'group';
@@ -99,6 +107,7 @@ export interface MenuInfo {
/** @deprecated This will not support in future. You should avoid to use this */
item: React.ReactInstance;
domEvent: React.MouseEvent | React.KeyboardEvent;
+ info: { item: MenuItemInfo };
}
export interface MenuTitleInfo {
diff --git a/src/utils/nodeUtil.tsx b/src/utils/nodeUtil.tsx
index aef40010..8307f851 100644
--- a/src/utils/nodeUtil.tsx
+++ b/src/utils/nodeUtil.tsx
@@ -51,7 +51,12 @@ function convertItemsToNodes(
const hasExtra = !!extra || extra === 0;
return (
-
+
{hasExtra ? (
<>
{label}
diff --git a/tests/MenuItem.spec.tsx b/tests/MenuItem.spec.tsx
index 7e7e2177..c9486416 100644
--- a/tests/MenuItem.spec.tsx
+++ b/tests/MenuItem.spec.tsx
@@ -150,6 +150,79 @@ describe('MenuItem', () => {
});
});
+ describe('info.item in event', () => {
+ it('should pass info.item in onSelect and onClick with children', () => {
+ const onSelect = jest.fn();
+ const onClick = jest.fn();
+ const { container } = render(
+ ,
+ );
+
+ fireEvent.click(container.querySelector('.rc-menu-item')!);
+ expect(onSelect).toHaveBeenCalledWith(
+ expect.objectContaining({
+ key: '1',
+ info: expect.objectContaining({
+ item: expect.objectContaining({
+ key: '1',
+ label: 'Menu Item',
+ }),
+ }),
+ }),
+ );
+ expect(onClick).toHaveBeenCalledWith(
+ expect.objectContaining({
+ key: '1',
+ info: expect.objectContaining({
+ item: expect.objectContaining({
+ key: '1',
+ label: 'Menu Item',
+ }),
+ }),
+ }),
+ );
+ });
+
+ it('should pass info.item in onSelect and onClick with items', () => {
+ const onSelect = jest.fn();
+ const onClick = jest.fn();
+ const { container } = render(
+ ,
+ );
+
+ fireEvent.click(container.querySelector('.rc-menu-item')!);
+ expect(onSelect).toHaveBeenCalledWith(
+ expect.objectContaining({
+ key: '1',
+ info: expect.objectContaining({
+ item: expect.objectContaining({
+ key: '1',
+ label: 'Menu Item',
+ }),
+ }),
+ }),
+ );
+ expect(onClick).toHaveBeenCalledWith(
+ expect.objectContaining({
+ key: '1',
+ info: expect.objectContaining({
+ item: expect.objectContaining({
+ key: '1',
+ label: 'Menu Item',
+ }),
+ }),
+ }),
+ );
+ });
+ });
+
describe('overwrite default role', () => {
it('should set role to none if null', () => {
const { container } = render(