2022-03-18 15:20:35 +08:00
|
|
|
import { ItemGroup } from 'rc-menu';
|
|
|
|
import type {
|
|
|
|
MenuDividerType as RcMenuDividerType,
|
|
|
|
MenuItemGroupType as RcMenuItemGroupType,
|
2022-06-22 14:57:09 +08:00
|
|
|
MenuItemType as RcMenuItemType,
|
|
|
|
SubMenuType as RcSubMenuType,
|
2022-03-18 15:20:35 +08:00
|
|
|
} from 'rc-menu/lib/interface';
|
2023-05-06 15:49:37 +08:00
|
|
|
import * as React from 'react';
|
2022-03-18 15:20:35 +08:00
|
|
|
import MenuDivider from '../MenuDivider';
|
|
|
|
import MenuItem from '../MenuItem';
|
2022-06-22 14:57:09 +08:00
|
|
|
import SubMenu from '../SubMenu';
|
2022-03-18 15:20:35 +08:00
|
|
|
|
2022-08-23 23:40:44 +08:00
|
|
|
export interface MenuItemType extends RcMenuItemType {
|
2022-03-18 15:20:35 +08:00
|
|
|
danger?: boolean;
|
|
|
|
icon?: React.ReactNode;
|
|
|
|
title?: string;
|
|
|
|
}
|
|
|
|
|
2023-05-10 10:20:17 +08:00
|
|
|
export interface SubMenuType<T extends MenuItemType = MenuItemType>
|
|
|
|
extends Omit<RcSubMenuType, 'children'> {
|
2022-03-18 15:20:35 +08:00
|
|
|
icon?: React.ReactNode;
|
|
|
|
theme?: 'dark' | 'light';
|
2023-05-10 10:20:17 +08:00
|
|
|
children: ItemType<T>[];
|
2022-03-18 15:20:35 +08:00
|
|
|
}
|
|
|
|
|
2023-05-10 10:20:17 +08:00
|
|
|
export interface MenuItemGroupType<T extends MenuItemType = MenuItemType>
|
|
|
|
extends Omit<RcMenuItemGroupType, 'children'> {
|
|
|
|
children?: ItemType<T>[];
|
2022-03-18 15:20:35 +08:00
|
|
|
key?: React.Key;
|
|
|
|
}
|
|
|
|
|
2022-08-23 23:40:44 +08:00
|
|
|
export interface MenuDividerType extends RcMenuDividerType {
|
2022-03-18 15:20:35 +08:00
|
|
|
dashed?: boolean;
|
|
|
|
key?: React.Key;
|
|
|
|
}
|
|
|
|
|
2023-05-10 10:20:17 +08:00
|
|
|
export type ItemType<T extends MenuItemType = MenuItemType> =
|
|
|
|
| T
|
|
|
|
| SubMenuType<T>
|
|
|
|
| MenuItemGroupType<T>
|
|
|
|
| MenuDividerType
|
|
|
|
| null;
|
2022-03-18 15:20:35 +08:00
|
|
|
|
|
|
|
function convertItemsToNodes(list: ItemType[]) {
|
|
|
|
return (list || [])
|
|
|
|
.map((opt, index) => {
|
|
|
|
if (opt && typeof opt === 'object') {
|
|
|
|
const { label, children, key, type, ...restProps } = opt as any;
|
|
|
|
const mergedKey = key ?? `tmp-${index}`;
|
|
|
|
|
|
|
|
// MenuItemGroup & SubMenuItem
|
|
|
|
if (children || type === 'group') {
|
|
|
|
if (type === 'group') {
|
|
|
|
// Group
|
|
|
|
return (
|
|
|
|
<ItemGroup key={mergedKey} {...restProps} title={label}>
|
|
|
|
{convertItemsToNodes(children)}
|
|
|
|
</ItemGroup>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sub Menu
|
|
|
|
return (
|
|
|
|
<SubMenu key={mergedKey} {...restProps} title={label}>
|
|
|
|
{convertItemsToNodes(children)}
|
|
|
|
</SubMenu>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// MenuItem & Divider
|
|
|
|
if (type === 'divider') {
|
|
|
|
return <MenuDivider key={mergedKey} {...restProps} />;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<MenuItem key={mergedKey} {...restProps}>
|
|
|
|
{label}
|
|
|
|
</MenuItem>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
})
|
2022-11-19 13:47:33 +08:00
|
|
|
.filter((opt) => opt);
|
2022-03-18 15:20:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Move logic here in v5
|
|
|
|
/**
|
|
|
|
* We simply convert `items` to ReactNode for reuse origin component logic. But we need move all the
|
|
|
|
* logic from component into this hooks when in v5
|
|
|
|
*/
|
|
|
|
export default function useItems(items?: ItemType[]) {
|
|
|
|
return React.useMemo(() => {
|
|
|
|
if (!items) {
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
return convertItemsToNodes(items);
|
|
|
|
}, [items]);
|
|
|
|
}
|