mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 15:09:33 +01:00
fix: correct submenu positioning
This commit is contained in:
@@ -10,6 +10,7 @@ import React, {
|
|||||||
import { Flex, Box, Text, Button } from "rebass";
|
import { Flex, Box, Text, Button } from "rebass";
|
||||||
import useMobile from "../../utils/use-mobile";
|
import useMobile from "../../utils/use-mobile";
|
||||||
import { AnimatedFlex } from "../animated";
|
import { AnimatedFlex } from "../animated";
|
||||||
|
import { getPosition } from "../../hooks/use-menu";
|
||||||
|
|
||||||
function useMenuFocus(items) {
|
function useMenuFocus(items) {
|
||||||
const [focusIndex, setFocusIndex] = useState(-1);
|
const [focusIndex, setFocusIndex] = useState(-1);
|
||||||
@@ -121,8 +122,7 @@ function MenuContainer({ title, children }) {
|
|||||||
borderRadius: "default",
|
borderRadius: "default",
|
||||||
boxShadow: "0px 0px 10px 0px #00000022",
|
boxShadow: "0px 0px 10px 0px #00000022",
|
||||||
border: "1px solid var(--border)",
|
border: "1px solid var(--border)",
|
||||||
minWidth: 200,
|
width: 220,
|
||||||
maxWidth: 500,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{title && (
|
{title && (
|
||||||
@@ -217,16 +217,35 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
|
|||||||
isPremium,
|
isPremium,
|
||||||
} = item;
|
} = item;
|
||||||
const itemRef = useRef();
|
const itemRef = useRef();
|
||||||
|
const subMenuRef = useRef();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFocused) itemRef.current?.focus();
|
if (isFocused) itemRef.current?.focus();
|
||||||
}, [isFocused]);
|
}, [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(
|
const onAction = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (onClose) onClose();
|
if (onClose) onClose();
|
||||||
onClick(data, item);
|
if (onClick) onClick(data, item);
|
||||||
},
|
},
|
||||||
[onClick, onClose, item, data]
|
[onClick, onClose, item, data]
|
||||||
);
|
);
|
||||||
@@ -249,7 +268,7 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
|
|||||||
as="li"
|
as="li"
|
||||||
flexDirection={"column"}
|
flexDirection={"column"}
|
||||||
flex={1}
|
flex={1}
|
||||||
sx={{ position: "relative" }}
|
// sx={{ position: "relative" }}
|
||||||
onMouseOver={onHover}
|
onMouseOver={onHover}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@@ -290,12 +309,14 @@ function MenuItem({ item, data, isFocused, isSubmenuOpen, onClose, onHover }) {
|
|||||||
{hasSubmenu && <ChevronRight size={14} />}
|
{hasSubmenu && <ChevronRight size={14} />}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Button>
|
</Button>
|
||||||
{hasSubmenu && isSubmenuOpen && (
|
{hasSubmenu && (
|
||||||
<Flex
|
<Flex
|
||||||
|
ref={subMenuRef}
|
||||||
|
style={{ visibility: "hidden" }}
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: 0,
|
// top: 0,
|
||||||
left: itemRef.current?.offsetWidth,
|
// left: itemRef.current?.offsetWidth,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Menu
|
<Menu
|
||||||
|
|||||||
@@ -46,28 +46,32 @@ export function useMenu() {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function getPosition(element, relativeTo = "mouse", location) {
|
export function getPosition(element, relativeTo = "mouse", location) {
|
||||||
const { x, y, width, height } =
|
const { x, y, width, height, actualX, actualY } =
|
||||||
relativeTo === "mouse" ? mousePosition : getElementPosition(relativeTo);
|
relativeTo === "mouse" ? mousePosition : getElementPosition(relativeTo);
|
||||||
|
|
||||||
const elementWidth = element.offsetWidth;
|
const elementWidth = element.offsetWidth;
|
||||||
const elementHeight = element.offsetHeight;
|
const elementHeight = element.offsetHeight;
|
||||||
|
|
||||||
const windowWidth = window.document.body.offsetWidth;
|
const windowWidth = window.innerHeight;
|
||||||
const windowHeight = window.document.body.offsetHeight;
|
const windowHeight = window.innerHeight - 50;
|
||||||
|
|
||||||
let position = { top: undefined, left: undefined };
|
let position = { top: undefined, left: undefined };
|
||||||
|
|
||||||
if (windowWidth - x < elementWidth) {
|
if (windowWidth - actualX < elementWidth) {
|
||||||
|
const xDiff = actualX - x;
|
||||||
position.left = windowWidth - elementWidth;
|
position.left = windowWidth - elementWidth;
|
||||||
|
position.left -= xDiff;
|
||||||
} else {
|
} else {
|
||||||
position.left = x;
|
position.left = x;
|
||||||
|
|
||||||
if (location === "right") position.top += width;
|
if (location === "right") position.left += width;
|
||||||
else if (location === "left") position.top -= 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 = windowHeight - elementHeight;
|
||||||
|
position.top -= yDiff;
|
||||||
} else {
|
} else {
|
||||||
position.top = y;
|
position.top = y;
|
||||||
if (location === "below") position.top += height;
|
if (location === "below") position.top += height;
|
||||||
@@ -98,6 +102,8 @@ function getMousePosition(e) {
|
|||||||
return {
|
return {
|
||||||
x: posx,
|
x: posx,
|
||||||
y: posy,
|
y: posy,
|
||||||
|
actualY: posy,
|
||||||
|
actualX: posx,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,11 +112,14 @@ function getMousePosition(e) {
|
|||||||
* @param {HTMLElement} element
|
* @param {HTMLElement} element
|
||||||
*/
|
*/
|
||||||
function getElementPosition(element) {
|
function getElementPosition(element) {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
return {
|
return {
|
||||||
x: element.offsetLeft,
|
x: element.offsetLeft,
|
||||||
y: element.offsetTop,
|
y: element.offsetTop,
|
||||||
width: element.offsetWidth,
|
width: element.offsetWidth,
|
||||||
height: element.offsetHeight,
|
height: element.offsetHeight,
|
||||||
|
actualY: rect.y,
|
||||||
|
actualX: rect.x,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +176,7 @@ function mapMenuItems(items, data) {
|
|||||||
color,
|
color,
|
||||||
iconColor,
|
iconColor,
|
||||||
|
|
||||||
items,
|
items: hasSubmenu ? mapMenuItems(items, data) : [],
|
||||||
};
|
};
|
||||||
|
|
||||||
prev.push(menuItem);
|
prev.push(menuItem);
|
||||||
|
|||||||
Reference in New Issue
Block a user