diff --git a/app/components/ContextMenu/MouseSafeArea.tsx b/app/components/ContextMenu/MouseSafeArea.tsx new file mode 100644 index 000000000..a1cd354bc --- /dev/null +++ b/app/components/ContextMenu/MouseSafeArea.tsx @@ -0,0 +1,66 @@ +import * as React from "react"; +import { useMousePosition } from "~/hooks/useMousePosition"; + +type Positions = { + /* Sub-menu x */ + x: number; + /* Sub-menu y */ + y: number; + /* Sub-menu height */ + h: number; + /* Sub-menu width */ + w: number; + /* Mouse x */ + mouseX: number; + /* Mouse y */ + mouseY: number; +}; + +/** + * Component to cover the area between the mouse cursor and the sub-menu, to + * allow moving cursor to lower parts of sub-menu without the sub-menu + * disappearing. + */ +export default function MouseSafeArea(props: { + parentRef: React.RefObject; +}) { + const { x = 0, y = 0, height: h = 0, width: w = 0 } = + props.parentRef.current?.getBoundingClientRect() || {}; + const [mouseX, mouseY] = useMousePosition(); + const positions = { x, y, h, w, mouseX, mouseY }; + + return ( +
+ ); +} + +const getLeft = ({ x, mouseX }: Positions) => + mouseX > x ? undefined : -Math.max(x - mouseX, 10) + "px"; + +const getRight = ({ x, w, mouseX }: Positions) => + mouseX > x ? -Math.max(mouseX - (x + w), 10) + "px" : undefined; + +const getWidth = ({ x, w, mouseX }: Positions) => + mouseX > x + ? Math.max(mouseX - (x + w), 10) + "px" + : Math.max(x - mouseX, 10) + "px"; + +const getClipPath = ({ x, y, h, mouseX, mouseY }: Positions) => + mouseX > x + ? `polygon(0% 0%, 0% 100%, 100% ${(100 * (mouseY - y)) / h - 10}%, 100% ${ + (100 * (mouseY - y)) / h + 5 + }%)` + : `polygon(100% 0%, 0% ${(100 * (mouseY - y)) / h - 10}%, 0% ${ + (100 * (mouseY - y)) / h + 5 + }%, 100% 100%)`; diff --git a/app/components/ContextMenu/Template.tsx b/app/components/ContextMenu/Template.tsx index 541a18176..cd92a12bf 100644 --- a/app/components/ContextMenu/Template.tsx +++ b/app/components/ContextMenu/Template.tsx @@ -21,6 +21,7 @@ import { } from "~/types"; import Header from "./Header"; import MenuItem, { MenuAnchor } from "./MenuItem"; +import MouseSafeArea from "./MouseSafeArea"; import Separator from "./Separator"; import ContextMenu from "."; @@ -59,6 +60,7 @@ const Submenu = React.forwardRef( )} +