diff --git a/web/components/menu.react.js b/web/components/menu.react.js --- a/web/components/menu.react.js +++ b/web/components/menu.react.js @@ -3,6 +3,7 @@ import classnames from 'classnames'; import * as React from 'react'; +import { useMenuPortalContext } from '../menu-portal-provider.react'; import css from './menu.css'; type MenuPosition = 'left' | 'right' | 'bottom'; @@ -14,19 +15,32 @@ position?: MenuPosition, size?: MenuSize, light?: boolean, + onChange?: boolean => void, }; function Menu(props: MenuProps): React.Node { const [isOpen, setIsOpen] = React.useState(false); + const [buttonPosition, setButtonPosition] = React.useState(null); + const buttonRef = React.useRef(); + const { renderInMenuPortal } = useMenuPortalContext(); const { icon, children, position = 'bottom', size = 'medium', light = false, + onChange, } = props; + const updatePosition = React.useCallback(() => { + if (buttonRef.current) { + setButtonPosition(buttonRef.current.getBoundingClientRect()); + } + }, []); + + React.useEffect(updatePosition, [updatePosition]); + const closeMenuCallback = React.useCallback(() => { document.removeEventListener('click', closeMenuCallback); if (isOpen) { @@ -34,6 +48,20 @@ } }, [isOpen]); + React.useEffect(() => { + if (onChange) { + onChange(isOpen); + } + }, [isOpen, onChange]); + + React.useEffect(() => { + if (!window) { + return undefined; + } + + window.addEventListener('resize', updatePosition); + return () => window.removeEventListener('resize', updatePosition); + }); React.useEffect(() => { if (!document || !isOpen) { return undefined; @@ -43,8 +71,9 @@ }, [closeMenuCallback, isOpen]); const switchMenuCallback = React.useCallback(() => { + updatePosition(); setIsOpen(isMenuOpen => !isMenuOpen); - }, []); + }, [updatePosition]); if (children.length === 0) { return null; @@ -60,20 +89,30 @@ [css.menuActionListLight]: light, }); - menuActionList = ( -
+ const actionListStyle = buttonPosition + ? { + top: buttonPosition.top, + left: buttonPosition.left, + } + : {}; + menuActionList = renderInMenuPortal( +
{children}
-
+
, ); } return ( -
- {menuActionList} -
+ ); }