Skip to content

Commit 8993061

Browse files
committed
feat: update code
1 parent a438a2e commit 8993061

File tree

10 files changed

+77
-47
lines changed

10 files changed

+77
-47
lines changed

docs/examples/items.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import '../../assets/index.less';
66

77
export default () => (
88
<Menu
9-
itemRender={(originNode, item) => {
9+
itemRender={(originNode, { item }) => {
1010
if (item.type === 'item') {
1111
return (
1212
<a href="https://ant.design" target="_blank" rel="noopener noreferrer">

src/Divider.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ import classNames from 'classnames';
33
import { MenuContext } from './context/MenuContext';
44
import { useMeasure } from './context/PathContext';
55
import type { MenuDividerType } from './interface';
6+
import { useFullPath } from './context/PathContext';
67

78
export type DividerProps = Omit<MenuDividerType, 'type'>;
89

9-
export default function Divider({ className, style, itemRender }: DividerProps) {
10-
const { prefixCls } = React.useContext(MenuContext);
10+
export default function Divider(props: DividerProps) {
11+
const { className, style, itemRender: propItemRender } = props;
12+
const { prefixCls, itemRender: contextItemRender } = React.useContext(MenuContext);
1113
const measure = useMeasure();
14+
const connectedKeyPath = useFullPath();
1215

1316
if (measure) {
1417
return null;
@@ -22,8 +25,13 @@ export default function Divider({ className, style, itemRender }: DividerProps)
2225
/>
2326
);
2427

25-
if (typeof itemRender === 'function') {
26-
return itemRender(renderNode);
28+
const mergedItemRender = propItemRender || contextItemRender;
29+
30+
if (typeof mergedItemRender === 'function') {
31+
return mergedItemRender(renderNode, {
32+
item: { type: 'divider', ...props },
33+
keys: connectedKeyPath,
34+
});
2735
}
2836

2937
return renderNode;

src/Menu.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import type {
2828
SelectInfo,
2929
TriggerSubMenuAction,
3030
PopupRender,
31+
ItemRenderType,
3132
} from './interface';
3233
import MenuItem from './MenuItem';
3334
import type { SemanticName } from './SubMenu';
@@ -159,7 +160,7 @@ export interface MenuProps
159160

160161
popupRender?: PopupRender;
161162

162-
itemRender?: (originNode: React.ReactNode, item: NonNullable<ItemType>) => React.ReactNode;
163+
itemRender?: ItemRenderType;
163164
}
164165

165166
interface LegacyMenuProps extends MenuProps {
@@ -255,8 +256,8 @@ const Menu = React.forwardRef<MenuRef, MenuProps>((props, ref) => {
255256
measureChildList: React.ReactElement[],
256257
] = React.useMemo(
257258
() => [
258-
parseItems(children, items, EMPTY_LIST, _internalComponents, prefixCls, itemRender),
259-
parseItems(children, items, EMPTY_LIST, {}, prefixCls, itemRender),
259+
parseItems(children, items, EMPTY_LIST, _internalComponents, prefixCls),
260+
parseItems(children, items, EMPTY_LIST, {}, prefixCls),
260261
],
261262
[children, items, _internalComponents, prefixCls],
262263
);
@@ -660,6 +661,7 @@ const Menu = React.forwardRef<MenuRef, MenuProps>((props, ref) => {
660661
onItemClick={onInternalClick}
661662
onOpenChange={onInternalOpenChange}
662663
popupRender={popupRender}
664+
itemRender={itemRender}
663665
>
664666
<PathUserContext.Provider value={pathUserContext}>{container}</PathUserContext.Provider>
665667

src/MenuItem.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import PrivateContext from './context/PrivateContext';
1212
import useActive from './hooks/useActive';
1313
import useDirectionStyle from './hooks/useDirectionStyle';
1414
import Icon from './Icon';
15-
import type { MenuInfo, MenuItemType } from './interface';
15+
import type { MenuInfo, MenuItemType, ItemType } from './interface';
1616
import { warnItemProp } from './utils/warnUtil';
1717

1818
export interface MenuItemProps
@@ -89,7 +89,7 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
8989

9090
onFocus,
9191

92-
itemRender,
92+
itemRender: propItemRender,
9393

9494
...restProps
9595
} = props;
@@ -111,8 +111,12 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
111111

112112
// Active
113113
onActive,
114+
115+
itemRender: contextItemRender,
114116
} = React.useContext(MenuContext);
115117

118+
const mergedItemRender = propItemRender || contextItemRender;
119+
116120
const { _internalRenderMenuItem } = React.useContext(PrivateContext);
117121

118122
const itemCls = `${prefixCls}-item`;
@@ -200,7 +204,7 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
200204
optionRoleProps['aria-selected'] = selected;
201205
}
202206

203-
let renderNode = (
207+
let renderNode: React.ReactElement = (
204208
<LegacyMenuItem
205209
ref={legacyMenuItemRef}
206210
elementRef={mergedEleRef}
@@ -240,8 +244,14 @@ const InternalMenuItem = React.forwardRef((props: MenuItemProps, ref: React.Ref<
240244
</LegacyMenuItem>
241245
);
242246

243-
if (typeof itemRender === 'function') {
244-
renderNode = itemRender(renderNode);
247+
if (typeof mergedItemRender === 'function') {
248+
renderNode = mergedItemRender(renderNode, {
249+
item: {
250+
type: 'item',
251+
...props,
252+
} as ItemType,
253+
keys: connectedKeys,
254+
}) as React.ReactElement;
245255
}
246256

247257
if (_internalRenderMenuItem) {

src/MenuItemGroup.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import omit from '@rc-component/util/lib/omit';
33
import * as React from 'react';
44
import { MenuContext } from './context/MenuContext';
55
import { useFullPath, useMeasure } from './context/PathContext';
6-
import type { MenuItemGroupType } from './interface';
6+
import type { MenuItemGroupType, ItemType } from './interface';
77
import { parseChildren } from './utils/commonUtil';
88

99
export interface MenuItemGroupProps extends Omit<MenuItemGroupType, 'type' | 'children' | 'label'> {
@@ -52,18 +52,28 @@ const InternalMenuItemGroup = React.forwardRef<HTMLLIElement, MenuItemGroupProps
5252
});
5353

5454
const MenuItemGroup = React.forwardRef<HTMLLIElement, MenuItemGroupProps>((props, ref) => {
55-
const { eventKey, children, itemRender } = props;
55+
const { eventKey, children, itemRender: propItemRender } = props;
5656
const connectedKeyPath = useFullPath(eventKey);
5757
const childList: React.ReactElement[] = parseChildren(children, connectedKeyPath);
58+
const { itemRender: contextItemRender } = React.useContext(MenuContext);
5859

5960
const measure = useMeasure();
6061
if (measure) {
6162
return childList as any as React.ReactElement;
6263
}
6364

65+
const mergedItemRender = propItemRender || contextItemRender;
6466
return (
6567
<InternalMenuItemGroup ref={ref} {...omit(props, ['warnKey'])}>
66-
{typeof itemRender === 'function' ? itemRender(childList) : childList}
68+
{typeof mergedItemRender === 'function'
69+
? mergedItemRender(childList, {
70+
item: {
71+
type: 'group',
72+
...props,
73+
} as ItemType,
74+
keys: connectedKeyPath,
75+
})
76+
: childList}
6777
</InternalMenuItemGroup>
6878
);
6979
});

src/SubMenu/index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Overflow from 'rc-overflow';
44
import warning from '@rc-component/util/lib/warning';
55
import SubMenuList from './SubMenuList';
66
import { parseChildren } from '../utils/commonUtil';
7-
import type { MenuInfo, SubMenuType, PopupRender } from '../interface';
7+
import type { MenuInfo, SubMenuType, PopupRender, ItemType } from '../interface';
88
import MenuContextProvider, { MenuContext } from '../context/MenuContext';
99
import useMemoCallback from '../hooks/useMemoCallback';
1010
import PopupTrigger from './PopupTrigger';
@@ -407,7 +407,16 @@ const SubMenu = React.forwardRef<HTMLLIElement, SubMenuProps>((props, ref) => {
407407

408408
// ======================== Render ========================
409409

410-
const childListNode = typeof itemRender === 'function' ? itemRender(childList) : childList;
410+
const childListNode =
411+
typeof itemRender === 'function'
412+
? itemRender(childList, {
413+
item: {
414+
type: 'submenu',
415+
...props,
416+
} as ItemType,
417+
keys: connectedKeyPath,
418+
})
419+
: childList;
411420

412421
if (measure) {
413422
renderNode = childListNode;

src/context/MenuContext.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
RenderIconType,
1010
TriggerSubMenuAction,
1111
PopupRender,
12+
ItemRenderType,
1213
} from '../interface';
1314
import { SubMenuProps } from '..';
1415

@@ -53,6 +54,8 @@ export interface MenuContextProps {
5354

5455
popupRender?: PopupRender;
5556

57+
itemRender?: ItemRenderType;
58+
5659
// Icon
5760
itemIcon?: RenderIconType;
5861
expandIcon?: RenderIconType;

src/interface.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import type * as React from 'react';
22
import type { SubMenuProps } from './SubMenu';
3+
import type { MenuItemProps } from './MenuItem';
4+
import type { MenuItemGroupProps } from './MenuItemGroup';
5+
import type { DividerProps } from './Divider';
36

47
// ========================= Options =========================
58
interface ItemSharedProps {
69
ref?: React.Ref<HTMLLIElement | null>;
710
style?: React.CSSProperties;
811
className?: string;
9-
itemRender?: (originNode: React.ReactNode) => React.ReactNode;
12+
itemRender?: ItemRenderType;
1013
}
1114

1215
export interface SubMenuType extends ItemSharedProps {
@@ -141,3 +144,8 @@ export type PopupRender = (
141144
node: React.ReactElement,
142145
info: { item: SubMenuProps; keys: string[] },
143146
) => React.ReactNode;
147+
148+
export type ItemRenderType = (
149+
node: React.ReactElement | React.ReactElement<any, string | React.JSXElementConstructor<any>>[],
150+
info: { item: ItemType; keys: string[] },
151+
) => React.ReactNode | React.ReactElement;

src/utils/nodeUtil.tsx

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ function convertItemsToNodes(
1010
list: ItemType[],
1111
components: Required<Components>,
1212
prefixCls?: string,
13-
itemRender?: (originNode: React.ReactNode, item: NonNullable<ItemType>) => React.ReactElement,
1413
) {
1514
const {
1615
item: MergedMenuItem,
@@ -21,9 +20,6 @@ function convertItemsToNodes(
2120

2221
return (list || [])
2322
.map((opt, index) => {
24-
const renderNodeWrapper = node => {
25-
return typeof itemRender === 'function' ? itemRender(node, opt as any) : node;
26-
};
2723
if (opt && typeof opt === 'object') {
2824
const { label, children, key, type, extra, ...restProps } = opt as any;
2925
const mergedKey = key ?? `tmp-${index}`;
@@ -33,42 +29,27 @@ function convertItemsToNodes(
3329
if (type === 'group') {
3430
// Group
3531
return (
36-
<MergedMenuItemGroup
37-
key={mergedKey}
38-
{...restProps}
39-
itemRender={renderNodeWrapper}
40-
title={label}
41-
>
42-
{convertItemsToNodes(children, components, prefixCls, itemRender)}
32+
<MergedMenuItemGroup key={mergedKey} {...restProps} title={label}>
33+
{convertItemsToNodes(children, components, prefixCls)}
4334
</MergedMenuItemGroup>
4435
);
4536
}
4637

4738
// Sub Menu
4839
return (
49-
<MergedSubMenu
50-
key={mergedKey}
51-
{...restProps}
52-
itemRender={renderNodeWrapper}
53-
title={label}
54-
>
55-
{convertItemsToNodes(children, components, prefixCls, itemRender)}
40+
<MergedSubMenu key={mergedKey} {...restProps} title={label}>
41+
{convertItemsToNodes(children, components, prefixCls)}
5642
</MergedSubMenu>
5743
);
5844
}
5945

6046
// MenuItem & Divider
6147
if (type === 'divider') {
62-
return <MergedDivider key={mergedKey} {...restProps} itemRender={renderNodeWrapper} />;
48+
return <MergedDivider key={mergedKey} {...restProps} />;
6349
}
6450

6551
return (
66-
<MergedMenuItem
67-
key={mergedKey}
68-
{...restProps}
69-
extra={extra}
70-
itemRender={renderNodeWrapper}
71-
>
52+
<MergedMenuItem key={mergedKey} {...restProps} extra={extra}>
7253
{label}
7354
{(!!extra || extra === 0) && <span className={`${prefixCls}-item-extra`}>{extra}</span>}
7455
</MergedMenuItem>
@@ -86,7 +67,6 @@ export function parseItems(
8667
keyPath: string[],
8768
components: Components,
8869
prefixCls?: string,
89-
itemRender?: (originNode: React.ReactNode, item?: NonNullable<ItemType>) => React.ReactElement,
9070
) {
9171
let childNodes = children;
9272

@@ -99,7 +79,7 @@ export function parseItems(
9979
};
10080

10181
if (items) {
102-
childNodes = convertItemsToNodes(items, mergedComponents, prefixCls, itemRender);
82+
childNodes = convertItemsToNodes(items, mergedComponents, prefixCls);
10383
}
10484

10585
return parseChildren(childNodes, keyPath);

tests/MenuItem.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ describe('MenuItem', () => {
232232
it('should wrap originNode with custom render', () => {
233233
const { container } = render(
234234
<Menu
235-
itemRender={(originNode, item) => {
235+
itemRender={(originNode, { item }) => {
236236
if (item.type === 'item') {
237237
return (
238238
<a href="https://ant.design" target="_blank" rel="noopener noreferrer">

0 commit comments

Comments
 (0)