Skip to content

Instantly share code, notes, and snippets.

@eldh
Created August 31, 2020 18:33
Show Gist options
  • Save eldh/51e3825b7aa55694f2a5ffa5f7de8a6a to your computer and use it in GitHub Desktop.
Save eldh/51e3825b7aa55694f2a5ffa5f7de8a6a to your computer and use it in GitHub Desktop.
import * as React from "react";
import { useMousePosition } from "~/hooks/useMousePosition";
/** 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 function MouseSafeArea(props: { parentRef: React.RefObject<HTMLDivElement> }) {
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 (
<div
style={{
position: "absolute",
top: 0,
// backgroundColor: "rgba(255,0,0,0.1)", // Debug
right: getRight(positions),
left: getLeft(positions),
height: h,
width: getWidth(positions),
clipPath: getClipPath(positions),
}}
/>
);
}
interface 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;
}
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}%)`
: `polygon(100% 0%, 0% ${(100 * (mouseY - y)) / h}%, 100% 100%)`;
@adeleke5140
Copy link

thx for sharing

@felixeichler
Copy link

awesome thanks! 👏
for the record, see also this original blog article.
and here's a version using useMouse from useHooks. not sure what that original useMousePosition is.
anyway this component shall be placed inside the hoverable container and passing in the parent (that shall remain hovered) as parentRef. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment