@mzc-fe/design-system 0.0.1 → 0.0.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/components/accordion.d.ts +7 -0
- package/dist/components/alert-dialog.d.ts +14 -0
- package/dist/components/alert.d.ts +9 -0
- package/dist/components/aspect-ratio.d.ts +3 -0
- package/dist/components/avatar.d.ts +6 -0
- package/dist/components/badge.d.ts +9 -0
- package/dist/components/breadcrumb.d.ts +11 -0
- package/dist/components/button-group.d.ts +11 -0
- package/dist/components/button.d.ts +10 -0
- package/dist/components/calendar.d.ts +8 -0
- package/dist/components/card.d.ts +9 -0
- package/dist/components/carousel.d.ts +19 -0
- package/dist/components/chart.d.ts +40 -0
- package/dist/components/checkbox.d.ts +4 -0
- package/dist/components/collapsible.d.ts +5 -0
- package/dist/components/command.d.ts +18 -0
- package/dist/components/context-menu.d.ts +25 -0
- package/dist/components/dialog.d.ts +15 -0
- package/dist/components/drawer.d.ts +13 -0
- package/dist/components/dropdown-menu.d.ts +25 -0
- package/dist/components/empty.d.ts +11 -0
- package/dist/components/field.d.ts +24 -0
- package/dist/components/form.d.ts +24 -0
- package/dist/components/hover-card.d.ts +6 -0
- package/dist/components/input-group.d.ts +16 -0
- package/dist/components/input-otp.d.ts +11 -0
- package/dist/components/input.d.ts +3 -0
- package/dist/components/item.d.ts +23 -0
- package/dist/components/kbd.d.ts +3 -0
- package/dist/components/label.d.ts +4 -0
- package/dist/components/menubar.d.ts +26 -0
- package/dist/components/navigation-menu.d.ts +14 -0
- package/dist/components/pagination.d.ts +13 -0
- package/dist/components/popover.d.ts +7 -0
- package/dist/components/progress.d.ts +4 -0
- package/dist/components/radio-group.d.ts +5 -0
- package/dist/components/resizable.d.ts +8 -0
- package/dist/components/scroll-area.d.ts +5 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/separator.d.ts +4 -0
- package/dist/components/sheet.d.ts +13 -0
- package/dist/components/sidebar.d.ts +69 -0
- package/dist/components/skeleton.d.ts +2 -0
- package/dist/components/slider.d.ts +4 -0
- package/dist/components/sonner.d.ts +3 -0
- package/dist/components/spinner.d.ts +2 -0
- package/dist/components/switch.d.ts +4 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/tabs.d.ts +7 -0
- package/dist/components/textarea.d.ts +3 -0
- package/dist/components/toggle-group.d.ts +9 -0
- package/dist/components/toggle.d.ts +9 -0
- package/dist/components/tooltip.d.ts +7 -0
- package/dist/design-system.css +1 -0
- package/dist/design-system.es.js +30200 -0
- package/dist/design-system.umd.js +260 -0
- package/dist/foundations/ThemeProvider.d.ts +13 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/lib/utils.d.ts +2 -0
- package/package.json +14 -1
- package/.husky/pre-push +0 -21
- package/.storybook/main.ts +0 -11
- package/.storybook/preview.tsx +0 -30
- package/.vscode/settings.json +0 -12
- package/.vscode/tailwind.json +0 -105
- package/bitbucket-pipelines.yml +0 -50
- package/components.json +0 -21
- package/eslint.config.js +0 -38
- package/src/components/accordion.stories.tsx +0 -258
- package/src/components/accordion.test.tsx +0 -390
- package/src/components/accordion.tsx +0 -64
- package/src/components/alert-dialog.stories.tsx +0 -213
- package/src/components/alert-dialog.test.tsx +0 -80
- package/src/components/alert-dialog.tsx +0 -155
- package/src/components/alert.stories.tsx +0 -84
- package/src/components/alert.test.tsx +0 -35
- package/src/components/alert.tsx +0 -66
- package/src/components/aspect-ratio.stories.tsx +0 -97
- package/src/components/aspect-ratio.test.tsx +0 -47
- package/src/components/aspect-ratio.tsx +0 -11
- package/src/components/avatar.stories.tsx +0 -76
- package/src/components/avatar.test.tsx +0 -50
- package/src/components/avatar.tsx +0 -51
- package/src/components/badge.stories.tsx +0 -64
- package/src/components/badge.test.tsx +0 -34
- package/src/components/badge.tsx +0 -46
- package/src/components/breadcrumb.stories.tsx +0 -86
- package/src/components/breadcrumb.test.tsx +0 -74
- package/src/components/breadcrumb.tsx +0 -109
- package/src/components/button-group.stories.tsx +0 -62
- package/src/components/button-group.tsx +0 -83
- package/src/components/button.stories.tsx +0 -118
- package/src/components/button.test.tsx +0 -64
- package/src/components/button.tsx +0 -62
- package/src/components/calendar.stories.tsx +0 -81
- package/src/components/calendar.tsx +0 -220
- package/src/components/card.stories.tsx +0 -110
- package/src/components/card.test.tsx +0 -56
- package/src/components/card.tsx +0 -92
- package/src/components/carousel.stories.tsx +0 -90
- package/src/components/carousel.tsx +0 -239
- package/src/components/chart.tsx +0 -357
- package/src/components/checkbox.stories.tsx +0 -108
- package/src/components/checkbox.test.tsx +0 -67
- package/src/components/checkbox.tsx +0 -32
- package/src/components/collapsible.stories.tsx +0 -106
- package/src/components/collapsible.test.tsx +0 -92
- package/src/components/collapsible.tsx +0 -31
- package/src/components/command.stories.tsx +0 -90
- package/src/components/command.tsx +0 -182
- package/src/components/context-menu.stories.tsx +0 -63
- package/src/components/context-menu.tsx +0 -252
- package/src/components/dialog.stories.tsx +0 -128
- package/src/components/dialog.tsx +0 -141
- package/src/components/drawer.stories.tsx +0 -104
- package/src/components/drawer.tsx +0 -135
- package/src/components/dropdown-menu.stories.tsx +0 -97
- package/src/components/dropdown-menu.tsx +0 -255
- package/src/components/empty.stories.tsx +0 -90
- package/src/components/empty.test.tsx +0 -55
- package/src/components/empty.tsx +0 -104
- package/src/components/field.tsx +0 -246
- package/src/components/form.tsx +0 -168
- package/src/components/hover-card.stories.tsx +0 -66
- package/src/components/hover-card.tsx +0 -44
- package/src/components/input-group.stories.tsx +0 -57
- package/src/components/input-group.test.tsx +0 -40
- package/src/components/input-group.tsx +0 -170
- package/src/components/input-otp.stories.tsx +0 -94
- package/src/components/input-otp.test.tsx +0 -60
- package/src/components/input-otp.tsx +0 -75
- package/src/components/input.stories.tsx +0 -94
- package/src/components/input.test.tsx +0 -53
- package/src/components/input.tsx +0 -21
- package/src/components/item.tsx +0 -193
- package/src/components/kbd.stories.tsx +0 -100
- package/src/components/kbd.test.tsx +0 -28
- package/src/components/kbd.tsx +0 -28
- package/src/components/label.stories.tsx +0 -48
- package/src/components/label.test.tsx +0 -28
- package/src/components/label.tsx +0 -24
- package/src/components/menubar.tsx +0 -274
- package/src/components/navigation-menu.tsx +0 -168
- package/src/components/pagination.stories.tsx +0 -107
- package/src/components/pagination.tsx +0 -127
- package/src/components/popover.stories.tsx +0 -102
- package/src/components/popover.tsx +0 -48
- package/src/components/progress.stories.tsx +0 -76
- package/src/components/progress.test.tsx +0 -36
- package/src/components/progress.tsx +0 -29
- package/src/components/radio-group.stories.tsx +0 -73
- package/src/components/radio-group.test.tsx +0 -74
- package/src/components/radio-group.tsx +0 -45
- package/src/components/resizable.stories.tsx +0 -120
- package/src/components/resizable.tsx +0 -54
- package/src/components/scroll-area.stories.tsx +0 -64
- package/src/components/scroll-area.test.tsx +0 -46
- package/src/components/scroll-area.tsx +0 -58
- package/src/components/select.stories.tsx +0 -111
- package/src/components/select.test.tsx +0 -90
- package/src/components/select.tsx +0 -188
- package/src/components/separator.stories.tsx +0 -76
- package/src/components/separator.test.tsx +0 -24
- package/src/components/separator.tsx +0 -28
- package/src/components/sheet.stories.tsx +0 -122
- package/src/components/sheet.tsx +0 -137
- package/src/components/sidebar.tsx +0 -726
- package/src/components/skeleton.stories.tsx +0 -53
- package/src/components/skeleton.test.tsx +0 -24
- package/src/components/skeleton.tsx +0 -13
- package/src/components/slider.stories.tsx +0 -97
- package/src/components/slider.test.tsx +0 -49
- package/src/components/slider.tsx +0 -63
- package/src/components/sonner.stories.tsx +0 -96
- package/src/components/sonner.tsx +0 -38
- package/src/components/spinner.stories.tsx +0 -54
- package/src/components/spinner.test.tsx +0 -30
- package/src/components/spinner.tsx +0 -16
- package/src/components/switch.stories.tsx +0 -108
- package/src/components/switch.test.tsx +0 -62
- package/src/components/switch.tsx +0 -31
- package/src/components/table.stories.tsx +0 -139
- package/src/components/table.test.tsx +0 -85
- package/src/components/table.tsx +0 -114
- package/src/components/tabs.stories.tsx +0 -99
- package/src/components/tabs.test.tsx +0 -64
- package/src/components/tabs.tsx +0 -66
- package/src/components/textarea.stories.tsx +0 -89
- package/src/components/textarea.test.tsx +0 -53
- package/src/components/textarea.tsx +0 -18
- package/src/components/toggle-group.stories.tsx +0 -108
- package/src/components/toggle-group.test.tsx +0 -66
- package/src/components/toggle-group.tsx +0 -81
- package/src/components/toggle.stories.tsx +0 -98
- package/src/components/toggle.test.tsx +0 -42
- package/src/components/toggle.tsx +0 -45
- package/src/components/tooltip.stories.tsx +0 -111
- package/src/components/tooltip.tsx +0 -61
- package/src/foundations/README.md +0 -141
- package/src/foundations/ThemeProvider.tsx +0 -77
- package/src/foundations/color.css +0 -232
- package/src/foundations/color.stories.tsx +0 -719
- package/src/foundations/palette.css +0 -249
- package/src/foundations/spacing.css +0 -8
- package/src/foundations/typography.css +0 -143
- package/src/foundations/typography.stories.tsx +0 -17
- package/src/hooks/use-mobile.ts +0 -19
- package/src/index.css +0 -176
- package/src/index.ts +0 -336
- package/src/lib/utils.ts +0 -6
- package/src/test/setup.ts +0 -8
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.app.json +0 -33
- package/tsconfig.json +0 -13
- package/tsconfig.node.json +0 -25
- package/vite.config.ts +0 -30
- package/vitest.config.ts +0 -25
- /package/{public → dist}/vite.svg +0 -0
|
@@ -1,390 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { render } from "@testing-library/react";
|
|
3
|
-
import userEvent from "@testing-library/user-event";
|
|
4
|
-
import {
|
|
5
|
-
Accordion,
|
|
6
|
-
AccordionItem,
|
|
7
|
-
AccordionTrigger,
|
|
8
|
-
AccordionContent,
|
|
9
|
-
} from "./accordion";
|
|
10
|
-
|
|
11
|
-
describe("Accordion", () => {
|
|
12
|
-
describe("Default (Single type with collapsible)", () => {
|
|
13
|
-
it("should render accordion with multiple items", () => {
|
|
14
|
-
const { getByText } = render(
|
|
15
|
-
<Accordion type="single" collapsible className="w-full">
|
|
16
|
-
<AccordionItem value="item-1">
|
|
17
|
-
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
18
|
-
<AccordionContent>
|
|
19
|
-
Yes. It adheres to the WAI-ARIA design pattern and is fully
|
|
20
|
-
accessible.
|
|
21
|
-
</AccordionContent>
|
|
22
|
-
</AccordionItem>
|
|
23
|
-
<AccordionItem value="item-2">
|
|
24
|
-
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
|
25
|
-
<AccordionContent>
|
|
26
|
-
Yes. It comes with default styles that match the other components'
|
|
27
|
-
aesthetic.
|
|
28
|
-
</AccordionContent>
|
|
29
|
-
</AccordionItem>
|
|
30
|
-
<AccordionItem value="item-3">
|
|
31
|
-
<AccordionTrigger>Is it animated?</AccordionTrigger>
|
|
32
|
-
<AccordionContent>
|
|
33
|
-
Yes. It's animated by default, but you can disable it if you
|
|
34
|
-
prefer.
|
|
35
|
-
</AccordionContent>
|
|
36
|
-
</AccordionItem>
|
|
37
|
-
</Accordion>
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
expect(getByText("Is it accessible?")).toBeInTheDocument();
|
|
41
|
-
expect(getByText("Is it styled?")).toBeInTheDocument();
|
|
42
|
-
expect(getByText("Is it animated?")).toBeInTheDocument();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should show content when trigger is clicked", async () => {
|
|
46
|
-
const user = userEvent.setup();
|
|
47
|
-
const { getByText } = render(
|
|
48
|
-
<Accordion type="single" collapsible>
|
|
49
|
-
<AccordionItem value="item-1">
|
|
50
|
-
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
51
|
-
<AccordionContent>
|
|
52
|
-
Yes. It adheres to the WAI-ARIA design pattern and is fully
|
|
53
|
-
accessible.
|
|
54
|
-
</AccordionContent>
|
|
55
|
-
</AccordionItem>
|
|
56
|
-
</Accordion>
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
const trigger = getByText("Is it accessible?");
|
|
60
|
-
await user.click(trigger);
|
|
61
|
-
|
|
62
|
-
expect(
|
|
63
|
-
getByText(
|
|
64
|
-
"Yes. It adheres to the WAI-ARIA design pattern and is fully accessible."
|
|
65
|
-
)
|
|
66
|
-
).toBeInTheDocument();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should close content when trigger is clicked again (collapsible)", async () => {
|
|
70
|
-
const user = userEvent.setup();
|
|
71
|
-
const { getByText, queryByText } = render(
|
|
72
|
-
<Accordion type="single" collapsible>
|
|
73
|
-
<AccordionItem value="item-1">
|
|
74
|
-
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
75
|
-
<AccordionContent>
|
|
76
|
-
Yes. It adheres to the WAI-ARIA design pattern and is fully
|
|
77
|
-
accessible.
|
|
78
|
-
</AccordionContent>
|
|
79
|
-
</AccordionItem>
|
|
80
|
-
</Accordion>
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
const trigger = getByText("Is it accessible?");
|
|
84
|
-
|
|
85
|
-
// Open
|
|
86
|
-
await user.click(trigger);
|
|
87
|
-
expect(
|
|
88
|
-
getByText(
|
|
89
|
-
"Yes. It adheres to the WAI-ARIA design pattern and is fully accessible."
|
|
90
|
-
)
|
|
91
|
-
).toBeInTheDocument();
|
|
92
|
-
|
|
93
|
-
// Close
|
|
94
|
-
await user.click(trigger);
|
|
95
|
-
expect(
|
|
96
|
-
queryByText(
|
|
97
|
-
"Yes. It adheres to the WAI-ARIA design pattern and is fully accessible."
|
|
98
|
-
)
|
|
99
|
-
).not.toBeInTheDocument();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("should only allow one item open at a time in single mode", async () => {
|
|
103
|
-
const user = userEvent.setup();
|
|
104
|
-
const { getByText, queryByText } = render(
|
|
105
|
-
<Accordion type="single" collapsible>
|
|
106
|
-
<AccordionItem value="item-1">
|
|
107
|
-
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
108
|
-
<AccordionContent>Content 1</AccordionContent>
|
|
109
|
-
</AccordionItem>
|
|
110
|
-
<AccordionItem value="item-2">
|
|
111
|
-
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
112
|
-
<AccordionContent>Content 2</AccordionContent>
|
|
113
|
-
</AccordionItem>
|
|
114
|
-
</Accordion>
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const trigger1 = getByText("Item 1");
|
|
118
|
-
const trigger2 = getByText("Item 2");
|
|
119
|
-
|
|
120
|
-
// Open first item
|
|
121
|
-
await user.click(trigger1);
|
|
122
|
-
expect(getByText("Content 1")).toBeInTheDocument();
|
|
123
|
-
expect(queryByText("Content 2")).not.toBeInTheDocument();
|
|
124
|
-
|
|
125
|
-
// Open second item (should close first)
|
|
126
|
-
await user.click(trigger2);
|
|
127
|
-
expect(queryByText("Content 1")).not.toBeInTheDocument();
|
|
128
|
-
expect(getByText("Content 2")).toBeInTheDocument();
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe("Multiple type", () => {
|
|
133
|
-
it("should allow multiple items to be open simultaneously", async () => {
|
|
134
|
-
const user = userEvent.setup();
|
|
135
|
-
const { getByText } = render(
|
|
136
|
-
<Accordion type="multiple">
|
|
137
|
-
<AccordionItem value="item-1">
|
|
138
|
-
<AccordionTrigger>Can I open multiple items?</AccordionTrigger>
|
|
139
|
-
<AccordionContent>
|
|
140
|
-
Yes! With the "multiple" type, you can have multiple items open at
|
|
141
|
-
the same time.
|
|
142
|
-
</AccordionContent>
|
|
143
|
-
</AccordionItem>
|
|
144
|
-
<AccordionItem value="item-2">
|
|
145
|
-
<AccordionTrigger>How does it work?</AccordionTrigger>
|
|
146
|
-
<AccordionContent>
|
|
147
|
-
Each accordion item can be independently opened or closed,
|
|
148
|
-
allowing users to view multiple sections simultaneously.
|
|
149
|
-
</AccordionContent>
|
|
150
|
-
</AccordionItem>
|
|
151
|
-
<AccordionItem value="item-3">
|
|
152
|
-
<AccordionTrigger>What are the use cases?</AccordionTrigger>
|
|
153
|
-
<AccordionContent>
|
|
154
|
-
This is useful for FAQ sections, settings panels, or any content
|
|
155
|
-
where users might want to compare information across different
|
|
156
|
-
sections.
|
|
157
|
-
</AccordionContent>
|
|
158
|
-
</AccordionItem>
|
|
159
|
-
</Accordion>
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const trigger1 = getByText("Can I open multiple items?");
|
|
163
|
-
const trigger2 = getByText("How does it work?");
|
|
164
|
-
|
|
165
|
-
// Open first item
|
|
166
|
-
await user.click(trigger1);
|
|
167
|
-
expect(
|
|
168
|
-
getByText(
|
|
169
|
-
'Yes! With the "multiple" type, you can have multiple items open at the same time.'
|
|
170
|
-
)
|
|
171
|
-
).toBeInTheDocument();
|
|
172
|
-
|
|
173
|
-
// Open second item (first should still be open)
|
|
174
|
-
await user.click(trigger2);
|
|
175
|
-
expect(
|
|
176
|
-
getByText(
|
|
177
|
-
'Yes! With the "multiple" type, you can have multiple items open at the same time.'
|
|
178
|
-
)
|
|
179
|
-
).toBeInTheDocument();
|
|
180
|
-
expect(
|
|
181
|
-
getByText(
|
|
182
|
-
"Each accordion item can be independently opened or closed, allowing users to view multiple sections simultaneously."
|
|
183
|
-
)
|
|
184
|
-
).toBeInTheDocument();
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
describe("SingleItem", () => {
|
|
189
|
-
it("should render single accordion item", () => {
|
|
190
|
-
const { getByText } = render(
|
|
191
|
-
<Accordion type="single" collapsible className="w-full">
|
|
192
|
-
<AccordionItem value="item-1">
|
|
193
|
-
<AccordionTrigger>What is this component?</AccordionTrigger>
|
|
194
|
-
<AccordionContent>
|
|
195
|
-
This is an accordion component built with Radix UI. It provides a
|
|
196
|
-
collapsible content area that can be toggled open and closed.
|
|
197
|
-
</AccordionContent>
|
|
198
|
-
</AccordionItem>
|
|
199
|
-
</Accordion>
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
expect(getByText("What is this component?")).toBeInTheDocument();
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe("LongContent", () => {
|
|
207
|
-
it("should render accordion with long content", async () => {
|
|
208
|
-
const user = userEvent.setup();
|
|
209
|
-
const { getByText } = render(
|
|
210
|
-
<Accordion type="single" collapsible className="w-full">
|
|
211
|
-
<AccordionItem value="item-1">
|
|
212
|
-
<AccordionTrigger>Item with long content</AccordionTrigger>
|
|
213
|
-
<AccordionContent>
|
|
214
|
-
<div className="space-y-2">
|
|
215
|
-
<p>
|
|
216
|
-
This accordion item contains longer content to demonstrate how
|
|
217
|
-
the component handles text that spans multiple lines or
|
|
218
|
-
paragraphs.
|
|
219
|
-
</p>
|
|
220
|
-
<p>
|
|
221
|
-
The content area will expand to accommodate the full text, and
|
|
222
|
-
the animation will smoothly transition between the collapsed
|
|
223
|
-
and expanded states.
|
|
224
|
-
</p>
|
|
225
|
-
<ul className="list-disc list-inside space-y-1 ml-4">
|
|
226
|
-
<li>First bullet point</li>
|
|
227
|
-
<li>Second bullet point</li>
|
|
228
|
-
<li>Third bullet point</li>
|
|
229
|
-
</ul>
|
|
230
|
-
</div>
|
|
231
|
-
</AccordionContent>
|
|
232
|
-
</AccordionItem>
|
|
233
|
-
</Accordion>
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
const trigger = getByText("Item with long content");
|
|
237
|
-
await user.click(trigger);
|
|
238
|
-
|
|
239
|
-
expect(
|
|
240
|
-
getByText(
|
|
241
|
-
"This accordion item contains longer content to demonstrate how the component handles text that spans multiple lines or paragraphs."
|
|
242
|
-
)
|
|
243
|
-
).toBeInTheDocument();
|
|
244
|
-
expect(getByText("First bullet point")).toBeInTheDocument();
|
|
245
|
-
expect(getByText("Second bullet point")).toBeInTheDocument();
|
|
246
|
-
expect(getByText("Third bullet point")).toBeInTheDocument();
|
|
247
|
-
});
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
describe("WithCustomStyling", () => {
|
|
251
|
-
it("should apply custom className to accordion", () => {
|
|
252
|
-
const { container } = render(
|
|
253
|
-
<Accordion type="single" collapsible className="w-full max-w-2xl">
|
|
254
|
-
<AccordionItem value="item-1" className="border-2 border-primary/20">
|
|
255
|
-
<AccordionTrigger className="text-lg font-semibold">
|
|
256
|
-
Custom styled item
|
|
257
|
-
</AccordionTrigger>
|
|
258
|
-
<AccordionContent className="text-base">
|
|
259
|
-
This accordion item has custom styling applied to demonstrate how
|
|
260
|
-
you can customize the appearance of individual items.
|
|
261
|
-
</AccordionContent>
|
|
262
|
-
</AccordionItem>
|
|
263
|
-
</Accordion>
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
const accordion = container.querySelector('[data-slot="accordion"]');
|
|
267
|
-
expect(accordion).toHaveClass("w-full", "max-w-2xl");
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it("should apply custom className to accordion item", () => {
|
|
271
|
-
const { container } = render(
|
|
272
|
-
<Accordion type="single" collapsible>
|
|
273
|
-
<AccordionItem value="item-1" className="border-2 border-primary/20">
|
|
274
|
-
<AccordionTrigger>Custom styled item</AccordionTrigger>
|
|
275
|
-
<AccordionContent>Content</AccordionContent>
|
|
276
|
-
</AccordionItem>
|
|
277
|
-
</Accordion>
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
const item = container.querySelector('[data-slot="accordion-item"]');
|
|
281
|
-
expect(item).toHaveClass("border-2", "border-primary/20");
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("should apply custom className to accordion trigger", () => {
|
|
285
|
-
const { container } = render(
|
|
286
|
-
<Accordion type="single" collapsible>
|
|
287
|
-
<AccordionItem value="item-1">
|
|
288
|
-
<AccordionTrigger className="text-lg font-semibold">
|
|
289
|
-
Custom styled item
|
|
290
|
-
</AccordionTrigger>
|
|
291
|
-
<AccordionContent>Content</AccordionContent>
|
|
292
|
-
</AccordionItem>
|
|
293
|
-
</Accordion>
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
const trigger = container.querySelector(
|
|
297
|
-
'[data-slot="accordion-trigger"]'
|
|
298
|
-
);
|
|
299
|
-
expect(trigger).toHaveClass("text-lg", "font-semibold");
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
describe("Accessibility", () => {
|
|
304
|
-
it("should have proper ARIA attributes", () => {
|
|
305
|
-
const { getByText } = render(
|
|
306
|
-
<Accordion type="single" collapsible>
|
|
307
|
-
<AccordionItem value="item-1">
|
|
308
|
-
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
309
|
-
<AccordionContent>
|
|
310
|
-
Yes. It adheres to the WAI-ARIA design pattern and is fully
|
|
311
|
-
accessible.
|
|
312
|
-
</AccordionContent>
|
|
313
|
-
</AccordionItem>
|
|
314
|
-
</Accordion>
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
const trigger = getByText("Is it accessible?");
|
|
318
|
-
expect(trigger).toHaveAttribute("aria-expanded");
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("should update aria-expanded when opened", async () => {
|
|
322
|
-
const user = userEvent.setup();
|
|
323
|
-
const { getByText } = render(
|
|
324
|
-
<Accordion type="single" collapsible>
|
|
325
|
-
<AccordionItem value="item-1">
|
|
326
|
-
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
|
327
|
-
<AccordionContent>
|
|
328
|
-
Yes. It adheres to the WAI-ARIA design pattern and is fully
|
|
329
|
-
accessible.
|
|
330
|
-
</AccordionContent>
|
|
331
|
-
</AccordionItem>
|
|
332
|
-
</Accordion>
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
const trigger = getByText("Is it accessible?");
|
|
336
|
-
|
|
337
|
-
// Initially closed
|
|
338
|
-
expect(trigger).toHaveAttribute("aria-expanded", "false");
|
|
339
|
-
|
|
340
|
-
// Open
|
|
341
|
-
await user.click(trigger);
|
|
342
|
-
expect(trigger).toHaveAttribute("aria-expanded", "true");
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
describe("Controlled mode", () => {
|
|
347
|
-
it("should work in controlled mode with value prop", async () => {
|
|
348
|
-
const user = userEvent.setup();
|
|
349
|
-
const onValueChange = vi.fn();
|
|
350
|
-
|
|
351
|
-
const { getByText } = render(
|
|
352
|
-
<Accordion type="single" value="item-1" onValueChange={onValueChange}>
|
|
353
|
-
<AccordionItem value="item-1">
|
|
354
|
-
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
355
|
-
<AccordionContent>Content 1</AccordionContent>
|
|
356
|
-
</AccordionItem>
|
|
357
|
-
<AccordionItem value="item-2">
|
|
358
|
-
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
359
|
-
<AccordionContent>Content 2</AccordionContent>
|
|
360
|
-
</AccordionItem>
|
|
361
|
-
</Accordion>
|
|
362
|
-
);
|
|
363
|
-
|
|
364
|
-
const trigger2 = getByText("Item 2");
|
|
365
|
-
await user.click(trigger2);
|
|
366
|
-
|
|
367
|
-
expect(onValueChange).toHaveBeenCalledWith("item-2");
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
describe("Default value", () => {
|
|
372
|
-
it("should open item with defaultValue", () => {
|
|
373
|
-
const { getByText, queryByText } = render(
|
|
374
|
-
<Accordion type="single" defaultValue="item-2">
|
|
375
|
-
<AccordionItem value="item-1">
|
|
376
|
-
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
377
|
-
<AccordionContent>Content 1</AccordionContent>
|
|
378
|
-
</AccordionItem>
|
|
379
|
-
<AccordionItem value="item-2">
|
|
380
|
-
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
381
|
-
<AccordionContent>Content 2</AccordionContent>
|
|
382
|
-
</AccordionItem>
|
|
383
|
-
</Accordion>
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
expect(getByText("Content 2")).toBeInTheDocument();
|
|
387
|
-
expect(queryByText("Content 1")).not.toBeInTheDocument();
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
3
|
-
import { ChevronDownIcon } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
|
|
7
|
-
function Accordion({
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
10
|
-
return <AccordionPrimitive.Root data-slot="accordion" {...props} />
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function AccordionItem({
|
|
14
|
-
className,
|
|
15
|
-
...props
|
|
16
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
17
|
-
return (
|
|
18
|
-
<AccordionPrimitive.Item
|
|
19
|
-
data-slot="accordion-item"
|
|
20
|
-
className={cn("border-b last:border-b-0", className)}
|
|
21
|
-
{...props}
|
|
22
|
-
/>
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function AccordionTrigger({
|
|
27
|
-
className,
|
|
28
|
-
children,
|
|
29
|
-
...props
|
|
30
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
|
31
|
-
return (
|
|
32
|
-
<AccordionPrimitive.Header className="flex">
|
|
33
|
-
<AccordionPrimitive.Trigger
|
|
34
|
-
data-slot="accordion-trigger"
|
|
35
|
-
className={cn(
|
|
36
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
37
|
-
className
|
|
38
|
-
)}
|
|
39
|
-
{...props}
|
|
40
|
-
>
|
|
41
|
-
{children}
|
|
42
|
-
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
|
|
43
|
-
</AccordionPrimitive.Trigger>
|
|
44
|
-
</AccordionPrimitive.Header>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function AccordionContent({
|
|
49
|
-
className,
|
|
50
|
-
children,
|
|
51
|
-
...props
|
|
52
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
53
|
-
return (
|
|
54
|
-
<AccordionPrimitive.Content
|
|
55
|
-
data-slot="accordion-content"
|
|
56
|
-
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
|
57
|
-
{...props}
|
|
58
|
-
>
|
|
59
|
-
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
|
60
|
-
</AccordionPrimitive.Content>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import {
|
|
4
|
-
AlertDialog,
|
|
5
|
-
AlertDialogAction,
|
|
6
|
-
AlertDialogCancel,
|
|
7
|
-
AlertDialogContent,
|
|
8
|
-
AlertDialogDescription,
|
|
9
|
-
AlertDialogFooter,
|
|
10
|
-
AlertDialogHeader,
|
|
11
|
-
AlertDialogTitle,
|
|
12
|
-
AlertDialogTrigger,
|
|
13
|
-
} from "./alert-dialog";
|
|
14
|
-
import { Button } from "./button";
|
|
15
|
-
|
|
16
|
-
const meta = {
|
|
17
|
-
title: "Components/AlertDialog",
|
|
18
|
-
component: AlertDialog,
|
|
19
|
-
parameters: {
|
|
20
|
-
layout: "padded",
|
|
21
|
-
},
|
|
22
|
-
tags: ["autodocs"],
|
|
23
|
-
argTypes: {
|
|
24
|
-
open: {
|
|
25
|
-
control: "boolean",
|
|
26
|
-
description: "The controlled open state of the dialog.",
|
|
27
|
-
table: {
|
|
28
|
-
type: { summary: "boolean" },
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
defaultOpen: {
|
|
32
|
-
control: "boolean",
|
|
33
|
-
description: "The default open state of the dialog.",
|
|
34
|
-
table: {
|
|
35
|
-
type: { summary: "boolean" },
|
|
36
|
-
defaultValue: { summary: "false" },
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
} satisfies Meta<typeof AlertDialog>;
|
|
41
|
-
|
|
42
|
-
export default meta;
|
|
43
|
-
type Story = StoryObj<typeof meta>;
|
|
44
|
-
|
|
45
|
-
export const Default: Story = {
|
|
46
|
-
render: () => {
|
|
47
|
-
const [open, setOpen] = useState(false);
|
|
48
|
-
return (
|
|
49
|
-
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
50
|
-
<AlertDialogTrigger asChild>
|
|
51
|
-
<Button>Open Dialog</Button>
|
|
52
|
-
</AlertDialogTrigger>
|
|
53
|
-
<AlertDialogContent>
|
|
54
|
-
<AlertDialogHeader>
|
|
55
|
-
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
|
56
|
-
<AlertDialogDescription>
|
|
57
|
-
This action cannot be undone. This will permanently delete your
|
|
58
|
-
account and remove your data from our servers.
|
|
59
|
-
</AlertDialogDescription>
|
|
60
|
-
</AlertDialogHeader>
|
|
61
|
-
<AlertDialogFooter>
|
|
62
|
-
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
63
|
-
<AlertDialogAction>Continue</AlertDialogAction>
|
|
64
|
-
</AlertDialogFooter>
|
|
65
|
-
</AlertDialogContent>
|
|
66
|
-
</AlertDialog>
|
|
67
|
-
);
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const Destructive: Story = {
|
|
72
|
-
render: () => {
|
|
73
|
-
const [open, setOpen] = useState(false);
|
|
74
|
-
return (
|
|
75
|
-
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
76
|
-
<AlertDialogTrigger asChild>
|
|
77
|
-
<Button variant="destructive">Delete Account</Button>
|
|
78
|
-
</AlertDialogTrigger>
|
|
79
|
-
<AlertDialogContent>
|
|
80
|
-
<AlertDialogHeader>
|
|
81
|
-
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
|
82
|
-
<AlertDialogDescription>
|
|
83
|
-
This action cannot be undone. This will permanently delete your
|
|
84
|
-
account and remove your data from our servers.
|
|
85
|
-
</AlertDialogDescription>
|
|
86
|
-
</AlertDialogHeader>
|
|
87
|
-
<AlertDialogFooter>
|
|
88
|
-
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
89
|
-
<AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
|
90
|
-
Delete
|
|
91
|
-
</AlertDialogAction>
|
|
92
|
-
</AlertDialogFooter>
|
|
93
|
-
</AlertDialogContent>
|
|
94
|
-
</AlertDialog>
|
|
95
|
-
);
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export const WithoutCancel: Story = {
|
|
100
|
-
render: () => {
|
|
101
|
-
const [open, setOpen] = useState(false);
|
|
102
|
-
return (
|
|
103
|
-
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
104
|
-
<AlertDialogTrigger asChild>
|
|
105
|
-
<Button>Show Information</Button>
|
|
106
|
-
</AlertDialogTrigger>
|
|
107
|
-
<AlertDialogContent>
|
|
108
|
-
<AlertDialogHeader>
|
|
109
|
-
<AlertDialogTitle>Information</AlertDialogTitle>
|
|
110
|
-
<AlertDialogDescription>
|
|
111
|
-
This is an informational dialog without a cancel button. The user
|
|
112
|
-
must click the action button to close it.
|
|
113
|
-
</AlertDialogDescription>
|
|
114
|
-
</AlertDialogHeader>
|
|
115
|
-
<AlertDialogFooter>
|
|
116
|
-
<AlertDialogAction>Got it</AlertDialogAction>
|
|
117
|
-
</AlertDialogFooter>
|
|
118
|
-
</AlertDialogContent>
|
|
119
|
-
</AlertDialog>
|
|
120
|
-
);
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
export const LongContent: Story = {
|
|
125
|
-
render: () => {
|
|
126
|
-
const [open, setOpen] = useState(false);
|
|
127
|
-
return (
|
|
128
|
-
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
129
|
-
<AlertDialogTrigger asChild>
|
|
130
|
-
<Button>View Terms</Button>
|
|
131
|
-
</AlertDialogTrigger>
|
|
132
|
-
<AlertDialogContent>
|
|
133
|
-
<AlertDialogHeader>
|
|
134
|
-
<AlertDialogTitle>Terms and Conditions</AlertDialogTitle>
|
|
135
|
-
<AlertDialogDescription className="max-h-[60vh] overflow-y-auto">
|
|
136
|
-
<div className="space-y-4">
|
|
137
|
-
<p>
|
|
138
|
-
Please read these terms and conditions carefully before using
|
|
139
|
-
our service. By accessing or using our service, you agree to
|
|
140
|
-
be bound by these terms.
|
|
141
|
-
</p>
|
|
142
|
-
<p>
|
|
143
|
-
<strong>1. Acceptance of Terms</strong>
|
|
144
|
-
</p>
|
|
145
|
-
<p>
|
|
146
|
-
By accessing and using this service, you accept and agree to
|
|
147
|
-
be bound by the terms and provision of this agreement.
|
|
148
|
-
</p>
|
|
149
|
-
<p>
|
|
150
|
-
<strong>2. Use License</strong>
|
|
151
|
-
</p>
|
|
152
|
-
<p>
|
|
153
|
-
Permission is granted to temporarily download one copy of the
|
|
154
|
-
materials on our website for personal, non-commercial
|
|
155
|
-
transitory viewing only.
|
|
156
|
-
</p>
|
|
157
|
-
<p>
|
|
158
|
-
<strong>3. Disclaimer</strong>
|
|
159
|
-
</p>
|
|
160
|
-
<p>
|
|
161
|
-
The materials on our website are provided on an 'as is' basis.
|
|
162
|
-
We make no warranties, expressed or implied, and hereby
|
|
163
|
-
disclaim and negate all other warranties.
|
|
164
|
-
</p>
|
|
165
|
-
<p>
|
|
166
|
-
<strong>4. Limitations</strong>
|
|
167
|
-
</p>
|
|
168
|
-
<p>
|
|
169
|
-
In no event shall we or our suppliers be liable for any
|
|
170
|
-
damages arising out of the use or inability to use the
|
|
171
|
-
materials on our website.
|
|
172
|
-
</p>
|
|
173
|
-
</div>
|
|
174
|
-
</AlertDialogDescription>
|
|
175
|
-
</AlertDialogHeader>
|
|
176
|
-
<AlertDialogFooter>
|
|
177
|
-
<AlertDialogCancel>Decline</AlertDialogCancel>
|
|
178
|
-
<AlertDialogAction>Accept</AlertDialogAction>
|
|
179
|
-
</AlertDialogFooter>
|
|
180
|
-
</AlertDialogContent>
|
|
181
|
-
</AlertDialog>
|
|
182
|
-
);
|
|
183
|
-
},
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
export const CustomActions: Story = {
|
|
187
|
-
render: () => {
|
|
188
|
-
const [open, setOpen] = useState(false);
|
|
189
|
-
return (
|
|
190
|
-
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
191
|
-
<AlertDialogTrigger asChild>
|
|
192
|
-
<Button variant="outline">Custom Actions</Button>
|
|
193
|
-
</AlertDialogTrigger>
|
|
194
|
-
<AlertDialogContent>
|
|
195
|
-
<AlertDialogHeader>
|
|
196
|
-
<AlertDialogTitle>Choose an option</AlertDialogTitle>
|
|
197
|
-
<AlertDialogDescription>
|
|
198
|
-
This dialog demonstrates custom action buttons with different
|
|
199
|
-
styles.
|
|
200
|
-
</AlertDialogDescription>
|
|
201
|
-
</AlertDialogHeader>
|
|
202
|
-
<AlertDialogFooter>
|
|
203
|
-
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
204
|
-
<AlertDialogAction className="bg-secondary text-secondary-foreground hover:bg-secondary/80">
|
|
205
|
-
Save Draft
|
|
206
|
-
</AlertDialogAction>
|
|
207
|
-
<AlertDialogAction>Publish</AlertDialogAction>
|
|
208
|
-
</AlertDialogFooter>
|
|
209
|
-
</AlertDialogContent>
|
|
210
|
-
</AlertDialog>
|
|
211
|
-
);
|
|
212
|
-
},
|
|
213
|
-
};
|