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.
- package/dist/assets/BRAND_GUIDELINES.md +0 -8
- package/dist/assets/components/accordion.stories.tsx +310 -0
- package/dist/assets/components/accordion.tsx +56 -30
- package/dist/assets/components/alert.stories.tsx +199 -0
- package/dist/assets/components/autocomplete.stories.tsx +307 -0
- package/dist/assets/components/autocomplete.tsx +28 -4
- package/dist/assets/components/avatar.stories.tsx +175 -0
- package/dist/assets/components/badge.stories.tsx +258 -0
- package/dist/assets/components/breadcrumbs.stories.tsx +175 -0
- package/dist/assets/components/button.stories.tsx +362 -0
- package/dist/assets/components/button.tsx +48 -3
- package/dist/assets/components/calendar.stories.tsx +247 -0
- package/dist/assets/components/card.stories.tsx +275 -0
- package/dist/assets/components/card.tsx +26 -1
- package/dist/assets/components/checkbox-group.stories.tsx +281 -0
- package/dist/assets/components/checkbox.stories.tsx +160 -0
- package/dist/assets/components/checkbox.tsx +32 -4
- package/dist/assets/components/code.stories.tsx +265 -0
- package/dist/assets/components/date-input.stories.tsx +278 -0
- package/dist/assets/components/date-input.tsx +24 -2
- package/dist/assets/components/date-picker.stories.tsx +337 -0
- package/dist/assets/components/date-picker.tsx +28 -4
- package/dist/assets/components/date-range-picker.stories.tsx +340 -0
- package/dist/assets/components/dialog.stories.tsx +285 -0
- package/dist/assets/components/divider.stories.tsx +176 -0
- package/dist/assets/components/drawer.stories.tsx +216 -0
- package/dist/assets/components/dropdown.stories.tsx +342 -0
- package/dist/assets/components/dropdown.tsx +55 -10
- package/dist/assets/components/form.stories.tsx +372 -0
- package/dist/assets/components/image.stories.tsx +348 -0
- package/dist/assets/components/input-otp.stories.tsx +336 -0
- package/dist/assets/components/input-otp.tsx +24 -2
- package/dist/assets/components/input.stories.tsx +223 -0
- package/dist/assets/components/input.tsx +27 -2
- package/dist/assets/components/kbd.stories.tsx +272 -0
- package/dist/assets/components/link.stories.tsx +199 -0
- package/dist/assets/components/link.tsx +50 -1
- package/dist/assets/components/listbox.stories.tsx +287 -0
- package/dist/assets/components/listbox.tsx +30 -7
- package/dist/assets/components/navbar.stories.tsx +218 -0
- package/dist/assets/components/number-input.stories.tsx +295 -0
- package/dist/assets/components/number-input.tsx +30 -8
- package/dist/assets/components/pagination.stories.tsx +280 -0
- package/dist/assets/components/pagination.tsx +45 -21
- package/dist/assets/components/popover.stories.tsx +219 -0
- package/dist/assets/components/progress.stories.tsx +153 -0
- package/dist/assets/components/radio-group.stories.tsx +187 -0
- package/dist/assets/components/radio-group.tsx +30 -6
- package/dist/assets/components/range-calendar.stories.tsx +334 -0
- package/dist/assets/components/scroll-shadow.stories.tsx +335 -0
- package/dist/assets/components/select.stories.tsx +192 -0
- package/dist/assets/components/select.tsx +54 -7
- package/dist/assets/components/skeleton.stories.tsx +166 -0
- package/dist/assets/components/slider.stories.tsx +145 -0
- package/dist/assets/components/slider.tsx +43 -8
- package/dist/assets/components/spacer.stories.tsx +216 -0
- package/dist/assets/components/spinner.stories.tsx +149 -0
- package/dist/assets/components/switch.stories.tsx +170 -0
- package/dist/assets/components/switch.tsx +29 -4
- package/dist/assets/components/table.stories.tsx +322 -0
- package/dist/assets/components/tabs.stories.tsx +306 -0
- package/dist/assets/components/tabs.tsx +25 -4
- package/dist/assets/components/textarea.stories.tsx +103 -0
- package/dist/assets/components/textarea.tsx +27 -3
- package/dist/assets/components/theme-toggle.stories.tsx +248 -0
- package/dist/assets/components/time-input.stories.tsx +365 -0
- package/dist/assets/components/time-input.tsx +25 -3
- package/dist/assets/components/toast.stories.tsx +195 -0
- package/dist/assets/components/tooltip.stories.tsx +226 -0
- package/dist/assets/components/user.stories.tsx +274 -0
- package/dist/assets/logo-manifest.json +0 -18
- package/dist/index.js +2142 -85
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, type CardState } from './card';
|
|
3
|
+
import { Button } from './button';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Card> = {
|
|
6
|
+
title: 'Components/Data Display/Card',
|
|
7
|
+
component: Card,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: 'A versatile card component for grouping related content. Supports default and elevated variants.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
variant: {
|
|
18
|
+
control: 'select',
|
|
19
|
+
options: ['default', 'elevated'],
|
|
20
|
+
description: 'Visual style variant',
|
|
21
|
+
table: {
|
|
22
|
+
defaultValue: { summary: 'default' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
state: {
|
|
26
|
+
control: 'select',
|
|
27
|
+
options: ['default', 'hover', 'focus'],
|
|
28
|
+
description: 'Visual state for documentation',
|
|
29
|
+
table: {
|
|
30
|
+
defaultValue: { summary: 'default' },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default meta;
|
|
37
|
+
type Story = StoryObj<typeof meta>;
|
|
38
|
+
|
|
39
|
+
// Default story
|
|
40
|
+
export const Default: Story = {
|
|
41
|
+
render: (args) => (
|
|
42
|
+
<Card {...args} className="w-80">
|
|
43
|
+
<CardHeader>
|
|
44
|
+
<CardTitle>Card Title</CardTitle>
|
|
45
|
+
<CardDescription>Card description goes here</CardDescription>
|
|
46
|
+
</CardHeader>
|
|
47
|
+
<CardContent>
|
|
48
|
+
<p className="text-foreground-secondary">
|
|
49
|
+
This is the card content area where you can place any content.
|
|
50
|
+
</p>
|
|
51
|
+
</CardContent>
|
|
52
|
+
</Card>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Elevated
|
|
57
|
+
export const Elevated: Story = {
|
|
58
|
+
render: () => (
|
|
59
|
+
<Card variant="elevated" className="w-80">
|
|
60
|
+
<CardHeader>
|
|
61
|
+
<CardTitle>Elevated Card</CardTitle>
|
|
62
|
+
<CardDescription>With shadow effect</CardDescription>
|
|
63
|
+
</CardHeader>
|
|
64
|
+
<CardContent>
|
|
65
|
+
<p className="text-foreground-secondary">
|
|
66
|
+
Elevated cards have a shadow that increases on hover.
|
|
67
|
+
</p>
|
|
68
|
+
</CardContent>
|
|
69
|
+
</Card>
|
|
70
|
+
),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// With Footer
|
|
74
|
+
export const WithFooter: Story = {
|
|
75
|
+
render: () => (
|
|
76
|
+
<Card className="w-80">
|
|
77
|
+
<CardHeader>
|
|
78
|
+
<CardTitle>Card with Actions</CardTitle>
|
|
79
|
+
<CardDescription>Includes action buttons in footer</CardDescription>
|
|
80
|
+
</CardHeader>
|
|
81
|
+
<CardContent>
|
|
82
|
+
<p className="text-foreground-secondary">
|
|
83
|
+
Cards can include a footer section for actions.
|
|
84
|
+
</p>
|
|
85
|
+
</CardContent>
|
|
86
|
+
<CardFooter className="gap-2">
|
|
87
|
+
<Button variant="primary" size="sm">Save</Button>
|
|
88
|
+
<Button variant="secondary" size="sm">Cancel</Button>
|
|
89
|
+
</CardFooter>
|
|
90
|
+
</Card>
|
|
91
|
+
),
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Product Card Example
|
|
95
|
+
export const ProductCard: Story = {
|
|
96
|
+
render: () => (
|
|
97
|
+
<Card className="w-72 overflow-hidden">
|
|
98
|
+
<div className="aspect-square bg-background-secondary flex items-center justify-center">
|
|
99
|
+
<span className="text-foreground-muted">Product Image</span>
|
|
100
|
+
</div>
|
|
101
|
+
<CardHeader>
|
|
102
|
+
<CardTitle>Sonance Speaker</CardTitle>
|
|
103
|
+
<CardDescription>Premium in-wall speaker</CardDescription>
|
|
104
|
+
</CardHeader>
|
|
105
|
+
<CardContent>
|
|
106
|
+
<p className="text-2xl font-light text-foreground">$1,299.00</p>
|
|
107
|
+
</CardContent>
|
|
108
|
+
<CardFooter>
|
|
109
|
+
<Button className="w-full">Add to Cart</Button>
|
|
110
|
+
</CardFooter>
|
|
111
|
+
</Card>
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Grid Layout
|
|
116
|
+
export const GridLayout: Story = {
|
|
117
|
+
render: () => (
|
|
118
|
+
<div className="grid grid-cols-3 gap-4">
|
|
119
|
+
{[1, 2, 3].map((i) => (
|
|
120
|
+
<Card key={i} variant="elevated" className="w-64">
|
|
121
|
+
<CardHeader>
|
|
122
|
+
<CardTitle>Feature {i}</CardTitle>
|
|
123
|
+
<CardDescription>Feature description</CardDescription>
|
|
124
|
+
</CardHeader>
|
|
125
|
+
<CardContent>
|
|
126
|
+
<p className="text-foreground-secondary text-sm">
|
|
127
|
+
Brief explanation of this feature and its benefits.
|
|
128
|
+
</p>
|
|
129
|
+
</CardContent>
|
|
130
|
+
</Card>
|
|
131
|
+
))}
|
|
132
|
+
</div>
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Variants Comparison
|
|
137
|
+
export const VariantsComparison: Story = {
|
|
138
|
+
render: () => (
|
|
139
|
+
<div className="flex gap-6">
|
|
140
|
+
<Card className="w-64">
|
|
141
|
+
<CardHeader>
|
|
142
|
+
<CardTitle>Default Card</CardTitle>
|
|
143
|
+
<CardDescription>Subtle border, hover effect</CardDescription>
|
|
144
|
+
</CardHeader>
|
|
145
|
+
<CardContent>
|
|
146
|
+
<p className="text-foreground-secondary text-sm">
|
|
147
|
+
Best for content lists and grids.
|
|
148
|
+
</p>
|
|
149
|
+
</CardContent>
|
|
150
|
+
</Card>
|
|
151
|
+
<Card variant="elevated" className="w-64">
|
|
152
|
+
<CardHeader>
|
|
153
|
+
<CardTitle>Elevated Card</CardTitle>
|
|
154
|
+
<CardDescription>Shadow with hover enhancement</CardDescription>
|
|
155
|
+
</CardHeader>
|
|
156
|
+
<CardContent>
|
|
157
|
+
<p className="text-foreground-secondary text-sm">
|
|
158
|
+
Best for featured or important content.
|
|
159
|
+
</p>
|
|
160
|
+
</CardContent>
|
|
161
|
+
</Card>
|
|
162
|
+
</div>
|
|
163
|
+
),
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Interactive States - for Figma documentation
|
|
167
|
+
export const StateMatrix: Story = {
|
|
168
|
+
render: () => {
|
|
169
|
+
const variants = ['default', 'elevated'] as const;
|
|
170
|
+
const states: CardState[] = ['default', 'hover', 'focus'];
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div className="space-y-8">
|
|
174
|
+
<h3 className="text-sm font-medium text-foreground-muted">Card State Matrix</h3>
|
|
175
|
+
<div className="grid grid-cols-4 gap-4">
|
|
176
|
+
<div></div>
|
|
177
|
+
{states.map((state) => (
|
|
178
|
+
<div key={state} className="text-xs font-medium text-foreground-muted uppercase text-center">
|
|
179
|
+
{state}
|
|
180
|
+
</div>
|
|
181
|
+
))}
|
|
182
|
+
</div>
|
|
183
|
+
{variants.map((variant) => (
|
|
184
|
+
<div key={variant} className="grid grid-cols-4 gap-4 items-start">
|
|
185
|
+
<div className="text-xs font-medium text-foreground-muted uppercase pt-4">{variant}</div>
|
|
186
|
+
{states.map((state) => (
|
|
187
|
+
<Card key={`${variant}-${state}`} variant={variant} state={state} className="w-full">
|
|
188
|
+
<CardHeader>
|
|
189
|
+
<CardTitle>Card Title</CardTitle>
|
|
190
|
+
<CardDescription>{state} state</CardDescription>
|
|
191
|
+
</CardHeader>
|
|
192
|
+
<CardContent>
|
|
193
|
+
<p className="text-foreground-secondary text-sm">
|
|
194
|
+
Card content goes here.
|
|
195
|
+
</p>
|
|
196
|
+
</CardContent>
|
|
197
|
+
</Card>
|
|
198
|
+
))}
|
|
199
|
+
</div>
|
|
200
|
+
))}
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Responsive Matrix - Mobile, Tablet, Desktop
|
|
207
|
+
export const ResponsiveMatrix: Story = {
|
|
208
|
+
render: () => (
|
|
209
|
+
<div className="space-y-8">
|
|
210
|
+
{/* Mobile */}
|
|
211
|
+
<div>
|
|
212
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
|
|
213
|
+
<div className="w-[375px] border border-dashed border-border p-4 space-y-4">
|
|
214
|
+
<Card className="w-full">
|
|
215
|
+
<CardHeader>
|
|
216
|
+
<CardTitle>Card Title</CardTitle>
|
|
217
|
+
<CardDescription>Card description</CardDescription>
|
|
218
|
+
</CardHeader>
|
|
219
|
+
<CardContent>
|
|
220
|
+
<p className="text-foreground-secondary text-sm">Content that fills the mobile width.</p>
|
|
221
|
+
</CardContent>
|
|
222
|
+
<CardFooter>
|
|
223
|
+
<Button className="w-full">Action</Button>
|
|
224
|
+
</CardFooter>
|
|
225
|
+
</Card>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
{/* Tablet */}
|
|
229
|
+
<div>
|
|
230
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
|
|
231
|
+
<div className="w-[768px] border border-dashed border-border p-4">
|
|
232
|
+
<div className="grid grid-cols-2 gap-4">
|
|
233
|
+
<Card>
|
|
234
|
+
<CardHeader>
|
|
235
|
+
<CardTitle>Feature One</CardTitle>
|
|
236
|
+
<CardDescription>Description</CardDescription>
|
|
237
|
+
</CardHeader>
|
|
238
|
+
<CardContent>
|
|
239
|
+
<p className="text-foreground-secondary text-sm">Card content for tablet view.</p>
|
|
240
|
+
</CardContent>
|
|
241
|
+
</Card>
|
|
242
|
+
<Card>
|
|
243
|
+
<CardHeader>
|
|
244
|
+
<CardTitle>Feature Two</CardTitle>
|
|
245
|
+
<CardDescription>Description</CardDescription>
|
|
246
|
+
</CardHeader>
|
|
247
|
+
<CardContent>
|
|
248
|
+
<p className="text-foreground-secondary text-sm">Card content for tablet view.</p>
|
|
249
|
+
</CardContent>
|
|
250
|
+
</Card>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
{/* Desktop */}
|
|
255
|
+
<div>
|
|
256
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
|
|
257
|
+
<div className="w-[1280px] border border-dashed border-border p-4">
|
|
258
|
+
<div className="grid grid-cols-4 gap-4">
|
|
259
|
+
{[1, 2, 3, 4].map((i) => (
|
|
260
|
+
<Card key={i} variant="elevated">
|
|
261
|
+
<CardHeader>
|
|
262
|
+
<CardTitle>Feature {i}</CardTitle>
|
|
263
|
+
<CardDescription>Feature description</CardDescription>
|
|
264
|
+
</CardHeader>
|
|
265
|
+
<CardContent>
|
|
266
|
+
<p className="text-foreground-secondary text-sm">Card content at desktop width.</p>
|
|
267
|
+
</CardContent>
|
|
268
|
+
</Card>
|
|
269
|
+
))}
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
),
|
|
275
|
+
};
|
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
import { cn } from "@/lib/utils";
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
3
|
|
|
4
|
+
export type CardState = "default" | "hover" | "focus";
|
|
5
|
+
|
|
4
6
|
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
7
|
variant?: "default" | "elevated";
|
|
8
|
+
/** Visual state for Storybook/Figma documentation */
|
|
9
|
+
state?: CardState;
|
|
6
10
|
}
|
|
7
11
|
|
|
12
|
+
// State styles for Storybook/Figma visualization
|
|
13
|
+
const getStateStyles = (variant: string, state?: CardState) => {
|
|
14
|
+
if (!state || state === "default") return "";
|
|
15
|
+
|
|
16
|
+
if (variant === "elevated") {
|
|
17
|
+
const stateMap: Record<string, string> = {
|
|
18
|
+
hover: "shadow-lg",
|
|
19
|
+
focus: "ring-2 ring-border-focus ring-offset-2 ring-offset-background",
|
|
20
|
+
};
|
|
21
|
+
return stateMap[state] || "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const stateMap: Record<string, string> = {
|
|
25
|
+
hover: "border-border-hover bg-card-hover",
|
|
26
|
+
focus: "ring-2 ring-border-focus ring-offset-2 ring-offset-background",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return stateMap[state] || "";
|
|
30
|
+
};
|
|
31
|
+
|
|
8
32
|
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
9
|
-
({ className, variant = "default", ...props }, ref) => {
|
|
33
|
+
({ className, variant = "default", state, ...props }, ref) => {
|
|
10
34
|
return (
|
|
11
35
|
<div
|
|
12
36
|
ref={ref}
|
|
@@ -14,6 +38,7 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
|
14
38
|
"bg-card border border-card-border transition-all duration-200",
|
|
15
39
|
variant === "elevated" && "shadow-md hover:shadow-lg",
|
|
16
40
|
variant === "default" && "hover:border-border-hover hover:bg-card-hover",
|
|
41
|
+
getStateStyles(variant, state),
|
|
17
42
|
className
|
|
18
43
|
)}
|
|
19
44
|
{...props}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/nextjs-vite';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { CheckboxGroup, CheckboxGroupItem, CheckboxList } from './checkbox-group';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof CheckboxGroup> = {
|
|
6
|
+
title: 'Components/Forms/CheckboxGroup',
|
|
7
|
+
component: CheckboxGroup,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
docs: {
|
|
11
|
+
description: {
|
|
12
|
+
component: 'A group of checkboxes for selecting multiple options. Supports vertical and horizontal layouts, labels, descriptions, and error states.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
orientation: {
|
|
18
|
+
control: 'select',
|
|
19
|
+
options: ['vertical', 'horizontal'],
|
|
20
|
+
description: 'Layout orientation of the checkbox group',
|
|
21
|
+
table: {
|
|
22
|
+
defaultValue: { summary: 'vertical' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
disabled: {
|
|
26
|
+
control: 'boolean',
|
|
27
|
+
description: 'Disable all checkboxes in the group',
|
|
28
|
+
},
|
|
29
|
+
label: {
|
|
30
|
+
control: 'text',
|
|
31
|
+
description: 'Group label text',
|
|
32
|
+
},
|
|
33
|
+
error: {
|
|
34
|
+
control: 'text',
|
|
35
|
+
description: 'Error message',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
type Story = StoryObj<typeof meta>;
|
|
42
|
+
|
|
43
|
+
// Default
|
|
44
|
+
export const Default: Story = {
|
|
45
|
+
render: () => {
|
|
46
|
+
const [values, setValues] = useState<string[]>([]);
|
|
47
|
+
return (
|
|
48
|
+
<CheckboxGroup value={values} onValueChange={setValues}>
|
|
49
|
+
<CheckboxGroupItem value="option1" label="Option 1" />
|
|
50
|
+
<CheckboxGroupItem value="option2" label="Option 2" />
|
|
51
|
+
<CheckboxGroupItem value="option3" label="Option 3" />
|
|
52
|
+
</CheckboxGroup>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// With Label
|
|
58
|
+
export const WithLabel: Story = {
|
|
59
|
+
render: () => {
|
|
60
|
+
const [values, setValues] = useState<string[]>(['notifications']);
|
|
61
|
+
return (
|
|
62
|
+
<CheckboxGroup
|
|
63
|
+
label="Communication Preferences"
|
|
64
|
+
value={values}
|
|
65
|
+
onValueChange={setValues}
|
|
66
|
+
>
|
|
67
|
+
<CheckboxGroupItem
|
|
68
|
+
value="notifications"
|
|
69
|
+
label="Push notifications"
|
|
70
|
+
description="Receive notifications on your device"
|
|
71
|
+
/>
|
|
72
|
+
<CheckboxGroupItem
|
|
73
|
+
value="emails"
|
|
74
|
+
label="Email updates"
|
|
75
|
+
description="Receive product updates via email"
|
|
76
|
+
/>
|
|
77
|
+
<CheckboxGroupItem
|
|
78
|
+
value="sms"
|
|
79
|
+
label="SMS alerts"
|
|
80
|
+
description="Receive text message alerts"
|
|
81
|
+
/>
|
|
82
|
+
</CheckboxGroup>
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Horizontal Layout
|
|
88
|
+
export const Horizontal: Story = {
|
|
89
|
+
render: () => {
|
|
90
|
+
const [values, setValues] = useState<string[]>([]);
|
|
91
|
+
return (
|
|
92
|
+
<CheckboxGroup
|
|
93
|
+
label="Select sizes"
|
|
94
|
+
orientation="horizontal"
|
|
95
|
+
value={values}
|
|
96
|
+
onValueChange={setValues}
|
|
97
|
+
>
|
|
98
|
+
<CheckboxGroupItem value="small" label="Small" />
|
|
99
|
+
<CheckboxGroupItem value="medium" label="Medium" />
|
|
100
|
+
<CheckboxGroupItem value="large" label="Large" />
|
|
101
|
+
<CheckboxGroupItem value="xlarge" label="X-Large" />
|
|
102
|
+
</CheckboxGroup>
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// With Error
|
|
108
|
+
export const WithError: Story = {
|
|
109
|
+
render: () => {
|
|
110
|
+
const [values, setValues] = useState<string[]>([]);
|
|
111
|
+
return (
|
|
112
|
+
<CheckboxGroup
|
|
113
|
+
label="Required Selection"
|
|
114
|
+
error="Please select at least one option"
|
|
115
|
+
value={values}
|
|
116
|
+
onValueChange={setValues}
|
|
117
|
+
>
|
|
118
|
+
<CheckboxGroupItem value="agree" label="I agree to the terms" />
|
|
119
|
+
<CheckboxGroupItem value="marketing" label="I want to receive marketing emails" />
|
|
120
|
+
</CheckboxGroup>
|
|
121
|
+
);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Disabled
|
|
126
|
+
export const Disabled: Story = {
|
|
127
|
+
render: () => {
|
|
128
|
+
return (
|
|
129
|
+
<CheckboxGroup
|
|
130
|
+
label="Disabled Group"
|
|
131
|
+
disabled
|
|
132
|
+
defaultValue={['option1']}
|
|
133
|
+
>
|
|
134
|
+
<CheckboxGroupItem value="option1" label="Option 1 (pre-selected)" />
|
|
135
|
+
<CheckboxGroupItem value="option2" label="Option 2" />
|
|
136
|
+
<CheckboxGroupItem value="option3" label="Option 3" />
|
|
137
|
+
</CheckboxGroup>
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// Individual Disabled Items
|
|
143
|
+
export const IndividualDisabled: Story = {
|
|
144
|
+
render: () => {
|
|
145
|
+
const [values, setValues] = useState<string[]>(['basic']);
|
|
146
|
+
return (
|
|
147
|
+
<CheckboxGroup
|
|
148
|
+
label="Select Features"
|
|
149
|
+
value={values}
|
|
150
|
+
onValueChange={setValues}
|
|
151
|
+
>
|
|
152
|
+
<CheckboxGroupItem value="basic" label="Basic features" description="Always included" />
|
|
153
|
+
<CheckboxGroupItem value="advanced" label="Advanced features" description="Requires Pro plan" />
|
|
154
|
+
<CheckboxGroupItem
|
|
155
|
+
value="enterprise"
|
|
156
|
+
label="Enterprise features"
|
|
157
|
+
description="Contact sales for access"
|
|
158
|
+
disabled
|
|
159
|
+
/>
|
|
160
|
+
</CheckboxGroup>
|
|
161
|
+
);
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Using CheckboxList (convenience component)
|
|
166
|
+
export const UsingCheckboxList: Story = {
|
|
167
|
+
render: () => {
|
|
168
|
+
const [values, setValues] = useState<string[]>(['speaker']);
|
|
169
|
+
const options = [
|
|
170
|
+
{ value: 'speaker', label: 'In-Wall Speakers', description: 'Premium architectural speakers' },
|
|
171
|
+
{ value: 'soundbar', label: 'Soundbar', description: 'For home theater setups' },
|
|
172
|
+
{ value: 'subwoofer', label: 'Subwoofer', description: 'Deep bass performance' },
|
|
173
|
+
{ value: 'outdoor', label: 'Outdoor Speakers', description: 'Weather-resistant design', disabled: true },
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<CheckboxList
|
|
178
|
+
label="Product Interests"
|
|
179
|
+
options={options}
|
|
180
|
+
value={values}
|
|
181
|
+
onValueChange={setValues}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Form Example
|
|
188
|
+
export const FormExample: Story = {
|
|
189
|
+
render: () => {
|
|
190
|
+
const [interests, setInterests] = useState<string[]>([]);
|
|
191
|
+
const [agreements, setAgreements] = useState<string[]>([]);
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div className="space-y-8 max-w-md">
|
|
195
|
+
<CheckboxGroup
|
|
196
|
+
label="Areas of Interest"
|
|
197
|
+
value={interests}
|
|
198
|
+
onValueChange={setInterests}
|
|
199
|
+
>
|
|
200
|
+
<CheckboxGroupItem value="residential" label="Residential Audio" />
|
|
201
|
+
<CheckboxGroupItem value="commercial" label="Commercial Installations" />
|
|
202
|
+
<CheckboxGroupItem value="outdoor" label="Outdoor Sound Systems" />
|
|
203
|
+
<CheckboxGroupItem value="marine" label="Marine Audio" />
|
|
204
|
+
</CheckboxGroup>
|
|
205
|
+
|
|
206
|
+
<CheckboxGroup
|
|
207
|
+
label="Agreements"
|
|
208
|
+
value={agreements}
|
|
209
|
+
onValueChange={setAgreements}
|
|
210
|
+
error={agreements.length === 0 ? "Please accept the required agreements" : undefined}
|
|
211
|
+
>
|
|
212
|
+
<CheckboxGroupItem
|
|
213
|
+
value="terms"
|
|
214
|
+
label="I accept the terms and conditions"
|
|
215
|
+
/>
|
|
216
|
+
<CheckboxGroupItem
|
|
217
|
+
value="privacy"
|
|
218
|
+
label="I have read the privacy policy"
|
|
219
|
+
/>
|
|
220
|
+
<CheckboxGroupItem
|
|
221
|
+
value="newsletter"
|
|
222
|
+
label="Subscribe to newsletter (optional)"
|
|
223
|
+
/>
|
|
224
|
+
</CheckboxGroup>
|
|
225
|
+
|
|
226
|
+
<div className="text-sm text-foreground-muted">
|
|
227
|
+
<p>Interests: {interests.join(', ') || 'None selected'}</p>
|
|
228
|
+
<p>Agreements: {agreements.join(', ') || 'None selected'}</p>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// Responsive Matrix - Mobile, Tablet, Desktop
|
|
236
|
+
export const ResponsiveMatrix: Story = {
|
|
237
|
+
render: () => (
|
|
238
|
+
<div className="space-y-8">
|
|
239
|
+
{/* Mobile */}
|
|
240
|
+
<div>
|
|
241
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Mobile (375px)</h4>
|
|
242
|
+
<div className="w-[375px] border border-dashed border-border p-4">
|
|
243
|
+
<CheckboxGroup label="Select Options" defaultValue={['option1']}>
|
|
244
|
+
<CheckboxGroupItem value="option1" label="Option 1" />
|
|
245
|
+
<CheckboxGroupItem value="option2" label="Option 2" />
|
|
246
|
+
<CheckboxGroupItem value="option3" label="Option 3" />
|
|
247
|
+
</CheckboxGroup>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
{/* Tablet */}
|
|
251
|
+
<div>
|
|
252
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Tablet (768px)</h4>
|
|
253
|
+
<div className="w-[768px] border border-dashed border-border p-4">
|
|
254
|
+
<CheckboxGroup label="Select Sizes" orientation="horizontal" defaultValue={['medium']}>
|
|
255
|
+
<CheckboxGroupItem value="small" label="Small" />
|
|
256
|
+
<CheckboxGroupItem value="medium" label="Medium" />
|
|
257
|
+
<CheckboxGroupItem value="large" label="Large" />
|
|
258
|
+
<CheckboxGroupItem value="xlarge" label="X-Large" />
|
|
259
|
+
</CheckboxGroup>
|
|
260
|
+
</div>
|
|
261
|
+
</div>
|
|
262
|
+
{/* Desktop */}
|
|
263
|
+
<div>
|
|
264
|
+
<h4 className="text-xs uppercase text-foreground-muted mb-2">Desktop (1280px)</h4>
|
|
265
|
+
<div className="w-[1280px] border border-dashed border-border p-4">
|
|
266
|
+
<div className="grid grid-cols-2 gap-8">
|
|
267
|
+
<CheckboxGroup label="Features" defaultValue={['basic']}>
|
|
268
|
+
<CheckboxGroupItem value="basic" label="Basic features" description="Always included" />
|
|
269
|
+
<CheckboxGroupItem value="advanced" label="Advanced features" description="Pro plan" />
|
|
270
|
+
<CheckboxGroupItem value="enterprise" label="Enterprise" description="Contact sales" disabled />
|
|
271
|
+
</CheckboxGroup>
|
|
272
|
+
<CheckboxGroup label="With Error" error="Please select at least one">
|
|
273
|
+
<CheckboxGroupItem value="agree" label="I agree to terms" />
|
|
274
|
+
<CheckboxGroupItem value="marketing" label="Marketing emails" />
|
|
275
|
+
</CheckboxGroup>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
),
|
|
281
|
+
};
|