/ src / components / ui / menubar.tsx
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  }