import * as React from 'react'; import classNames from 'classnames'; import { SubMenu as RcSubMenu, useFullPath } from 'rc-menu'; import omit from 'rc-util/lib/omit'; import { useZIndex } from '../_util/hooks/useZIndex'; import { cloneElement } from '../_util/reactNode'; import type { MenuContextProps, MenuTheme } from './MenuContext'; import MenuContext from './MenuContext'; interface TitleEventEntity { key: string; domEvent: React.MouseEvent | React.KeyboardEvent; } export interface SubMenuProps { className?: string; disabled?: boolean; level?: number; title?: React.ReactNode; icon?: React.ReactNode; style?: React.CSSProperties; onTitleClick?: (e: TitleEventEntity) => void; onTitleMouseEnter?: (e: TitleEventEntity) => void; onTitleMouseLeave?: (e: TitleEventEntity) => void; popupOffset?: [number, number]; popupClassName?: string; children?: React.ReactNode; theme?: MenuTheme; } const SubMenu: React.FC = (props) => { const { popupClassName, icon, title, theme: customTheme } = props; const context = React.useContext(MenuContext); const { prefixCls, inlineCollapsed, theme: contextTheme } = context; const parentPath = useFullPath(); let titleNode: React.ReactNode; if (!icon) { titleNode = inlineCollapsed && !parentPath.length && title && typeof title === 'string' ? (
{title.charAt(0)}
) : ( {title} ); } else { // inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span // ref: https://github.com/ant-design/ant-design/pull/23456 const titleIsSpan = React.isValidElement(title) && title.type === 'span'; titleNode = ( <> {cloneElement(icon, { className: classNames( React.isValidElement(icon) ? icon.props?.className : '', `${prefixCls}-item-icon`, ), })} {titleIsSpan ? title : {title}} ); } const contextValue = React.useMemo( () => ({ ...context, firstLevel: false }), [context], ); // ============================ zIndex ============================ const [zIndex] = useZIndex('Menu'); return ( ); }; export default SubMenu;