import React, { useState, useContext, useMemo, forwardRef } from "react"; import classNames from "classnames"; import { StyledProps } from "../_type"; import { Icon } from "../icon"; import { useDefault } from "../_util/use-default"; import { useConfig } from "../_util/config-context"; import { MenuContext, SubMenuContext } from "./MenuContext"; import { MenuItem } from "./MenuItem"; import { isChildOfType } from "../_util/is-child-of-type"; export interface SubMenuProps extends StyledProps { /** * 标题 */ title?: React.ReactNode; /** * 菜单折叠后标题处显示的图标 URL 或自定义节点内容 * * **传入 `string` 类型将作为 URL 解析** * * **传递一组 URL 时,第一个 URL 会作为未激活态图标,第二个 URL 会作为激活态图标** * * @docType [React.ReactNode, React.ReactNode] | React.ReactNode */ icon?: React.ReactNode | [React.ReactNode, React.ReactNode]; /** * 菜单内容(Menu.Item) */ children?: React.ReactNode; /** * 是否默认展开 * * @default false */ defaultOpened?: boolean; /** * 是否展开 */ opened?: boolean; /** * 展开状态变化时回调 */ onOpenedChange?: (opened: boolean) => void; } function hasSelectedItem(children: React.ReactNode) { let hasSelected = false; React.Children.forEach(children, child => { if (isChildOfType(child, MenuItem) && child.props.selected) { hasSelected = true; } }); return hasSelected; } export const SubMenu = forwardRef(function SubMenu( props: SubMenuProps, ref: React.Ref ) { const defaultDefaultOpened = useMemo( () => hasSelectedItem(props.children), [] // eslint-disable-line react-hooks/exhaustive-deps ); const { title, icon, children, defaultOpened = defaultDefaultOpened, opened: _opened, onOpenedChange: _onOpenedChange, className, ...restProps } = props; const { classPrefix } = useConfig(); // 包含 tag 的子菜单项 const [tags, setTags] = useState([]); // 子菜单被选中项 const [selectedId, setSelectedId] = useState(null); const { collapsed } = useContext(MenuContext); // eslint-disable-next-line no-param-reassign const [opened, onOpenedChange] = useDefault( _opened, defaultOpened, _onOpenedChange ); const [defaultIcon, activeIcon] = Array.isArray(icon) ? icon : [icon, icon]; return (
  • onOpenedChange(!opened)} > {defaultIcon && (typeof defaultIcon === "string" ? ( icon ) : ( defaultIcon ))} {activeIcon && (typeof activeIcon === "string" ? ( icon ) : ( activeIcon ))}
    {title}
      setTags(tags => { if (hasTag) { return [...tags, id]; } return tags.filter(i => i !== id); }), onSelectedChange: (id, selected) => setSelectedId(selectedId => { if (selected) { return id; } if (id === selectedId) { return null; } return selectedId; }), }} > {children}
  • ); }); SubMenu.displayName = "SubMenu";