fix: correct submenu positioning

This commit is contained in:
thecodrr
2022-02-04 23:21:29 +05:00
parent 3015a60764
commit ae4cc13804
2 changed files with 45 additions and 15 deletions

View File

@@ -10,6 +10,7 @@ import React, {
import { Flex, Box, Text, Button } from "rebass";
import useMobile from "../../utils/use-mobile";
import { AnimatedFlex } from "../animated";
import { getPosition } from "../../hooks/use-menu";
function useMenuFocus(items) {
const [focusIndex, setFocusIndex] = useState(-1);
@@ -121,8 +122,7 @@ function MenuContainer({ title, children }) {
borderRadius: "default",
boxShadow: "0px 0px 10px 0px #00000022",
border: "1px solid var(--border)",
minWidth: 200,
maxWidth: 500,
width: 220,
}}
>
{title && (
@@ -217,16 +217,35 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
isPremium,
} = item;
const itemRef = useRef();
const subMenuRef = useRef();
useEffect(() => {
if (isFocused) itemRef.current?.focus();
}, [isFocused]);
useEffect(() => {
if (!subMenuRef.current) return;
if (!isSubmenuOpen) {
subMenuRef.current.style.visibility = "hidden";
return;
}
const { top, left } = getPosition(
subMenuRef.current,
itemRef.current,
"right"
);
subMenuRef.current.style.visibility = "visible";
subMenuRef.current.style.top = `${top}px`;
subMenuRef.current.style.left = `${left}px`;
}, [isSubmenuOpen]);
const onAction = useCallback(
(e) => {
e.stopPropagation();
if (onClose) onClose();
onClick(data, item);
if (onClick) onClick(data, item);
},
[onClick, onClose, item, data]
);
@@ -249,7 +268,7 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
as="li"
flexDirection={"column"}
flex={1}
sx={{ position: "relative" }}
// sx={{ position: "relative" }}
onMouseOver={onHover}
>
<Button
@@ -290,12 +309,14 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
{hasSubmenu && <ChevronRight size={14} />}
</Flex>
</Button>
{hasSubmenu && isSubmenuOpen && (
{hasSubmenu && (
<Flex
ref={subMenuRef}
style={{ visibility: "hidden" }}
sx={{
position: "absolute",
top: 0,
left: itemRef.current?.offsetWidth,
// top: 0,
// left: itemRef.current?.offsetWidth,
}}
>
<Menu

View File

@@ -46,28 +46,32 @@ export function useMenu() {
* @returns
*/
export function getPosition(element, relativeTo = "mouse", location) {
const { x, y, width, height } =
const { x, y, width, height, actualX, actualY } =
relativeTo === "mouse" ? mousePosition : getElementPosition(relativeTo);
const elementWidth = element.offsetWidth;
const elementHeight = element.offsetHeight;
const windowWidth = window.document.body.offsetWidth;
const windowHeight = window.document.body.offsetHeight;
const windowWidth = window.innerHeight;
const windowHeight = window.innerHeight - 50;
let position = { top: undefined, left: undefined };
if (windowWidth - x < elementWidth) {
if (windowWidth - actualX < elementWidth) {
const xDiff = actualX - x;
position.left = windowWidth - elementWidth;
position.left -= xDiff;
} else {
position.left = x;
if (location === "right") position.top += width;
else if (location === "left") position.top -= width;
if (location === "right") position.left += width;
else if (location === "left") position.left -= width;
}
if (windowHeight - y < elementHeight) {
if (windowHeight - actualY < elementHeight) {
const yDiff = actualY - y;
position.top = windowHeight - elementHeight;
position.top -= yDiff;
} else {
position.top = y;
if (location === "below") position.top += height;
@@ -98,6 +102,8 @@ function getMousePosition(e) {
return {
x: posx,
y: posy,
actualY: posy,
actualX: posx,
};
}
@@ -106,11 +112,14 @@ function getMousePosition(e) {
* @param {HTMLElement} element
*/
function getElementPosition(element) {
const rect = element.getBoundingClientRect();
return {
x: element.offsetLeft,
y: element.offsetTop,
width: element.offsetWidth,
height: element.offsetHeight,
actualY: rect.y,
actualX: rect.x,
};
}
@@ -167,7 +176,7 @@ function mapMenuItems(items, data) {
color,
iconColor,
items,
items: hasSubmenu ? mapMenuItems(items, data) : [],
};
prev.push(menuItem);