sonance-brand-mcp 1.2.5 → 1.3.2

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 (189) hide show
  1. package/dist/assets/api/sonance-analyze/route.ts +1116 -0
  2. package/dist/assets/api/sonance-assets/route.ts +113 -0
  3. package/dist/assets/api/sonance-components/route.ts +41 -0
  4. package/dist/assets/api/sonance-inject-id/route.ts +363 -0
  5. package/dist/assets/api/sonance-save-logo/route.ts +426 -0
  6. package/dist/assets/api/sonance-theme/route.ts +106 -0
  7. package/dist/assets/brand-system.ts +1265 -0
  8. package/dist/assets/components/accordion.stories.tsx +26 -26
  9. package/dist/assets/components/accordion.tsx +3 -3
  10. package/dist/assets/components/alert-dialog.stories.tsx +142 -0
  11. package/dist/assets/components/alert-dialog.tsx +143 -0
  12. package/dist/assets/components/alert.stories.tsx +3 -3
  13. package/dist/assets/components/alert.tsx +4 -3
  14. package/dist/assets/components/aspect-ratio.stories.tsx +70 -0
  15. package/dist/assets/components/aspect-ratio.tsx +8 -0
  16. package/dist/assets/components/autocomplete.stories.tsx +9 -9
  17. package/dist/assets/components/autocomplete.tsx +3 -3
  18. package/dist/assets/components/avatar.stories.tsx +5 -5
  19. package/dist/assets/components/avatar.tsx +67 -23
  20. package/dist/assets/components/badge.stories.tsx +10 -10
  21. package/dist/assets/components/badge.tsx +3 -3
  22. package/dist/assets/components/breadcrumbs.stories.tsx +7 -7
  23. package/dist/assets/components/breadcrumbs.tsx +13 -8
  24. package/dist/assets/components/button.stories.tsx +74 -74
  25. package/dist/assets/components/button.tsx +2 -0
  26. package/dist/assets/components/calendar.stories.tsx +11 -11
  27. package/dist/assets/components/calendar.tsx +4 -4
  28. package/dist/assets/components/card.stories.tsx +22 -22
  29. package/dist/assets/components/card.tsx +7 -3
  30. package/dist/assets/components/carousel.stories.tsx +158 -0
  31. package/dist/assets/components/carousel.tsx +264 -0
  32. package/dist/assets/components/chart.stories.tsx +376 -0
  33. package/dist/assets/components/chart.tsx +384 -0
  34. package/dist/assets/components/checkbox-group.stories.tsx +6 -6
  35. package/dist/assets/components/checkbox-group.tsx +3 -3
  36. package/dist/assets/components/checkbox.stories.tsx +23 -20
  37. package/dist/assets/components/checkbox.tsx +13 -6
  38. package/dist/assets/components/code.stories.tsx +24 -24
  39. package/dist/assets/components/code.tsx +22 -27
  40. package/dist/assets/components/collapsible.stories.tsx +128 -0
  41. package/dist/assets/components/collapsible.tsx +10 -0
  42. package/dist/assets/components/command.stories.tsx +183 -0
  43. package/dist/assets/components/command.tsx +171 -0
  44. package/dist/assets/components/context-menu.stories.tsx +159 -0
  45. package/dist/assets/components/context-menu.tsx +214 -0
  46. package/dist/assets/components/date-input.stories.tsx +9 -9
  47. package/dist/assets/components/date-input.tsx +2 -2
  48. package/dist/assets/components/date-picker.stories.tsx +9 -9
  49. package/dist/assets/components/date-picker.tsx +3 -3
  50. package/dist/assets/components/date-range-picker.stories.tsx +12 -12
  51. package/dist/assets/components/date-range-picker.tsx +3 -3
  52. package/dist/assets/components/dialog.stories.tsx +40 -40
  53. package/dist/assets/components/dialog.tsx +8 -12
  54. package/dist/assets/components/divider.stories.tsx +30 -30
  55. package/dist/assets/components/divider.tsx +34 -35
  56. package/dist/assets/components/drawer.stories.tsx +32 -31
  57. package/dist/assets/components/drawer.tsx +7 -6
  58. package/dist/assets/components/dropdown-menu.tsx +213 -0
  59. package/dist/assets/components/dropdown.stories.tsx +12 -12
  60. package/dist/assets/components/dropdown.tsx +5 -5
  61. package/dist/assets/components/form.stories.tsx +30 -29
  62. package/dist/assets/components/form.tsx +5 -5
  63. package/dist/assets/components/hover-card.stories.tsx +115 -0
  64. package/dist/assets/components/hover-card.tsx +35 -0
  65. package/dist/assets/components/image.stories.tsx +48 -25
  66. package/dist/assets/components/image.tsx +8 -5
  67. package/dist/assets/components/input-otp.stories.tsx +15 -15
  68. package/dist/assets/components/input-otp.tsx +5 -5
  69. package/dist/assets/components/input.stories.tsx +30 -25
  70. package/dist/assets/components/input.tsx +7 -4
  71. package/dist/assets/components/kbd.stories.tsx +34 -34
  72. package/dist/assets/components/kbd.tsx +9 -9
  73. package/dist/assets/components/link.stories.tsx +36 -36
  74. package/dist/assets/components/link.tsx +4 -0
  75. package/dist/assets/components/listbox.stories.tsx +5 -5
  76. package/dist/assets/components/listbox.tsx +4 -4
  77. package/dist/assets/components/menubar.stories.tsx +208 -0
  78. package/dist/assets/components/menubar.tsx +247 -0
  79. package/dist/assets/components/navbar.stories.tsx +24 -24
  80. package/dist/assets/components/navbar.tsx +8 -14
  81. package/dist/assets/components/navigation-menu.stories.tsx +239 -0
  82. package/dist/assets/components/navigation-menu.tsx +135 -0
  83. package/dist/assets/components/number-input.stories.tsx +11 -11
  84. package/dist/assets/components/number-input.tsx +3 -3
  85. package/dist/assets/components/pagination.stories.tsx +13 -13
  86. package/dist/assets/components/pagination.tsx +6 -6
  87. package/dist/assets/components/popover.stories.tsx +35 -35
  88. package/dist/assets/components/popover.tsx +98 -15
  89. package/dist/assets/components/progress.stories.tsx +5 -5
  90. package/dist/assets/components/progress.tsx +5 -5
  91. package/dist/assets/components/radio-group.stories.tsx +7 -7
  92. package/dist/assets/components/radio-group.tsx +3 -3
  93. package/dist/assets/components/range-calendar.stories.tsx +18 -18
  94. package/dist/assets/components/range-calendar.tsx +3 -3
  95. package/dist/assets/components/resizable.stories.tsx +197 -0
  96. package/dist/assets/components/resizable.tsx +47 -0
  97. package/dist/assets/components/scroll-area.stories.tsx +123 -0
  98. package/dist/assets/components/scroll-area.tsx +48 -0
  99. package/dist/assets/components/scroll-shadow.stories.tsx +17 -17
  100. package/dist/assets/components/scroll-shadow.tsx +31 -9
  101. package/dist/assets/components/select.stories.tsx +20 -19
  102. package/dist/assets/components/select.tsx +10 -6
  103. package/dist/assets/components/separator.tsx +32 -0
  104. package/dist/assets/components/sheet.tsx +137 -0
  105. package/dist/assets/components/sidebar.stories.tsx +351 -0
  106. package/dist/assets/components/sidebar.tsx +757 -0
  107. package/dist/assets/components/skeleton.stories.tsx +3 -3
  108. package/dist/assets/components/skeleton.tsx +2 -2
  109. package/dist/assets/components/slider.stories.tsx +6 -6
  110. package/dist/assets/components/slider.tsx +3 -3
  111. package/dist/assets/components/spacer.stories.tsx +11 -11
  112. package/dist/assets/components/spacer.tsx +2 -2
  113. package/dist/assets/components/spinner.stories.tsx +8 -8
  114. package/dist/assets/components/spinner.tsx +5 -5
  115. package/dist/assets/components/switch.stories.tsx +24 -20
  116. package/dist/assets/components/switch.tsx +14 -6
  117. package/dist/assets/components/table.stories.tsx +7 -7
  118. package/dist/assets/components/table.tsx +8 -8
  119. package/dist/assets/components/tabs.stories.tsx +37 -37
  120. package/dist/assets/components/tabs.tsx +3 -3
  121. package/dist/assets/components/textarea.stories.tsx +13 -12
  122. package/dist/assets/components/textarea.tsx +3 -3
  123. package/dist/assets/components/theme-toggle.stories.tsx +31 -30
  124. package/dist/assets/components/theme-toggle.tsx +2 -2
  125. package/dist/assets/components/time-input.stories.tsx +16 -16
  126. package/dist/assets/components/time-input.tsx +2 -2
  127. package/dist/assets/components/toast.stories.tsx +8 -5
  128. package/dist/assets/components/toast.tsx +6 -6
  129. package/dist/assets/components/toggle-group.stories.tsx +153 -0
  130. package/dist/assets/components/toggle-group.tsx +61 -0
  131. package/dist/assets/components/toggle.stories.tsx +77 -0
  132. package/dist/assets/components/toggle.tsx +46 -0
  133. package/dist/assets/components/tooltip.stories.tsx +49 -27
  134. package/dist/assets/components/tooltip.tsx +23 -90
  135. package/dist/assets/components/user.stories.tsx +23 -23
  136. package/dist/assets/components/user.tsx +7 -4
  137. package/dist/assets/dev-tools/SonanceDevTools.tsx +4201 -0
  138. package/dist/assets/dev-tools/index.ts +10 -0
  139. package/dist/assets/globals.css +39 -0
  140. package/dist/assets/logos/40th-anniversary/Sonance_40_Logo_CMYK_BEAM_BLUE_40_AND_BEAM_DARK.png +0 -0
  141. package/dist/assets/logos/Sonance logo dark mode.png +0 -0
  142. package/dist/assets/logos/Sonance logo light mode.png +0 -0
  143. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_2C_Light_RGB_05162025.png +0 -0
  144. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_3C_Dark_RGB_05162025.png +0 -0
  145. package/dist/assets/logos/blaze/BlazeBySonance_Logo_Lockup_White_RGB_05162025.png +0 -0
  146. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Dark_RGB.png +0 -0
  147. package/dist/assets/logos/iport/IPORT_Sonance_LockUp_2C_Light_RGB.png +0 -0
  148. package/dist/assets/logos/james/James_Logo_Black_CMYK.png +0 -0
  149. package/dist/assets/logos/james/James_Logo_Black_RGB.png +0 -0
  150. package/dist/assets/logos/james/James_Logo_LtGray_CMYK.png +0 -0
  151. package/dist/assets/logos/james/James_Logo_LtGray_RGB.png +0 -0
  152. package/dist/assets/logos/james/James_Logo_Polished_RGB.png +0 -0
  153. package/dist/assets/logos/james/James_Logo_Reverse_CMYK.png +0 -0
  154. package/dist/assets/logos/james/James_Logo_Reverse_RGB.png +0 -0
  155. package/dist/assets/logos/james/James_Logo_White_CMYK.png +0 -0
  156. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Dark_RGB.png +0 -0
  157. package/dist/assets/logos/life-is-better/Sonance_LifeisBetter_Light_RGB.png +0 -0
  158. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Dark_RGB.png +0 -0
  159. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Light_RGB.png +0 -0
  160. package/dist/assets/logos/my-sonance/My.Sonance_Logo_2C_Reverse_RGB.png +0 -0
  161. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Black_RGB.png +0 -0
  162. package/dist/assets/logos/my-sonance/My.Sonance_Logo_Reverse_RGB.png +0 -0
  163. package/dist/assets/logos/sonance/Sonance_Logo_2C_Dark_RGB.png +0 -0
  164. package/dist/assets/logos/sonance/Sonance_Logo_2C_Light_RGB.png +0 -0
  165. package/dist/assets/logos/sonance/Sonance_Logo_2C_Reverse_RGB.png +0 -0
  166. package/dist/assets/logos/sonance/Sonance_Logo_Black_RGB.png +0 -0
  167. package/dist/assets/logos/sonance/Sonance_Logo_Grayscale_RGB.png +0 -0
  168. package/dist/assets/logos/sonance/Sonance_Logo_Reverse_RGB.png +0 -0
  169. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Dark_CMYK.png +0 -0
  170. package/dist/assets/logos/sonance-academy/SonanceAcademy_Logo_Light_CMYK.png +0 -0
  171. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Dark_RGB.png +0 -0
  172. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Light_RGB.png +0 -0
  173. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_3C_Reverse_RGB.png +0 -0
  174. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Black_RGB.png +0 -0
  175. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Grayscale_RGB.png +0 -0
  176. package/dist/assets/logos/sonance-iport/Sonance_IPORT_LockUp_Reverse_RGB.png +0 -0
  177. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Dark.png +0 -0
  178. package/dist/assets/logos/sonance-james/Sonance_James_Lockup_Light.png +0 -0
  179. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Dark.png +0 -0
  180. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_LockupStacked_Light.png +0 -0
  181. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Dark.png +0 -0
  182. package/dist/assets/logos/sonance-james-iport/Sonance_James_IPORT_Lockup_Light.png +0 -0
  183. package/dist/assets/logos/trufig/TrufigLogo_Black.png +0 -0
  184. package/dist/assets/logos/trufig/TrufigLogo_Light.png +0 -0
  185. package/dist/assets/logos/trufig/TrufigWatermark_Black.png +0 -0
  186. package/dist/assets/logos/trufig/TrufigWatermark_Light.png +0 -0
  187. package/dist/assets/styles/brand-overrides.css +37 -0
  188. package/dist/index.js +2055 -15
  189. package/package.json +1 -1
@@ -20,15 +20,7 @@ export const Navbar = forwardRef<HTMLElement, NavbarProps>(
20
20
  };
21
21
 
22
22
  return (
23
- <nav
24
- ref={ref}
25
- className={cn(
26
- "w-full px-6 py-4",
27
- variantClasses[variant],
28
- sticky && "sticky top-0 z-40",
29
- bordered && variant !== "dark" && variant !== "transparent" && "border-b border-border",
30
- className
31
- )}
23
+ <nav data-sonance-name="navbar"
32
24
  {...props}
33
25
  >
34
26
  {children}
@@ -53,7 +45,7 @@ export const NavbarContent = forwardRef<
53
45
  return (
54
46
  <div
55
47
  ref={ref}
56
- className={cn("flex items-center gap-6", justifyClasses[justify], className)}
48
+ className={cn("flex items-center gap-6", justifyClasses[justify], className)} data-sonance-name="navbar"
57
49
  {...props}
58
50
  />
59
51
  );
@@ -67,7 +59,7 @@ export const NavbarBrand = forwardRef<
67
59
  >(({ className, ...props }, ref) => (
68
60
  <div
69
61
  ref={ref}
70
- className={cn("flex items-center gap-2 shrink-0", className)}
62
+ className={cn("flex items-center gap-2 shrink-0", className)} data-sonance-name="navbar"
71
63
  {...props}
72
64
  />
73
65
  ));
@@ -80,7 +72,7 @@ export const NavbarItems = forwardRef<
80
72
  >(({ className, ...props }, ref) => (
81
73
  <div
82
74
  ref={ref}
83
- className={cn("hidden md:flex items-center gap-6", className)}
75
+ className={cn("hidden md:flex items-center gap-6", className)} data-sonance-name="navbar"
84
76
  {...props}
85
77
  />
86
78
  ));
@@ -94,12 +86,13 @@ interface NavbarItemProps extends React.AnchorHTMLAttributes<HTMLAnchorElement>
94
86
  export const NavbarItem = forwardRef<HTMLAnchorElement, NavbarItemProps>(
95
87
  ({ className, active, ...props }, ref) => (
96
88
  <a
89
+ id="navbar-item-a"
97
90
  ref={ref}
98
91
  className={cn(
99
92
  "text-sm font-normal transition-opacity",
100
93
  active ? "opacity-100 font-medium" : "opacity-85 hover:opacity-100",
101
94
  className
102
- )}
95
+ )} data-sonance-name="navbar"
103
96
  {...props}
104
97
  />
105
98
  )
@@ -116,7 +109,7 @@ interface NavbarMobileToggleProps {
116
109
 
117
110
  export function NavbarMobileToggle({ isOpen, onToggle, className }: NavbarMobileToggleProps) {
118
111
  return (
119
- <button
112
+ <button data-sonance-name="navbar"
120
113
  type="button"
121
114
  onClick={onToggle}
122
115
  className={cn("md:hidden p-2 -m-2", className)}
@@ -193,6 +186,7 @@ export function ResponsiveNavbar({
193
186
  <NavbarMobileMenu isOpen={mobileMenuOpen}>
194
187
  {items.map((item) => (
195
188
  <a
189
+ id="nav-a"
196
190
  key={item.href}
197
191
  href={item.href}
198
192
  className={cn(
@@ -0,0 +1,239 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import {
3
+ NavigationMenu,
4
+ NavigationMenuContent,
5
+ NavigationMenuItem,
6
+ NavigationMenuLink,
7
+ NavigationMenuList,
8
+ NavigationMenuTrigger,
9
+ navigationMenuTriggerStyle,
10
+ } from "./navigation-menu";
11
+ import { cn } from "@/lib/utils";
12
+ import React from "react";
13
+
14
+ const meta: Meta<typeof NavigationMenu> = {
15
+ title: "Components/Navigation/NavigationMenu",
16
+ component: NavigationMenu,
17
+ parameters: {
18
+ layout: "centered",
19
+ },
20
+ tags: ["autodocs"],
21
+ };
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof NavigationMenu>;
25
+
26
+ const components: { title: string; href: string; description: string }[] = [
27
+ {
28
+ title: "Alert Dialog",
29
+ href: "#",
30
+ description:
31
+ "A modal dialog that interrupts the user with important content and expects a response.",
32
+ },
33
+ {
34
+ title: "Hover Card",
35
+ href: "#",
36
+ description:
37
+ "For sighted users to preview content available behind a link.",
38
+ },
39
+ {
40
+ title: "Progress",
41
+ href: "#",
42
+ description:
43
+ "Displays an indicator showing the completion progress of a task.",
44
+ },
45
+ {
46
+ title: "Scroll Area",
47
+ href: "#",
48
+ description: "Visually or semantically separates content.",
49
+ },
50
+ {
51
+ title: "Tabs",
52
+ href: "#",
53
+ description:
54
+ "A set of layered sections of content—known as tab panels.",
55
+ },
56
+ {
57
+ title: "Tooltip",
58
+ href: "#",
59
+ description:
60
+ "A popup that displays information related to an element.",
61
+ },
62
+ ];
63
+
64
+ const ListItem = React.forwardRef<
65
+ React.ElementRef<"a">,
66
+ React.ComponentPropsWithoutRef<"a">
67
+ >(({ className, title, children, ...props }, ref) => {
68
+ return (
69
+ <li>
70
+ <NavigationMenuLink asChild>
71
+ <a
72
+ id="nav-a"
73
+ ref={ref}
74
+ className={cn(
75
+ "block select-none space-y-1 rounded-sm p-3 leading-none no-underline outline-none transition-colors hover:bg-secondary-hover hover:text-foreground focus:bg-secondary-hover focus:text-foreground",
76
+ className
77
+ )} data-sonance-name="navigation-menu.stories"
78
+ {...props}
79
+ >
80
+ <div className="text-sm font-medium leading-none">{title}</div>
81
+ <p id="nav-p-children" className="line-clamp-2 text-sm leading-snug text-foreground-muted">
82
+ {children}
83
+ </p>
84
+ </a>
85
+ </NavigationMenuLink>
86
+ </li>
87
+ );
88
+ });
89
+ ListItem.displayName = "ListItem";
90
+
91
+ export const Default: Story = {
92
+ render: () => (
93
+ <NavigationMenu>
94
+ <NavigationMenuList>
95
+ <NavigationMenuItem>
96
+ <NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
97
+ <NavigationMenuContent>
98
+ <ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
99
+ <li className="row-span-3">
100
+ <NavigationMenuLink asChild>
101
+ <a
102
+ id="nav-a"
103
+ className="flex h-full w-full select-none flex-col justify-end rounded-sm bg-gradient-to-b from-secondary-hover/50 to-secondary-hover p-6 no-underline outline-none focus:shadow-md"
104
+ href="#"
105
+ >
106
+ <div className="mb-2 mt-4 text-lg font-medium">
107
+ Sonance
108
+ </div>
109
+ <p id="nav-p-premium-architectura" className="text-sm leading-tight text-foreground-muted">
110
+ Premium architectural speakers and outdoor audio solutions.
111
+ </p>
112
+ </a>
113
+ </NavigationMenuLink>
114
+ </li>
115
+ <ListItem href="#" title="Introduction">
116
+ Learn about the Sonance brand and our commitment to audio excellence.
117
+ </ListItem>
118
+ <ListItem href="#" title="Installation">
119
+ How to get started with your Sonance audio system.
120
+ </ListItem>
121
+ <ListItem href="#" title="Support">
122
+ Find answers and get help from our team.
123
+ </ListItem>
124
+ </ul>
125
+ </NavigationMenuContent>
126
+ </NavigationMenuItem>
127
+ <NavigationMenuItem>
128
+ <NavigationMenuTrigger>Components</NavigationMenuTrigger>
129
+ <NavigationMenuContent>
130
+ <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
131
+ {components.map((component) => (
132
+ <ListItem
133
+ key={component.title}
134
+ title={component.title}
135
+ href={component.href}
136
+ >
137
+ {component.description}
138
+ </ListItem>
139
+ ))}
140
+ </ul>
141
+ </NavigationMenuContent>
142
+ </NavigationMenuItem>
143
+ <NavigationMenuItem>
144
+ <a id="nav-a" href="#">
145
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
146
+ Documentation
147
+ </NavigationMenuLink>
148
+ </a>
149
+ </NavigationMenuItem>
150
+ </NavigationMenuList>
151
+ </NavigationMenu>
152
+ ),
153
+ };
154
+
155
+ export const Simple: Story = {
156
+ render: () => (
157
+ <NavigationMenu>
158
+ <NavigationMenuList>
159
+ <NavigationMenuItem>
160
+ <a id="nav-a" href="#">
161
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
162
+ Products
163
+ </NavigationMenuLink>
164
+ </a>
165
+ </NavigationMenuItem>
166
+ <NavigationMenuItem>
167
+ <a id="nav-a" href="#">
168
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
169
+ Solutions
170
+ </NavigationMenuLink>
171
+ </a>
172
+ </NavigationMenuItem>
173
+ <NavigationMenuItem>
174
+ <a id="nav-a" href="#">
175
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
176
+ Support
177
+ </NavigationMenuLink>
178
+ </a>
179
+ </NavigationMenuItem>
180
+ <NavigationMenuItem>
181
+ <a id="nav-a" href="#">
182
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
183
+ About
184
+ </NavigationMenuLink>
185
+ </a>
186
+ </NavigationMenuItem>
187
+ </NavigationMenuList>
188
+ </NavigationMenu>
189
+ ),
190
+ };
191
+
192
+ export const ProductsMenu: Story = {
193
+ render: () => (
194
+ <NavigationMenu>
195
+ <NavigationMenuList>
196
+ <NavigationMenuItem>
197
+ <NavigationMenuTrigger>Architectural</NavigationMenuTrigger>
198
+ <NavigationMenuContent>
199
+ <ul className="grid gap-3 p-4 w-[400px]">
200
+ <ListItem href="#" title="In-Ceiling Speakers">
201
+ Invisible audio solutions for residential and commercial spaces.
202
+ </ListItem>
203
+ <ListItem href="#" title="In-Wall Speakers">
204
+ Seamless integration into any wall surface.
205
+ </ListItem>
206
+ <ListItem href="#" title="Invisible Series">
207
+ Completely hidden speakers that disappear into your walls.
208
+ </ListItem>
209
+ </ul>
210
+ </NavigationMenuContent>
211
+ </NavigationMenuItem>
212
+ <NavigationMenuItem>
213
+ <NavigationMenuTrigger>Outdoor</NavigationMenuTrigger>
214
+ <NavigationMenuContent>
215
+ <ul className="grid gap-3 p-4 w-[400px]">
216
+ <ListItem href="#" title="Landscape Series">
217
+ Outdoor speakers designed to blend into your garden.
218
+ </ListItem>
219
+ <ListItem href="#" title="Patio Series">
220
+ Weather-resistant speakers for covered outdoor areas.
221
+ </ListItem>
222
+ <ListItem href="#" title="Subwoofers">
223
+ Powerful bass for your outdoor entertainment.
224
+ </ListItem>
225
+ </ul>
226
+ </NavigationMenuContent>
227
+ </NavigationMenuItem>
228
+ <NavigationMenuItem>
229
+ <a id="nav-a" href="#">
230
+ <NavigationMenuLink className={navigationMenuTriggerStyle()}>
231
+ View All
232
+ </NavigationMenuLink>
233
+ </a>
234
+ </NavigationMenuItem>
235
+ </NavigationMenuList>
236
+ </NavigationMenu>
237
+ ),
238
+ };
239
+
@@ -0,0 +1,135 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
5
+ import { ChevronDown } from "lucide-react";
6
+ import { cva } from "class-variance-authority";
7
+ import { cn } from "@/lib/utils";
8
+
9
+ const NavigationMenu = React.forwardRef<
10
+ React.ElementRef<typeof NavigationMenuPrimitive.Root>,
11
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
12
+ >(({ className, children, ...props }, ref) => (
13
+ <NavigationMenuPrimitive.Root
14
+ ref={ref}
15
+ className={cn(
16
+ "relative z-10 flex max-w-max flex-1 items-center justify-center",
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ {children}
22
+ <NavigationMenuViewport />
23
+ </NavigationMenuPrimitive.Root>
24
+ ));
25
+ NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
26
+
27
+ const NavigationMenuList = React.forwardRef<
28
+ React.ElementRef<typeof NavigationMenuPrimitive.List>,
29
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
30
+ >(({ className, ...props }, ref) => (
31
+ <NavigationMenuPrimitive.List
32
+ ref={ref}
33
+ className={cn(
34
+ "group flex flex-1 list-none items-center justify-center space-x-1",
35
+ className
36
+ )}
37
+ {...props}
38
+ />
39
+ ));
40
+ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
41
+
42
+ const NavigationMenuItem = NavigationMenuPrimitive.Item;
43
+
44
+ const navigationMenuTriggerStyle = cva(
45
+ "group inline-flex h-10 w-max items-center justify-center rounded-sm bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-secondary-hover hover:text-foreground focus:bg-secondary-hover focus:text-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-secondary-hover/50 data-[state=open]:bg-secondary-hover/50"
46
+ );
47
+
48
+ const NavigationMenuTrigger = React.forwardRef<
49
+ React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
50
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
51
+ >(({ className, children, ...props }, ref) => (
52
+ <NavigationMenuPrimitive.Trigger
53
+ ref={ref}
54
+ className={cn(navigationMenuTriggerStyle(), "group", className)}
55
+ {...props}
56
+ >
57
+ {children}{" "}
58
+ <ChevronDown
59
+ className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
60
+ aria-hidden="true"
61
+ />
62
+ </NavigationMenuPrimitive.Trigger>
63
+ ));
64
+ NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
65
+
66
+ const NavigationMenuContent = React.forwardRef<
67
+ React.ElementRef<typeof NavigationMenuPrimitive.Content>,
68
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
69
+ >(({ className, ...props }, ref) => (
70
+ <NavigationMenuPrimitive.Content
71
+ ref={ref}
72
+ className={cn(
73
+ "left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
74
+ className
75
+ )}
76
+ {...props}
77
+ />
78
+ ));
79
+ NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
80
+
81
+ const NavigationMenuLink = NavigationMenuPrimitive.Link;
82
+
83
+ const NavigationMenuViewport = React.forwardRef<
84
+ React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
85
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
86
+ >(({ className, ...props }, ref) => (
87
+ <div data-sonance-name="navigation-menu" className={cn("absolute left-0 top-full flex justify-center")}>
88
+ <NavigationMenuPrimitive.Viewport
89
+ className={cn(
90
+ "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-sm border border-border bg-card text-foreground shadow-lg",
91
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
92
+ "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90",
93
+ "md:w-[var(--radix-navigation-menu-viewport-width)]",
94
+ className
95
+ )}
96
+ ref={ref}
97
+ {...props}
98
+ />
99
+ </div>
100
+ ));
101
+ NavigationMenuViewport.displayName =
102
+ NavigationMenuPrimitive.Viewport.displayName;
103
+
104
+ const NavigationMenuIndicator = React.forwardRef<
105
+ React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
106
+ React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
107
+ >(({ className, ...props }, ref) => (
108
+ <NavigationMenuPrimitive.Indicator
109
+ ref={ref}
110
+ className={cn(
111
+ "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
112
+ "data-[state=visible]:animate-in data-[state=hidden]:animate-out",
113
+ "data-[state=hidden]:fade-out data-[state=visible]:fade-in",
114
+ className
115
+ )}
116
+ {...props}
117
+ >
118
+ <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
119
+ </NavigationMenuPrimitive.Indicator>
120
+ ));
121
+ NavigationMenuIndicator.displayName =
122
+ NavigationMenuPrimitive.Indicator.displayName;
123
+
124
+ export {
125
+ navigationMenuTriggerStyle,
126
+ NavigationMenu,
127
+ NavigationMenuList,
128
+ NavigationMenuItem,
129
+ NavigationMenuContent,
130
+ NavigationMenuTrigger,
131
+ NavigationMenuLink,
132
+ NavigationMenuIndicator,
133
+ NavigationMenuViewport,
134
+ };
135
+
@@ -157,7 +157,7 @@ export const Controlled: Story = {
157
157
  render: () => {
158
158
  const [value, setValue] = useState(10);
159
159
  return (
160
- <div className="w-48 space-y-4">
160
+ <div data-sonance-name="number-input.stories" className="w-48 space-y-4">
161
161
  <NumberInput
162
162
  label="Controlled Input"
163
163
  value={value}
@@ -165,7 +165,7 @@ export const Controlled: Story = {
165
165
  min={0}
166
166
  max={20}
167
167
  />
168
- <p className="text-sm text-foreground-muted">
168
+ <p id="controlled-p-current-value-value" className="text-sm text-foreground-muted">
169
169
  Current value: {value}
170
170
  </p>
171
171
  <div className="flex gap-2">
@@ -211,8 +211,8 @@ export const QuantitySelector: Story = {
211
211
 
212
212
  return (
213
213
  <div className="p-4 border border-border w-80">
214
- <h3 className="font-medium text-foreground">VP66 TL In-Wall Speaker</h3>
215
- <p className="text-sm text-foreground-muted mt-1">${pricePerUnit.toFixed(2)} each</p>
214
+ <h3 id="quantity-selector-h3-vp66-tl-inwall-speak" className="font-medium text-foreground">VP66 TL In-Wall Speaker</h3>
215
+ <p id="quantity-selector-p-priceperunittofixed2" className="text-sm text-foreground-muted mt-1">${pricePerUnit.toFixed(2)} each</p>
216
216
  <div className="mt-4">
217
217
  <NumberInput
218
218
  label="Quantity"
@@ -223,8 +223,8 @@ export const QuantitySelector: Story = {
223
223
  />
224
224
  </div>
225
225
  <div className="mt-4 pt-4 border-t border-border flex justify-between items-center">
226
- <span className="text-sm text-foreground-muted">Total:</span>
227
- <span className="text-lg font-medium text-foreground">
226
+ <span id="quantity-selector-span-total" className="text-sm text-foreground-muted">Total:</span>
227
+ <span id="quantity-selector-span-totaltofixed2" className="text-lg font-medium text-foreground">
228
228
  ${total.toFixed(2)}
229
229
  </span>
230
230
  </div>
@@ -239,11 +239,11 @@ export const StateMatrix: Story = {
239
239
  const states: NumberInputState[] = ['default', 'hover', 'focus', 'error', 'disabled'];
240
240
  return (
241
241
  <div className="space-y-6 w-48">
242
- <h3 className="text-sm font-medium text-foreground-muted">NumberInput States</h3>
242
+ <h3 id="state-matrix-h3-numberinput-states" className="text-sm font-medium text-foreground-muted">NumberInput States</h3>
243
243
  <div className="space-y-4">
244
244
  {states.map((state) => (
245
245
  <div key={state}>
246
- <span className="text-xs font-medium text-foreground-muted uppercase">{state}</span>
246
+ <span id="state-matrix-span-state" className="text-xs font-medium text-foreground-muted uppercase">{state}</span>
247
247
  <NumberInput
248
248
  state={state}
249
249
  defaultValue={5}
@@ -263,14 +263,14 @@ export const ResponsiveMatrix: Story = {
263
263
  <div className="space-y-8">
264
264
  {/* Mobile */}
265
265
  <div>
266
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
266
+ <h4 id="responsive-matrix-h4-mobile-375px" className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
267
267
  <div className="w-[375px] border border-dashed border-border p-4">
268
268
  <NumberInput label="Quantity" defaultValue={1} min={1} max={10} />
269
269
  </div>
270
270
  </div>
271
271
  {/* Tablet */}
272
272
  <div>
273
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
273
+ <h4 id="responsive-matrix-h4-tablet-768px" className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
274
274
  <div className="w-[768px] border border-dashed border-border p-4">
275
275
  <div className="grid grid-cols-2 gap-4">
276
276
  <NumberInput label="Quantity" defaultValue={5} />
@@ -280,7 +280,7 @@ export const ResponsiveMatrix: Story = {
280
280
  </div>
281
281
  {/* Desktop */}
282
282
  <div>
283
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
283
+ <h4 id="responsive-matrix-h4-desktop-1280px" className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
284
284
  <div className="w-[1280px] border border-dashed border-border p-4">
285
285
  <div className="grid grid-cols-4 gap-4">
286
286
  <NumberInput label="Default" defaultValue={5} />
@@ -134,7 +134,7 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
134
134
  : inputValue;
135
135
 
136
136
  return (
137
- <div className={cn("w-full", className)}>
137
+ <div data-sonance-name="number-input" className={cn("w-full", className)}>
138
138
  {label && (
139
139
  <label className="mb-2 block text-xs font-medium uppercase tracking-widest text-foreground-muted">
140
140
  {label}
@@ -196,7 +196,7 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
196
196
  </button>
197
197
  )}
198
198
  </div>
199
- {error && <p className="mt-1 text-sm text-error">{error}</p>}
199
+ {error && <p id="p-error" className="mt-1 text-sm text-error">{error}</p>}
200
200
  </div>
201
201
  );
202
202
  }
@@ -218,7 +218,7 @@ export function Stepper({ size = "md", className, ...props }: StepperProps) {
218
218
 
219
219
  return (
220
220
  <NumberInput
221
- {...props}
221
+ data-sonance-name="number-input" {...props}
222
222
  className={cn(sizeClasses[size], className)}
223
223
  />
224
224
  );
@@ -37,7 +37,7 @@ export const Default: Story = {
37
37
  render: () => {
38
38
  const [page, setPage] = useState(1);
39
39
  return (
40
- <Pagination
40
+ <Pagination data-sonance-name="pagination.stories"
41
41
  currentPage={page}
42
42
  totalPages={10}
43
43
  onPageChange={setPage}
@@ -131,7 +131,7 @@ export const BothStyles: Story = {
131
131
  return (
132
132
  <div className="space-y-8">
133
133
  <div>
134
- <p className="text-xs text-foreground-muted mb-2">Full Pagination</p>
134
+ <p id="both-styles-p-full-pagination" className="text-xs text-foreground-muted mb-2">Full Pagination</p>
135
135
  <Pagination
136
136
  currentPage={page}
137
137
  totalPages={20}
@@ -139,7 +139,7 @@ export const BothStyles: Story = {
139
139
  />
140
140
  </div>
141
141
  <div>
142
- <p className="text-xs text-foreground-muted mb-2">Compact Pagination</p>
142
+ <p id="both-styles-p-compact-pagination" className="text-xs text-foreground-muted mb-2">Compact Pagination</p>
143
143
  <CompactPagination
144
144
  currentPage={page}
145
145
  totalPages={20}
@@ -186,7 +186,7 @@ export const TableExample: Story = {
186
186
  </table>
187
187
  </div>
188
188
  <div className="flex items-center justify-between">
189
- <p className="text-sm text-foreground-muted">
189
+ <p id="table-example-p-showing-page-1-items" className="text-sm text-foreground-muted">
190
190
  Showing {(page - 1) * itemsPerPage + 1} to{' '}
191
191
  {Math.min(page * itemsPerPage, items.length)} of {items.length} results
192
192
  </p>
@@ -207,19 +207,19 @@ export const StateMatrix: Story = {
207
207
  const states: PaginationButtonState[] = ['default', 'hover', 'focus', 'active', 'disabled'];
208
208
  return (
209
209
  <div className="space-y-6">
210
- <h3 className="text-sm font-medium text-foreground-muted">PaginationButton States</h3>
211
- <p className="text-xs text-foreground-muted">States are demonstrated via the Pagination component&apos;s active and disabled props.</p>
210
+ <h3 id="state-matrix-h3-paginationbutton-sta" className="text-sm font-medium text-foreground-muted">PaginationButton States</h3>
211
+ <p id="state-matrix-p-states-are-demonstra" className="text-xs text-foreground-muted">States are demonstrated via the Pagination component&apos;s active and disabled props.</p>
212
212
  <div className="space-y-4">
213
213
  <div>
214
- <span className="text-xs font-medium text-foreground-muted uppercase">Default + Active</span>
214
+ <span id="state-matrix-span-default-active" className="text-xs font-medium text-foreground-muted uppercase">Default + Active</span>
215
215
  <Pagination currentPage={3} totalPages={5} onPageChange={() => {}} />
216
216
  </div>
217
217
  <div>
218
- <span className="text-xs font-medium text-foreground-muted uppercase">First Page (prev disabled)</span>
218
+ <span id="state-matrix-span-first-page-prev-disa" className="text-xs font-medium text-foreground-muted uppercase">First Page (prev disabled)</span>
219
219
  <Pagination currentPage={1} totalPages={5} onPageChange={() => {}} />
220
220
  </div>
221
221
  <div>
222
- <span className="text-xs font-medium text-foreground-muted uppercase">Last Page (next disabled)</span>
222
+ <span id="state-matrix-span-last-page-next-disab" className="text-xs font-medium text-foreground-muted uppercase">Last Page (next disabled)</span>
223
223
  <Pagination currentPage={5} totalPages={5} onPageChange={() => {}} />
224
224
  </div>
225
225
  </div>
@@ -239,7 +239,7 @@ export const ResponsiveMatrix: Story = {
239
239
  <div className="space-y-8">
240
240
  {/* Mobile */}
241
241
  <div>
242
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
242
+ <h4 id="responsive-matrix-h4-mobile-375px" className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
243
243
  <div className="w-[375px] border border-dashed border-border p-4">
244
244
  <CompactPagination
245
245
  currentPage={mobilePage}
@@ -250,7 +250,7 @@ export const ResponsiveMatrix: Story = {
250
250
  </div>
251
251
  {/* Tablet */}
252
252
  <div>
253
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
253
+ <h4 id="responsive-matrix-h4-tablet-768px" className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
254
254
  <div className="w-[768px] border border-dashed border-border p-4 flex justify-center">
255
255
  <Pagination
256
256
  currentPage={tabletPage}
@@ -261,9 +261,9 @@ export const ResponsiveMatrix: Story = {
261
261
  </div>
262
262
  {/* Desktop */}
263
263
  <div>
264
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
264
+ <h4 id="responsive-matrix-h4-desktop-1280px" className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
265
265
  <div className="w-[1280px] border border-dashed border-border p-4 flex items-center justify-between">
266
- <p className="text-sm text-foreground-muted">
266
+ <p id="responsive-matrix-p-showing-91100-of-500" className="text-sm text-foreground-muted">
267
267
  Showing 91-100 of 500 results
268
268
  </p>
269
269
  <Pagination