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,372 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { Form, FormField, FormLabel, FormDescription, FormMessage, FormSubmit } from './form';
3
+ import { Input } from './input';
4
+ import { Textarea } from './textarea';
5
+ import { Select } from './select';
6
+ import { Checkbox } from './checkbox';
7
+
8
+ const meta: Meta<typeof Form> = {
9
+ title: 'Components/Forms/Form',
10
+ component: Form,
11
+ tags: ['autodocs'],
12
+ parameters: {
13
+ docs: {
14
+ description: {
15
+ component: 'A form component with built-in validation, error handling, and submission state management. Provides context for FormField components.',
16
+ },
17
+ },
18
+ },
19
+ };
20
+
21
+ export default meta;
22
+ type Story = StoryObj<typeof meta>;
23
+
24
+ // Default Simple Form
25
+ export const Default: Story = {
26
+ render: () => {
27
+ const handleSubmit = (data: FormData) => {
28
+ alert(`Submitted: ${data.get('email')}`);
29
+ };
30
+
31
+ return (
32
+ <Form onSubmit={handleSubmit} className="w-80 space-y-4">
33
+ <FormField name="email">
34
+ <FormLabel>Email</FormLabel>
35
+ <Input name="email" type="email" placeholder="Enter your email" />
36
+ </FormField>
37
+ <FormSubmit>Subscribe</FormSubmit>
38
+ </Form>
39
+ );
40
+ },
41
+ };
42
+
43
+ // With Validation
44
+ export const WithValidation: Story = {
45
+ render: () => {
46
+ const handleValidate = (data: FormData) => {
47
+ const errors: Record<string, string> = {};
48
+ const email = data.get('email') as string;
49
+ const password = data.get('password') as string;
50
+
51
+ if (!email) {
52
+ errors.email = 'Email is required';
53
+ } else if (!email.includes('@')) {
54
+ errors.email = 'Please enter a valid email';
55
+ }
56
+
57
+ if (!password) {
58
+ errors.password = 'Password is required';
59
+ } else if (password.length < 8) {
60
+ errors.password = 'Password must be at least 8 characters';
61
+ }
62
+
63
+ return errors;
64
+ };
65
+
66
+ const handleSubmit = (data: FormData) => {
67
+ alert('Form submitted successfully!');
68
+ };
69
+
70
+ return (
71
+ <Form
72
+ onSubmit={handleSubmit}
73
+ onValidate={handleValidate}
74
+ className="w-80 space-y-4"
75
+ >
76
+ <FormField name="email">
77
+ <FormLabel required>Email</FormLabel>
78
+ <Input name="email" type="email" placeholder="you@example.com" />
79
+ <FormMessage />
80
+ </FormField>
81
+
82
+ <FormField name="password">
83
+ <FormLabel required>Password</FormLabel>
84
+ <Input name="password" type="password" placeholder="Enter password" />
85
+ <FormDescription>Must be at least 8 characters</FormDescription>
86
+ <FormMessage />
87
+ </FormField>
88
+
89
+ <FormSubmit>Sign In</FormSubmit>
90
+ </Form>
91
+ );
92
+ },
93
+ };
94
+
95
+ // Contact Form
96
+ export const ContactForm: Story = {
97
+ render: () => {
98
+ const handleValidate = (data: FormData) => {
99
+ const errors: Record<string, string> = {};
100
+
101
+ if (!data.get('name')) errors.name = 'Name is required';
102
+ if (!data.get('email')) errors.email = 'Email is required';
103
+ if (!data.get('subject')) errors.subject = 'Please select a subject';
104
+ if (!data.get('message')) errors.message = 'Message is required';
105
+
106
+ return errors;
107
+ };
108
+
109
+ const handleSubmit = async (data: FormData) => {
110
+ // Simulate API call
111
+ await new Promise(resolve => setTimeout(resolve, 1500));
112
+ alert('Message sent!');
113
+ };
114
+
115
+ return (
116
+ <Form
117
+ onSubmit={handleSubmit}
118
+ onValidate={handleValidate}
119
+ className="w-96 space-y-4"
120
+ >
121
+ <div className="grid grid-cols-2 gap-4">
122
+ <FormField name="name">
123
+ <FormLabel required>Name</FormLabel>
124
+ <Input name="name" placeholder="Your name" />
125
+ <FormMessage />
126
+ </FormField>
127
+
128
+ <FormField name="email">
129
+ <FormLabel required>Email</FormLabel>
130
+ <Input name="email" type="email" placeholder="you@example.com" />
131
+ <FormMessage />
132
+ </FormField>
133
+ </div>
134
+
135
+ <FormField name="subject">
136
+ <FormLabel required>Subject</FormLabel>
137
+ <Select
138
+ placeholder="Select a topic"
139
+ options={[
140
+ { value: 'sales', label: 'Sales Inquiry' },
141
+ { value: 'support', label: 'Technical Support' },
142
+ { value: 'partnership', label: 'Partnership' },
143
+ { value: 'other', label: 'Other' },
144
+ ]}
145
+ />
146
+ <FormMessage />
147
+ </FormField>
148
+
149
+ <FormField name="message">
150
+ <FormLabel required>Message</FormLabel>
151
+ <Textarea name="message" placeholder="How can we help?" rows={4} />
152
+ <FormMessage />
153
+ </FormField>
154
+
155
+ <FormSubmit className="w-full">Send Message</FormSubmit>
156
+ </Form>
157
+ );
158
+ },
159
+ };
160
+
161
+ // Registration Form
162
+ export const RegistrationForm: Story = {
163
+ render: () => {
164
+ const handleValidate = (data: FormData) => {
165
+ const errors: Record<string, string> = {};
166
+ const password = data.get('password') as string;
167
+ const confirmPassword = data.get('confirmPassword') as string;
168
+
169
+ if (!data.get('firstName')) errors.firstName = 'First name is required';
170
+ if (!data.get('lastName')) errors.lastName = 'Last name is required';
171
+ if (!data.get('email')) errors.email = 'Email is required';
172
+
173
+ if (!password) {
174
+ errors.password = 'Password is required';
175
+ } else if (password.length < 8) {
176
+ errors.password = 'Password must be at least 8 characters';
177
+ }
178
+
179
+ if (password !== confirmPassword) {
180
+ errors.confirmPassword = 'Passwords do not match';
181
+ }
182
+
183
+ if (!data.get('terms')) {
184
+ errors.terms = 'You must accept the terms';
185
+ }
186
+
187
+ return errors;
188
+ };
189
+
190
+ const handleSubmit = async (data: FormData) => {
191
+ await new Promise(resolve => setTimeout(resolve, 1000));
192
+ alert('Account created!');
193
+ };
194
+
195
+ return (
196
+ <Form
197
+ onSubmit={handleSubmit}
198
+ onValidate={handleValidate}
199
+ className="w-96 space-y-4"
200
+ >
201
+ <div className="grid grid-cols-2 gap-4">
202
+ <FormField name="firstName">
203
+ <FormLabel required>First Name</FormLabel>
204
+ <Input name="firstName" placeholder="John" />
205
+ <FormMessage />
206
+ </FormField>
207
+
208
+ <FormField name="lastName">
209
+ <FormLabel required>Last Name</FormLabel>
210
+ <Input name="lastName" placeholder="Doe" />
211
+ <FormMessage />
212
+ </FormField>
213
+ </div>
214
+
215
+ <FormField name="email">
216
+ <FormLabel required>Email</FormLabel>
217
+ <Input name="email" type="email" placeholder="john@example.com" />
218
+ <FormMessage />
219
+ </FormField>
220
+
221
+ <FormField name="password">
222
+ <FormLabel required>Password</FormLabel>
223
+ <Input name="password" type="password" />
224
+ <FormDescription>Minimum 8 characters</FormDescription>
225
+ <FormMessage />
226
+ </FormField>
227
+
228
+ <FormField name="confirmPassword">
229
+ <FormLabel required>Confirm Password</FormLabel>
230
+ <Input name="confirmPassword" type="password" />
231
+ <FormMessage />
232
+ </FormField>
233
+
234
+ <FormField name="terms">
235
+ <Checkbox name="terms" value="accepted" label="I accept the terms and conditions" />
236
+ <FormMessage />
237
+ </FormField>
238
+
239
+ <FormSubmit className="w-full">Create Account</FormSubmit>
240
+ </Form>
241
+ );
242
+ },
243
+ };
244
+
245
+ // Form Components Showcase
246
+ export const ComponentsShowcase: Story = {
247
+ render: () => (
248
+ <div className="w-80 space-y-6">
249
+ <div>
250
+ <h4 className="text-sm font-medium mb-2">FormLabel</h4>
251
+ <FormLabel>Regular Label</FormLabel>
252
+ <FormLabel required>Required Label</FormLabel>
253
+ </div>
254
+
255
+ <div>
256
+ <h4 className="text-sm font-medium mb-2">FormDescription</h4>
257
+ <FormDescription>
258
+ This is helper text that provides additional context for the field.
259
+ </FormDescription>
260
+ </div>
261
+
262
+ <div>
263
+ <h4 className="text-sm font-medium mb-2">FormMessage (Error)</h4>
264
+ <FormMessage>This field is required</FormMessage>
265
+ </div>
266
+
267
+ <div>
268
+ <h4 className="text-sm font-medium mb-2">FormSubmit</h4>
269
+ <FormSubmit>Submit Button</FormSubmit>
270
+ </div>
271
+ </div>
272
+ ),
273
+ };
274
+
275
+ // Async Submission
276
+ export const AsyncSubmission: Story = {
277
+ render: () => {
278
+ const handleSubmit = async (data: FormData) => {
279
+ // Simulate slow API call
280
+ await new Promise(resolve => setTimeout(resolve, 3000));
281
+ alert('Submitted!');
282
+ };
283
+
284
+ return (
285
+ <Form onSubmit={handleSubmit} className="w-80 space-y-4">
286
+ <FormField name="data">
287
+ <FormLabel>Data</FormLabel>
288
+ <Input name="data" placeholder="Enter something" />
289
+ <FormDescription>
290
+ The submit button shows loading state during submission
291
+ </FormDescription>
292
+ </FormField>
293
+ <FormSubmit>Submit (3s delay)</FormSubmit>
294
+ </Form>
295
+ );
296
+ },
297
+ };
298
+
299
+ // Responsive Matrix - Mobile, Tablet, Desktop
300
+ export const ResponsiveMatrix: Story = {
301
+ render: () => (
302
+ <div className="space-y-8">
303
+ {/* Mobile */}
304
+ <div>
305
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
306
+ <div className="w-[375px] border border-dashed border-border p-4">
307
+ <Form className="space-y-4">
308
+ <FormField name="email">
309
+ <FormLabel>Email</FormLabel>
310
+ <Input name="email" type="email" placeholder="you@example.com" />
311
+ </FormField>
312
+ <FormSubmit className="w-full">Subscribe</FormSubmit>
313
+ </Form>
314
+ </div>
315
+ </div>
316
+ {/* Tablet */}
317
+ <div>
318
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
319
+ <div className="w-[768px] border border-dashed border-border p-4">
320
+ <Form className="space-y-4">
321
+ <div className="grid grid-cols-2 gap-4">
322
+ <FormField name="firstName">
323
+ <FormLabel>First Name</FormLabel>
324
+ <Input name="firstName" placeholder="John" />
325
+ </FormField>
326
+ <FormField name="lastName">
327
+ <FormLabel>Last Name</FormLabel>
328
+ <Input name="lastName" placeholder="Doe" />
329
+ </FormField>
330
+ </div>
331
+ <FormField name="email">
332
+ <FormLabel>Email</FormLabel>
333
+ <Input name="email" type="email" placeholder="john@example.com" />
334
+ </FormField>
335
+ <FormSubmit>Submit</FormSubmit>
336
+ </Form>
337
+ </div>
338
+ </div>
339
+ {/* Desktop */}
340
+ <div>
341
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
342
+ <div className="w-[1280px] border border-dashed border-border p-4">
343
+ <Form className="space-y-4 max-w-2xl">
344
+ <div className="grid grid-cols-3 gap-4">
345
+ <FormField name="firstName">
346
+ <FormLabel required>First Name</FormLabel>
347
+ <Input name="firstName" placeholder="John" />
348
+ <FormMessage />
349
+ </FormField>
350
+ <FormField name="lastName">
351
+ <FormLabel required>Last Name</FormLabel>
352
+ <Input name="lastName" placeholder="Doe" />
353
+ <FormMessage />
354
+ </FormField>
355
+ <FormField name="email">
356
+ <FormLabel required>Email</FormLabel>
357
+ <Input name="email" type="email" placeholder="john@example.com" />
358
+ <FormMessage />
359
+ </FormField>
360
+ </div>
361
+ <FormField name="message">
362
+ <FormLabel>Message</FormLabel>
363
+ <Textarea name="message" placeholder="How can we help?" rows={3} />
364
+ <FormDescription>Optional message</FormDescription>
365
+ </FormField>
366
+ <FormSubmit>Send Message</FormSubmit>
367
+ </Form>
368
+ </div>
369
+ </div>
370
+ </div>
371
+ ),
372
+ };