sonance-brand-mcp 1.1.3 → 1.1.7

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 (71) hide show
  1. package/dist/assets/components/accordion.stories.tsx +310 -0
  2. package/dist/assets/components/accordion.tsx +56 -30
  3. package/dist/assets/components/alert.stories.tsx +199 -0
  4. package/dist/assets/components/autocomplete.stories.tsx +307 -0
  5. package/dist/assets/components/autocomplete.tsx +28 -4
  6. package/dist/assets/components/avatar.stories.tsx +175 -0
  7. package/dist/assets/components/badge.stories.tsx +258 -0
  8. package/dist/assets/components/breadcrumbs.stories.tsx +175 -0
  9. package/dist/assets/components/button.stories.tsx +362 -0
  10. package/dist/assets/components/button.tsx +48 -3
  11. package/dist/assets/components/calendar.stories.tsx +247 -0
  12. package/dist/assets/components/card.stories.tsx +275 -0
  13. package/dist/assets/components/card.tsx +26 -1
  14. package/dist/assets/components/checkbox-group.stories.tsx +281 -0
  15. package/dist/assets/components/checkbox.stories.tsx +160 -0
  16. package/dist/assets/components/checkbox.tsx +32 -4
  17. package/dist/assets/components/code.stories.tsx +265 -0
  18. package/dist/assets/components/date-input.stories.tsx +278 -0
  19. package/dist/assets/components/date-input.tsx +24 -2
  20. package/dist/assets/components/date-picker.stories.tsx +337 -0
  21. package/dist/assets/components/date-picker.tsx +28 -4
  22. package/dist/assets/components/date-range-picker.stories.tsx +340 -0
  23. package/dist/assets/components/dialog.stories.tsx +285 -0
  24. package/dist/assets/components/divider.stories.tsx +176 -0
  25. package/dist/assets/components/drawer.stories.tsx +216 -0
  26. package/dist/assets/components/dropdown.stories.tsx +342 -0
  27. package/dist/assets/components/dropdown.tsx +55 -10
  28. package/dist/assets/components/form.stories.tsx +372 -0
  29. package/dist/assets/components/image.stories.tsx +348 -0
  30. package/dist/assets/components/input-otp.stories.tsx +336 -0
  31. package/dist/assets/components/input-otp.tsx +24 -2
  32. package/dist/assets/components/input.stories.tsx +223 -0
  33. package/dist/assets/components/input.tsx +27 -2
  34. package/dist/assets/components/kbd.stories.tsx +272 -0
  35. package/dist/assets/components/link.stories.tsx +199 -0
  36. package/dist/assets/components/link.tsx +50 -1
  37. package/dist/assets/components/listbox.stories.tsx +287 -0
  38. package/dist/assets/components/listbox.tsx +30 -7
  39. package/dist/assets/components/navbar.stories.tsx +218 -0
  40. package/dist/assets/components/number-input.stories.tsx +295 -0
  41. package/dist/assets/components/number-input.tsx +30 -8
  42. package/dist/assets/components/pagination.stories.tsx +280 -0
  43. package/dist/assets/components/pagination.tsx +45 -21
  44. package/dist/assets/components/popover.stories.tsx +219 -0
  45. package/dist/assets/components/progress.stories.tsx +153 -0
  46. package/dist/assets/components/radio-group.stories.tsx +187 -0
  47. package/dist/assets/components/radio-group.tsx +30 -6
  48. package/dist/assets/components/range-calendar.stories.tsx +334 -0
  49. package/dist/assets/components/scroll-shadow.stories.tsx +335 -0
  50. package/dist/assets/components/select.stories.tsx +192 -0
  51. package/dist/assets/components/select.tsx +54 -7
  52. package/dist/assets/components/skeleton.stories.tsx +166 -0
  53. package/dist/assets/components/slider.stories.tsx +145 -0
  54. package/dist/assets/components/slider.tsx +43 -8
  55. package/dist/assets/components/spacer.stories.tsx +216 -0
  56. package/dist/assets/components/spinner.stories.tsx +149 -0
  57. package/dist/assets/components/switch.stories.tsx +170 -0
  58. package/dist/assets/components/switch.tsx +29 -4
  59. package/dist/assets/components/table.stories.tsx +322 -0
  60. package/dist/assets/components/tabs.stories.tsx +306 -0
  61. package/dist/assets/components/tabs.tsx +25 -4
  62. package/dist/assets/components/textarea.stories.tsx +103 -0
  63. package/dist/assets/components/textarea.tsx +27 -3
  64. package/dist/assets/components/theme-toggle.stories.tsx +248 -0
  65. package/dist/assets/components/time-input.stories.tsx +365 -0
  66. package/dist/assets/components/time-input.tsx +25 -3
  67. package/dist/assets/components/toast.stories.tsx +195 -0
  68. package/dist/assets/components/tooltip.stories.tsx +226 -0
  69. package/dist/assets/components/user.stories.tsx +274 -0
  70. package/dist/index.js +1732 -13
  71. package/package.json +1 -1
@@ -0,0 +1,310 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { ComponentProps } from 'react';
3
+ import {
4
+ Accordion,
5
+ AccordionItem,
6
+ AccordionTrigger,
7
+ AccordionContent,
8
+ type AccordionTriggerState,
9
+ } from './accordion';
10
+
11
+ type AccordionStoryProps = ComponentProps<typeof Accordion> & {
12
+ state?: AccordionTriggerState;
13
+ };
14
+
15
+ const meta: Meta<AccordionStoryProps> = {
16
+ title: 'Components/Data Display/Accordion',
17
+ component: Accordion,
18
+ tags: ['autodocs'],
19
+ parameters: {
20
+ docs: {
21
+ description: {
22
+ component: 'A vertically stacked set of interactive headings that reveal or hide associated content.',
23
+ },
24
+ },
25
+ },
26
+ argTypes: {
27
+ state: {
28
+ control: 'select',
29
+ options: ['default', 'hover', 'focus', 'expanded', 'disabled'],
30
+ description: 'Visual state for AccordionTrigger documentation',
31
+ table: {
32
+ defaultValue: { summary: 'default' },
33
+ },
34
+ },
35
+ },
36
+ };
37
+
38
+ export default meta;
39
+ type Story = StoryObj<AccordionStoryProps>;
40
+
41
+ const faqItems = [
42
+ {
43
+ value: 'item-1',
44
+ question: 'What makes Sonance speakers unique?',
45
+ answer: 'Sonance speakers are designed to deliver exceptional audio performance while seamlessly blending into any architectural environment. Our "Designed to Disappear" philosophy ensures that you hear great sound without seeing obtrusive speakers.',
46
+ },
47
+ {
48
+ value: 'item-2',
49
+ question: 'Are Sonance speakers suitable for outdoor use?',
50
+ answer: 'Yes! Our Garden Series and Landscape Collection are specifically engineered for outdoor environments. They feature weather-resistant construction and can withstand various climate conditions while delivering premium sound quality.',
51
+ },
52
+ {
53
+ value: 'item-3',
54
+ question: 'How do I choose the right speakers for my space?',
55
+ answer: 'Consider factors like room size, listening preferences, and installation requirements. Our in-wall and in-ceiling speakers are perfect for whole-home audio, while our soundbars excel in dedicated entertainment spaces. Contact our team for personalized recommendations.',
56
+ },
57
+ {
58
+ value: 'item-4',
59
+ question: 'Do Sonance products come with a warranty?',
60
+ answer: 'All Sonance products come with a comprehensive warranty. Residential products typically include a limited warranty, while professional installations may qualify for extended coverage. Check the specific product documentation for details.',
61
+ },
62
+ ];
63
+
64
+ export const Default: Story = {
65
+ render: () => (
66
+ <Accordion type="single" collapsible className="w-full max-w-lg">
67
+ {faqItems.map((item) => (
68
+ <AccordionItem key={item.value} value={item.value}>
69
+ <AccordionTrigger>{item.question}</AccordionTrigger>
70
+ <AccordionContent>{item.answer}</AccordionContent>
71
+ </AccordionItem>
72
+ ))}
73
+ </Accordion>
74
+ ),
75
+ };
76
+
77
+ export const DefaultOpen: Story = {
78
+ render: () => (
79
+ <Accordion type="single" collapsible defaultValue="item-1" className="w-full max-w-lg">
80
+ {faqItems.map((item) => (
81
+ <AccordionItem key={item.value} value={item.value}>
82
+ <AccordionTrigger>{item.question}</AccordionTrigger>
83
+ <AccordionContent>{item.answer}</AccordionContent>
84
+ </AccordionItem>
85
+ ))}
86
+ </Accordion>
87
+ ),
88
+ };
89
+
90
+ export const MultipleOpen: Story = {
91
+ render: () => (
92
+ <Accordion type="multiple" defaultValue={['item-1', 'item-2']} className="w-full max-w-lg">
93
+ {faqItems.map((item) => (
94
+ <AccordionItem key={item.value} value={item.value}>
95
+ <AccordionTrigger>{item.question}</AccordionTrigger>
96
+ <AccordionContent>{item.answer}</AccordionContent>
97
+ </AccordionItem>
98
+ ))}
99
+ </Accordion>
100
+ ),
101
+ };
102
+
103
+ export const NonCollapsible: Story = {
104
+ render: () => (
105
+ <Accordion type="single" defaultValue="item-1" className="w-full max-w-lg">
106
+ <AccordionItem value="item-1">
107
+ <AccordionTrigger>Always One Open</AccordionTrigger>
108
+ <AccordionContent>
109
+ This accordion has collapsible=false (default), so one item must always be open.
110
+ Try clicking another item - the current one will close.
111
+ </AccordionContent>
112
+ </AccordionItem>
113
+ <AccordionItem value="item-2">
114
+ <AccordionTrigger>Click to Switch</AccordionTrigger>
115
+ <AccordionContent>
116
+ You can switch between items, but you cannot close all of them.
117
+ </AccordionContent>
118
+ </AccordionItem>
119
+ <AccordionItem value="item-3">
120
+ <AccordionTrigger>Third Option</AccordionTrigger>
121
+ <AccordionContent>
122
+ This behavior is useful for settings panels where at least one option must be visible.
123
+ </AccordionContent>
124
+ </AccordionItem>
125
+ </Accordion>
126
+ ),
127
+ };
128
+
129
+ export const ProductSpecs: Story = {
130
+ render: () => (
131
+ <Accordion type="multiple" className="w-full max-w-lg">
132
+ <AccordionItem value="specs">
133
+ <AccordionTrigger>Technical Specifications</AccordionTrigger>
134
+ <AccordionContent>
135
+ <div className="space-y-2 text-sm">
136
+ <div className="flex justify-between">
137
+ <span className="text-foreground-muted">Frequency Response</span>
138
+ <span>50Hz - 20kHz</span>
139
+ </div>
140
+ <div className="flex justify-between">
141
+ <span className="text-foreground-muted">Impedance</span>
142
+ <span>8 Ohms</span>
143
+ </div>
144
+ <div className="flex justify-between">
145
+ <span className="text-foreground-muted">Power Handling</span>
146
+ <span>100W RMS</span>
147
+ </div>
148
+ <div className="flex justify-between">
149
+ <span className="text-foreground-muted">Sensitivity</span>
150
+ <span>89dB @ 1W/1m</span>
151
+ </div>
152
+ </div>
153
+ </AccordionContent>
154
+ </AccordionItem>
155
+ <AccordionItem value="dimensions">
156
+ <AccordionTrigger>Dimensions</AccordionTrigger>
157
+ <AccordionContent>
158
+ <div className="space-y-2 text-sm">
159
+ <div className="flex justify-between">
160
+ <span className="text-foreground-muted">Height</span>
161
+ <span>8.5&quot;</span>
162
+ </div>
163
+ <div className="flex justify-between">
164
+ <span className="text-foreground-muted">Width</span>
165
+ <span>10.5&quot;</span>
166
+ </div>
167
+ <div className="flex justify-between">
168
+ <span className="text-foreground-muted">Depth</span>
169
+ <span>3.8&quot;</span>
170
+ </div>
171
+ <div className="flex justify-between">
172
+ <span className="text-foreground-muted">Weight</span>
173
+ <span>4.2 lbs</span>
174
+ </div>
175
+ </div>
176
+ </AccordionContent>
177
+ </AccordionItem>
178
+ <AccordionItem value="installation">
179
+ <AccordionTrigger>Installation Notes</AccordionTrigger>
180
+ <AccordionContent>
181
+ <ul className="list-disc list-inside space-y-1 text-sm">
182
+ <li>Suitable for new construction or retrofit</li>
183
+ <li>Requires 9&quot; x 11&quot; cutout</li>
184
+ <li>Mounting depth: 4&quot; minimum</li>
185
+ <li>Dog-ear mounting clips included</li>
186
+ </ul>
187
+ </AccordionContent>
188
+ </AccordionItem>
189
+ </Accordion>
190
+ ),
191
+ };
192
+
193
+ export const SettingsPanel: Story = {
194
+ render: () => (
195
+ <div className="w-full max-w-lg border border-border rounded-lg overflow-hidden">
196
+ <Accordion type="single" collapsible>
197
+ <AccordionItem value="appearance">
198
+ <AccordionTrigger className="px-4">Appearance</AccordionTrigger>
199
+ <AccordionContent className="px-4">
200
+ <p className="text-foreground-muted mb-4">
201
+ Customize how the application looks on your device.
202
+ </p>
203
+ <div className="flex gap-4">
204
+ <button className="p-4 border-2 border-primary rounded text-sm">Light</button>
205
+ <button className="p-4 border border-border rounded text-sm">Dark</button>
206
+ <button className="p-4 border border-border rounded text-sm">System</button>
207
+ </div>
208
+ </AccordionContent>
209
+ </AccordionItem>
210
+ <AccordionItem value="notifications">
211
+ <AccordionTrigger className="px-4">Notifications</AccordionTrigger>
212
+ <AccordionContent className="px-4">
213
+ <p className="text-foreground-muted">
214
+ Configure how you receive notifications and alerts.
215
+ </p>
216
+ </AccordionContent>
217
+ </AccordionItem>
218
+ <AccordionItem value="privacy">
219
+ <AccordionTrigger className="px-4">Privacy & Security</AccordionTrigger>
220
+ <AccordionContent className="px-4">
221
+ <p className="text-foreground-muted">
222
+ Manage your privacy settings and security preferences.
223
+ </p>
224
+ </AccordionContent>
225
+ </AccordionItem>
226
+ </Accordion>
227
+ </div>
228
+ ),
229
+ };
230
+
231
+ // State Matrix - Visual documentation of all AccordionTrigger states
232
+ export const StateMatrix: Story = {
233
+ render: () => {
234
+ const states: AccordionTriggerState[] = ['default', 'hover', 'focus', 'expanded', 'disabled'];
235
+ return (
236
+ <div className="space-y-6 w-96">
237
+ <h3 className="text-sm font-medium text-foreground-muted">AccordionTrigger States</h3>
238
+ <div className="space-y-2">
239
+ {states.map((state) => (
240
+ <Accordion key={state} type="single" collapsible className="w-full">
241
+ <AccordionItem value="item">
242
+ <AccordionTrigger state={state}>{state} state</AccordionTrigger>
243
+ <AccordionContent>Content for {state} state demonstration.</AccordionContent>
244
+ </AccordionItem>
245
+ </Accordion>
246
+ ))}
247
+ </div>
248
+ </div>
249
+ );
250
+ },
251
+ };
252
+
253
+ // Responsive Matrix - Mobile, Tablet, Desktop
254
+ export const ResponsiveMatrix: Story = {
255
+ render: () => (
256
+ <div className="space-y-8">
257
+ {/* Mobile */}
258
+ <div>
259
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
260
+ <div className="w-[375px] border border-dashed border-border p-4">
261
+ <Accordion type="single" collapsible defaultValue="item-1" className="w-full">
262
+ <AccordionItem value="item-1">
263
+ <AccordionTrigger>FAQ Question 1</AccordionTrigger>
264
+ <AccordionContent>Answer to the first question displayed on mobile.</AccordionContent>
265
+ </AccordionItem>
266
+ <AccordionItem value="item-2">
267
+ <AccordionTrigger>FAQ Question 2</AccordionTrigger>
268
+ <AccordionContent>Answer to the second question.</AccordionContent>
269
+ </AccordionItem>
270
+ </Accordion>
271
+ </div>
272
+ </div>
273
+ {/* Tablet */}
274
+ <div>
275
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
276
+ <div className="w-[768px] border border-dashed border-border p-4">
277
+ <Accordion type="single" collapsible defaultValue="specs" className="w-full">
278
+ <AccordionItem value="specs">
279
+ <AccordionTrigger>Technical Specifications</AccordionTrigger>
280
+ <AccordionContent>
281
+ <div className="grid grid-cols-2 gap-4 text-sm">
282
+ <div className="flex justify-between"><span className="text-foreground-muted">Frequency</span><span>50Hz - 20kHz</span></div>
283
+ <div className="flex justify-between"><span className="text-foreground-muted">Impedance</span><span>8 Ohms</span></div>
284
+ </div>
285
+ </AccordionContent>
286
+ </AccordionItem>
287
+ <AccordionItem value="dimensions">
288
+ <AccordionTrigger>Dimensions</AccordionTrigger>
289
+ <AccordionContent>Height: 8.5&quot;, Width: 10.5&quot;, Depth: 3.8&quot;</AccordionContent>
290
+ </AccordionItem>
291
+ </Accordion>
292
+ </div>
293
+ </div>
294
+ {/* Desktop */}
295
+ <div>
296
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
297
+ <div className="w-[1280px] border border-dashed border-border p-4">
298
+ <Accordion type="multiple" defaultValue={['item-1']} className="w-full">
299
+ {faqItems.map((item) => (
300
+ <AccordionItem key={item.value} value={item.value}>
301
+ <AccordionTrigger>{item.question}</AccordionTrigger>
302
+ <AccordionContent>{item.answer}</AccordionContent>
303
+ </AccordionItem>
304
+ ))}
305
+ </Accordion>
306
+ </div>
307
+ </div>
308
+ </div>
309
+ ),
310
+ };
@@ -4,6 +4,22 @@ import { forwardRef, createContext, useContext, useState } from "react";
4
4
  import { ChevronDown } from "lucide-react";
5
5
  import { cn } from "@/lib/utils";
6
6
 
7
+ export type AccordionTriggerState = "default" | "hover" | "focus" | "expanded" | "disabled";
8
+
9
+ // State styles for Storybook/Figma visualization
10
+ const getStateStyles = (state?: AccordionTriggerState) => {
11
+ if (!state || state === "default") return "";
12
+
13
+ const stateMap: Record<string, string> = {
14
+ hover: "text-foreground-secondary",
15
+ focus: "ring-2 ring-border-focus ring-offset-2 ring-offset-background",
16
+ expanded: "",
17
+ disabled: "opacity-50 cursor-not-allowed",
18
+ };
19
+
20
+ return stateMap[state] || "";
21
+ };
22
+
7
23
  interface AccordionContextValue {
8
24
  openItems: string[];
9
25
  toggleItem: (value: string) => void;
@@ -79,40 +95,50 @@ export function AccordionItem({ value, className, children }: AccordionItemProps
79
95
  );
80
96
  }
81
97
 
82
- export const AccordionTrigger = forwardRef<
83
- HTMLButtonElement,
84
- React.ButtonHTMLAttributes<HTMLButtonElement>
85
- >(({ className, children, ...props }, ref) => {
86
- const accordionContext = useContext(AccordionContext);
87
- const itemContext = useContext(AccordionItemContext);
98
+ interface AccordionTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
99
+ /** Visual state for Storybook/Figma documentation */
100
+ state?: AccordionTriggerState;
101
+ }
88
102
 
89
- if (!accordionContext || !itemContext) {
90
- throw new Error("AccordionTrigger must be used within AccordionItem");
91
- }
103
+ export const AccordionTrigger = forwardRef<HTMLButtonElement, AccordionTriggerProps>(
104
+ ({ className, children, state, disabled, ...props }, ref) => {
105
+ const accordionContext = useContext(AccordionContext);
106
+ const itemContext = useContext(AccordionItemContext);
92
107
 
93
- return (
94
- <button
95
- ref={ref}
96
- type="button"
97
- onClick={() => accordionContext.toggleItem(itemContext.value)}
98
- className={cn(
99
- "flex w-full items-center justify-between py-4 text-left font-medium text-foreground",
100
- "transition-colors hover:text-foreground-secondary",
101
- className
102
- )}
103
- aria-expanded={itemContext.isOpen}
104
- {...props}
105
- >
106
- {children}
107
- <ChevronDown
108
+ if (!accordionContext || !itemContext) {
109
+ throw new Error("AccordionTrigger must be used within AccordionItem");
110
+ }
111
+
112
+ const isExpanded = itemContext.isOpen || state === "expanded";
113
+ const isDisabled = disabled || state === "disabled";
114
+
115
+ return (
116
+ <button
117
+ ref={ref}
118
+ type="button"
119
+ onClick={() => !isDisabled && accordionContext.toggleItem(itemContext.value)}
120
+ disabled={isDisabled}
108
121
  className={cn(
109
- "h-4 w-4 shrink-0 text-foreground-muted transition-transform duration-200",
110
- itemContext.isOpen && "rotate-180"
122
+ "flex w-full items-center justify-between py-4 text-left font-medium text-foreground",
123
+ "transition-colors hover:text-foreground-secondary",
124
+ isDisabled && "opacity-50 cursor-not-allowed",
125
+ getStateStyles(state),
126
+ className
111
127
  )}
112
- />
113
- </button>
114
- );
115
- });
128
+ aria-expanded={isExpanded}
129
+ {...props}
130
+ >
131
+ {children}
132
+ <ChevronDown
133
+ className={cn(
134
+ "h-4 w-4 shrink-0 text-foreground-muted transition-transform duration-200",
135
+ isExpanded && "rotate-180"
136
+ )}
137
+ />
138
+ </button>
139
+ );
140
+ }
141
+ );
116
142
 
117
143
  AccordionTrigger.displayName = "AccordionTrigger";
118
144
 
@@ -0,0 +1,199 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { Alert } from './alert';
3
+
4
+ const meta: Meta<typeof Alert> = {
5
+ title: 'Components/Feedback/Alert',
6
+ component: Alert,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: 'An alert component for displaying important messages. Supports multiple variants for different message types.',
12
+ },
13
+ },
14
+ },
15
+ argTypes: {
16
+ variant: {
17
+ control: 'select',
18
+ options: ['default', 'success', 'error', 'warning', 'info'],
19
+ description: 'Visual style variant',
20
+ table: {
21
+ defaultValue: { summary: 'default' },
22
+ },
23
+ },
24
+ title: {
25
+ control: 'text',
26
+ description: 'Alert title',
27
+ },
28
+ children: {
29
+ control: 'text',
30
+ description: 'Alert content',
31
+ },
32
+ dismissible: {
33
+ control: 'boolean',
34
+ description: 'Show close button',
35
+ },
36
+ },
37
+ };
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ // Default
43
+ export const Default: Story = {
44
+ args: {
45
+ title: 'Heads up!',
46
+ children: 'You can add components and dependencies to your app using the CLI.',
47
+ },
48
+ };
49
+
50
+ // Success
51
+ export const Success: Story = {
52
+ args: {
53
+ variant: 'success',
54
+ title: 'Success',
55
+ children: 'Your changes have been saved successfully.',
56
+ },
57
+ };
58
+
59
+ // Error
60
+ export const Error: Story = {
61
+ args: {
62
+ variant: 'error',
63
+ title: 'Error',
64
+ children: 'There was a problem with your request. Please try again.',
65
+ },
66
+ };
67
+
68
+ // Warning
69
+ export const Warning: Story = {
70
+ args: {
71
+ variant: 'warning',
72
+ title: 'Warning',
73
+ children: 'Your subscription will expire in 3 days. Please renew to avoid interruption.',
74
+ },
75
+ };
76
+
77
+ // Info
78
+ export const Info: Story = {
79
+ args: {
80
+ variant: 'info',
81
+ title: 'Information',
82
+ children: 'A new version is available. Refresh to update.',
83
+ },
84
+ };
85
+
86
+ // Dismissible
87
+ export const Dismissible: Story = {
88
+ args: {
89
+ variant: 'info',
90
+ title: 'Dismissible Alert',
91
+ children: 'This alert can be dismissed by clicking the X button.',
92
+ dismissible: true,
93
+ onClose: () => console.log('Alert dismissed'),
94
+ },
95
+ };
96
+
97
+ // Without Title
98
+ export const WithoutTitle: Story = {
99
+ args: {
100
+ variant: 'info',
101
+ children: 'This is a simple alert without a title.',
102
+ },
103
+ };
104
+
105
+ // All Variants
106
+ export const AllVariants: Story = {
107
+ render: () => (
108
+ <div className="space-y-4 w-[500px]">
109
+ <Alert variant="default" title="Default">
110
+ This is a default alert for general information.
111
+ </Alert>
112
+ <Alert variant="success" title="Success">
113
+ Your operation completed successfully.
114
+ </Alert>
115
+ <Alert variant="error" title="Error">
116
+ Something went wrong. Please try again.
117
+ </Alert>
118
+ <Alert variant="warning" title="Warning">
119
+ Please review before proceeding.
120
+ </Alert>
121
+ <Alert variant="info" title="Info">
122
+ Here&apos;s some helpful information.
123
+ </Alert>
124
+ </div>
125
+ ),
126
+ };
127
+
128
+ // Form Validation Example
129
+ export const FormValidationExample: Story = {
130
+ render: () => (
131
+ <div className="space-y-4 w-[400px]">
132
+ <Alert variant="error" title="Form Error">
133
+ <ul className="list-disc list-inside mt-2 space-y-1">
134
+ <li>Email address is required</li>
135
+ <li>Password must be at least 8 characters</li>
136
+ <li>Please accept the terms and conditions</li>
137
+ </ul>
138
+ </Alert>
139
+ </div>
140
+ ),
141
+ };
142
+
143
+ // Dismissible Examples
144
+ export const DismissibleExamples: Story = {
145
+ render: () => (
146
+ <div className="space-y-4 w-[500px]">
147
+ <Alert variant="success" title="File uploaded" dismissible onClose={() => {}}>
148
+ document.pdf has been uploaded successfully.
149
+ </Alert>
150
+ <Alert variant="warning" dismissible onClose={() => {}}>
151
+ Your session will expire in 5 minutes.
152
+ </Alert>
153
+ </div>
154
+ ),
155
+ };
156
+
157
+ // Responsive Matrix - Mobile, Tablet, Desktop
158
+ export const ResponsiveMatrix: Story = {
159
+ render: () => (
160
+ <div className="space-y-8">
161
+ {/* Mobile */}
162
+ <div>
163
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
164
+ <div className="w-[375px] border border-dashed border-border p-4 space-y-4">
165
+ <Alert variant="success" title="Success">
166
+ Your changes have been saved.
167
+ </Alert>
168
+ <Alert variant="error" title="Error">
169
+ Something went wrong.
170
+ </Alert>
171
+ </div>
172
+ </div>
173
+ {/* Tablet */}
174
+ <div>
175
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
176
+ <div className="w-[768px] border border-dashed border-border p-4 space-y-4">
177
+ <Alert variant="info" title="Information">
178
+ A new version is available. Please refresh to update.
179
+ </Alert>
180
+ <Alert variant="warning" title="Warning" dismissible onClose={() => {}}>
181
+ Your subscription expires in 3 days. Please renew to continue.
182
+ </Alert>
183
+ </div>
184
+ </div>
185
+ {/* Desktop */}
186
+ <div>
187
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
188
+ <div className="w-[1280px] border border-dashed border-border p-4">
189
+ <div className="grid grid-cols-2 gap-4">
190
+ <Alert variant="success" title="Success">Operation completed successfully.</Alert>
191
+ <Alert variant="error" title="Error">Please try again later.</Alert>
192
+ <Alert variant="warning" title="Warning">Review before proceeding.</Alert>
193
+ <Alert variant="info" title="Info">Helpful information here.</Alert>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ ),
199
+ };