81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import * as React from "react";
|
|
import { ChevronDown } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export interface MenuItemProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
icon?: React.ReactNode;
|
|
title: string;
|
|
active?: boolean;
|
|
expanded?: boolean;
|
|
disabled?: boolean;
|
|
children?: React.ReactNode;
|
|
onClick?: () => void;
|
|
}
|
|
|
|
const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(
|
|
({ className, icon, title, active, expanded, disabled, children, onClick, ...props }, ref) => {
|
|
return (
|
|
<div ref={ref} className={cn("relative", className)} {...props}>
|
|
<div
|
|
className={cn(
|
|
"group flex cursor-pointer items-center rounded-lg px-3 py-2 text-sm font-medium",
|
|
"transition-all duration-200 ease-in-out",
|
|
"hover:bg-accent/50 hover:text-accent-foreground",
|
|
"dark:hover:bg-slate-800 dark:hover:text-slate-100",
|
|
active && "bg-accent text-accent-foreground dark:bg-slate-800 dark:text-slate-100",
|
|
disabled && "pointer-events-none opacity-50",
|
|
className
|
|
)}
|
|
onClick={onClick}
|
|
>
|
|
{icon && (
|
|
<span className={cn(
|
|
"mr-2 transition-colors",
|
|
"text-muted-foreground group-hover:text-current",
|
|
active && "text-current"
|
|
)}>
|
|
{icon}
|
|
</span>
|
|
)}
|
|
<span className="flex-1">{title}</span>
|
|
{children && (
|
|
<ChevronDown
|
|
className={cn(
|
|
"ml-1 h-4 w-4 transition-transform duration-200",
|
|
"text-muted-foreground group-hover:text-current",
|
|
active && "text-current",
|
|
expanded && "rotate-180"
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
{expanded && children && (
|
|
<div className={cn(
|
|
"mt-1 space-y-1 pl-4",
|
|
"animate-in slide-in-from-left-5 duration-200"
|
|
)}>
|
|
{children}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
MenuItem.displayName = "MenuItem";
|
|
|
|
const MenuGroup = React.forwardRef<
|
|
HTMLDivElement,
|
|
React.HTMLAttributes<HTMLDivElement>
|
|
>(({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"space-y-1.5 px-3",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
));
|
|
MenuGroup.displayName = "MenuGroup";
|
|
|
|
export { MenuItem, MenuGroup };
|