diff --git a/web/components/menu.react.js b/web/components/menu.react.js index dea192da5..fedd647c7 100644 --- a/web/components/menu.react.js +++ b/web/components/menu.react.js @@ -1,122 +1,118 @@ // @flow import classnames from 'classnames'; import * as React from 'react'; import { useRenderMenu } from '../menu-provider.react'; import css from './menu.css'; type MenuVariant = 'thread-actions' | 'member-actions'; type MenuProps = { +icon: React.Node, +children?: React.Node, +variant?: MenuVariant, +onChange?: boolean => void, }; function Menu(props: MenuProps): React.Node { const buttonRef = React.useRef(); const { renderMenu, setMenuPosition, closeMenu, setCurrentOpenMenu, currentOpenMenu, } = useRenderMenu(); const { icon, children, variant = 'thread-actions', onChange } = props; const ourSymbol = React.useRef(Symbol()); const menuActionListClasses = React.useMemo( () => classnames(css.menuActionList, { [css.menuActionListThreadActions]: variant === 'thread-actions', [css.menuActionListMemberActions]: variant === 'member-actions', }), [variant], ); const menuActionList = React.useMemo( () =>
{children}
, [children, menuActionListClasses], ); const isOurMenuOpen = currentOpenMenu === ourSymbol.current; const updatePosition = React.useCallback(() => { if (buttonRef.current && isOurMenuOpen) { const { top, left } = buttonRef.current.getBoundingClientRect(); setMenuPosition({ top, left }); } }, [isOurMenuOpen, setMenuPosition]); React.useEffect(() => { if (!window) { return undefined; } window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); }, [updatePosition]); - // useLayoutEffect is necessary so that the menu position is immediately - // updated in the first render of component - React.useLayoutEffect(() => { - updatePosition(); - }, [updatePosition]); + React.useEffect(updatePosition, [updatePosition]); const closeMenuCallback = React.useCallback(() => { closeMenu(menuActionList); }, [closeMenu, menuActionList]); React.useEffect(() => { onChange?.(isOurMenuOpen); }, [isOurMenuOpen, onChange]); React.useEffect(() => { if (!isOurMenuOpen) { return undefined; } document.addEventListener('click', closeMenuCallback); return () => { document.removeEventListener('click', closeMenuCallback); }; }, [closeMenuCallback, isOurMenuOpen]); const prevActionListRef = React.useRef(null); React.useEffect(() => { if (!isOurMenuOpen) { prevActionListRef.current = null; return; } if (prevActionListRef.current === menuActionList) { return; } renderMenu(menuActionList); prevActionListRef.current = menuActionList; }, [isOurMenuOpen, menuActionList, renderMenu]); React.useEffect(() => { return () => closeMenu(prevActionListRef.current); }, [closeMenu]); const onClickMenuCallback = React.useCallback(() => { setCurrentOpenMenu(ourSymbol.current); }, [setCurrentOpenMenu]); if (React.Children.count(children) === 0) { return null; } return ( ); } export default Menu;