dropdown-menu.tsx
1 "use client" 2 3 import * as React from "react" 4 import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" 5 import { Check, ChevronRight, Circle } from "lucide-react" 6 7 import { cn } from "@/lib/utils" 8 9 const DropdownMenu = DropdownMenuPrimitive.Root 10 11 const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger 12 13 const DropdownMenuGroup = DropdownMenuPrimitive.Group 14 15 const DropdownMenuPortal = DropdownMenuPrimitive.Portal 16 17 const DropdownMenuSub = DropdownMenuPrimitive.Sub 18 19 const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup 20 21 const DropdownMenuSubTrigger = React.forwardRef< 22 React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, 23 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { 24 inset?: boolean 25 } 26 >(({ className, inset, children, ...props }, ref) => ( 27 <DropdownMenuPrimitive.SubTrigger 28 ref={ref} 29 className={cn( 30 "flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 31 inset && "pl-8", 32 className 33 )} 34 {...props} 35 > 36 {children} 37 <ChevronRight className="ml-auto" /> 38 </DropdownMenuPrimitive.SubTrigger> 39 )) 40 DropdownMenuSubTrigger.displayName = 41 DropdownMenuPrimitive.SubTrigger.displayName 42 43 const DropdownMenuSubContent = React.forwardRef< 44 React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, 45 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> 46 >(({ className, ...props }, ref) => ( 47 <DropdownMenuPrimitive.SubContent 48 ref={ref} 49 className={cn( 50 "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", 51 className 52 )} 53 {...props} 54 /> 55 )) 56 DropdownMenuSubContent.displayName = 57 DropdownMenuPrimitive.SubContent.displayName 58 59 const DropdownMenuContent = React.forwardRef< 60 React.ElementRef<typeof DropdownMenuPrimitive.Content>, 61 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> 62 >(({ className, sideOffset = 4, ...props }, ref) => ( 63 <DropdownMenuPrimitive.Portal> 64 <DropdownMenuPrimitive.Content 65 ref={ref} 66 sideOffset={sideOffset} 67 className={cn( 68 "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", 69 "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", 70 className 71 )} 72 {...props} 73 /> 74 </DropdownMenuPrimitive.Portal> 75 )) 76 DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName 77 78 const DropdownMenuItem = React.forwardRef< 79 React.ElementRef<typeof DropdownMenuPrimitive.Item>, 80 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { 81 inset?: boolean 82 } 83 >(({ className, inset, ...props }, ref) => ( 84 <DropdownMenuPrimitive.Item 85 ref={ref} 86 className={cn( 87 "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0", 88 inset && "pl-8", 89 className 90 )} 91 {...props} 92 /> 93 )) 94 DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName 95 96 const DropdownMenuCheckboxItem = React.forwardRef< 97 React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, 98 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> 99 >(({ className, children, checked, ...props }, ref) => ( 100 <DropdownMenuPrimitive.CheckboxItem 101 ref={ref} 102 className={cn( 103 "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 104 className 105 )} 106 checked={checked} 107 {...props} 108 > 109 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 110 <DropdownMenuPrimitive.ItemIndicator> 111 <Check className="h-4 w-4" /> 112 </DropdownMenuPrimitive.ItemIndicator> 113 </span> 114 {children} 115 </DropdownMenuPrimitive.CheckboxItem> 116 )) 117 DropdownMenuCheckboxItem.displayName = 118 DropdownMenuPrimitive.CheckboxItem.displayName 119 120 const DropdownMenuRadioItem = React.forwardRef< 121 React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, 122 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> 123 >(({ className, children, ...props }, ref) => ( 124 <DropdownMenuPrimitive.RadioItem 125 ref={ref} 126 className={cn( 127 "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 128 className 129 )} 130 {...props} 131 > 132 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 133 <DropdownMenuPrimitive.ItemIndicator> 134 <Circle className="h-2 w-2 fill-current" /> 135 </DropdownMenuPrimitive.ItemIndicator> 136 </span> 137 {children} 138 </DropdownMenuPrimitive.RadioItem> 139 )) 140 DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName 141 142 const DropdownMenuLabel = React.forwardRef< 143 React.ElementRef<typeof DropdownMenuPrimitive.Label>, 144 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { 145 inset?: boolean 146 } 147 >(({ className, inset, ...props }, ref) => ( 148 <DropdownMenuPrimitive.Label 149 ref={ref} 150 className={cn( 151 "px-2 py-1.5 text-sm font-semibold", 152 inset && "pl-8", 153 className 154 )} 155 {...props} 156 /> 157 )) 158 DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName 159 160 const DropdownMenuSeparator = React.forwardRef< 161 React.ElementRef<typeof DropdownMenuPrimitive.Separator>, 162 React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> 163 >(({ className, ...props }, ref) => ( 164 <DropdownMenuPrimitive.Separator 165 ref={ref} 166 className={cn("-mx-1 my-1 h-px bg-muted", className)} 167 {...props} 168 /> 169 )) 170 DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName 171 172 const DropdownMenuShortcut = ({ 173 className, 174 ...props 175 }: React.HTMLAttributes<HTMLSpanElement>) => { 176 return ( 177 <span 178 className={cn("ml-auto text-xs tracking-widest opacity-60", className)} 179 {...props} 180 /> 181 ) 182 } 183 DropdownMenuShortcut.displayName = "DropdownMenuShortcut" 184 185 export { 186 DropdownMenu, 187 DropdownMenuTrigger, 188 DropdownMenuContent, 189 DropdownMenuItem, 190 DropdownMenuCheckboxItem, 191 DropdownMenuRadioItem, 192 DropdownMenuLabel, 193 DropdownMenuSeparator, 194 DropdownMenuShortcut, 195 DropdownMenuGroup, 196 DropdownMenuPortal, 197 DropdownMenuSub, 198 DropdownMenuSubContent, 199 DropdownMenuSubTrigger, 200 DropdownMenuRadioGroup, 201 }