sonance-brand-mcp 1.1.4 → 1.2.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 (73) hide show
  1. package/dist/assets/BRAND_GUIDELINES.md +0 -8
  2. package/dist/assets/components/accordion.stories.tsx +310 -0
  3. package/dist/assets/components/accordion.tsx +56 -30
  4. package/dist/assets/components/alert.stories.tsx +199 -0
  5. package/dist/assets/components/autocomplete.stories.tsx +307 -0
  6. package/dist/assets/components/autocomplete.tsx +28 -4
  7. package/dist/assets/components/avatar.stories.tsx +175 -0
  8. package/dist/assets/components/badge.stories.tsx +258 -0
  9. package/dist/assets/components/breadcrumbs.stories.tsx +175 -0
  10. package/dist/assets/components/button.stories.tsx +362 -0
  11. package/dist/assets/components/button.tsx +48 -3
  12. package/dist/assets/components/calendar.stories.tsx +247 -0
  13. package/dist/assets/components/card.stories.tsx +275 -0
  14. package/dist/assets/components/card.tsx +26 -1
  15. package/dist/assets/components/checkbox-group.stories.tsx +281 -0
  16. package/dist/assets/components/checkbox.stories.tsx +160 -0
  17. package/dist/assets/components/checkbox.tsx +32 -4
  18. package/dist/assets/components/code.stories.tsx +265 -0
  19. package/dist/assets/components/date-input.stories.tsx +278 -0
  20. package/dist/assets/components/date-input.tsx +24 -2
  21. package/dist/assets/components/date-picker.stories.tsx +337 -0
  22. package/dist/assets/components/date-picker.tsx +28 -4
  23. package/dist/assets/components/date-range-picker.stories.tsx +340 -0
  24. package/dist/assets/components/dialog.stories.tsx +285 -0
  25. package/dist/assets/components/divider.stories.tsx +176 -0
  26. package/dist/assets/components/drawer.stories.tsx +216 -0
  27. package/dist/assets/components/dropdown.stories.tsx +342 -0
  28. package/dist/assets/components/dropdown.tsx +55 -10
  29. package/dist/assets/components/form.stories.tsx +372 -0
  30. package/dist/assets/components/image.stories.tsx +348 -0
  31. package/dist/assets/components/input-otp.stories.tsx +336 -0
  32. package/dist/assets/components/input-otp.tsx +24 -2
  33. package/dist/assets/components/input.stories.tsx +223 -0
  34. package/dist/assets/components/input.tsx +27 -2
  35. package/dist/assets/components/kbd.stories.tsx +272 -0
  36. package/dist/assets/components/link.stories.tsx +199 -0
  37. package/dist/assets/components/link.tsx +50 -1
  38. package/dist/assets/components/listbox.stories.tsx +287 -0
  39. package/dist/assets/components/listbox.tsx +30 -7
  40. package/dist/assets/components/navbar.stories.tsx +218 -0
  41. package/dist/assets/components/number-input.stories.tsx +295 -0
  42. package/dist/assets/components/number-input.tsx +30 -8
  43. package/dist/assets/components/pagination.stories.tsx +280 -0
  44. package/dist/assets/components/pagination.tsx +45 -21
  45. package/dist/assets/components/popover.stories.tsx +219 -0
  46. package/dist/assets/components/progress.stories.tsx +153 -0
  47. package/dist/assets/components/radio-group.stories.tsx +187 -0
  48. package/dist/assets/components/radio-group.tsx +30 -6
  49. package/dist/assets/components/range-calendar.stories.tsx +334 -0
  50. package/dist/assets/components/scroll-shadow.stories.tsx +335 -0
  51. package/dist/assets/components/select.stories.tsx +192 -0
  52. package/dist/assets/components/select.tsx +54 -7
  53. package/dist/assets/components/skeleton.stories.tsx +166 -0
  54. package/dist/assets/components/slider.stories.tsx +145 -0
  55. package/dist/assets/components/slider.tsx +43 -8
  56. package/dist/assets/components/spacer.stories.tsx +216 -0
  57. package/dist/assets/components/spinner.stories.tsx +149 -0
  58. package/dist/assets/components/switch.stories.tsx +170 -0
  59. package/dist/assets/components/switch.tsx +29 -4
  60. package/dist/assets/components/table.stories.tsx +322 -0
  61. package/dist/assets/components/tabs.stories.tsx +306 -0
  62. package/dist/assets/components/tabs.tsx +25 -4
  63. package/dist/assets/components/textarea.stories.tsx +103 -0
  64. package/dist/assets/components/textarea.tsx +27 -3
  65. package/dist/assets/components/theme-toggle.stories.tsx +248 -0
  66. package/dist/assets/components/time-input.stories.tsx +365 -0
  67. package/dist/assets/components/time-input.tsx +25 -3
  68. package/dist/assets/components/toast.stories.tsx +195 -0
  69. package/dist/assets/components/tooltip.stories.tsx +226 -0
  70. package/dist/assets/components/user.stories.tsx +274 -0
  71. package/dist/assets/logo-manifest.json +0 -18
  72. package/dist/index.js +2142 -85
  73. package/package.json +1 -1
@@ -0,0 +1,334 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { useState } from 'react';
3
+ import { addDays, addMonths } from 'date-fns';
4
+ import { RangeCalendar } from './range-calendar';
5
+
6
+ interface DateRange {
7
+ start: Date | undefined;
8
+ end: Date | undefined;
9
+ }
10
+
11
+ const meta: Meta<typeof RangeCalendar> = {
12
+ title: 'Components/Forms/RangeCalendar',
13
+ component: RangeCalendar,
14
+ tags: ['autodocs'],
15
+ parameters: {
16
+ docs: {
17
+ description: {
18
+ component: 'A calendar component for selecting date ranges. Displays two months side-by-side by default. Supports hover preview, min/max dates, and disabled dates.',
19
+ },
20
+ },
21
+ },
22
+ argTypes: {
23
+ numberOfMonths: {
24
+ control: { type: 'number', min: 1, max: 3 },
25
+ description: 'Number of months to display',
26
+ table: {
27
+ defaultValue: { summary: '2' },
28
+ },
29
+ },
30
+ },
31
+ };
32
+
33
+ export default meta;
34
+ type Story = StoryObj<typeof meta>;
35
+
36
+ // Default
37
+ export const Default: Story = {
38
+ render: () => {
39
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
40
+ return (
41
+ <div className="space-y-4">
42
+ <RangeCalendar
43
+ value={range}
44
+ onValueChange={setRange}
45
+ />
46
+ <div className="text-sm text-foreground-muted">
47
+ {range.start && <span>Start: {range.start.toLocaleDateString()}</span>}
48
+ {range.start && range.end && <span> | </span>}
49
+ {range.end && <span>End: {range.end.toLocaleDateString()}</span>}
50
+ </div>
51
+ </div>
52
+ );
53
+ },
54
+ };
55
+
56
+ // With Selected Range
57
+ export const WithSelectedRange: Story = {
58
+ render: () => {
59
+ const today = new Date();
60
+ const [range, setRange] = useState<DateRange>({
61
+ start: today,
62
+ end: addDays(today, 7),
63
+ });
64
+ return (
65
+ <RangeCalendar
66
+ value={range}
67
+ onValueChange={setRange}
68
+ />
69
+ );
70
+ },
71
+ };
72
+
73
+ // Single Month
74
+ export const SingleMonth: Story = {
75
+ render: () => {
76
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
77
+ return (
78
+ <RangeCalendar
79
+ value={range}
80
+ onValueChange={setRange}
81
+ numberOfMonths={1}
82
+ />
83
+ );
84
+ },
85
+ };
86
+
87
+ // Three Months
88
+ export const ThreeMonths: Story = {
89
+ render: () => {
90
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
91
+ return (
92
+ <RangeCalendar
93
+ value={range}
94
+ onValueChange={setRange}
95
+ numberOfMonths={3}
96
+ />
97
+ );
98
+ },
99
+ };
100
+
101
+ // With Min/Max Dates
102
+ export const WithMinMaxDates: Story = {
103
+ render: () => {
104
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
105
+ const today = new Date();
106
+ return (
107
+ <div className="space-y-4">
108
+ <p className="text-sm text-foreground-muted">
109
+ Selection limited to next 60 days
110
+ </p>
111
+ <RangeCalendar
112
+ value={range}
113
+ onValueChange={setRange}
114
+ minDate={today}
115
+ maxDate={addDays(today, 60)}
116
+ />
117
+ </div>
118
+ );
119
+ },
120
+ };
121
+
122
+ // With Disabled Dates (Weekends)
123
+ export const DisabledWeekends: Story = {
124
+ render: () => {
125
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
126
+ const isWeekend = (date: Date) => {
127
+ const day = date.getDay();
128
+ return day === 0 || day === 6;
129
+ };
130
+ return (
131
+ <div className="space-y-4">
132
+ <p className="text-sm text-foreground-muted">
133
+ Weekends are disabled (business days only)
134
+ </p>
135
+ <RangeCalendar
136
+ value={range}
137
+ onValueChange={setRange}
138
+ disabled={isWeekend}
139
+ />
140
+ </div>
141
+ );
142
+ },
143
+ };
144
+
145
+ // Hotel Booking Example
146
+ export const HotelBookingExample: Story = {
147
+ render: () => {
148
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
149
+ const today = new Date();
150
+
151
+ // Simulate blocked dates (already booked)
152
+ const blockedRanges = [
153
+ { start: addDays(today, 5), end: addDays(today, 8) },
154
+ { start: addDays(today, 15), end: addDays(today, 18) },
155
+ ];
156
+
157
+ const isBlocked = (date: Date) => {
158
+ return blockedRanges.some(
159
+ blocked =>
160
+ date >= blocked.start && date <= blocked.end
161
+ );
162
+ };
163
+
164
+ const nights = range.start && range.end
165
+ ? Math.ceil((range.end.getTime() - range.start.getTime()) / (1000 * 60 * 60 * 24))
166
+ : 0;
167
+
168
+ return (
169
+ <div className="space-y-4">
170
+ <div className="flex items-center gap-4 text-sm">
171
+ <div className="flex items-center gap-2">
172
+ <div className="w-4 h-4 bg-primary rounded-sm" />
173
+ <span>Selected</span>
174
+ </div>
175
+ <div className="flex items-center gap-2">
176
+ <div className="w-4 h-4 bg-primary/20 rounded-sm" />
177
+ <span>In Range</span>
178
+ </div>
179
+ <div className="flex items-center gap-2">
180
+ <div className="w-4 h-4 bg-secondary text-foreground-subtle text-xs flex items-center justify-center">x</div>
181
+ <span>Unavailable</span>
182
+ </div>
183
+ </div>
184
+ <RangeCalendar
185
+ value={range}
186
+ onValueChange={setRange}
187
+ minDate={today}
188
+ maxDate={addMonths(today, 6)}
189
+ disabled={isBlocked}
190
+ />
191
+ {nights > 0 && (
192
+ <div className="p-4 border border-border rounded-sm">
193
+ <div className="flex justify-between">
194
+ <span className="text-foreground-muted">Duration</span>
195
+ <span className="font-medium">{nights} night{nights !== 1 ? 's' : ''}</span>
196
+ </div>
197
+ </div>
198
+ )}
199
+ </div>
200
+ );
201
+ },
202
+ };
203
+
204
+ // Report Date Range Example
205
+ export const ReportDateRangeExample: Story = {
206
+ render: () => {
207
+ const [range, setRange] = useState<DateRange>({ start: undefined, end: undefined });
208
+ const today = new Date();
209
+
210
+ const presets = [
211
+ { label: 'Last 7 days', start: addDays(today, -7), end: today },
212
+ { label: 'Last 30 days', start: addDays(today, -30), end: today },
213
+ { label: 'This month', start: new Date(today.getFullYear(), today.getMonth(), 1), end: today },
214
+ { label: 'Last month', start: new Date(today.getFullYear(), today.getMonth() - 1, 1), end: new Date(today.getFullYear(), today.getMonth(), 0) },
215
+ ];
216
+
217
+ return (
218
+ <div className="space-y-4">
219
+ <div className="flex gap-2 flex-wrap">
220
+ {presets.map(preset => (
221
+ <button
222
+ key={preset.label}
223
+ onClick={() => setRange({ start: preset.start, end: preset.end })}
224
+ className="px-3 py-1 text-sm border border-border rounded-sm hover:bg-secondary-hover transition-colors"
225
+ >
226
+ {preset.label}
227
+ </button>
228
+ ))}
229
+ <button
230
+ onClick={() => setRange({ start: undefined, end: undefined })}
231
+ className="px-3 py-1 text-sm border border-border rounded-sm hover:bg-secondary-hover transition-colors text-foreground-muted"
232
+ >
233
+ Clear
234
+ </button>
235
+ </div>
236
+ <RangeCalendar
237
+ value={range}
238
+ onValueChange={setRange}
239
+ maxDate={today}
240
+ />
241
+ {range.start && range.end && (
242
+ <p className="text-sm">
243
+ Selected: {range.start.toLocaleDateString()} - {range.end.toLocaleDateString()}
244
+ </p>
245
+ )}
246
+ </div>
247
+ );
248
+ },
249
+ };
250
+
251
+ // All Configurations
252
+ export const AllConfigurations: Story = {
253
+ render: () => {
254
+ const [range1, setRange1] = useState<DateRange>({ start: undefined, end: undefined });
255
+ const [range2, setRange2] = useState<DateRange>({ start: undefined, end: undefined });
256
+ const [range3, setRange3] = useState<DateRange>({ start: undefined, end: undefined });
257
+
258
+ return (
259
+ <div className="space-y-8">
260
+ <div>
261
+ <h4 className="text-sm font-medium mb-2">Single Month</h4>
262
+ <RangeCalendar
263
+ value={range1}
264
+ onValueChange={setRange1}
265
+ numberOfMonths={1}
266
+ />
267
+ </div>
268
+ <div>
269
+ <h4 className="text-sm font-medium mb-2">Two Months (Default)</h4>
270
+ <RangeCalendar
271
+ value={range2}
272
+ onValueChange={setRange2}
273
+ numberOfMonths={2}
274
+ />
275
+ </div>
276
+ <div>
277
+ <h4 className="text-sm font-medium mb-2">Three Months</h4>
278
+ <RangeCalendar
279
+ value={range3}
280
+ onValueChange={setRange3}
281
+ numberOfMonths={3}
282
+ />
283
+ </div>
284
+ </div>
285
+ );
286
+ },
287
+ };
288
+
289
+ // Responsive Matrix - Mobile, Tablet, Desktop
290
+ export const ResponsiveMatrix: Story = {
291
+ render: () => {
292
+ const [mobile, setMobile] = useState<DateRange>({ start: undefined, end: undefined });
293
+ const [tablet, setTablet] = useState<DateRange>({ start: undefined, end: undefined });
294
+ const [desktop, setDesktop] = useState<DateRange>({ start: undefined, end: undefined });
295
+
296
+ return (
297
+ <div className="space-y-8">
298
+ {/* Mobile */}
299
+ <div>
300
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
301
+ <div className="w-[375px] border border-dashed border-border p-4 overflow-x-auto">
302
+ <RangeCalendar
303
+ value={mobile}
304
+ onValueChange={setMobile}
305
+ numberOfMonths={1}
306
+ />
307
+ </div>
308
+ </div>
309
+ {/* Tablet */}
310
+ <div>
311
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
312
+ <div className="w-[768px] border border-dashed border-border p-4">
313
+ <RangeCalendar
314
+ value={tablet}
315
+ onValueChange={setTablet}
316
+ numberOfMonths={2}
317
+ />
318
+ </div>
319
+ </div>
320
+ {/* Desktop */}
321
+ <div>
322
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
323
+ <div className="w-[1280px] border border-dashed border-border p-4">
324
+ <RangeCalendar
325
+ value={desktop}
326
+ onValueChange={setDesktop}
327
+ numberOfMonths={3}
328
+ />
329
+ </div>
330
+ </div>
331
+ </div>
332
+ );
333
+ },
334
+ };
@@ -0,0 +1,335 @@
1
+ import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2
+ import { ScrollShadow } from './scroll-shadow';
3
+
4
+ const meta: Meta<typeof ScrollShadow> = {
5
+ title: 'Components/Utilities/ScrollShadow',
6
+ component: ScrollShadow,
7
+ tags: ['autodocs'],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: 'A container that shows gradient shadows at scroll boundaries to indicate more content. Useful for scroll containers with fixed heights.',
12
+ },
13
+ },
14
+ },
15
+ argTypes: {
16
+ orientation: {
17
+ control: 'select',
18
+ options: ['vertical', 'horizontal', 'both'],
19
+ description: 'Scroll direction to show shadows for',
20
+ table: {
21
+ defaultValue: { summary: 'vertical' },
22
+ },
23
+ },
24
+ size: {
25
+ control: 'select',
26
+ options: ['sm', 'md', 'lg'],
27
+ description: 'Size of the shadow gradient',
28
+ table: {
29
+ defaultValue: { summary: 'md' },
30
+ },
31
+ },
32
+ hideScrollbar: {
33
+ control: 'boolean',
34
+ description: 'Hide the scrollbar',
35
+ },
36
+ },
37
+ };
38
+
39
+ export default meta;
40
+ type Story = StoryObj<typeof meta>;
41
+
42
+ const sampleContent = Array.from({ length: 20 }, (_, i) => (
43
+ <div key={i} className="p-4 border-b border-border">
44
+ <h4 className="font-medium">Item {i + 1}</h4>
45
+ <p className="text-sm text-foreground-muted">
46
+ This is sample content for item {i + 1}. Scroll to see the shadow effect.
47
+ </p>
48
+ </div>
49
+ ));
50
+
51
+ const horizontalItems = Array.from({ length: 15 }, (_, i) => (
52
+ <div
53
+ key={i}
54
+ className="flex-shrink-0 w-48 h-32 p-4 border border-border rounded-sm bg-card"
55
+ >
56
+ <h4 className="font-medium">Card {i + 1}</h4>
57
+ <p className="text-sm text-foreground-muted">Scroll horizontally</p>
58
+ </div>
59
+ ));
60
+
61
+ // Vertical (Default)
62
+ export const Vertical: Story = {
63
+ render: () => (
64
+ <ScrollShadow
65
+ orientation="vertical"
66
+ className="h-64 w-80 border border-border rounded-sm"
67
+ >
68
+ {sampleContent}
69
+ </ScrollShadow>
70
+ ),
71
+ };
72
+
73
+ // Horizontal
74
+ export const Horizontal: Story = {
75
+ render: () => (
76
+ <ScrollShadow
77
+ orientation="horizontal"
78
+ className="w-96 border border-border rounded-sm"
79
+ >
80
+ <div className="flex gap-4 p-4">
81
+ {horizontalItems}
82
+ </div>
83
+ </ScrollShadow>
84
+ ),
85
+ };
86
+
87
+ // Both Directions
88
+ export const Both: Story = {
89
+ render: () => (
90
+ <ScrollShadow
91
+ orientation="both"
92
+ className="h-64 w-80 border border-border rounded-sm"
93
+ >
94
+ <div className="w-[600px]">
95
+ {sampleContent}
96
+ <div className="p-4 text-sm text-foreground-muted">
97
+ This content extends beyond the container width to demonstrate horizontal scrolling.
98
+ </div>
99
+ </div>
100
+ </ScrollShadow>
101
+ ),
102
+ };
103
+
104
+ // Small Shadow
105
+ export const SmallShadow: Story = {
106
+ render: () => (
107
+ <ScrollShadow
108
+ size="sm"
109
+ className="h-64 w-80 border border-border rounded-sm"
110
+ >
111
+ {sampleContent}
112
+ </ScrollShadow>
113
+ ),
114
+ };
115
+
116
+ // Medium Shadow (Default)
117
+ export const MediumShadow: Story = {
118
+ render: () => (
119
+ <ScrollShadow
120
+ size="md"
121
+ className="h-64 w-80 border border-border rounded-sm"
122
+ >
123
+ {sampleContent}
124
+ </ScrollShadow>
125
+ ),
126
+ };
127
+
128
+ // Large Shadow
129
+ export const LargeShadow: Story = {
130
+ render: () => (
131
+ <ScrollShadow
132
+ size="lg"
133
+ className="h-64 w-80 border border-border rounded-sm"
134
+ >
135
+ {sampleContent}
136
+ </ScrollShadow>
137
+ ),
138
+ };
139
+
140
+ // Hidden Scrollbar
141
+ export const HiddenScrollbar: Story = {
142
+ render: () => (
143
+ <div className="space-y-4">
144
+ <p className="text-sm text-foreground-muted">
145
+ Scrollbar is hidden but scrolling still works
146
+ </p>
147
+ <ScrollShadow
148
+ hideScrollbar
149
+ className="h-64 w-80 border border-border rounded-sm"
150
+ >
151
+ {sampleContent}
152
+ </ScrollShadow>
153
+ </div>
154
+ ),
155
+ };
156
+
157
+ // Product List Example
158
+ export const ProductListExample: Story = {
159
+ render: () => {
160
+ const products = [
161
+ { name: 'In-Wall Speaker VP66', price: '$599', category: 'Architectural' },
162
+ { name: 'Soundbar SB500', price: '$799', category: 'Home Theater' },
163
+ { name: 'Outdoor Speaker LS6', price: '$449', category: 'Landscape' },
164
+ { name: 'Subwoofer SUB10', price: '$899', category: 'Performance' },
165
+ { name: 'In-Ceiling Speaker VP68', price: '$649', category: 'Architectural' },
166
+ { name: 'Garden Speaker GS6', price: '$399', category: 'Landscape' },
167
+ { name: 'Invisible Speaker IS4', price: '$1,199', category: 'Invisible' },
168
+ { name: 'Amplifier SA500', price: '$1,499', category: 'Electronics' },
169
+ { name: 'In-Wall Speaker VP86', price: '$799', category: 'Architectural' },
170
+ { name: 'Outdoor Rock Speaker RS6', price: '$549', category: 'Landscape' },
171
+ ];
172
+
173
+ return (
174
+ <div className="w-80 border border-border rounded-sm">
175
+ <div className="p-4 border-b border-border">
176
+ <h3 className="font-medium">Products ({products.length})</h3>
177
+ </div>
178
+ <ScrollShadow className="h-64">
179
+ {products.map((product, i) => (
180
+ <div key={i} className="p-4 border-b border-border hover:bg-secondary-hover transition-colors cursor-pointer">
181
+ <div className="flex justify-between items-start">
182
+ <div>
183
+ <h4 className="font-medium text-sm">{product.name}</h4>
184
+ <p className="text-xs text-foreground-muted">{product.category}</p>
185
+ </div>
186
+ <span className="font-medium">{product.price}</span>
187
+ </div>
188
+ </div>
189
+ ))}
190
+ </ScrollShadow>
191
+ </div>
192
+ );
193
+ },
194
+ };
195
+
196
+ // Image Gallery Example
197
+ export const ImageGalleryExample: Story = {
198
+ render: () => {
199
+ const images = Array.from({ length: 10 }, (_, i) => ({
200
+ id: i,
201
+ title: `Image ${i + 1}`,
202
+ }));
203
+
204
+ return (
205
+ <div className="space-y-2">
206
+ <h3 className="font-medium">Gallery</h3>
207
+ <ScrollShadow
208
+ orientation="horizontal"
209
+ hideScrollbar
210
+ className="w-full"
211
+ >
212
+ <div className="flex gap-3 p-1">
213
+ {images.map((image) => (
214
+ <div
215
+ key={image.id}
216
+ className="flex-shrink-0 w-32 h-32 bg-secondary rounded-sm flex items-center justify-center text-foreground-muted text-sm"
217
+ >
218
+ {image.title}
219
+ </div>
220
+ ))}
221
+ </div>
222
+ </ScrollShadow>
223
+ </div>
224
+ );
225
+ },
226
+ };
227
+
228
+ // Dropdown Menu Example
229
+ export const DropdownMenuExample: Story = {
230
+ render: () => {
231
+ const menuItems = [
232
+ 'Dashboard',
233
+ 'Products',
234
+ 'Orders',
235
+ 'Customers',
236
+ 'Analytics',
237
+ 'Reports',
238
+ 'Settings',
239
+ 'Help Center',
240
+ 'Documentation',
241
+ 'API Reference',
242
+ 'System Status',
243
+ 'Logout',
244
+ ];
245
+
246
+ return (
247
+ <div className="w-48 border border-border rounded-sm shadow-lg bg-card">
248
+ <ScrollShadow className="max-h-64">
249
+ {menuItems.map((item, i) => (
250
+ <button
251
+ key={i}
252
+ className="w-full px-4 py-2 text-left text-sm hover:bg-secondary-hover transition-colors"
253
+ >
254
+ {item}
255
+ </button>
256
+ ))}
257
+ </ScrollShadow>
258
+ </div>
259
+ );
260
+ },
261
+ };
262
+
263
+ // All Sizes Comparison
264
+ export const AllSizesComparison: Story = {
265
+ render: () => (
266
+ <div className="flex gap-8">
267
+ <div className="space-y-2">
268
+ <p className="text-sm font-medium">Small</p>
269
+ <ScrollShadow size="sm" className="h-48 w-64 border border-border rounded-sm">
270
+ {sampleContent.slice(0, 10)}
271
+ </ScrollShadow>
272
+ </div>
273
+ <div className="space-y-2">
274
+ <p className="text-sm font-medium">Medium</p>
275
+ <ScrollShadow size="md" className="h-48 w-64 border border-border rounded-sm">
276
+ {sampleContent.slice(0, 10)}
277
+ </ScrollShadow>
278
+ </div>
279
+ <div className="space-y-2">
280
+ <p className="text-sm font-medium">Large</p>
281
+ <ScrollShadow size="lg" className="h-48 w-64 border border-border rounded-sm">
282
+ {sampleContent.slice(0, 10)}
283
+ </ScrollShadow>
284
+ </div>
285
+ </div>
286
+ ),
287
+ };
288
+
289
+ // Responsive Matrix - Mobile, Tablet, Desktop
290
+ export const ResponsiveMatrix: Story = {
291
+ render: () => (
292
+ <div className="space-y-8">
293
+ {/* Mobile */}
294
+ <div>
295
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
296
+ <div className="w-[375px] border border-dashed border-border p-4">
297
+ <ScrollShadow className="h-48 border border-border rounded-sm">
298
+ {sampleContent.slice(0, 8)}
299
+ </ScrollShadow>
300
+ </div>
301
+ </div>
302
+ {/* Tablet */}
303
+ <div>
304
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
305
+ <div className="w-[768px] border border-dashed border-border p-4">
306
+ <ScrollShadow
307
+ orientation="horizontal"
308
+ className="border border-border rounded-sm"
309
+ >
310
+ <div className="flex gap-4 p-4">
311
+ {horizontalItems.slice(0, 8)}
312
+ </div>
313
+ </ScrollShadow>
314
+ </div>
315
+ </div>
316
+ {/* Desktop */}
317
+ <div>
318
+ <h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
319
+ <div className="w-[1280px] border border-dashed border-border p-4">
320
+ <div className="grid grid-cols-3 gap-4">
321
+ <ScrollShadow size="sm" className="h-48 border border-border rounded-sm">
322
+ {sampleContent.slice(0, 8)}
323
+ </ScrollShadow>
324
+ <ScrollShadow size="md" className="h-48 border border-border rounded-sm">
325
+ {sampleContent.slice(0, 8)}
326
+ </ScrollShadow>
327
+ <ScrollShadow size="lg" className="h-48 border border-border rounded-sm">
328
+ {sampleContent.slice(0, 8)}
329
+ </ScrollShadow>
330
+ </div>
331
+ </div>
332
+ </div>
333
+ </div>
334
+ ),
335
+ };