fix: Context menus can extend outside of window bounds

closes #2492
This commit is contained in:
Tom Moor
2021-09-26 17:07:44 -07:00
parent 9545113d9e
commit 6f136e342f
2 changed files with 30 additions and 4 deletions

View File

@@ -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 (
<>
<Menu hideOnClickOutside preventBodyScroll {...rest}>
@@ -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}
</Background>

View File

@@ -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);