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,218 @@
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 { cn } from "@/lib/utils";
7
+
8
+ const ContextMenu = ContextMenuPrimitive.Root;
9
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
10
+ const ContextMenuGroup = ContextMenuPrimitive.Group;
11
+ const ContextMenuPortal = ContextMenuPrimitive.Portal;
12
+ const ContextMenuSub = ContextMenuPrimitive.Sub;
13
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
14
+
15
+ const ContextMenuSubTrigger = React.forwardRef<
16
+ React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
17
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
18
+ inset?: boolean;
19
+ }
20
+ >(({ className, inset, children, ...props }, ref) => (
21
+ <ContextMenuPrimitive.SubTrigger
22
+ ref={ref}
23
+ className={cn(
24
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
25
+ "focus:bg-secondary-hover focus:text-foreground",
26
+ "data-[state=open]:bg-secondary-hover data-[state=open]:text-foreground",
27
+ inset && "pl-8",
28
+ className
29
+ )}
30
+ {...props}
31
+ >
32
+ {children}
33
+ <ChevronRight className="ml-auto h-4 w-4" />
34
+ </ContextMenuPrimitive.SubTrigger>
35
+ ));
36
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
37
+
38
+ const ContextMenuSubContent = React.forwardRef<
39
+ React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
40
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
41
+ >(({ className, ...props }, ref) => (
42
+ <ContextMenuPrimitive.SubContent
43
+ ref={ref}
44
+ className={cn(
45
+ "z-50 min-w-[8rem] overflow-hidden rounded-sm border border-border bg-card p-1 text-foreground shadow-md",
46
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
47
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
48
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
49
+ "data-[side=bottom]:slide-in-from-top-2",
50
+ "data-[side=left]:slide-in-from-right-2",
51
+ "data-[side=right]:slide-in-from-left-2",
52
+ "data-[side=top]:slide-in-from-bottom-2",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ ));
58
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
59
+
60
+ const ContextMenuContent = React.forwardRef<
61
+ React.ElementRef<typeof ContextMenuPrimitive.Content>,
62
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
63
+ >(({ className, ...props }, ref) => (
64
+ <ContextMenuPrimitive.Portal>
65
+ <ContextMenuPrimitive.Content
66
+ ref={ref}
67
+ className={cn(
68
+ "z-50 min-w-[8rem] overflow-hidden rounded-sm border border-border bg-card p-1 text-foreground shadow-md",
69
+ "animate-in fade-in-80",
70
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
71
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
72
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
73
+ "data-[side=bottom]:slide-in-from-top-2",
74
+ "data-[side=left]:slide-in-from-right-2",
75
+ "data-[side=right]:slide-in-from-left-2",
76
+ "data-[side=top]:slide-in-from-bottom-2",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ </ContextMenuPrimitive.Portal>
82
+ ));
83
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
84
+
85
+ const ContextMenuItem = React.forwardRef<
86
+ React.ElementRef<typeof ContextMenuPrimitive.Item>,
87
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
88
+ inset?: boolean;
89
+ }
90
+ >(({ className, inset, ...props }, ref) => (
91
+ <ContextMenuPrimitive.Item
92
+ ref={ref}
93
+ className={cn(
94
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
95
+ "focus:bg-secondary-hover focus:text-foreground",
96
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
97
+ inset && "pl-8",
98
+ className
99
+ )}
100
+ {...props}
101
+ />
102
+ ));
103
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
104
+
105
+ const ContextMenuCheckboxItem = React.forwardRef<
106
+ React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
107
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
108
+ >(({ className, children, checked, ...props }, ref) => (
109
+ <ContextMenuPrimitive.CheckboxItem
110
+ ref={ref}
111
+ className={cn(
112
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
113
+ "focus:bg-secondary-hover focus:text-foreground",
114
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
115
+ className
116
+ )}
117
+ checked={checked}
118
+ {...props}
119
+ >
120
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
121
+ <ContextMenuPrimitive.ItemIndicator>
122
+ <Check className="h-4 w-4" />
123
+ </ContextMenuPrimitive.ItemIndicator>
124
+ </span>
125
+ {children}
126
+ </ContextMenuPrimitive.CheckboxItem>
127
+ ));
128
+ ContextMenuCheckboxItem.displayName =
129
+ ContextMenuPrimitive.CheckboxItem.displayName;
130
+
131
+ const ContextMenuRadioItem = React.forwardRef<
132
+ React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
133
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
134
+ >(({ className, children, ...props }, ref) => (
135
+ <ContextMenuPrimitive.RadioItem
136
+ ref={ref}
137
+ className={cn(
138
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
139
+ "focus:bg-secondary-hover focus:text-foreground",
140
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
141
+ className
142
+ )}
143
+ {...props}
144
+ >
145
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
146
+ <ContextMenuPrimitive.ItemIndicator>
147
+ <Circle className="h-2 w-2 fill-current" />
148
+ </ContextMenuPrimitive.ItemIndicator>
149
+ </span>
150
+ {children}
151
+ </ContextMenuPrimitive.RadioItem>
152
+ ));
153
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
154
+
155
+ const ContextMenuLabel = React.forwardRef<
156
+ React.ElementRef<typeof ContextMenuPrimitive.Label>,
157
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
158
+ inset?: boolean;
159
+ }
160
+ >(({ className, inset, ...props }, ref) => (
161
+ <ContextMenuPrimitive.Label
162
+ ref={ref}
163
+ className={cn(
164
+ "px-2 py-1.5 text-xs font-medium uppercase tracking-widest text-foreground-muted",
165
+ inset && "pl-8",
166
+ className
167
+ )}
168
+ {...props}
169
+ />
170
+ ));
171
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
172
+
173
+ const ContextMenuSeparator = React.forwardRef<
174
+ React.ElementRef<typeof ContextMenuPrimitive.Separator>,
175
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
176
+ >(({ className, ...props }, ref) => (
177
+ <ContextMenuPrimitive.Separator
178
+ ref={ref}
179
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
180
+ {...props}
181
+ />
182
+ ));
183
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
184
+
185
+ const ContextMenuShortcut = ({
186
+ className,
187
+ ...props
188
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
189
+ return (
190
+ <span
191
+ className={cn(
192
+ "ml-auto text-xs tracking-widest text-foreground-muted",
193
+ className
194
+ )}
195
+ {...props}
196
+ />
197
+ );
198
+ };
199
+ ContextMenuShortcut.displayName = "ContextMenuShortcut";
200
+
201
+ export {
202
+ ContextMenu,
203
+ ContextMenuTrigger,
204
+ ContextMenuContent,
205
+ ContextMenuItem,
206
+ ContextMenuCheckboxItem,
207
+ ContextMenuRadioItem,
208
+ ContextMenuLabel,
209
+ ContextMenuSeparator,
210
+ ContextMenuShortcut,
211
+ ContextMenuGroup,
212
+ ContextMenuPortal,
213
+ ContextMenuSub,
214
+ ContextMenuSubContent,
215
+ ContextMenuSubTrigger,
216
+ ContextMenuRadioGroup,
217
+ };
218
+
@@ -1,50 +1,53 @@
1
+ import { forwardRef } from "react";
1
2
  import { cn } from "@/lib/utils";
2
3
 
3
- interface DividerProps extends React.HTMLAttributes<HTMLDivElement> {
4
+ export interface DividerProps extends React.HTMLAttributes<HTMLDivElement> {
4
5
  orientation?: "horizontal" | "vertical";
5
6
  label?: string;
6
7
  }
7
8
 
8
- export function Divider({
9
- orientation = "horizontal",
10
- label,
11
- className,
12
- ...props
13
- }: DividerProps) {
14
- if (orientation === "vertical") {
15
- return (
16
- <div
17
- role="separator"
18
- aria-orientation="vertical"
19
- className={cn("h-full w-px bg-border", className)}
20
- {...props}
21
- />
22
- );
23
- }
9
+ export const Divider = forwardRef<HTMLDivElement, DividerProps>(
10
+ ({ orientation = "horizontal", label, className, ...props }, ref) => {
11
+ if (orientation === "vertical") {
12
+ return (
13
+ <div
14
+ ref={ref}
15
+ role="separator"
16
+ aria-orientation="vertical"
17
+ className={cn("h-full w-px bg-border", className)}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ if (label) {
24
+ return (
25
+ <div
26
+ ref={ref}
27
+ role="separator"
28
+ className={cn("flex items-center gap-4", className)}
29
+ {...props}
30
+ >
31
+ <div className="h-px flex-1 bg-border" />
32
+ <span className="text-xs font-medium uppercase tracking-widest text-foreground-muted">
33
+ {label}
34
+ </span>
35
+ <div className="h-px flex-1 bg-border" />
36
+ </div>
37
+ );
38
+ }
24
39
 
25
- if (label) {
26
40
  return (
27
41
  <div
42
+ ref={ref}
28
43
  role="separator"
29
- className={cn("flex items-center gap-4", className)}
44
+ aria-orientation="horizontal"
45
+ className={cn("h-px w-full bg-border", className)}
30
46
  {...props}
31
- >
32
- <div className="h-px flex-1 bg-border" />
33
- <span className="text-xs font-medium uppercase tracking-widest text-foreground-muted">
34
- {label}
35
- </span>
36
- <div className="h-px flex-1 bg-border" />
37
- </div>
47
+ />
38
48
  );
39
49
  }
50
+ );
40
51
 
41
- return (
42
- <div
43
- role="separator"
44
- aria-orientation="horizontal"
45
- className={cn("h-px w-full bg-border", className)}
46
- {...props}
47
- />
48
- );
49
- }
52
+ Divider.displayName = "Divider";
50
53
 
@@ -0,0 +1,217 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
5
+ import { Check, ChevronRight, Circle } from "lucide-react";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ const DropdownMenu = DropdownMenuPrimitive.Root;
9
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
10
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
11
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
12
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
13
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
14
+
15
+ const DropdownMenuSubTrigger = React.forwardRef<
16
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
17
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
18
+ inset?: boolean;
19
+ }
20
+ >(({ className, inset, children, ...props }, ref) => (
21
+ <DropdownMenuPrimitive.SubTrigger
22
+ ref={ref}
23
+ className={cn(
24
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
25
+ "focus:bg-secondary-hover focus:text-foreground",
26
+ "data-[state=open]:bg-secondary-hover data-[state=open]:text-foreground",
27
+ inset && "pl-8",
28
+ className
29
+ )}
30
+ {...props}
31
+ >
32
+ {children}
33
+ <ChevronRight className="ml-auto h-4 w-4" />
34
+ </DropdownMenuPrimitive.SubTrigger>
35
+ ));
36
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
37
+
38
+ const DropdownMenuSubContent = React.forwardRef<
39
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
40
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
41
+ >(({ className, ...props }, ref) => (
42
+ <DropdownMenuPrimitive.SubContent
43
+ ref={ref}
44
+ className={cn(
45
+ "z-50 min-w-[8rem] overflow-hidden rounded-sm border border-border bg-card p-1 text-foreground shadow-lg",
46
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
47
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
48
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
49
+ "data-[side=bottom]:slide-in-from-top-2",
50
+ "data-[side=left]:slide-in-from-right-2",
51
+ "data-[side=right]:slide-in-from-left-2",
52
+ "data-[side=top]:slide-in-from-bottom-2",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ ));
58
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
59
+
60
+ const DropdownMenuContent = React.forwardRef<
61
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
62
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
63
+ >(({ className, sideOffset = 4, ...props }, ref) => (
64
+ <DropdownMenuPrimitive.Portal>
65
+ <DropdownMenuPrimitive.Content
66
+ ref={ref}
67
+ sideOffset={sideOffset}
68
+ className={cn(
69
+ "z-50 min-w-[8rem] overflow-hidden rounded-sm border border-border bg-card p-1 text-foreground shadow-md",
70
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
71
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
72
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
73
+ "data-[side=bottom]:slide-in-from-top-2",
74
+ "data-[side=left]:slide-in-from-right-2",
75
+ "data-[side=right]:slide-in-from-left-2",
76
+ "data-[side=top]:slide-in-from-bottom-2",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ </DropdownMenuPrimitive.Portal>
82
+ ));
83
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
84
+
85
+ const DropdownMenuItem = React.forwardRef<
86
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
87
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
88
+ inset?: boolean;
89
+ }
90
+ >(({ className, inset, ...props }, ref) => (
91
+ <DropdownMenuPrimitive.Item
92
+ ref={ref}
93
+ className={cn(
94
+ "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors",
95
+ "focus:bg-secondary-hover focus:text-foreground",
96
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
97
+ inset && "pl-8",
98
+ className
99
+ )}
100
+ {...props}
101
+ />
102
+ ));
103
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
104
+
105
+ const DropdownMenuCheckboxItem = React.forwardRef<
106
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
107
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
108
+ >(({ className, children, checked, ...props }, ref) => (
109
+ <DropdownMenuPrimitive.CheckboxItem
110
+ ref={ref}
111
+ className={cn(
112
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors",
113
+ "focus:bg-secondary-hover focus:text-foreground",
114
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
115
+ className
116
+ )}
117
+ checked={checked}
118
+ {...props}
119
+ >
120
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
121
+ <DropdownMenuPrimitive.ItemIndicator>
122
+ <Check className="h-4 w-4" />
123
+ </DropdownMenuPrimitive.ItemIndicator>
124
+ </span>
125
+ {children}
126
+ </DropdownMenuPrimitive.CheckboxItem>
127
+ ));
128
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
129
+
130
+ const DropdownMenuRadioItem = React.forwardRef<
131
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
132
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
133
+ >(({ className, children, ...props }, ref) => (
134
+ <DropdownMenuPrimitive.RadioItem
135
+ ref={ref}
136
+ className={cn(
137
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors",
138
+ "focus:bg-secondary-hover focus:text-foreground",
139
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
140
+ className
141
+ )}
142
+ {...props}
143
+ >
144
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
145
+ <DropdownMenuPrimitive.ItemIndicator>
146
+ <Circle className="h-2 w-2 fill-current" />
147
+ </DropdownMenuPrimitive.ItemIndicator>
148
+ </span>
149
+ {children}
150
+ </DropdownMenuPrimitive.RadioItem>
151
+ ));
152
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
153
+
154
+ const DropdownMenuLabel = React.forwardRef<
155
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
156
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
157
+ inset?: boolean;
158
+ }
159
+ >(({ className, inset, ...props }, ref) => (
160
+ <DropdownMenuPrimitive.Label
161
+ ref={ref}
162
+ className={cn(
163
+ "px-2 py-1.5 text-xs font-medium uppercase tracking-widest text-foreground-muted",
164
+ inset && "pl-8",
165
+ className
166
+ )}
167
+ {...props}
168
+ />
169
+ ));
170
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
171
+
172
+ const DropdownMenuSeparator = React.forwardRef<
173
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
174
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
175
+ >(({ className, ...props }, ref) => (
176
+ <DropdownMenuPrimitive.Separator
177
+ ref={ref}
178
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
179
+ {...props}
180
+ />
181
+ ));
182
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
183
+
184
+ const DropdownMenuShortcut = ({
185
+ className,
186
+ ...props
187
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
188
+ return (
189
+ <span
190
+ className={cn(
191
+ "ml-auto text-xs tracking-widest text-foreground-muted",
192
+ className
193
+ )}
194
+ {...props}
195
+ />
196
+ );
197
+ };
198
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
199
+
200
+ export {
201
+ DropdownMenu,
202
+ DropdownMenuTrigger,
203
+ DropdownMenuContent,
204
+ DropdownMenuItem,
205
+ DropdownMenuCheckboxItem,
206
+ DropdownMenuRadioItem,
207
+ DropdownMenuLabel,
208
+ DropdownMenuSeparator,
209
+ DropdownMenuShortcut,
210
+ DropdownMenuGroup,
211
+ DropdownMenuPortal,
212
+ DropdownMenuSub,
213
+ DropdownMenuSubContent,
214
+ DropdownMenuSubTrigger,
215
+ DropdownMenuRadioGroup,
216
+ };
217
+
@@ -0,0 +1,113 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { CalendarDays } from "lucide-react";
3
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from "./hover-card";
4
+ import { Avatar } from "./avatar";
5
+
6
+ const meta: Meta<typeof HoverCard> = {
7
+ title: "Components/Overlays/HoverCard",
8
+ component: HoverCard,
9
+ parameters: {
10
+ layout: "centered",
11
+ },
12
+ tags: ["autodocs"],
13
+ };
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof HoverCard>;
17
+
18
+ export const Default: Story = {
19
+ render: () => (
20
+ <HoverCard>
21
+ <HoverCardTrigger asChild>
22
+ <a
23
+ href="#"
24
+ className="text-sm font-medium text-primary underline underline-offset-4"
25
+ >
26
+ @sonance
27
+ </a>
28
+ </HoverCardTrigger>
29
+ <HoverCardContent className="w-80">
30
+ <div className="flex justify-between space-x-4">
31
+ <Avatar
32
+ fallback="Sonance"
33
+ size="md"
34
+ />
35
+ <div className="space-y-1">
36
+ <h4 className="text-sm font-medium text-foreground">@sonance</h4>
37
+ <p className="text-sm text-foreground-secondary">
38
+ Premium architectural speakers and outdoor audio solutions.
39
+ </p>
40
+ <div className="flex items-center pt-2">
41
+ <CalendarDays className="mr-2 h-4 w-4 opacity-70" />{" "}
42
+ <span className="text-xs text-foreground-muted">
43
+ Joined December 2021
44
+ </span>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ </HoverCardContent>
49
+ </HoverCard>
50
+ ),
51
+ };
52
+
53
+ export const ProductPreview: Story = {
54
+ render: () => (
55
+ <HoverCard>
56
+ <HoverCardTrigger asChild>
57
+ <button className="text-sm font-medium underline underline-offset-4">
58
+ View Sonance Landscape Series
59
+ </button>
60
+ </HoverCardTrigger>
61
+ <HoverCardContent className="w-80">
62
+ <div className="space-y-3">
63
+ <div className="h-32 rounded-sm bg-secondary-hover flex items-center justify-center">
64
+ <span className="text-foreground-muted text-xs">Product Image</span>
65
+ </div>
66
+ <div className="space-y-1">
67
+ <h4 className="text-sm font-medium text-foreground">
68
+ Landscape Series
69
+ </h4>
70
+ <p className="text-sm text-foreground-secondary">
71
+ Outdoor speakers designed to blend seamlessly into your landscape
72
+ while delivering exceptional audio quality.
73
+ </p>
74
+ <p className="text-xs text-foreground-muted pt-1">
75
+ Starting at $599
76
+ </p>
77
+ </div>
78
+ </div>
79
+ </HoverCardContent>
80
+ </HoverCard>
81
+ ),
82
+ };
83
+
84
+ export const LinkPreview: Story = {
85
+ render: () => (
86
+ <p className="text-sm text-foreground-secondary">
87
+ Learn more about our{" "}
88
+ <HoverCard>
89
+ <HoverCardTrigger asChild>
90
+ <a
91
+ href="#"
92
+ className="font-medium text-foreground underline underline-offset-4"
93
+ >
94
+ installation services
95
+ </a>
96
+ </HoverCardTrigger>
97
+ <HoverCardContent>
98
+ <div className="space-y-2">
99
+ <h4 className="text-sm font-medium text-foreground">
100
+ Professional Installation
101
+ </h4>
102
+ <p className="text-sm text-foreground-secondary">
103
+ Our certified integrators ensure your audio system is installed
104
+ correctly for optimal performance.
105
+ </p>
106
+ </div>
107
+ </HoverCardContent>
108
+ </HoverCard>{" "}
109
+ for your home.
110
+ </p>
111
+ ),
112
+ };
113
+
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const HoverCard = HoverCardPrimitive.Root;
8
+ const HoverCardTrigger = HoverCardPrimitive.Trigger;
9
+
10
+ const HoverCardContent = React.forwardRef<
11
+ React.ElementRef<typeof HoverCardPrimitive.Content>,
12
+ React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
13
+ >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
14
+ <HoverCardPrimitive.Content
15
+ ref={ref}
16
+ align={align}
17
+ sideOffset={sideOffset}
18
+ className={cn(
19
+ "z-50 w-64 rounded-sm border border-border bg-card p-4 text-foreground shadow-md outline-none",
20
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
21
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
23
+ "data-[side=bottom]:slide-in-from-top-2",
24
+ "data-[side=left]:slide-in-from-right-2",
25
+ "data-[side=right]:slide-in-from-left-2",
26
+ "data-[side=top]:slide-in-from-bottom-2",
27
+ className
28
+ )}
29
+ {...props}
30
+ />
31
+ ));
32
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
33
+
34
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
35
+