2024-07-25 12:30:02 +02:00

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>
);
}