diff --git a/app/components/ContextMenu/index.js b/app/components/ContextMenu/index.js index d49c1eeae..d6ea66931 100644 --- a/app/components/ContextMenu/index.js +++ b/app/components/ContextMenu/index.js @@ -5,6 +5,7 @@ import { Menu } from "reakit/Menu"; import styled from "styled-components"; import breakpoint from "styled-components-breakpoint"; import usePrevious from "hooks/usePrevious"; +import useWindowSize from "hooks/useWindowSize"; import { fadeIn, fadeAndSlideUp, @@ -18,6 +19,9 @@ type Props = {| placement?: string, animating?: boolean, children: React.Node, + unstable_disclosureRef?: { + current: null | React.ElementRef<"button">, + }, onOpen?: () => void, onClose?: () => void, hide?: () => void, @@ -30,6 +34,9 @@ export default function ContextMenu({ ...rest }: Props) { const previousVisible = usePrevious(rest.visible); + const [maxHeight, setMaxHeight] = React.useState(undefined); + const backgroundRef = React.useRef(); + const { height: windowHeight } = useWindowSize(); React.useEffect(() => { if (rest.visible && !previousVisible) { @@ -44,6 +51,23 @@ export default function ContextMenu({ } }, [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) { + setMaxHeight( + rest.unstable_disclosureRef?.current + ? windowHeight - + rest.unstable_disclosureRef.current.getBoundingClientRect() + .bottom - + padding + : undefined + ); + } + }, [rest.visible, rest.unstable_disclosureRef, windowHeight]); + return ( <> @@ -60,6 +84,8 @@ export default function ContextMenu({ dir="auto" topAnchor={topAnchor} rightAnchor={rightAnchor} + ref={backgroundRef} + style={maxHeight && topAnchor ? { maxHeight } : undefined} > {rest.visible || rest.animating ? children : null} diff --git a/app/hooks/useWindowSize.js b/app/hooks/useWindowSize.js index 8c2111b24..a91f64ba0 100644 --- a/app/hooks/useWindowSize.js +++ b/app/hooks/useWindowSize.js @@ -4,8 +4,8 @@ import * as React from "react"; export default function useWindowSize() { const [windowSize, setWindowSize] = React.useState({ - width: undefined, - height: undefined, + width: parseInt(window.innerWidth), + height: parseInt(window.innerHeight), }); React.useEffect(() => { @@ -13,8 +13,8 @@ export default function useWindowSize() { const handleResize = debounce(() => { // Set window width/height to state setWindowSize({ - width: window.innerWidth, - height: window.innerHeight, + width: parseInt(window.innerWidth), + height: parseInt(window.innerHeight), }); }, 100);