import * as React from 'react' ; import classNames from 'classnames' ; import Overflow from 'rc-overflow' ; import warning from 'rc-util/lib/warning' ; import SubMenuList from './SubMenuList' ; import { parseChildren } from '../utils/nodeUtil' ; import type { MenuClickEventHandler , MenuHoverEventHandler , MenuInfo , MenuTitleInfo , RenderIconType , } from '../interface' ; import MenuContextProvider , { MenuContext } from '../context/MenuContext' ; import useMemoCallback from '../hooks/useMemoCallback' ; import PopupTrigger from './PopupTrigger' ; import Icon from '../Icon' ; import useActive from '../hooks/useActive' ; import { warnItemProp } from '../utils/warnUtil' ; import useDirectionStyle from '../hooks/useDirectionStyle' ; import InlineSubMenuList from './InlineSubMenuList' ; import { PathTrackerContext , PathUserContext , useFullPath , useMeasure , } from '../context/PathContext' ; import { useMenuId } from '../context/IdContext' ; import PrivateContext from '../context/PrivateContext' ; export interface SubMenuProps { style ? : React . CSSProperties ; className ? : string ; title ? : React . ReactNode ; children ? : React . ReactNode ; disabled ? : boolean ; private internalPopupClose ? : boolean ; private eventKey ? : string ; private warnKey ? : boolean ; itemIcon ? : RenderIconType ; expandIcon ? : RenderIconType ; onMouseEnter ? : MenuHoverEventHandler ; onMouseLeave ? : MenuHoverEventHandler ; popupClassName ? : string ; popupOffset ? : number [ ] ; onClick ? : MenuClickEventHandler ; onTitleClick ? : ( info : MenuTitleInfo ) => void ; onTitleMouseEnter ? : MenuHoverEventHandler ; onTitleMouseLeave ? : MenuHoverEventHandler ; } const InternalSubMenu = ( props ) => { const { style , className , title , eventKey , warnKey , disabled , internalPopupClose , children , itemIcon , expandIcon , popupClassName , popupOffset , onClick , onMouseEnter , onMouseLeave , onTitleClick , onTitleMouseEnter , onTitleMouseLeave , ... restProps } = props ; const domDataId = useMenuId ( eventKey ) ; const { prefixCls , mode , openKeys , disabled : contextDisabled , overflowDisabled , activeKey , selectedKeys , itemIcon : contextItemIcon , expandIcon : contextExpandIcon , onItemClick , onOpenChange , onActive , } = React . useContext ( MenuContext ) ; const { _internalRenderSubMenuItem } = React . useContext ( PrivateContext ) ; const { isSubPathKey } = React . useContext ( PathUserContext ) ; const connectedPath = useFullPath ( ) ; const subMenuPrefixCls = `${ prefixCls }-submenu` ; const mergedDisabled = contextDisabled || disabled ; const elementRef = React . useRef < HTMLDivElement > ( ) ; const popupRef = React . useRef < HTMLUListElement > ( ) ; if ( process . env . NODE_ENV !== 'production' && warnKey ) { warning ( false , 'SubMenu should not leave undefined `key`.' ) ; } const mergedItemIcon = itemIcon || contextItemIcon ; const mergedExpandIcon = expandIcon || contextExpandIcon ; const originOpen = openKeys . includes ( eventKey ) ; const open = ! overflowDisabled && originOpen ; const childrenSelected = isSubPathKey ( selectedKeys , eventKey ) ; const { active , ... activeProps } = useActive ( eventKey , mergedDisabled , onTitleMouseEnter , onTitleMouseLeave ) ; const [ childrenActive , setChildrenActive ] = React . useState ( false ) ; const triggerChildrenActive = ( newActive ) => { if ( ! mergedDisabled ) { setChildrenActive ( newActive ) ; } } ; const onInternalMouseEnter = domEvent => { triggerChildrenActive ( true ) ; onMouseEnter ?. ( { key : eventKey , domEvent , } ) ; } ; const onInternalMouseLeave = domEvent => { triggerChildrenActive ( false ) ; onMouseLeave ?. ( { key : eventKey , domEvent , } ) ; } ; const mergedActive = React . useMemo ( ( ) => { if ( active ) { return active ; } if ( mode !== 'inline' ) { return childrenActive || isSubPathKey ( [ activeKey ] , eventKey ) ; } return false ; } , [ mode , active , activeKey , childrenActive , eventKey , isSubPathKey ] ) ; const directionStyle = useDirectionStyle ( connectedPath . length ) ; const onInternalTitleClick = e => { if ( mergedDisabled ) { return ; } onTitleClick ?. ( { key : eventKey , domEvent : e , } ) ; if ( mode === 'inline' ) { onOpenChange ( eventKey , ! originOpen ) ; } } ; const onMergedItemClick = useMemoCallback ( ( info ) => { onClick ?. ( warnItemProp ( info ) ) ; onItemClick ( info ) ; } ) ; const onPopupVisibleChange = ( newVisible ) => { if ( mode !== 'inline' ) { onOpenChange ( eventKey , newVisible ) ; } } ; /**
     * Used for accessibility. Helper will focus element without key board.
     * We should manually trigger an active
     */ const onInternalFocus = ( ) => { onActive ( eventKey ) ; } ; const popupId = domDataId && `${ domDataId }-popup` ; let titleNode = ( < div role = "menuitem" style = { directionStyle } className = { `${ subMenuPrefixCls }-title` } tabIndex = { mergedDisabled ? null : - 1 } ref = { elementRef } title = { typeof title === 'string' ? title : null } data - menu - id = { overflowDisabled && domDataId ? null : domDataId } aria - expanded = { open } aria - haspopup aria - controls = { popupId } aria - disabled = { mergedDisabled } onClick = { onInternalTitleClick } onFocus = { onInternalFocus } { ... activeProps } > { title } { } < Icon icon = { mode !== 'horizontal' ? mergedExpandIcon : null } props = { { ... props , isOpen : open , isSubMenu : true , } } > < i className = { `${ subMenuPrefixCls }-arrow` } /> < /Icon> < /div>); const triggerModeRef = React . useRef ( mode ) ; if ( mode !== 'inline' ) { triggerModeRef . current = connectedPath . length > 1 ? 'vertical' : mode ; } if ( ! overflowDisabled ) { const triggerMode = triggerModeRef . current ; titleNode = ( < PopupTrigger mode = { triggerMode } prefixCls = { subMenuPrefixCls } visible = { ! internalPopupClose && open && mode !== 'inline' } popupClassName = { popupClassName } popupOffset = { popupOffset } popup = { < MenuContextProvider mode = { triggerMode === 'horizontal' ? 'vertical' : triggerMode } > < SubMenuList id = { popupId } ref = { popupRef } > { children } < /SubMenuList> < /MenuContextProvider>} disabled={mergedDisabled} onVisibleChange={onPopupVisibleChange}> { titleNode } < /PopupTrigger>); } let listNode = ( < Overflow . Item role = "none" { ... restProps } component = "li" style = { style } className = { classNames ( subMenuPrefixCls , `${ subMenuPrefixCls } - $ { mode } `, className, {
            [` $ { subMenuPrefixCls } - open `]: open,
            [` $ { subMenuPrefixCls } - active `]: mergedActive,
            [` $ { subMenuPrefixCls } - selected `]: childrenSelected,
            [` $ { subMenuPrefixCls } - disabled `]: mergedDisabled,
        })} onMouseEnter={onInternalMouseEnter} onMouseLeave={onInternalMouseLeave}>
      {titleNode}

      {/* Inline mode */}
      {!overflowDisabled && (<InlineSubMenuList id={popupId} open={open} keyPath={connectedPath}>
          {children}
        </InlineSubMenuList>)}
    </Overflow.Item>);
    if (_internalRenderSubMenuItem) {
        listNode = _internalRenderSubMenuItem(listNode, props, {
            selected: childrenSelected,
        });
    }
    // >>>>> Render
    return (<MenuContextProvider onItemClick={onMergedItemClick} mode={mode === 'horizontal' ? 'vertical' : mode} itemIcon={mergedItemIcon} expandIcon={mergedExpandIcon}>
      {listNode}
    </MenuContextProvider>);
};
export default function SubMenu(props) {
    const { eventKey, children } = props;
    const connectedKeyPath = useFullPath(eventKey);
    const childList = parseChildren(children, connectedKeyPath);
    // ==================== Record KeyPath ====================
    const measure = useMeasure();
    // eslint-disable-next-line consistent-return
    React.useEffect(() => {
        if (measure) {
            measure.registerPath(eventKey, connectedKeyPath);
            return () => {
                measure.unregisterPath(eventKey, connectedKeyPath);
            };
        }
    }, [connectedKeyPath]);
    let renderNode;
    // ======================== Render ========================
    if (measure) {
        renderNode = childList;
    }
    else {
        renderNode = <InternalSubMenu {...props}>{childList}</InternalSubMenu>;
    }
    return (<PathTrackerContext.Provider value={connectedKeyPath}>
      {renderNode}
    </PathTrackerContext.Provider>);
}
