menubar.tsx
1 import * as React from "react" 2 import * as MenubarPrimitive from "@radix-ui/react-menubar" 3 import { Check, ChevronRight, Circle } from "lucide-react" 4 5 import { cn } from "@/lib/utils" 6 7 const MenubarMenu = MenubarPrimitive.Menu 8 9 const MenubarGroup = MenubarPrimitive.Group 10 11 const MenubarPortal = MenubarPrimitive.Portal 12 13 const MenubarSub = MenubarPrimitive.Sub 14 15 const MenubarRadioGroup = MenubarPrimitive.RadioGroup 16 17 const Menubar = React.forwardRef< 18 React.ElementRef<typeof MenubarPrimitive.Root>, 19 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root> 20 >(({ className, ...props }, ref) => ( 21 <MenubarPrimitive.Root 22 ref={ref} 23 className={cn( 24 "flex h-10 items-center space-x-1 rounded-md border bg-background p-1", 25 className 26 )} 27 {...props} 28 /> 29 )) 30 Menubar.displayName = MenubarPrimitive.Root.displayName 31 32 const MenubarTrigger = React.forwardRef< 33 React.ElementRef<typeof MenubarPrimitive.Trigger>, 34 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger> 35 >(({ className, ...props }, ref) => ( 36 <MenubarPrimitive.Trigger 37 ref={ref} 38 className={cn( 39 "flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", 40 className 41 )} 42 {...props} 43 /> 44 )) 45 MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName 46 47 const MenubarSubTrigger = React.forwardRef< 48 React.ElementRef<typeof MenubarPrimitive.SubTrigger>, 49 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & { 50 inset?: boolean 51 } 52 >(({ className, inset, children, ...props }, ref) => ( 53 <MenubarPrimitive.SubTrigger 54 ref={ref} 55 className={cn( 56 "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", 57 inset && "pl-8", 58 className 59 )} 60 {...props} 61 > 62 {children} 63 <ChevronRight className="ml-auto h-4 w-4" /> 64 </MenubarPrimitive.SubTrigger> 65 )) 66 MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName 67 68 const MenubarSubContent = React.forwardRef< 69 React.ElementRef<typeof MenubarPrimitive.SubContent>, 70 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent> 71 >(({ className, ...props }, ref) => ( 72 <MenubarPrimitive.SubContent 73 ref={ref} 74 className={cn( 75 "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground 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", 76 className 77 )} 78 {...props} 79 /> 80 )) 81 MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName 82 83 const MenubarContent = React.forwardRef< 84 React.ElementRef<typeof MenubarPrimitive.Content>, 85 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content> 86 >( 87 ( 88 { className, align = "start", alignOffset = -4, sideOffset = 8, ...props }, 89 ref 90 ) => ( 91 <MenubarPrimitive.Portal> 92 <MenubarPrimitive.Content 93 ref={ref} 94 align={align} 95 alignOffset={alignOffset} 96 sideOffset={sideOffset} 97 className={cn( 98 "z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in 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", 99 className 100 )} 101 {...props} 102 /> 103 </MenubarPrimitive.Portal> 104 ) 105 ) 106 MenubarContent.displayName = MenubarPrimitive.Content.displayName 107 108 const MenubarItem = React.forwardRef< 109 React.ElementRef<typeof MenubarPrimitive.Item>, 110 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & { 111 inset?: boolean 112 } 113 >(({ className, inset, ...props }, ref) => ( 114 <MenubarPrimitive.Item 115 ref={ref} 116 className={cn( 117 "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 118 inset && "pl-8", 119 className 120 )} 121 {...props} 122 /> 123 )) 124 MenubarItem.displayName = MenubarPrimitive.Item.displayName 125 126 const MenubarCheckboxItem = React.forwardRef< 127 React.ElementRef<typeof MenubarPrimitive.CheckboxItem>, 128 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem> 129 >(({ className, children, checked, ...props }, ref) => ( 130 <MenubarPrimitive.CheckboxItem 131 ref={ref} 132 className={cn( 133 "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 134 className 135 )} 136 checked={checked} 137 {...props} 138 > 139 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 140 <MenubarPrimitive.ItemIndicator> 141 <Check className="h-4 w-4" /> 142 </MenubarPrimitive.ItemIndicator> 143 </span> 144 {children} 145 </MenubarPrimitive.CheckboxItem> 146 )) 147 MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName 148 149 const MenubarRadioItem = React.forwardRef< 150 React.ElementRef<typeof MenubarPrimitive.RadioItem>, 151 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem> 152 >(({ className, children, ...props }, ref) => ( 153 <MenubarPrimitive.RadioItem 154 ref={ref} 155 className={cn( 156 "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 157 className 158 )} 159 {...props} 160 > 161 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 162 <MenubarPrimitive.ItemIndicator> 163 <Circle className="h-2 w-2 fill-current" /> 164 </MenubarPrimitive.ItemIndicator> 165 </span> 166 {children} 167 </MenubarPrimitive.RadioItem> 168 )) 169 MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName 170 171 const MenubarLabel = React.forwardRef< 172 React.ElementRef<typeof MenubarPrimitive.Label>, 173 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & { 174 inset?: boolean 175 } 176 >(({ className, inset, ...props }, ref) => ( 177 <MenubarPrimitive.Label 178 ref={ref} 179 className={cn( 180 "px-2 py-1.5 text-sm font-semibold", 181 inset && "pl-8", 182 className 183 )} 184 {...props} 185 /> 186 )) 187 MenubarLabel.displayName = MenubarPrimitive.Label.displayName 188 189 const MenubarSeparator = React.forwardRef< 190 React.ElementRef<typeof MenubarPrimitive.Separator>, 191 React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator> 192 >(({ className, ...props }, ref) => ( 193 <MenubarPrimitive.Separator 194 ref={ref} 195 className={cn("-mx-1 my-1 h-px bg-muted", className)} 196 {...props} 197 /> 198 )) 199 MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName 200 201 const MenubarShortcut = ({ 202 className, 203 ...props 204 }: React.HTMLAttributes<HTMLSpanElement>) => { 205 return ( 206 <span 207 className={cn( 208 "ml-auto text-xs tracking-widest text-muted-foreground", 209 className 210 )} 211 {...props} 212 /> 213 ) 214 } 215 MenubarShortcut.displayname = "MenubarShortcut" 216 217 export { 218 Menubar, 219 MenubarMenu, 220 MenubarTrigger, 221 MenubarContent, 222 MenubarItem, 223 MenubarSeparator, 224 MenubarLabel, 225 MenubarCheckboxItem, 226 MenubarRadioGroup, 227 MenubarRadioItem, 228 MenubarPortal, 229 MenubarSubContent, 230 MenubarSubTrigger, 231 MenubarGroup, 232 MenubarSub, 233 MenubarShortcut, 234 }