sonance-brand-mcp 1.2.4 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/assets/components/alert-dialog.stories.tsx +142 -0
  2. package/dist/assets/components/alert-dialog.tsx +142 -0
  3. package/dist/assets/components/aspect-ratio.stories.tsx +67 -0
  4. package/dist/assets/components/aspect-ratio.tsx +8 -0
  5. package/dist/assets/components/avatar.tsx +64 -20
  6. package/dist/assets/components/carousel.stories.tsx +158 -0
  7. package/dist/assets/components/carousel.tsx +262 -0
  8. package/dist/assets/components/chart.stories.tsx +376 -0
  9. package/dist/assets/components/chart.tsx +384 -0
  10. package/dist/assets/components/checkbox.tsx +12 -2
  11. package/dist/assets/components/code.tsx +22 -20
  12. package/dist/assets/components/collapsible.stories.tsx +128 -0
  13. package/dist/assets/components/collapsible.tsx +10 -0
  14. package/dist/assets/components/command.stories.tsx +183 -0
  15. package/dist/assets/components/command.tsx +170 -0
  16. package/dist/assets/components/context-menu.stories.tsx +159 -0
  17. package/dist/assets/components/context-menu.tsx +218 -0
  18. package/dist/assets/components/divider.tsx +38 -35
  19. package/dist/assets/components/dropdown-menu.tsx +217 -0
  20. package/dist/assets/components/hover-card.stories.tsx +113 -0
  21. package/dist/assets/components/hover-card.tsx +35 -0
  22. package/dist/assets/components/kbd.tsx +6 -6
  23. package/dist/assets/components/menubar.stories.tsx +208 -0
  24. package/dist/assets/components/menubar.tsx +251 -0
  25. package/dist/assets/components/navigation-menu.stories.tsx +237 -0
  26. package/dist/assets/components/navigation-menu.tsx +135 -0
  27. package/dist/assets/components/resizable.stories.tsx +197 -0
  28. package/dist/assets/components/resizable.tsx +47 -0
  29. package/dist/assets/components/scroll-area.stories.tsx +123 -0
  30. package/dist/assets/components/scroll-area.tsx +48 -0
  31. package/dist/assets/components/scroll-shadow.tsx +29 -7
  32. package/dist/assets/components/separator.tsx +32 -0
  33. package/dist/assets/components/sheet.tsx +141 -0
  34. package/dist/assets/components/sidebar.stories.tsx +351 -0
  35. package/dist/assets/components/sidebar.tsx +760 -0
  36. package/dist/assets/components/toggle-group.stories.tsx +153 -0
  37. package/dist/assets/components/toggle-group.tsx +61 -0
  38. package/dist/assets/components/toggle.stories.tsx +77 -0
  39. package/dist/assets/components/toggle.tsx +46 -0
  40. package/dist/assets/components/tooltip.tsx +23 -90
  41. package/dist/assets/globals.css +30 -0
  42. package/dist/assets/logos/40th-anniversary/Sonance_40_Logo_CMYK_BEAM_BLUE_40_AND_BEAM_DARK.png +0 -0
  43. package/dist/assets/logos/Sonance logo dark mode.png +0 -0
  44. package/dist/assets/logos/Sonance logo light mode.png +0 -0
  45. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_2C_Light_RGB_05162025.png +0 -0
  46. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_3C_Dark_RGB_05162025.png +0 -0
  47. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_White_RGB_05162025.png +0 -0
  48. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Dark_RGB.png +0 -0
  49. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Light_RGB.png +0 -0
  50. package/dist/assets/logos/james/James_Logo_Black_CMYK.png +0 -0
  51. package/dist/assets/logos/james/James_Logo_Black_RGB.png +0 -0
  52. package/dist/assets/logos/james/James_Logo_LtGray_CMYK.png +0 -0
  53. package/dist/assets/logos/james/James_Logo_LtGray_RGB.png +0 -0
  54. package/dist/assets/logos/james/James_Logo_Polished_RGB.png +0 -0
  55. package/dist/assets/logos/james/James_Logo_Reverse_CMYK.png +0 -0
  56. package/dist/assets/logos/james/James_Logo_Reverse_RGB.png +0 -0
  57. package/dist/assets/logos/james/James_Logo_White_CMYK.png +0 -0
  58. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Dark_RGB.png +0 -0
  59. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Light_RGB.png +0 -0
  60. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Dark_RGB.png +0 -0
  61. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Light_RGB.png +0 -0
  62. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Reverse_RGB.png +0 -0
  63. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Black_RGB.png +0 -0
  64. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Reverse_RGB.png +0 -0
  65. package/dist/assets/logos/sonance/Sonance_Logo_2C_Dark_RGB.png +0 -0
  66. package/dist/assets/logos/sonance/Sonance_Logo_2C_Light_RGB.png +0 -0
  67. package/dist/assets/logos/sonance/Sonance_Logo_2C_Reverse_RGB.png +0 -0
  68. package/dist/assets/logos/sonance/Sonance_Logo_Black_RGB.png +0 -0
  69. package/dist/assets/logos/sonance/Sonance_Logo_Grayscale_RGB.png +0 -0
  70. package/dist/assets/logos/sonance/Sonance_Logo_Reverse_RGB.png +0 -0
  71. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Dark_CMYK.png +0 -0
  72. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Light_CMYK.png +0 -0
  73. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Dark_RGB.png +0 -0
  74. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Light_RGB.png +0 -0
  75. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Reverse_RGB.png +0 -0
  76. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Black_RGB.png +0 -0
  77. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Grayscale_RGB.png +0 -0
  78. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Reverse_RGB.png +0 -0
  79. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Dark.png +0 -0
  80. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Light.png +0 -0
  81. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Dark.png +0 -0
  82. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Light.png +0 -0
  83. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Dark.png +0 -0
  84. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Light.png +0 -0
  85. package/dist/assets/logos/trufig/TrufigLogo_Black.png +0 -0
  86. package/dist/assets/logos/trufig/TrufigLogo_Light.png +0 -0
  87. package/dist/assets/logos/trufig/TrufigWatermark_Black.png +0 -0
  88. package/dist/assets/logos/trufig/TrufigWatermark_Light.png +0 -0
  89. package/dist/index.js +416 -17
  90. package/package.json +1 -1
@@ -0,0 +1,183 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+ import { useState, useEffect } from "react";
5
+ import {
6
+ Calculator,
7
+ Calendar,
8
+ CreditCard,
9
+ Settings,
10
+ Smile,
11
+ User,
12
+ } from "lucide-react";
13
+ import {
14
+ Command,
15
+ CommandDialog,
16
+ CommandEmpty,
17
+ CommandGroup,
18
+ CommandInput,
19
+ CommandItem,
20
+ CommandList,
21
+ CommandSeparator,
22
+ CommandShortcut,
23
+ } from "./command";
24
+
25
+ const meta: Meta<typeof Command> = {
26
+ title: "Components/Forms/Command",
27
+ component: Command,
28
+ parameters: {
29
+ layout: "centered",
30
+ },
31
+ tags: ["autodocs"],
32
+ };
33
+
34
+ export default meta;
35
+ type Story = StoryObj<typeof Command>;
36
+
37
+ export const Default: Story = {
38
+ render: () => (
39
+ <Command className="rounded-sm border border-border shadow-md w-[400px]">
40
+ <CommandInput placeholder="Type a command or search..." />
41
+ <CommandList>
42
+ <CommandEmpty>No results found.</CommandEmpty>
43
+ <CommandGroup heading="Suggestions">
44
+ <CommandItem>
45
+ <Calendar className="mr-2 h-4 w-4" />
46
+ <span>Calendar</span>
47
+ </CommandItem>
48
+ <CommandItem>
49
+ <Smile className="mr-2 h-4 w-4" />
50
+ <span>Search Emoji</span>
51
+ </CommandItem>
52
+ <CommandItem>
53
+ <Calculator className="mr-2 h-4 w-4" />
54
+ <span>Calculator</span>
55
+ </CommandItem>
56
+ </CommandGroup>
57
+ <CommandSeparator />
58
+ <CommandGroup heading="Settings">
59
+ <CommandItem>
60
+ <User className="mr-2 h-4 w-4" />
61
+ <span>Profile</span>
62
+ <CommandShortcut>⌘P</CommandShortcut>
63
+ </CommandItem>
64
+ <CommandItem>
65
+ <CreditCard className="mr-2 h-4 w-4" />
66
+ <span>Billing</span>
67
+ <CommandShortcut>⌘B</CommandShortcut>
68
+ </CommandItem>
69
+ <CommandItem>
70
+ <Settings className="mr-2 h-4 w-4" />
71
+ <span>Settings</span>
72
+ <CommandShortcut>⌘S</CommandShortcut>
73
+ </CommandItem>
74
+ </CommandGroup>
75
+ </CommandList>
76
+ </Command>
77
+ ),
78
+ };
79
+
80
+ function CommandDialogDemo() {
81
+ const [open, setOpen] = useState(false);
82
+
83
+ useEffect(() => {
84
+ const down = (e: KeyboardEvent) => {
85
+ if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
86
+ e.preventDefault();
87
+ setOpen((open) => !open);
88
+ }
89
+ };
90
+
91
+ document.addEventListener("keydown", down);
92
+ return () => document.removeEventListener("keydown", down);
93
+ }, []);
94
+
95
+ return (
96
+ <>
97
+ <p className="text-sm text-foreground-muted">
98
+ Press{" "}
99
+ <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-card px-1.5 font-mono text-[10px] font-medium text-foreground-muted opacity-100">
100
+ <span className="text-xs">⌘</span>K
101
+ </kbd>
102
+ </p>
103
+ <CommandDialog open={open} onOpenChange={setOpen}>
104
+ <CommandInput placeholder="Type a command or search..." />
105
+ <CommandList>
106
+ <CommandEmpty>No results found.</CommandEmpty>
107
+ <CommandGroup heading="Suggestions">
108
+ <CommandItem>
109
+ <Calendar className="mr-2 h-4 w-4" />
110
+ <span>Calendar</span>
111
+ </CommandItem>
112
+ <CommandItem>
113
+ <Smile className="mr-2 h-4 w-4" />
114
+ <span>Search Emoji</span>
115
+ </CommandItem>
116
+ <CommandItem>
117
+ <Calculator className="mr-2 h-4 w-4" />
118
+ <span>Calculator</span>
119
+ </CommandItem>
120
+ </CommandGroup>
121
+ <CommandSeparator />
122
+ <CommandGroup heading="Settings">
123
+ <CommandItem>
124
+ <User className="mr-2 h-4 w-4" />
125
+ <span>Profile</span>
126
+ <CommandShortcut>⌘P</CommandShortcut>
127
+ </CommandItem>
128
+ <CommandItem>
129
+ <CreditCard className="mr-2 h-4 w-4" />
130
+ <span>Billing</span>
131
+ <CommandShortcut>⌘B</CommandShortcut>
132
+ </CommandItem>
133
+ <CommandItem>
134
+ <Settings className="mr-2 h-4 w-4" />
135
+ <span>Settings</span>
136
+ <CommandShortcut>⌘S</CommandShortcut>
137
+ </CommandItem>
138
+ </CommandGroup>
139
+ </CommandList>
140
+ </CommandDialog>
141
+ </>
142
+ );
143
+ }
144
+
145
+ export const Dialog: Story = {
146
+ render: () => <CommandDialogDemo />,
147
+ };
148
+
149
+ export const Simple: Story = {
150
+ render: () => (
151
+ <Command className="rounded-sm border border-border shadow-md w-[300px]">
152
+ <CommandInput placeholder="Search products..." />
153
+ <CommandList>
154
+ <CommandEmpty>No products found.</CommandEmpty>
155
+ <CommandGroup heading="Products">
156
+ <CommandItem>Architectural Speakers</CommandItem>
157
+ <CommandItem>Outdoor Speakers</CommandItem>
158
+ <CommandItem>Subwoofers</CommandItem>
159
+ <CommandItem>Amplifiers</CommandItem>
160
+ <CommandItem>Accessories</CommandItem>
161
+ </CommandGroup>
162
+ </CommandList>
163
+ </Command>
164
+ ),
165
+ };
166
+
167
+ export const WithDisabledItems: Story = {
168
+ render: () => (
169
+ <Command className="rounded-sm border border-border shadow-md w-[350px]">
170
+ <CommandInput placeholder="Search..." />
171
+ <CommandList>
172
+ <CommandEmpty>No results found.</CommandEmpty>
173
+ <CommandGroup heading="Actions">
174
+ <CommandItem>Create new project</CommandItem>
175
+ <CommandItem>Open existing project</CommandItem>
176
+ <CommandItem disabled>Import from Figma (Pro)</CommandItem>
177
+ <CommandItem disabled>Export to PDF (Pro)</CommandItem>
178
+ </CommandGroup>
179
+ </CommandList>
180
+ </Command>
181
+ ),
182
+ };
183
+
@@ -0,0 +1,170 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Command as CommandPrimitive } from "cmdk";
5
+ import { Search } from "lucide-react";
6
+ import { cn } from "@/lib/utils";
7
+ import {
8
+ Dialog,
9
+ DialogContent,
10
+ DialogTitle,
11
+ } from "@/components/ui/dialog";
12
+
13
+ const Command = React.forwardRef<
14
+ React.ElementRef<typeof CommandPrimitive>,
15
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive>
16
+ >(({ className, ...props }, ref) => (
17
+ <CommandPrimitive
18
+ ref={ref}
19
+ className={cn(
20
+ "flex h-full w-full flex-col overflow-hidden rounded-sm bg-card text-foreground",
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ ));
26
+ Command.displayName = CommandPrimitive.displayName;
27
+
28
+ interface CommandDialogProps {
29
+ open?: boolean;
30
+ onOpenChange?: (open: boolean) => void;
31
+ children: React.ReactNode;
32
+ }
33
+
34
+ const CommandDialog = ({ children, open, onOpenChange }: CommandDialogProps) => {
35
+ const handleClose = React.useCallback(() => {
36
+ onOpenChange?.(false);
37
+ }, [onOpenChange]);
38
+
39
+ return (
40
+ <Dialog open={open ?? false} onClose={handleClose}>
41
+ <DialogContent className="overflow-hidden p-0 shadow-lg" showClose={false}>
42
+ <DialogTitle className="sr-only">Command Menu</DialogTitle>
43
+ <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-foreground-muted [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
44
+ {children}
45
+ </Command>
46
+ </DialogContent>
47
+ </Dialog>
48
+ );
49
+ };
50
+
51
+ const CommandInput = React.forwardRef<
52
+ React.ElementRef<typeof CommandPrimitive.Input>,
53
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
54
+ >(({ className, ...props }, ref) => (
55
+ <div className="flex items-center border-b border-border px-3" cmdk-input-wrapper="">
56
+ <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
57
+ <CommandPrimitive.Input
58
+ ref={ref}
59
+ className={cn(
60
+ "flex h-11 w-full rounded-sm bg-transparent py-3 text-sm outline-none placeholder:text-foreground-muted disabled:cursor-not-allowed disabled:opacity-50",
61
+ className
62
+ )}
63
+ {...props}
64
+ />
65
+ </div>
66
+ ));
67
+
68
+ CommandInput.displayName = CommandPrimitive.Input.displayName;
69
+
70
+ const CommandList = React.forwardRef<
71
+ React.ElementRef<typeof CommandPrimitive.List>,
72
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
73
+ >(({ className, ...props }, ref) => (
74
+ <CommandPrimitive.List
75
+ ref={ref}
76
+ className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
77
+ {...props}
78
+ />
79
+ ));
80
+
81
+ CommandList.displayName = CommandPrimitive.List.displayName;
82
+
83
+ const CommandEmpty = React.forwardRef<
84
+ React.ElementRef<typeof CommandPrimitive.Empty>,
85
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
86
+ >((props, ref) => (
87
+ <CommandPrimitive.Empty
88
+ ref={ref}
89
+ className="py-6 text-center text-sm text-foreground-muted"
90
+ {...props}
91
+ />
92
+ ));
93
+
94
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
95
+
96
+ const CommandGroup = React.forwardRef<
97
+ React.ElementRef<typeof CommandPrimitive.Group>,
98
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
99
+ >(({ className, ...props }, ref) => (
100
+ <CommandPrimitive.Group
101
+ ref={ref}
102
+ className={cn(
103
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-widest [&_[cmdk-group-heading]]:text-foreground-muted",
104
+ className
105
+ )}
106
+ {...props}
107
+ />
108
+ ));
109
+
110
+ CommandGroup.displayName = CommandPrimitive.Group.displayName;
111
+
112
+ const CommandSeparator = React.forwardRef<
113
+ React.ElementRef<typeof CommandPrimitive.Separator>,
114
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
115
+ >(({ className, ...props }, ref) => (
116
+ <CommandPrimitive.Separator
117
+ ref={ref}
118
+ className={cn("-mx-1 h-px bg-border", className)}
119
+ {...props}
120
+ />
121
+ ));
122
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
123
+
124
+ const CommandItem = React.forwardRef<
125
+ React.ElementRef<typeof CommandPrimitive.Item>,
126
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
127
+ >(({ className, ...props }, ref) => (
128
+ <CommandPrimitive.Item
129
+ ref={ref}
130
+ className={cn(
131
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none",
132
+ "data-[selected=true]:bg-secondary-hover data-[selected=true]:text-foreground",
133
+ "data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
134
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
135
+ className
136
+ )}
137
+ {...props}
138
+ />
139
+ ));
140
+
141
+ CommandItem.displayName = CommandPrimitive.Item.displayName;
142
+
143
+ const CommandShortcut = ({
144
+ className,
145
+ ...props
146
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
147
+ return (
148
+ <span
149
+ className={cn(
150
+ "ml-auto text-xs tracking-widest text-foreground-muted",
151
+ className
152
+ )}
153
+ {...props}
154
+ />
155
+ );
156
+ };
157
+ CommandShortcut.displayName = "CommandShortcut";
158
+
159
+ export {
160
+ Command,
161
+ CommandDialog,
162
+ CommandInput,
163
+ CommandList,
164
+ CommandEmpty,
165
+ CommandGroup,
166
+ CommandItem,
167
+ CommandShortcut,
168
+ CommandSeparator,
169
+ };
170
+
@@ -0,0 +1,159 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+ import { useState } from "react";
5
+ import {
6
+ ContextMenu,
7
+ ContextMenuCheckboxItem,
8
+ ContextMenuContent,
9
+ ContextMenuItem,
10
+ ContextMenuLabel,
11
+ ContextMenuRadioGroup,
12
+ ContextMenuRadioItem,
13
+ ContextMenuSeparator,
14
+ ContextMenuShortcut,
15
+ ContextMenuSub,
16
+ ContextMenuSubContent,
17
+ ContextMenuSubTrigger,
18
+ ContextMenuTrigger,
19
+ } from "./context-menu";
20
+
21
+ const meta: Meta<typeof ContextMenu> = {
22
+ title: "Components/Navigation/ContextMenu",
23
+ component: ContextMenu,
24
+ parameters: {
25
+ layout: "centered",
26
+ },
27
+ tags: ["autodocs"],
28
+ };
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof ContextMenu>;
32
+
33
+ export const Default: Story = {
34
+ render: () => (
35
+ <ContextMenu>
36
+ <ContextMenuTrigger className="flex h-[150px] w-[300px] items-center justify-center rounded-sm border border-dashed border-border text-sm text-foreground-muted">
37
+ Right click here
38
+ </ContextMenuTrigger>
39
+ <ContextMenuContent className="w-64">
40
+ <ContextMenuItem>
41
+ Back
42
+ <ContextMenuShortcut>⌘[</ContextMenuShortcut>
43
+ </ContextMenuItem>
44
+ <ContextMenuItem disabled>
45
+ Forward
46
+ <ContextMenuShortcut>⌘]</ContextMenuShortcut>
47
+ </ContextMenuItem>
48
+ <ContextMenuItem>
49
+ Reload
50
+ <ContextMenuShortcut>⌘R</ContextMenuShortcut>
51
+ </ContextMenuItem>
52
+ <ContextMenuSub>
53
+ <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
54
+ <ContextMenuSubContent className="w-48">
55
+ <ContextMenuItem>
56
+ Save Page As...
57
+ <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
58
+ </ContextMenuItem>
59
+ <ContextMenuItem>Create Shortcut...</ContextMenuItem>
60
+ <ContextMenuItem>Name Window...</ContextMenuItem>
61
+ <ContextMenuSeparator />
62
+ <ContextMenuItem>Developer Tools</ContextMenuItem>
63
+ </ContextMenuSubContent>
64
+ </ContextMenuSub>
65
+ <ContextMenuSeparator />
66
+ <ContextMenuCheckboxItem checked>
67
+ Show Bookmarks Bar
68
+ <ContextMenuShortcut>⌘⇧B</ContextMenuShortcut>
69
+ </ContextMenuCheckboxItem>
70
+ <ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem>
71
+ <ContextMenuSeparator />
72
+ <ContextMenuRadioGroup value="pedro">
73
+ <ContextMenuLabel inset>People</ContextMenuLabel>
74
+ <ContextMenuRadioItem value="pedro">
75
+ Pedro Duarte
76
+ </ContextMenuRadioItem>
77
+ <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
78
+ </ContextMenuRadioGroup>
79
+ </ContextMenuContent>
80
+ </ContextMenu>
81
+ ),
82
+ };
83
+
84
+ function ContextMenuWithStateDemo() {
85
+ const [bookmarksChecked, setBookmarksChecked] = useState(true);
86
+ const [urlsChecked, setUrlsChecked] = useState(false);
87
+ const [person, setPerson] = useState("pedro");
88
+
89
+ return (
90
+ <ContextMenu>
91
+ <ContextMenuTrigger className="flex h-[150px] w-[300px] items-center justify-center rounded-sm border border-dashed border-border text-sm text-foreground-muted">
92
+ Right click here
93
+ </ContextMenuTrigger>
94
+ <ContextMenuContent className="w-64">
95
+ <ContextMenuItem>New Tab</ContextMenuItem>
96
+ <ContextMenuItem>New Window</ContextMenuItem>
97
+ <ContextMenuSeparator />
98
+ <ContextMenuCheckboxItem
99
+ checked={bookmarksChecked}
100
+ onCheckedChange={setBookmarksChecked}
101
+ >
102
+ Show Bookmarks
103
+ </ContextMenuCheckboxItem>
104
+ <ContextMenuCheckboxItem
105
+ checked={urlsChecked}
106
+ onCheckedChange={setUrlsChecked}
107
+ >
108
+ Show Full URLs
109
+ </ContextMenuCheckboxItem>
110
+ <ContextMenuSeparator />
111
+ <ContextMenuLabel>Switch User</ContextMenuLabel>
112
+ <ContextMenuRadioGroup value={person} onValueChange={setPerson}>
113
+ <ContextMenuRadioItem value="pedro">Pedro</ContextMenuRadioItem>
114
+ <ContextMenuRadioItem value="colm">Colm</ContextMenuRadioItem>
115
+ <ContextMenuRadioItem value="guest">Guest</ContextMenuRadioItem>
116
+ </ContextMenuRadioGroup>
117
+ </ContextMenuContent>
118
+ </ContextMenu>
119
+ );
120
+ }
121
+
122
+ export const WithState: Story = {
123
+ render: () => <ContextMenuWithStateDemo />,
124
+ };
125
+
126
+ export const FileContextMenu: Story = {
127
+ render: () => (
128
+ <ContextMenu>
129
+ <ContextMenuTrigger className="flex h-[100px] w-[200px] flex-col items-center justify-center gap-2 rounded-sm border border-border bg-card p-4">
130
+ <div className="h-12 w-12 rounded-sm bg-secondary-hover" />
131
+ <span className="text-sm text-foreground">Document.pdf</span>
132
+ </ContextMenuTrigger>
133
+ <ContextMenuContent className="w-48">
134
+ <ContextMenuItem>
135
+ Open
136
+ <ContextMenuShortcut>⌘O</ContextMenuShortcut>
137
+ </ContextMenuItem>
138
+ <ContextMenuItem>Open With...</ContextMenuItem>
139
+ <ContextMenuSeparator />
140
+ <ContextMenuItem>
141
+ Copy
142
+ <ContextMenuShortcut>⌘C</ContextMenuShortcut>
143
+ </ContextMenuItem>
144
+ <ContextMenuItem>
145
+ Cut
146
+ <ContextMenuShortcut>⌘X</ContextMenuShortcut>
147
+ </ContextMenuItem>
148
+ <ContextMenuItem>Rename</ContextMenuItem>
149
+ <ContextMenuSeparator />
150
+ <ContextMenuItem>Share...</ContextMenuItem>
151
+ <ContextMenuItem className="text-error">
152
+ Delete
153
+ <ContextMenuShortcut>⌘⌫</ContextMenuShortcut>
154
+ </ContextMenuItem>
155
+ </ContextMenuContent>
156
+ </ContextMenu>
157
+ ),
158
+ };
159
+