1 import * as React from "react"
2 import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
3 import { Check, ChevronRight, Circle } from "lucide-react"
4
5 import { cn } from "@/lib/utils"
6
7 const ContextMenu = ContextMenuPrimitive.Root
8
9 const ContextMenuTrigger = ContextMenuPrimitive.Trigger
10
11 const ContextMenuGroup = ContextMenuPrimitive.Group
12
13 const ContextMenuPortal = ContextMenuPrimitive.Portal
14
15 const ContextMenuSub = ContextMenuPrimitive.Sub
16
17 const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
18
19 const 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-none 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 ))
38 ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
39
40 const 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-[8rem] 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 origin-[--radix-context-menu-content-transform-origin]",
48 className
49 )}
50 {...props}
51 />
52 ))
53 ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
54
55 const 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 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-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 origin-[--radix-context-menu-content-transform-origin]",
64 className
65 )}
66 {...props}
67 />
68 </ContextMenuPrimitive.Portal>
69 ))
70 ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
71
72 const 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-none 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 ))
88 ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
89
90 const 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-none 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 ))
111 ContextMenuCheckboxItem.displayName =
112 ContextMenuPrimitive.CheckboxItem.displayName
113
114 const 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-none 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 ))
134 ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
135
136 const 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 ))
152 ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
153
154 const 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 ))
164 ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
165
166 const 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 }
180 ContextMenuShortcut.displayName = "ContextMenuShortcut"
181
182 export {
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 }