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