Skip to content

Commit d2762aa

Browse files
authored
feat: add shadcn context menus (#5055)
* feat: add shadcn context menus * feat: adding Plasmic registrations for context-menu
1 parent 383a902 commit d2762aa

File tree

4 files changed

+445
-0
lines changed

4 files changed

+445
-0
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
"use client";
2+
3+
import * as React from "react";
4+
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
5+
import { Check, ChevronRight, Circle } from "lucide-react";
6+
import { CodeComponentMeta } from "@plasmicapp/loader-nextjs";
7+
import { cn } from "@/lib/utils";
8+
9+
const ContextMenu = ContextMenuPrimitive.Root;
10+
11+
export const ContextMenuMeta: CodeComponentMeta<
12+
React.ComponentProps<typeof ContextMenu>
13+
> = {
14+
name: "ContextMenu",
15+
description: "shadcn/ui ContextMenu component",
16+
props: {
17+
children: "slot",
18+
},
19+
};
20+
21+
const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
22+
23+
export const ContextMenuTriggerMeta: CodeComponentMeta<
24+
React.ComponentProps<typeof ContextMenuTrigger>
25+
> = {
26+
name: "ContextMenuTrigger",
27+
description: "shadcn/ui ContextMenuTrigger component",
28+
props: {
29+
children: "slot",
30+
},
31+
};
32+
33+
const ContextMenuGroup = ContextMenuPrimitive.Group;
34+
35+
export const ContextMenuGroupMeta: CodeComponentMeta<
36+
React.ComponentProps<typeof ContextMenuGroup>
37+
> = {
38+
name: "ContextMenuGroup",
39+
description: "shadcn/ui ContextMenuGroup component",
40+
props: {
41+
children: "slot",
42+
},
43+
};
44+
45+
const ContextMenuPortal = ContextMenuPrimitive.Portal;
46+
47+
const ContextMenuSub = ContextMenuPrimitive.Sub;
48+
49+
export const ContextMenuSubMeta: CodeComponentMeta<
50+
React.ComponentProps<typeof ContextMenuSub>
51+
> = {
52+
name: "ContextMenuSub",
53+
description: "shadcn/ui ContextMenuSub component",
54+
props: {
55+
children: "slot",
56+
},
57+
};
58+
59+
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
60+
61+
export const ContextMenuRadioGroupMeta: CodeComponentMeta<
62+
React.ComponentProps<typeof ContextMenuRadioGroup>
63+
> = {
64+
name: "ContextMenuRadioGroup",
65+
description: "shadcn/ui ContextMenuRadioGroup component",
66+
props: {
67+
children: "slot",
68+
value: "string",
69+
},
70+
};
71+
72+
type ContextMenuSubTriggerProps = React.ComponentPropsWithoutRef<
73+
typeof ContextMenuPrimitive.SubTrigger
74+
> & {
75+
inset?: boolean;
76+
};
77+
78+
export const ContextMenuSubTriggerMeta: CodeComponentMeta<ContextMenuSubTriggerProps> =
79+
{
80+
name: "ContextMenuSubTrigger",
81+
description: "shadcn/ui ContextMenuSubTrigger component",
82+
props: {
83+
children: "slot",
84+
inset: "boolean",
85+
},
86+
};
87+
88+
const ContextMenuSubTrigger = React.forwardRef<
89+
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
90+
ContextMenuSubTriggerProps
91+
>(({ className, inset, children, ...props }, ref) => (
92+
<ContextMenuPrimitive.SubTrigger
93+
ref={ref}
94+
className={cn(
95+
"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",
96+
inset && "pl-8",
97+
className,
98+
)}
99+
{...props}
100+
>
101+
{children}
102+
<ChevronRight className="ml-auto h-4 w-4" />
103+
</ContextMenuPrimitive.SubTrigger>
104+
));
105+
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
106+
107+
type ContextMenuSubContentProps = React.ComponentPropsWithoutRef<
108+
typeof ContextMenuPrimitive.SubContent
109+
>;
110+
111+
export const ContextMenuSubContentMeta: CodeComponentMeta<ContextMenuSubContentProps> =
112+
{
113+
name: "ContextMenuSubContent",
114+
description: "shadcn/ui ContextMenuSubContent component",
115+
props: {
116+
children: "slot",
117+
},
118+
};
119+
120+
const ContextMenuSubContent = React.forwardRef<
121+
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
122+
ContextMenuSubContentProps
123+
>(({ className, ...props }, ref) => (
124+
<ContextMenuPrimitive.SubContent
125+
ref={ref}
126+
className={cn(
127+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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]",
128+
className,
129+
)}
130+
{...props}
131+
/>
132+
));
133+
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
134+
135+
type ContextMenuContentProps = React.ComponentPropsWithoutRef<
136+
typeof ContextMenuPrimitive.Content
137+
>;
138+
139+
export const ContextMenuContentMeta: CodeComponentMeta<ContextMenuContentProps> =
140+
{
141+
name: "ContextMenuContent",
142+
description: "shadcn/ui ContextMenuContent component",
143+
props: {
144+
children: "slot",
145+
},
146+
};
147+
148+
const ContextMenuContent = React.forwardRef<
149+
React.ElementRef<typeof ContextMenuPrimitive.Content>,
150+
ContextMenuContentProps
151+
>(({ className, ...props }, ref) => (
152+
<ContextMenuPrimitive.Portal>
153+
<ContextMenuPrimitive.Content
154+
ref={ref}
155+
className={cn(
156+
"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 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]",
157+
className,
158+
)}
159+
{...props}
160+
/>
161+
</ContextMenuPrimitive.Portal>
162+
));
163+
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
164+
165+
type ContextMenuItemProps = React.ComponentPropsWithoutRef<
166+
typeof ContextMenuPrimitive.Item
167+
> & {
168+
inset?: boolean;
169+
};
170+
171+
export const ContextMenuItemMeta: CodeComponentMeta<ContextMenuItemProps> = {
172+
name: "ContextMenuItem",
173+
description: "shadcn/ui ContextMenuItem component",
174+
props: {
175+
children: "slot",
176+
inset: "boolean",
177+
},
178+
};
179+
180+
const ContextMenuItem = React.forwardRef<
181+
React.ElementRef<typeof ContextMenuPrimitive.Item>,
182+
ContextMenuItemProps
183+
>(({ className, inset, ...props }, ref) => (
184+
<ContextMenuPrimitive.Item
185+
ref={ref}
186+
className={cn(
187+
"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",
188+
inset && "pl-8",
189+
className,
190+
)}
191+
{...props}
192+
/>
193+
));
194+
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
195+
196+
type ContextMenuCheckboxItemProps = React.ComponentPropsWithoutRef<
197+
typeof ContextMenuPrimitive.CheckboxItem
198+
>;
199+
200+
export const ContextMenuCheckboxItemMeta: CodeComponentMeta<ContextMenuCheckboxItemProps> =
201+
{
202+
name: "ContextMenuCheckboxItem",
203+
description: "shadcn/ui ContextMenuCheckboxItem component",
204+
props: {
205+
children: "slot",
206+
checked: "boolean",
207+
},
208+
};
209+
210+
const ContextMenuCheckboxItem = React.forwardRef<
211+
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
212+
ContextMenuCheckboxItemProps
213+
>(({ className, children, checked, ...props }, ref) => (
214+
<ContextMenuPrimitive.CheckboxItem
215+
ref={ref}
216+
className={cn(
217+
"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",
218+
className,
219+
)}
220+
checked={checked}
221+
{...props}
222+
>
223+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
224+
<ContextMenuPrimitive.ItemIndicator>
225+
<Check className="h-4 w-4" />
226+
</ContextMenuPrimitive.ItemIndicator>
227+
</span>
228+
{children}
229+
</ContextMenuPrimitive.CheckboxItem>
230+
));
231+
ContextMenuCheckboxItem.displayName =
232+
ContextMenuPrimitive.CheckboxItem.displayName;
233+
234+
type ContextMenuRadioItemProps = React.ComponentPropsWithoutRef<
235+
typeof ContextMenuPrimitive.RadioItem
236+
>;
237+
238+
export const ContextMenuRadioItemMeta: CodeComponentMeta<ContextMenuRadioItemProps> =
239+
{
240+
name: "ContextMenuRadioItem",
241+
description: "shadcn/ui ContextMenuRadioItem component",
242+
props: {
243+
children: "slot",
244+
value: "string",
245+
},
246+
};
247+
248+
const ContextMenuRadioItem = React.forwardRef<
249+
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
250+
ContextMenuRadioItemProps
251+
>(({ className, children, ...props }, ref) => (
252+
<ContextMenuPrimitive.RadioItem
253+
ref={ref}
254+
className={cn(
255+
"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",
256+
className,
257+
)}
258+
{...props}
259+
>
260+
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
261+
<ContextMenuPrimitive.ItemIndicator>
262+
<Circle className="h-4 w-4 fill-current" />
263+
</ContextMenuPrimitive.ItemIndicator>
264+
</span>
265+
{children}
266+
</ContextMenuPrimitive.RadioItem>
267+
));
268+
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
269+
270+
type ContextMenuLabelProps = React.ComponentPropsWithoutRef<
271+
typeof ContextMenuPrimitive.Label
272+
> & {
273+
inset?: boolean;
274+
};
275+
276+
export const ContextMenuLabelMeta: CodeComponentMeta<ContextMenuLabelProps> = {
277+
name: "ContextMenuLabel",
278+
description: "shadcn/ui ContextMenuLabel component",
279+
props: {
280+
children: "slot",
281+
inset: "boolean",
282+
},
283+
};
284+
285+
const ContextMenuLabel = React.forwardRef<
286+
React.ElementRef<typeof ContextMenuPrimitive.Label>,
287+
ContextMenuLabelProps
288+
>(({ className, inset, ...props }, ref) => (
289+
<ContextMenuPrimitive.Label
290+
ref={ref}
291+
className={cn(
292+
"px-2 py-1.5 text-sm font-semibold text-foreground",
293+
inset && "pl-8",
294+
className,
295+
)}
296+
{...props}
297+
/>
298+
));
299+
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
300+
301+
type ContextMenuSeparatorProps = React.ComponentPropsWithoutRef<
302+
typeof ContextMenuPrimitive.Separator
303+
>;
304+
305+
export const ContextMenuSeparatorMeta: CodeComponentMeta<ContextMenuSeparatorProps> =
306+
{
307+
name: "ContextMenuSeparator",
308+
description: "shadcn/ui ContextMenuSeparator component",
309+
props: {},
310+
};
311+
312+
const ContextMenuSeparator = React.forwardRef<
313+
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
314+
ContextMenuSeparatorProps
315+
>(({ className, ...props }, ref) => (
316+
<ContextMenuPrimitive.Separator
317+
ref={ref}
318+
className={cn("-mx-1 my-1 h-px bg-border", className)}
319+
{...props}
320+
/>
321+
));
322+
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
323+
324+
type ContextMenuShortcutProps = React.HTMLAttributes<HTMLSpanElement>;
325+
326+
export const ContextMenuShortcutMeta: CodeComponentMeta<ContextMenuShortcutProps> =
327+
{
328+
name: "ContextMenuShortcut",
329+
description: "shadcn/ui ContextMenuShortcut component",
330+
props: {
331+
children: "slot",
332+
},
333+
};
334+
335+
const ContextMenuShortcut = ({
336+
className,
337+
...props
338+
}: ContextMenuShortcutProps) => {
339+
return (
340+
<span
341+
className={cn(
342+
"ml-auto text-xs tracking-widest text-muted-foreground",
343+
className,
344+
)}
345+
{...props}
346+
/>
347+
);
348+
};
349+
ContextMenuShortcut.displayName = "ContextMenuShortcut";
350+
351+
export {
352+
ContextMenu,
353+
ContextMenuTrigger,
354+
ContextMenuContent,
355+
ContextMenuItem,
356+
ContextMenuCheckboxItem,
357+
ContextMenuRadioItem,
358+
ContextMenuLabel,
359+
ContextMenuSeparator,
360+
ContextMenuShortcut,
361+
ContextMenuGroup,
362+
ContextMenuPortal,
363+
ContextMenuSub,
364+
ContextMenuSubContent,
365+
ContextMenuSubTrigger,
366+
ContextMenuRadioGroup,
367+
};

0 commit comments

Comments
 (0)