import React, {
createContext,
useContext,
useState,
useRef,
useEffect,
} from "react";
import { cn } from "@/lib/utils";
const DropdownContext = createContext(null);
export function DropdownMenu({ children }) {
const [open, setOpen] = useState(false);
const triggerRef = useRef(null);
// Close on outside click
useEffect(() => {
if (!open) return;
function handleClick(e) {
if (!triggerRef.current) return;
if (!triggerRef.current.parentElement.contains(e.target)) {
setOpen(false);
}
}
document.addEventListener("mousedown", handleClick);
return () => document.removeEventListener("mousedown", handleClick);
}, [open]);
return (
{children}
);
}
export function DropdownMenuTrigger({ asChild, children }) {
const { setOpen, triggerRef } = useContext(DropdownContext);
const handleClick = (e) => {
e.stopPropagation();
setOpen((o) => !o);
};
if (asChild && React.isValidElement(children)) {
return React.cloneElement(children, {
ref: triggerRef,
onClick: (e) => {
children.props.onClick?.(e);
handleClick(e);
},
});
}
return (
);
}
export function DropdownMenuContent({ className, align = "end", ...props }) {
const { open } = useContext(DropdownContext);
if (!open) return null;
const alignment =
align === "end"
? "right-0 origin-top-right"
: align === "start"
? "left-0 origin-top-left"
: "left-1/2 -translate-x-1/2 origin-top";
return (
);
}
export function DropdownMenuItem({ className, onClick, ...props }) {
const { setOpen } = useContext(DropdownContext);
const handleClick = (e) => {
onClick?.(e);
setOpen(false);
};
return (
);
}
export function DropdownMenuSeparator({ className }) {
return (
);
}