main
tsx 178 lines 7.02 KB
Raw
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 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground focus:bg-accent focus: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",
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 min-w-[8rem] 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 ));
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 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
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 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
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 = ContextMenuPrimitive.CheckboxItem.displayName;
112
113 const ContextMenuRadioItem = React.forwardRef<
114 React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
115 React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
116 >(({ className, children, ...props }, ref) => (
117 <ContextMenuPrimitive.RadioItem
118 ref={ref}
119 className={cn(
120 "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 focus:bg-accent focus:text-accent-foreground",
121 className,
122 )}
123 {...props}
124 >
125 <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
126 <ContextMenuPrimitive.ItemIndicator>
127 <Circle className="h-2 w-2 fill-current" />
128 </ContextMenuPrimitive.ItemIndicator>
129 </span>
130 {children}
131 </ContextMenuPrimitive.RadioItem>
132 ));
133 ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
134
135 const ContextMenuLabel = React.forwardRef<
136 React.ElementRef<typeof ContextMenuPrimitive.Label>,
137 React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
138 inset?: boolean;
139 }
140 >(({ className, inset, ...props }, ref) => (
141 <ContextMenuPrimitive.Label
142 ref={ref}
143 className={cn("px-2 py-1.5 text-sm font-semibold text-foreground", inset && "pl-8", className)}
144 {...props}
145 />
146 ));
147 ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
148
149 const ContextMenuSeparator = React.forwardRef<
150 React.ElementRef<typeof ContextMenuPrimitive.Separator>,
151 React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
152 >(({ className, ...props }, ref) => (
153 <ContextMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} />
154 ));
155 ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
156
157 const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
158 return <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />;
159 };
160 ContextMenuShortcut.displayName = "ContextMenuShortcut";
161
162 export {
163 ContextMenu,
164 ContextMenuTrigger,
165 ContextMenuContent,
166 ContextMenuItem,
167 ContextMenuCheckboxItem,
168 ContextMenuRadioItem,
169 ContextMenuLabel,
170 ContextMenuSeparator,
171 ContextMenuShortcut,
172 ContextMenuGroup,
173 ContextMenuPortal,
174 ContextMenuSub,
175 ContextMenuSubContent,
176 ContextMenuSubTrigger,
177 ContextMenuRadioGroup,
178 };