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
@@ -25,7 +25,7 @@ type Story = StoryObj<typeof meta>;
25
25
 
26
26
  export const InlineDefault: Story = {
27
27
  render: () => (
28
- <p className="text-foreground-secondary">
28
+ <p id="inline-default-p" className="text-foreground-secondary">
29
29
  Use the <Code>npm install</Code> command to install dependencies.
30
30
  </p>
31
31
  ),
@@ -33,7 +33,7 @@ export const InlineDefault: Story = {
33
33
 
34
34
  export const InlinePrimary: Story = {
35
35
  render: () => (
36
- <p className="text-foreground-secondary">
36
+ <p id="inline-primary-p" className="text-foreground-secondary">
37
37
  The <Code variant="primary">useState</Code> hook is used for managing state in React.
38
38
  </p>
39
39
  ),
@@ -79,7 +79,7 @@ export function Counter() {
79
79
  const [count, setCount] = useState(0);
80
80
 
81
81
  return (
82
- <button onClick={() => setCount(count + 1)}>
82
+ <button data-sonance-name="code.stories" onClick={() => setCount(count + 1)}>
83
83
  Count: {count}
84
84
  </button>
85
85
  );
@@ -104,7 +104,7 @@ export function Counter() {
104
104
  return (
105
105
  <div>
106
106
  <button onClick={decrement}>-</button>
107
- <span>{count}</span>
107
+ <span id="counter-span-count">{count}</span>
108
108
  <button onClick={increment}>+</button>
109
109
  </div>
110
110
  );
@@ -131,15 +131,15 @@ export const InstallCommands: Story = {
131
131
  render: () => (
132
132
  <div className="space-y-4">
133
133
  <div>
134
- <p className="text-xs text-foreground-muted mb-2">npm</p>
134
+ <p id="install-commands-p-npm" className="text-xs text-foreground-muted mb-2">npm</p>
135
135
  <Snippet text="npm install @sonance/ui" />
136
136
  </div>
137
137
  <div>
138
- <p className="text-xs text-foreground-muted mb-2">pnpm</p>
138
+ <p id="install-commands-p-pnpm" className="text-xs text-foreground-muted mb-2">pnpm</p>
139
139
  <Snippet text="pnpm add @sonance/ui" />
140
140
  </div>
141
141
  <div>
142
- <p className="text-xs text-foreground-muted mb-2">yarn</p>
142
+ <p id="install-commands-p-yarn" className="text-xs text-foreground-muted mb-2">yarn</p>
143
143
  <Snippet text="yarn add @sonance/ui" />
144
144
  </div>
145
145
  </div>
@@ -149,9 +149,9 @@ export const InstallCommands: Story = {
149
149
  export const DocumentationExample: Story = {
150
150
  render: () => (
151
151
  <div className="max-w-2xl space-y-6">
152
- <h2 className="text-xl font-semibold text-foreground">Button Component</h2>
152
+ <h2 id="documentation-example-h2-button-component" className="text-xl font-semibold text-foreground">Button Component</h2>
153
153
 
154
- <p className="text-foreground-secondary">
154
+ <p id="documentation-example-p" className="text-foreground-secondary">
155
155
  Import the <Code>Button</Code> component from the UI library:
156
156
  </p>
157
157
 
@@ -162,16 +162,16 @@ export const DocumentationExample: Story = {
162
162
 
163
163
  export function MyComponent() {
164
164
  return (
165
- <Button variant="primary" size="lg">
165
+ <Button id="my-component-button-primary" variant="primary" size="lg">
166
166
  Click me
167
167
  </Button>
168
168
  );
169
169
  }`}
170
170
  />
171
171
 
172
- <h3 className="text-lg font-medium text-foreground">Props</h3>
172
+ <h3 id="my-component-h3-props" className="text-lg font-medium text-foreground">Props</h3>
173
173
 
174
- <p className="text-foreground-secondary">
174
+ <p id="my-component-p" className="text-foreground-secondary">
175
175
  The <Code variant="primary">variant</Code> prop accepts{' '}
176
176
  <Code>primary</Code>, <Code>secondary</Code>, <Code>ghost</Code>, or{' '}
177
177
  <Code>inverted</Code>.
@@ -184,14 +184,14 @@ export const AllExamples: Story = {
184
184
  render: () => (
185
185
  <div className="space-y-8 max-w-2xl">
186
186
  <div>
187
- <h3 className="text-sm font-medium text-foreground mb-2">Inline Code</h3>
188
- <p className="text-foreground-secondary">
187
+ <h3 id="all-examples-h3-inline-code" className="text-sm font-medium text-foreground mb-2">Inline Code</h3>
188
+ <p id="all-examples-p" className="text-foreground-secondary">
189
189
  Default: <Code>const x = 1</Code> | Primary: <Code variant="primary">useState</Code>
190
190
  </p>
191
191
  </div>
192
192
 
193
193
  <div>
194
- <h3 className="text-sm font-medium text-foreground mb-2">Code Block</h3>
194
+ <h3 id="all-examples-h3-code-block" className="text-sm font-medium text-foreground mb-2">Code Block</h3>
195
195
  <CodeBlock
196
196
  code={`const greeting = "Hello, World!";
197
197
  console.log(greeting);`}
@@ -199,7 +199,7 @@ console.log(greeting);`}
199
199
  </div>
200
200
 
201
201
  <div>
202
- <h3 className="text-sm font-medium text-foreground mb-2">Snippet</h3>
202
+ <h3 id="all-examples-h3-snippet" className="text-sm font-medium text-foreground mb-2">Snippet</h3>
203
203
  <Snippet text="npm install @sonance/ui" />
204
204
  </div>
205
205
  </div>
@@ -212,9 +212,9 @@ export const ResponsiveMatrix: Story = {
212
212
  <div className="space-y-8">
213
213
  {/* Mobile */}
214
214
  <div>
215
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
215
+ <h4 id="responsive-matrix-h4-mobile-375px" className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
216
216
  <div className="w-[375px] border border-dashed border-border p-4 space-y-4">
217
- <p className="text-foreground-secondary text-sm">
217
+ <p id="responsive-matrix-p" className="text-foreground-secondary text-sm">
218
218
  Use <Code>npm install</Code> to install.
219
219
  </p>
220
220
  <Snippet text="npm install @sonance/ui" />
@@ -222,13 +222,13 @@ export const ResponsiveMatrix: Story = {
222
222
  </div>
223
223
  {/* Tablet */}
224
224
  <div>
225
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
225
+ <h4 id="responsive-matrix-h4-tablet-768px" className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
226
226
  <div className="w-[768px] border border-dashed border-border p-4">
227
227
  <CodeBlock
228
228
  code={`import { Button } from '@sonance/ui';
229
229
 
230
230
  export function App() {
231
- return <Button>Click me</Button>;
231
+ return <Button id="app-button">Click me</Button>;
232
232
  }`}
233
233
  language="tsx"
234
234
  />
@@ -236,7 +236,7 @@ export function App() {
236
236
  </div>
237
237
  {/* Desktop */}
238
238
  <div>
239
- <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
239
+ <h4 id="app-h4-desktop-1280px" className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
240
240
  <div className="w-[1280px] border border-dashed border-border p-4">
241
241
  <CodeBlock
242
242
  filename="component.tsx"
@@ -250,9 +250,9 @@ export function ContactForm() {
250
250
 
251
251
  return (
252
252
  <Card>
253
- <Input label="Name" value={name} onChange={(e) => setName(e.target.value)} />
254
- <Input label="Email" value={email} onChange={(e) => setEmail(e.target.value)} />
255
- <Button>Submit</Button>
253
+ <Input id="contact-form-input" label="Name" value={name} onChange={(e) => setName(e.target.value)} />
254
+ <Input id="contact-form-input" label="Email" value={email} onChange={(e) => setEmail(e.target.value)} />
255
+ <Button id="contact-form-button">Submit</Button>
256
256
  </Card>
257
257
  );
258
258
  }`}
@@ -17,13 +17,7 @@ export const Code = forwardRef<HTMLElement, CodeProps>(
17
17
  };
18
18
 
19
19
  return (
20
- <code
21
- ref={ref}
22
- className={cn(
23
- "px-1.5 py-0.5 font-mono text-sm rounded-sm",
24
- variantClasses[variant],
25
- className
26
- )}
20
+ <code data-sonance-name="code"
27
21
  {...props}
28
22
  />
29
23
  );
@@ -61,12 +55,12 @@ export function CodeBlock({
61
55
  const lines = code.split("\n");
62
56
 
63
57
  return (
64
- <div className={cn("relative group", className)}>
58
+ <div data-sonance-name="code" className={cn("relative group w-full max-w-full overflow-hidden", className)}>
65
59
  {filename && (
66
- <div className="flex items-center justify-between px-4 py-2 border-b border-border bg-background-tertiary">
67
- <span className="text-xs font-medium text-foreground-muted">{filename}</span>
60
+ <div className="flex items-center justify-between px-3 sm:px-4 py-2 border-b border-border bg-background-tertiary">
61
+ <span id="code-block-span-filename" className="text-xs font-medium text-foreground-muted truncate">{filename}</span>
68
62
  {language && (
69
- <span className="text-xs uppercase tracking-wider text-foreground-subtle">
63
+ <span id="code-block-span-language" className="text-xs uppercase tracking-wider text-foreground-subtle flex-shrink-0 ml-2">
70
64
  {language}
71
65
  </span>
72
66
  )}
@@ -75,25 +69,25 @@ export function CodeBlock({
75
69
  <div className="relative">
76
70
  <pre
77
71
  className={cn(
78
- "overflow-x-auto bg-background-secondary p-4",
79
- "font-mono text-sm text-foreground-secondary",
72
+ "overflow-x-auto bg-background-secondary p-3 sm:p-4 w-full max-w-full",
73
+ "font-mono text-xs sm:text-sm text-foreground-secondary",
80
74
  filename && "rounded-t-none"
81
75
  )}
82
76
  >
83
- <code>
77
+ <code className="block">
84
78
  {showLineNumbers ? (
85
79
  lines.map((line, index) => (
86
80
  <div
87
81
  key={index}
88
82
  className={cn(
89
83
  "flex",
90
- highlightLines.includes(index + 1) && "bg-primary/10 -mx-4 px-4"
84
+ highlightLines.includes(index + 1) && "bg-primary/10 -mx-3 sm:-mx-4 px-3 sm:px-4"
91
85
  )}
92
86
  >
93
- <span className="mr-4 inline-block w-8 select-none text-right text-foreground-subtle">
87
+ <span id="code-block-span-index-1" className="mr-3 sm:mr-4 inline-block w-6 sm:w-8 select-none text-right text-foreground-subtle">
94
88
  {index + 1}
95
89
  </span>
96
- <span>{line}</span>
90
+ <span id="code-block-span-line">{line}</span>
97
91
  </div>
98
92
  ))
99
93
  ) : (
@@ -104,7 +98,7 @@ export function CodeBlock({
104
98
  <button
105
99
  onClick={copyToClipboard}
106
100
  className={cn(
107
- "absolute right-2 top-2 p-2",
101
+ "absolute right-1.5 sm:right-2 top-1.5 sm:top-2 p-1.5 sm:p-2",
108
102
  "bg-background border border-border rounded-sm",
109
103
  "text-foreground-muted hover:text-foreground",
110
104
  "opacity-0 group-hover:opacity-100 transition-opacity",
@@ -113,9 +107,9 @@ export function CodeBlock({
113
107
  aria-label={copied ? "Copied!" : "Copy code"}
114
108
  >
115
109
  {copied ? (
116
- <Check className="h-4 w-4 text-success" />
110
+ <Check className="h-3.5 w-3.5 sm:h-4 sm:w-4 text-success" />
117
111
  ) : (
118
- <Copy className="h-4 w-4" />
112
+ <Copy className="h-3.5 w-3.5 sm:h-4 sm:w-4" />
119
113
  )}
120
114
  </button>
121
115
  </div>
@@ -148,24 +142,25 @@ export function Snippet({
148
142
  return (
149
143
  <div
150
144
  className={cn(
151
- "inline-flex items-center gap-2 px-3 py-2",
145
+ "inline-flex items-center gap-1.5 sm:gap-2 px-2 sm:px-3 py-1.5 sm:py-2",
152
146
  "bg-background-secondary border border-border rounded-sm",
153
- "font-mono text-sm",
147
+ "font-mono text-xs sm:text-sm",
148
+ "max-w-full overflow-hidden",
154
149
  className
155
150
  )}
156
151
  >
157
- {symbol && <span className="text-foreground-muted">{symbol}</span>}
158
- <code className="text-foreground">{text}</code>
152
+ {symbol && <span id="snippet-span-symbol" className="text-foreground-muted flex-shrink-0">{symbol}</span>}
153
+ <code className="text-foreground truncate">{text}</code>
159
154
  {!hideCopyButton && (
160
155
  <button
161
156
  onClick={copyToClipboard}
162
- className="ml-2 p-1 text-foreground-muted hover:text-foreground transition-colors"
157
+ className="ml-1 sm:ml-2 p-1 text-foreground-muted hover:text-foreground transition-colors flex-shrink-0"
163
158
  aria-label={copied ? "Copied!" : "Copy"}
164
159
  >
165
160
  {copied ? (
166
- <Check className="h-3.5 w-3.5 text-success" />
161
+ <Check className="h-3 w-3 sm:h-3.5 sm:w-3.5 text-success" />
167
162
  ) : (
168
- <Copy className="h-3.5 w-3.5" />
163
+ <Copy className="h-3 w-3 sm:h-3.5 sm:w-3.5" />
169
164
  )}
170
165
  </button>
171
166
  )}
@@ -0,0 +1,128 @@
1
+ "use client";
2
+
3
+ import type { Meta, StoryObj } from "@storybook/react";
4
+ import { useState } from "react";
5
+ import { ChevronDown } from "lucide-react";
6
+ import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "./collapsible";
7
+ import { cn } from "@/lib/utils";
8
+
9
+ const meta: Meta<typeof Collapsible> = {
10
+ title: "Components/Data Display/Collapsible",
11
+ component: Collapsible,
12
+ parameters: {
13
+ layout: "centered",
14
+ },
15
+ tags: ["autodocs"],
16
+ };
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof Collapsible>;
20
+
21
+ function CollapsibleDemo() {
22
+ const [isOpen, setIsOpen] = useState(false);
23
+
24
+ return (
25
+ <Collapsible data-sonance-name="collapsible.stories"
26
+ open={isOpen}
27
+ onOpenChange={setIsOpen}
28
+ className="w-[350px] space-y-2"
29
+ >
30
+ <div className="flex items-center justify-between space-x-4 px-4">
31
+ <h4 id="collapsible-demo-h4-peduarte-starred-3-r" className="text-sm font-medium text-foreground">
32
+ @peduarte starred 3 repositories
33
+ </h4>
34
+ <CollapsibleTrigger asChild>
35
+ <button className="inline-flex h-8 w-8 items-center justify-center rounded-sm border border-border bg-transparent hover:bg-secondary-hover transition-colors">
36
+ <ChevronDown
37
+ className={cn(
38
+ "h-4 w-4 transition-transform duration-200",
39
+ isOpen && "rotate-180"
40
+ )}
41
+ />
42
+ <span id="collapsible-demo-span-toggle" className="sr-only">Toggle</span>
43
+ </button>
44
+ </CollapsibleTrigger>
45
+ </div>
46
+ <div className="rounded-sm border border-border px-4 py-3 text-sm text-foreground">
47
+ @radix-ui/primitives
48
+ </div>
49
+ <CollapsibleContent className="space-y-2">
50
+ <div className="rounded-sm border border-border px-4 py-3 text-sm text-foreground">
51
+ @radix-ui/colors
52
+ </div>
53
+ <div className="rounded-sm border border-border px-4 py-3 text-sm text-foreground">
54
+ @stitches/react
55
+ </div>
56
+ </CollapsibleContent>
57
+ </Collapsible>
58
+ );
59
+ }
60
+
61
+ export const Default: Story = {
62
+ render: () => <CollapsibleDemo />,
63
+ };
64
+
65
+ function CollapsibleFAQDemo() {
66
+ const [openItems, setOpenItems] = useState<string[]>([]);
67
+
68
+ const toggleItem = (item: string) => {
69
+ setOpenItems((prev) =>
70
+ prev.includes(item) ? prev.filter((i) => i !== item) : [...prev, item]
71
+ );
72
+ };
73
+
74
+ const faqs = [
75
+ {
76
+ id: "1",
77
+ question: "What is Sonance?",
78
+ answer:
79
+ "Sonance is a premium audio brand specializing in architectural speakers and outdoor audio solutions.",
80
+ },
81
+ {
82
+ id: "2",
83
+ question: "How do I install outdoor speakers?",
84
+ answer:
85
+ "Outdoor speakers should be installed by a certified integrator to ensure proper weatherproofing and optimal audio performance.",
86
+ },
87
+ {
88
+ id: "3",
89
+ question: "Do you offer warranties?",
90
+ answer:
91
+ "Yes, all Sonance products come with comprehensive warranty coverage. Please refer to your product documentation for specific terms.",
92
+ },
93
+ ];
94
+
95
+ return (
96
+ <div className="w-[400px] space-y-2">
97
+ {faqs.map((faq) => (
98
+ <Collapsible
99
+ key={faq.id}
100
+ open={openItems.includes(faq.id)}
101
+ onOpenChange={() => toggleItem(faq.id)}
102
+ >
103
+ <CollapsibleTrigger asChild>
104
+ <button className="flex w-full items-center justify-between rounded-sm border border-border bg-card px-4 py-3 text-left text-sm font-medium text-foreground hover:bg-card-hover transition-colors">
105
+ {faq.question}
106
+ <ChevronDown
107
+ className={cn(
108
+ "h-4 w-4 shrink-0 transition-transform duration-200",
109
+ openItems.includes(faq.id) && "rotate-180"
110
+ )}
111
+ />
112
+ </button>
113
+ </CollapsibleTrigger>
114
+ <CollapsibleContent>
115
+ <div className="border border-t-0 border-border bg-background px-4 py-3 text-sm text-foreground-secondary">
116
+ {faq.answer}
117
+ </div>
118
+ </CollapsibleContent>
119
+ </Collapsible>
120
+ ))}
121
+ </div>
122
+ );
123
+ }
124
+
125
+ export const FAQ: Story = {
126
+ render: () => <CollapsibleFAQDemo />,
127
+ };
128
+
@@ -0,0 +1,10 @@
1
+ "use client";
2
+
3
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
4
+
5
+ const Collapsible = CollapsiblePrimitive.Root;
6
+ const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
7
+ const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
8
+
9
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };
10
+
@@ -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 id="default-span-calendar">Calendar</span>
47
+ </CommandItem>
48
+ <CommandItem>
49
+ <Smile className="mr-2 h-4 w-4" />
50
+ <span id="default-span-search-emoji">Search Emoji</span>
51
+ </CommandItem>
52
+ <CommandItem>
53
+ <Calculator className="mr-2 h-4 w-4" />
54
+ <span id="default-span-calculator">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 id="default-span-profile">Profile</span>
62
+ <CommandShortcut>⌘P</CommandShortcut>
63
+ </CommandItem>
64
+ <CommandItem>
65
+ <CreditCard className="mr-2 h-4 w-4" />
66
+ <span id="default-span-billing">Billing</span>
67
+ <CommandShortcut>⌘B</CommandShortcut>
68
+ </CommandItem>
69
+ <CommandItem>
70
+ <Settings className="mr-2 h-4 w-4" />
71
+ <span id="default-span-settings">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 id="command-dialog-demo-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 id="command-dialog-demo-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 id="command-dialog-demo-span-calendar">Calendar</span>
111
+ </CommandItem>
112
+ <CommandItem>
113
+ <Smile className="mr-2 h-4 w-4" />
114
+ <span id="command-dialog-demo-span-search-emoji">Search Emoji</span>
115
+ </CommandItem>
116
+ <CommandItem>
117
+ <Calculator className="mr-2 h-4 w-4" />
118
+ <span id="command-dialog-demo-span-calculator">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 id="command-dialog-demo-span-profile">Profile</span>
126
+ <CommandShortcut>⌘P</CommandShortcut>
127
+ </CommandItem>
128
+ <CommandItem>
129
+ <CreditCard className="mr-2 h-4 w-4" />
130
+ <span id="command-dialog-demo-span-billing">Billing</span>
131
+ <CommandShortcut>⌘B</CommandShortcut>
132
+ </CommandItem>
133
+ <CommandItem>
134
+ <Settings className="mr-2 h-4 w-4" />
135
+ <span id="command-dialog-demo-span-settings">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
+