104 lines
2.1 KiB
TypeScript
104 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useRef, useEffect, ReactNode } from "react";
|
|
import clsx from "clsx";
|
|
import styles from "@/styles/Dropdown.module.css";
|
|
|
|
interface DropdownItem {
|
|
text: string;
|
|
onClick: () => void;
|
|
}
|
|
|
|
interface DropdownProps {
|
|
trigger?: string;
|
|
triggerIcon?: string;
|
|
disabled?: boolean;
|
|
items?: DropdownItem[];
|
|
customContent?: ReactNode;
|
|
align?: "left" | "right";
|
|
}
|
|
|
|
export function Dropdown({
|
|
trigger,
|
|
triggerIcon,
|
|
disabled = false,
|
|
items = [],
|
|
customContent,
|
|
align = "left",
|
|
}: DropdownProps) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
function handleClickOutside(event: MouseEvent) {
|
|
if (
|
|
dropdownRef.current &&
|
|
!dropdownRef.current.contains(event.target as Node)
|
|
) {
|
|
setIsOpen(false);
|
|
}
|
|
}
|
|
|
|
if (isOpen) {
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
}
|
|
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
};
|
|
}, [isOpen]);
|
|
|
|
return (
|
|
<div
|
|
className={clsx(styles.dropdown, isOpen && styles.isActive)}
|
|
ref={dropdownRef}
|
|
>
|
|
<button
|
|
className={styles.dropdownTrigger}
|
|
type="button"
|
|
onClick={() => !disabled && setIsOpen(!isOpen)}
|
|
disabled={disabled}
|
|
>
|
|
{triggerIcon && <i className={`mdi mdi-${triggerIcon}`} />}
|
|
{trigger && <span>{trigger}</span>}
|
|
{!triggerIcon && !trigger && (
|
|
<i className="mdi mdi-dots-horizontal" />
|
|
)}
|
|
<i className="mdi mdi-menu-down" />
|
|
</button>
|
|
|
|
{isOpen && (
|
|
<div
|
|
className={clsx(
|
|
styles.dropdownMenu,
|
|
align === "right" && styles.alignRight,
|
|
)}
|
|
>
|
|
<div className={styles.dropdownContent}>
|
|
{customContent ? (
|
|
<div className={styles.dropdownItem}>
|
|
{customContent}
|
|
</div>
|
|
) : (
|
|
items.map((item, index) => (
|
|
<a
|
|
key={index}
|
|
href="#"
|
|
className={styles.dropdownItem}
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
item.onClick();
|
|
setIsOpen(false);
|
|
}}
|
|
>
|
|
{item.text}
|
|
</a>
|
|
))
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|