Skip to content

Commit

Permalink
fix(Menu): 修复当嵌套多个子菜单时,会有遮住子菜单问题 # 779 (#797)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuilanxin committed Apr 26, 2022
1 parent 971dc8b commit 83b1306
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 44 deletions.
32 changes: 24 additions & 8 deletions packages/react-menu/src/Menu.tsx
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useMemo, createContext } from 'react';
import { IProps, HTMLUlProps } from '@uiw/utils';
import { MenuItem } from './MenuItem';
import { MenuDivider } from './Divider';
Expand All @@ -19,8 +19,17 @@ export interface MenuProps extends IProps, HTMLUlProps {
inlineIndent?: number;
bordered?: boolean;
}
interface MenuContextType {
height: number;
ele: EventTarget | null;
}
export const ThemeContext = createContext(
{} as MenuContextType & {
setContextHeight: React.Dispatch<React.SetStateAction<MenuContextType>>;
},
);

const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
export const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
const {
prefixCls = 'w-menu',
className,
Expand All @@ -45,7 +54,6 @@ const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
.trim(),
[prefixCls, bordered, inlineCollapsed, theme, className],
);

return (
<ul {...htmlProps} ref={ref} className={cls} data-menu="menu">
{React.Children.map(children, (child: React.ReactNode, key) => {
Expand All @@ -61,16 +69,24 @@ const Menu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
);
});

export const ContextMenu = React.forwardRef<HTMLUListElement, MenuProps>((props, ref) => {
const [contextHeight, setContextHeight] = React.useState<MenuContextType>({ height: 0, ele: null });
return (
<ThemeContext.Provider value={{ ...contextHeight, setContextHeight }}>
<Menu {...props} ref={ref} />
</ThemeContext.Provider>
);
});
Menu.displayName = 'uiw.Menu';
ContextMenu.displayName = 'uiw.Menu';

type Menu = typeof Menu & {
Item: typeof MenuItem;
SubMenu: typeof SubMenu;
Divider: typeof MenuDivider;
};

(Menu as Menu).Item = MenuItem;
(Menu as Menu).SubMenu = SubMenu;
(Menu as Menu).Divider = MenuDivider;

export default Menu as Menu;
(ContextMenu as Menu).Item = MenuItem;
(ContextMenu as Menu).SubMenu = SubMenu;
(ContextMenu as Menu).Divider = MenuDivider;
export default ContextMenu as Menu;
103 changes: 67 additions & 36 deletions packages/react-menu/src/SubMenu.tsx
@@ -1,10 +1,10 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo, useState, useContext } from 'react';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
import OverlayTrigger, { OverlayTriggerProps, OverlayTriggerRef } from '@uiw/react-overlay-trigger';
import Icon from '@uiw/react-icon';
import { IProps } from '@uiw/utils';
import { MenuItem, MenuItemProps, TagType } from './MenuItem';
import Menu, { MenuProps } from './Menu';
import { MenuProps, Menu, ThemeContext } from './Menu';
import './style/submenu.less';

export interface SubMenuProps<T extends TagType> extends IProps, MenuItemProps<T> {
Expand Down Expand Up @@ -49,6 +49,7 @@ function IconView({ prefixCls, collapse, isOpen }: { prefixCls?: string; collaps
[prefixCls, collapse, isOpen],
);
}

export const SubMenu = React.forwardRef(function <Tag extends TagType = 'a'>(
props: SubMenuProps<Tag>,
ref: React.Ref<HTMLLIElement>,
Expand All @@ -72,7 +73,20 @@ export const SubMenu = React.forwardRef(function <Tag extends TagType = 'a'>(
className: [prefixCls ? `${prefixCls}-overlay` : null].filter(Boolean).join(' ').trim(),
};
const popupRef = React.useRef<OverlayTriggerRef>(null);
const refNode = React.useRef<HTMLElement | null>();
const currentHeight = React.useRef<number>(0);
const elementSource = React.useRef<EventTarget | null>();
const [isOpen, setIsOpen] = useState(!!overlayProps.isOpen);
const { height, setContextHeight, ele } = useContext(ThemeContext);

React.useEffect(() => {
if (refNode.current && refNode.current.style && ele === elementSource.current) {
const currentHeight = refNode.current!.style.height;
if (height + 'px' === currentHeight) return;
refNode.current!.style.height = Number(currentHeight.substr(0, currentHeight.length - 2)) + height + 'px';
}
}, [height]);

useMemo(() => {
if (collapse) setIsOpen(false);
}, [collapse]);
Expand All @@ -93,21 +107,28 @@ export const SubMenu = React.forwardRef(function <Tag extends TagType = 'a'>(
}
function onExiting(node: HTMLElement) {
node.style.height = '0px';
setContextHeight({
height: -currentHeight.current,
ele: elementSource.current!,
});
}
function onEnter(node: HTMLElement) {
node.style.height = '1px';
setIsOpen(true);
currentHeight.current = popupRef.current!.overlayDom.current!.getBoundingClientRect().height;
setContextHeight({
height: currentHeight.current,
ele: elementSource.current!,
});
}
function onEntering(node: HTMLElement) {
node.style.height = `${node.scrollHeight}px`;
}
function onEntered(node: HTMLElement) {
node.style.height = 'initial';
if (popupRef.current && popupRef.current.overlayDom) {
node.style.height = popupRef.current.overlayDom.current!.getBoundingClientRect().height + 'px';
}
// node.style.height = 'initial';
node.style.height = currentHeight.current + 'px';
refNode.current = node;
}

if (!collapse) {
delete menuProps.onClick;
menuProps.bordered = false;
Expand All @@ -130,36 +151,46 @@ export const SubMenu = React.forwardRef(function <Tag extends TagType = 'a'>(
menuProps.onClick = onClick;
}
return (
<li data-menu="subitem" ref={ref}>
<OverlayTrigger
placement="rightTop"
autoAdjustOverflow
disabled={disabled}
isOpen={isOpen}
usePortal={false}
isOutside
{...overlayTriggerProps}
{...overlayProps}
ref={popupRef}
overlay={<Menu {...menuProps} style={!collapse ? { paddingLeft: inlineIndent } : {}} />}
>
<MenuItem
{...other}
ref={null}
<div
onClick={(e) => {
if (collapse) {
e.stopPropagation();
return;
}
elementSource.current = e.target;
}}
>
<li data-menu="subitem" ref={ref}>
<OverlayTrigger
placement="rightTop"
autoAdjustOverflow
disabled={disabled}
isSubMenuItem
addonAfter={<IconView collapse={collapse} prefixCls={prefixCls} isOpen={isOpen} />}
className={[
prefixCls ? `${prefixCls}-title` : null,
!collapse ? `${prefixCls}-collapse-title` : null,
className,
]
.filter(Boolean)
.join(' ')
.trim()}
/>
</OverlayTrigger>
</li>
isOpen={isOpen}
usePortal={false}
isOutside
{...overlayTriggerProps}
{...overlayProps}
ref={popupRef}
overlay={<Menu {...menuProps} style={!collapse ? { paddingLeft: inlineIndent } : {}} />}
>
<MenuItem
{...other}
ref={null}
disabled={disabled}
isSubMenuItem
addonAfter={<IconView collapse={collapse} prefixCls={prefixCls} isOpen={isOpen} />}
className={[
prefixCls ? `${prefixCls}-title` : null,
!collapse ? `${prefixCls}-collapse-title` : null,
className,
]
.filter(Boolean)
.join(' ')
.trim()}
/>
</OverlayTrigger>
</li>
</div>
);
});

Expand Down

0 comments on commit 83b1306

Please sign in to comment.