// @flow import * as React from "react"; import { Portal } from "react-portal"; import { Menu } from "reakit/Menu"; import styled from "styled-components"; import breakpoint from "styled-components-breakpoint"; import useMobile from "hooks/useMobile"; import usePrevious from "hooks/usePrevious"; import useWindowSize from "hooks/useWindowSize"; import { fadeIn, fadeAndSlideUp, fadeAndSlideDown, mobileContextMenu, } from "styles/animations"; type Props = {| "aria-label": string, visible?: boolean, placement?: string, animating?: boolean, children: React.Node, unstable_disclosureRef?: { current: null | React.ElementRef<"button">, }, onOpen?: () => void, onClose?: () => void, hide?: () => void, |}; export default function ContextMenu({ children, onOpen, onClose, ...rest }: Props) { const previousVisible = usePrevious(rest.visible); const [maxHeight, setMaxHeight] = React.useState(undefined); const isMobile = useMobile(); const { height: windowHeight } = useWindowSize(); const backgroundRef = React.useRef(); React.useEffect(() => { if (rest.visible && !previousVisible) { if (onOpen) { onOpen(); } } if (!rest.visible && previousVisible) { if (onClose) { onClose(); } } }, [onOpen, onClose, previousVisible, rest.visible]); // sets the menu height based on the available space between the disclosure/ // trigger and the bottom of the window React.useLayoutEffect(() => { const padding = 8; if (rest.visible && !isMobile) { setMaxHeight( rest.unstable_disclosureRef?.current ? windowHeight - rest.unstable_disclosureRef.current.getBoundingClientRect() .bottom - padding : undefined ); } }, [rest.visible, rest.unstable_disclosureRef, windowHeight, isMobile]); return ( <>
{(rest.visible || rest.animating) && (