glass-app-manager
Version:
Informatica's Glass Framework CLI for bootstrapping
76 lines (62 loc) • 2.39 kB
JavaScript
// @flow
import * as React from "react";
import { openMenu, closeMenu, MenuOpener } from "./utils";
export type SubmenuProps = {
/**
* Children of the submenu.
*/
children: Node,
/**
* Label of the menu.
*/
label: string,
};
export default function Submenu({ children, label, disabled }: SubmenuProps) {
const [open, setOpen] = React.useState(false);
const ref = React.useRef(null);
// Close the submenu if the mouse moves to another sibling.
const handleMouseMove = React.useCallback(e => {
const parentRect = ref.current.parentNode.parentNode.getBoundingClientRect();
const inSameMenu =
e.clientX >= parentRect.left &&
e.clientX <= parentRect.left + parentRect.width &&
e.clientY >= parentRect.top &&
e.clientY <= parentRect.top + parentRect.height;
const rect = ref.current.getBoundingClientRect();
const inDiffItem = e.clientY < rect.top || e.clientY > rect.top + ref.current.clientHeight;
if (inSameMenu && inDiffItem) {
closeMenu(open, setOpen);
}
});
React.useEffect(() => {
if (open) {
window.addEventListener("mousemove", handleMouseMove);
}
return () => window.removeEventListener("mousemove", handleMouseMove);
}, [open]);
return (
<MenuOpener
open={open}
setOpen={setOpen}
position={["right", "start"]}
align="start"
contentLocation={({ targetRect, popoverRect, position, align, nudgedLeft, nudgedTop }) => {
const { scrollX: windowX, scrollY: windowY } = window;
return { top: nudgedTop + windowY - 11, left: nudgedLeft - windowX };
}}
onClickOutside={() => closeMenu(open, setOpen)}
trigger={
<li
ref={ref}
className="menu__item menu__submenu"
onClick={() => openMenu(open, setOpen)}
onMouseEnter={() => openMenu(open, setOpen)}>
{label}
<i className="menu__submenu-icon" />
</li>
}>
{children}
</MenuOpener>
);
}
Submenu.displayName = "Menu.Submenu";