67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
import Rules, { RulesMode } from "@Front/Components/Elements/Rules";
|
|
import useHoverable from "@Front/Hooks/useHoverable";
|
|
import useOpenable from "@Front/Hooks/useOpenable";
|
|
import React, { useEffect, useRef } from "react";
|
|
|
|
import classes from "./classes.module.scss";
|
|
import MenuItem, { IItem } from "./MenuItem";
|
|
|
|
type IProps = {
|
|
children: React.ReactNode;
|
|
items: IItem[];
|
|
openingSide?: "left" | "right" | "center";
|
|
openOnHover?: boolean;
|
|
};
|
|
|
|
export default function Menu(props: IProps) {
|
|
const { openingSide = "left", items, children, openOnHover } = props;
|
|
|
|
const { handleMouseLeave, handleMouseEnter, isHovered } = useHoverable(100);
|
|
|
|
const { isOpen, toggle, close } = useOpenable();
|
|
|
|
const subMenuRef = useRef<HTMLDivElement>(null);
|
|
const iconRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (e: MouseEvent) => {
|
|
if (
|
|
subMenuRef.current &&
|
|
!subMenuRef.current.contains(e.target as Node) &&
|
|
iconRef.current &&
|
|
!iconRef.current.contains(e.target as Node)
|
|
) {
|
|
close();
|
|
}
|
|
};
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
}, [close]);
|
|
|
|
return (
|
|
<Rules mode={RulesMode.OPTIONAL} rules={items.flatMap((item) => item?.rules ?? [])}>
|
|
<div
|
|
className={classes["root"]}
|
|
onClick={toggle}
|
|
onMouseEnter={openOnHover ? handleMouseEnter : undefined}
|
|
onMouseLeave={openOnHover ? handleMouseLeave : undefined}>
|
|
<div ref={iconRef} className={classes["main"]}>
|
|
{children}
|
|
</div>
|
|
|
|
{((!openOnHover && isOpen) || (openOnHover && isHovered)) && (
|
|
<div className={classes["sub-menu"]} ref={subMenuRef} data-opening-side={openingSide}>
|
|
{items.map((item, index) => {
|
|
return (
|
|
<Rules mode={RulesMode.NECESSARY} rules={item.rules ?? []} key={item.link}>
|
|
<MenuItem item={item} key={index} />
|
|
</Rules>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Rules>
|
|
);
|
|
}
|