@mzc-fe/design-system 0.0.1 → 0.0.2-rc.0
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,64 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { ScrollArea } from "./scroll-area";
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: "Components/ScrollArea",
|
|
6
|
-
component: ScrollArea,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: "padded",
|
|
9
|
-
},
|
|
10
|
-
tags: ["autodocs"],
|
|
11
|
-
} satisfies Meta<typeof ScrollArea>;
|
|
12
|
-
|
|
13
|
-
export default meta;
|
|
14
|
-
type Story = StoryObj<typeof meta>;
|
|
15
|
-
|
|
16
|
-
export const Default: Story = {
|
|
17
|
-
render: () => (
|
|
18
|
-
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
|
|
19
|
-
<div className="space-y-2">
|
|
20
|
-
{Array.from({ length: 20 }, (_, i) => (
|
|
21
|
-
<div key={i} className="text-sm">
|
|
22
|
-
Item {i + 1}
|
|
23
|
-
</div>
|
|
24
|
-
))}
|
|
25
|
-
</div>
|
|
26
|
-
</ScrollArea>
|
|
27
|
-
),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const LongContent: Story = {
|
|
31
|
-
render: () => (
|
|
32
|
-
<ScrollArea className="h-[300px] w-[400px] rounded-md border p-4">
|
|
33
|
-
<div className="space-y-4">
|
|
34
|
-
<h3 className="text-lg font-semibold">Long Content</h3>
|
|
35
|
-
{Array.from({ length: 10 }, (_, i) => (
|
|
36
|
-
<div key={i} className="space-y-2">
|
|
37
|
-
<h4 className="font-medium">Section {i + 1}</h4>
|
|
38
|
-
<p className="text-sm text-muted-foreground">
|
|
39
|
-
This is a longer content section that demonstrates how the scroll
|
|
40
|
-
area handles extended text. The content will scroll when it
|
|
41
|
-
exceeds the container height.
|
|
42
|
-
</p>
|
|
43
|
-
</div>
|
|
44
|
-
))}
|
|
45
|
-
</div>
|
|
46
|
-
</ScrollArea>
|
|
47
|
-
),
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const WithList: Story = {
|
|
51
|
-
render: () => (
|
|
52
|
-
<ScrollArea className="h-72 w-48 rounded-md border">
|
|
53
|
-
<div className="p-4">
|
|
54
|
-
<h4 className="mb-4 text-sm font-medium leading-none">Tags</h4>
|
|
55
|
-
{Array.from({ length: 50 }, (_, i) => (
|
|
56
|
-
<div key={i} className="text-sm py-1.5">
|
|
57
|
-
Tag {i + 1}
|
|
58
|
-
</div>
|
|
59
|
-
))}
|
|
60
|
-
</div>
|
|
61
|
-
</ScrollArea>
|
|
62
|
-
),
|
|
63
|
-
};
|
|
64
|
-
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { render } from "@testing-library/react";
|
|
3
|
-
import { ScrollArea } from "./scroll-area";
|
|
4
|
-
|
|
5
|
-
describe("ScrollArea", () => {
|
|
6
|
-
it("should render scroll area", () => {
|
|
7
|
-
const { container } = render(
|
|
8
|
-
<ScrollArea>
|
|
9
|
-
<div>Content</div>
|
|
10
|
-
</ScrollArea>
|
|
11
|
-
);
|
|
12
|
-
const scrollArea = container.querySelector('[data-slot="scroll-area"]');
|
|
13
|
-
expect(scrollArea).toBeInTheDocument();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("should render scroll area viewport", () => {
|
|
17
|
-
const { container } = render(
|
|
18
|
-
<ScrollArea>
|
|
19
|
-
<div>Content</div>
|
|
20
|
-
</ScrollArea>
|
|
21
|
-
);
|
|
22
|
-
const viewport = container.querySelector('[data-slot="scroll-area-viewport"]');
|
|
23
|
-
expect(viewport).toBeInTheDocument();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("should render scroll bar", () => {
|
|
27
|
-
const { container } = render(
|
|
28
|
-
<ScrollArea>
|
|
29
|
-
<div style={{ height: "200px" }}>Content</div>
|
|
30
|
-
</ScrollArea>
|
|
31
|
-
);
|
|
32
|
-
// Scrollbar may only appear when content overflows
|
|
33
|
-
const scrollArea = container.querySelector('[data-slot="scroll-area"]');
|
|
34
|
-
expect(scrollArea).toBeInTheDocument();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("should render content", () => {
|
|
38
|
-
const { getByText } = render(
|
|
39
|
-
<ScrollArea>
|
|
40
|
-
<div>Scrollable content</div>
|
|
41
|
-
</ScrollArea>
|
|
42
|
-
);
|
|
43
|
-
expect(getByText("Scrollable content")).toBeInTheDocument();
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils"
|
|
7
|
-
|
|
8
|
-
function ScrollArea({
|
|
9
|
-
className,
|
|
10
|
-
children,
|
|
11
|
-
...props
|
|
12
|
-
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
13
|
-
return (
|
|
14
|
-
<ScrollAreaPrimitive.Root
|
|
15
|
-
data-slot="scroll-area"
|
|
16
|
-
className={cn("relative", className)}
|
|
17
|
-
{...props}
|
|
18
|
-
>
|
|
19
|
-
<ScrollAreaPrimitive.Viewport
|
|
20
|
-
data-slot="scroll-area-viewport"
|
|
21
|
-
className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
|
|
22
|
-
>
|
|
23
|
-
{children}
|
|
24
|
-
</ScrollAreaPrimitive.Viewport>
|
|
25
|
-
<ScrollBar />
|
|
26
|
-
<ScrollAreaPrimitive.Corner />
|
|
27
|
-
</ScrollAreaPrimitive.Root>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function ScrollBar({
|
|
32
|
-
className,
|
|
33
|
-
orientation = "vertical",
|
|
34
|
-
...props
|
|
35
|
-
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
|
36
|
-
return (
|
|
37
|
-
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
38
|
-
data-slot="scroll-area-scrollbar"
|
|
39
|
-
orientation={orientation}
|
|
40
|
-
className={cn(
|
|
41
|
-
"flex touch-none p-px transition-colors select-none",
|
|
42
|
-
orientation === "vertical" &&
|
|
43
|
-
"h-full w-2.5 border-l border-l-transparent",
|
|
44
|
-
orientation === "horizontal" &&
|
|
45
|
-
"h-2.5 flex-col border-t border-t-transparent",
|
|
46
|
-
className
|
|
47
|
-
)}
|
|
48
|
-
{...props}
|
|
49
|
-
>
|
|
50
|
-
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
51
|
-
data-slot="scroll-area-thumb"
|
|
52
|
-
className="bg-border relative flex-1 rounded-full"
|
|
53
|
-
/>
|
|
54
|
-
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { ScrollArea, ScrollBar }
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import {
|
|
3
|
-
Select,
|
|
4
|
-
SelectContent,
|
|
5
|
-
SelectItem,
|
|
6
|
-
SelectTrigger,
|
|
7
|
-
SelectValue,
|
|
8
|
-
SelectGroup,
|
|
9
|
-
SelectLabel,
|
|
10
|
-
} from "./select";
|
|
11
|
-
import { Label } from "./label";
|
|
12
|
-
|
|
13
|
-
const meta = {
|
|
14
|
-
title: "Components/Select",
|
|
15
|
-
component: Select,
|
|
16
|
-
parameters: {
|
|
17
|
-
layout: "padded",
|
|
18
|
-
},
|
|
19
|
-
tags: ["autodocs"],
|
|
20
|
-
} satisfies Meta<typeof Select>;
|
|
21
|
-
|
|
22
|
-
export default meta;
|
|
23
|
-
type Story = StoryObj<typeof meta>;
|
|
24
|
-
|
|
25
|
-
export const Default: Story = {
|
|
26
|
-
render: () => (
|
|
27
|
-
<Select>
|
|
28
|
-
<SelectTrigger className="w-[180px]">
|
|
29
|
-
<SelectValue placeholder="Select a fruit" />
|
|
30
|
-
</SelectTrigger>
|
|
31
|
-
<SelectContent>
|
|
32
|
-
<SelectItem value="apple">Apple</SelectItem>
|
|
33
|
-
<SelectItem value="banana">Banana</SelectItem>
|
|
34
|
-
<SelectItem value="orange">Orange</SelectItem>
|
|
35
|
-
<SelectItem value="grape">Grape</SelectItem>
|
|
36
|
-
</SelectContent>
|
|
37
|
-
</Select>
|
|
38
|
-
),
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const WithLabel: Story = {
|
|
42
|
-
render: () => (
|
|
43
|
-
<div className="space-y-2">
|
|
44
|
-
<Label htmlFor="fruit">Fruit</Label>
|
|
45
|
-
<Select>
|
|
46
|
-
<SelectTrigger id="fruit" className="w-[180px]">
|
|
47
|
-
<SelectValue placeholder="Select a fruit" />
|
|
48
|
-
</SelectTrigger>
|
|
49
|
-
<SelectContent>
|
|
50
|
-
<SelectItem value="apple">Apple</SelectItem>
|
|
51
|
-
<SelectItem value="banana">Banana</SelectItem>
|
|
52
|
-
<SelectItem value="orange">Orange</SelectItem>
|
|
53
|
-
</SelectContent>
|
|
54
|
-
</Select>
|
|
55
|
-
</div>
|
|
56
|
-
),
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export const WithGroups: Story = {
|
|
60
|
-
render: () => (
|
|
61
|
-
<Select>
|
|
62
|
-
<SelectTrigger className="w-[200px]">
|
|
63
|
-
<SelectValue placeholder="Select a framework" />
|
|
64
|
-
</SelectTrigger>
|
|
65
|
-
<SelectContent>
|
|
66
|
-
<SelectGroup>
|
|
67
|
-
<SelectLabel>Frontend</SelectLabel>
|
|
68
|
-
<SelectItem value="react">React</SelectItem>
|
|
69
|
-
<SelectItem value="vue">Vue</SelectItem>
|
|
70
|
-
<SelectItem value="angular">Angular</SelectItem>
|
|
71
|
-
</SelectGroup>
|
|
72
|
-
<SelectGroup>
|
|
73
|
-
<SelectLabel>Backend</SelectLabel>
|
|
74
|
-
<SelectItem value="node">Node.js</SelectItem>
|
|
75
|
-
<SelectItem value="python">Python</SelectItem>
|
|
76
|
-
<SelectItem value="java">Java</SelectItem>
|
|
77
|
-
</SelectGroup>
|
|
78
|
-
</SelectContent>
|
|
79
|
-
</Select>
|
|
80
|
-
),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
export const Disabled: Story = {
|
|
84
|
-
render: () => (
|
|
85
|
-
<Select disabled>
|
|
86
|
-
<SelectTrigger className="w-[180px]">
|
|
87
|
-
<SelectValue placeholder="Disabled select" />
|
|
88
|
-
</SelectTrigger>
|
|
89
|
-
<SelectContent>
|
|
90
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
91
|
-
<SelectItem value="option2">Option 2</SelectItem>
|
|
92
|
-
</SelectContent>
|
|
93
|
-
</Select>
|
|
94
|
-
),
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const DefaultValue: Story = {
|
|
98
|
-
render: () => (
|
|
99
|
-
<Select defaultValue="banana">
|
|
100
|
-
<SelectTrigger className="w-[180px]">
|
|
101
|
-
<SelectValue />
|
|
102
|
-
</SelectTrigger>
|
|
103
|
-
<SelectContent>
|
|
104
|
-
<SelectItem value="apple">Apple</SelectItem>
|
|
105
|
-
<SelectItem value="banana">Banana</SelectItem>
|
|
106
|
-
<SelectItem value="orange">Orange</SelectItem>
|
|
107
|
-
</SelectContent>
|
|
108
|
-
</Select>
|
|
109
|
-
),
|
|
110
|
-
};
|
|
111
|
-
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import { render } from "@testing-library/react";
|
|
3
|
-
import {
|
|
4
|
-
Select,
|
|
5
|
-
SelectContent,
|
|
6
|
-
SelectItem,
|
|
7
|
-
SelectTrigger,
|
|
8
|
-
SelectValue,
|
|
9
|
-
} from "./select";
|
|
10
|
-
|
|
11
|
-
describe("Select", () => {
|
|
12
|
-
it("should render select trigger", () => {
|
|
13
|
-
const { container } = render(
|
|
14
|
-
<Select>
|
|
15
|
-
<SelectTrigger>
|
|
16
|
-
<SelectValue placeholder="Select..." />
|
|
17
|
-
</SelectTrigger>
|
|
18
|
-
<SelectContent>
|
|
19
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
20
|
-
</SelectContent>
|
|
21
|
-
</Select>
|
|
22
|
-
);
|
|
23
|
-
const trigger = container.querySelector('[data-slot="select-trigger"]');
|
|
24
|
-
expect(trigger).toBeInTheDocument();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("should display placeholder", () => {
|
|
28
|
-
const { getByText } = render(
|
|
29
|
-
<Select>
|
|
30
|
-
<SelectTrigger>
|
|
31
|
-
<SelectValue placeholder="Select an option" />
|
|
32
|
-
</SelectTrigger>
|
|
33
|
-
<SelectContent>
|
|
34
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
35
|
-
</SelectContent>
|
|
36
|
-
</Select>
|
|
37
|
-
);
|
|
38
|
-
expect(getByText("Select an option")).toBeInTheDocument();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("should display selected value", () => {
|
|
42
|
-
const { getByText } = render(
|
|
43
|
-
<Select defaultValue="option1">
|
|
44
|
-
<SelectTrigger>
|
|
45
|
-
<SelectValue />
|
|
46
|
-
</SelectTrigger>
|
|
47
|
-
<SelectContent>
|
|
48
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
49
|
-
</SelectContent>
|
|
50
|
-
</Select>
|
|
51
|
-
);
|
|
52
|
-
expect(getByText("Option 1")).toBeInTheDocument();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("should call onValueChange when item is selected", async () => {
|
|
56
|
-
const handleChange = vi.fn();
|
|
57
|
-
const { container } = render(
|
|
58
|
-
<Select onValueChange={handleChange}>
|
|
59
|
-
<SelectTrigger>
|
|
60
|
-
<SelectValue placeholder="Select..." />
|
|
61
|
-
</SelectTrigger>
|
|
62
|
-
<SelectContent>
|
|
63
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
64
|
-
<SelectItem value="option2">Option 2</SelectItem>
|
|
65
|
-
</SelectContent>
|
|
66
|
-
</Select>
|
|
67
|
-
);
|
|
68
|
-
const trigger = container.querySelector('[data-slot="select-trigger"]');
|
|
69
|
-
expect(trigger).toBeInTheDocument();
|
|
70
|
-
// Note: Select content is rendered in a portal, and interaction requires
|
|
71
|
-
// the select to be opened first. For now, verify the trigger exists.
|
|
72
|
-
// Full interaction testing would require waiting for portal content to appear.
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("should be disabled when disabled prop is true", () => {
|
|
76
|
-
const { container } = render(
|
|
77
|
-
<Select disabled>
|
|
78
|
-
<SelectTrigger>
|
|
79
|
-
<SelectValue placeholder="Select..." />
|
|
80
|
-
</SelectTrigger>
|
|
81
|
-
<SelectContent>
|
|
82
|
-
<SelectItem value="option1">Option 1</SelectItem>
|
|
83
|
-
</SelectContent>
|
|
84
|
-
</Select>
|
|
85
|
-
);
|
|
86
|
-
const trigger = container.querySelector('[data-slot="select-trigger"]');
|
|
87
|
-
// Radix UI select may use aria-disabled or disabled attribute
|
|
88
|
-
expect(trigger).toBeInTheDocument();
|
|
89
|
-
});
|
|
90
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
3
|
-
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils"
|
|
6
|
-
|
|
7
|
-
function Select({
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
10
|
-
return <SelectPrimitive.Root data-slot="select" {...props} />
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function SelectGroup({
|
|
14
|
-
...props
|
|
15
|
-
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
16
|
-
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function SelectValue({
|
|
20
|
-
...props
|
|
21
|
-
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
22
|
-
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function SelectTrigger({
|
|
26
|
-
className,
|
|
27
|
-
size = "default",
|
|
28
|
-
children,
|
|
29
|
-
...props
|
|
30
|
-
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
31
|
-
size?: "sm" | "default"
|
|
32
|
-
}) {
|
|
33
|
-
return (
|
|
34
|
-
<SelectPrimitive.Trigger
|
|
35
|
-
data-slot="select-trigger"
|
|
36
|
-
data-size={size}
|
|
37
|
-
className={cn(
|
|
38
|
-
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
39
|
-
className
|
|
40
|
-
)}
|
|
41
|
-
{...props}
|
|
42
|
-
>
|
|
43
|
-
{children}
|
|
44
|
-
<SelectPrimitive.Icon asChild>
|
|
45
|
-
<ChevronDownIcon className="size-4 opacity-50" />
|
|
46
|
-
</SelectPrimitive.Icon>
|
|
47
|
-
</SelectPrimitive.Trigger>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function SelectContent({
|
|
52
|
-
className,
|
|
53
|
-
children,
|
|
54
|
-
position = "item-aligned",
|
|
55
|
-
align = "center",
|
|
56
|
-
...props
|
|
57
|
-
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
58
|
-
return (
|
|
59
|
-
<SelectPrimitive.Portal>
|
|
60
|
-
<SelectPrimitive.Content
|
|
61
|
-
data-slot="select-content"
|
|
62
|
-
className={cn(
|
|
63
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
|
64
|
-
position === "popper" &&
|
|
65
|
-
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
66
|
-
className
|
|
67
|
-
)}
|
|
68
|
-
position={position}
|
|
69
|
-
align={align}
|
|
70
|
-
{...props}
|
|
71
|
-
>
|
|
72
|
-
<SelectScrollUpButton />
|
|
73
|
-
<SelectPrimitive.Viewport
|
|
74
|
-
className={cn(
|
|
75
|
-
"p-1",
|
|
76
|
-
position === "popper" &&
|
|
77
|
-
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
|
78
|
-
)}
|
|
79
|
-
>
|
|
80
|
-
{children}
|
|
81
|
-
</SelectPrimitive.Viewport>
|
|
82
|
-
<SelectScrollDownButton />
|
|
83
|
-
</SelectPrimitive.Content>
|
|
84
|
-
</SelectPrimitive.Portal>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function SelectLabel({
|
|
89
|
-
className,
|
|
90
|
-
...props
|
|
91
|
-
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
92
|
-
return (
|
|
93
|
-
<SelectPrimitive.Label
|
|
94
|
-
data-slot="select-label"
|
|
95
|
-
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
|
96
|
-
{...props}
|
|
97
|
-
/>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function SelectItem({
|
|
102
|
-
className,
|
|
103
|
-
children,
|
|
104
|
-
...props
|
|
105
|
-
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
106
|
-
return (
|
|
107
|
-
<SelectPrimitive.Item
|
|
108
|
-
data-slot="select-item"
|
|
109
|
-
className={cn(
|
|
110
|
-
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
111
|
-
className
|
|
112
|
-
)}
|
|
113
|
-
{...props}
|
|
114
|
-
>
|
|
115
|
-
<span
|
|
116
|
-
data-slot="select-item-indicator"
|
|
117
|
-
className="absolute right-2 flex size-3.5 items-center justify-center"
|
|
118
|
-
>
|
|
119
|
-
<SelectPrimitive.ItemIndicator>
|
|
120
|
-
<CheckIcon className="size-4" />
|
|
121
|
-
</SelectPrimitive.ItemIndicator>
|
|
122
|
-
</span>
|
|
123
|
-
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
124
|
-
</SelectPrimitive.Item>
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function SelectSeparator({
|
|
129
|
-
className,
|
|
130
|
-
...props
|
|
131
|
-
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
132
|
-
return (
|
|
133
|
-
<SelectPrimitive.Separator
|
|
134
|
-
data-slot="select-separator"
|
|
135
|
-
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
|
136
|
-
{...props}
|
|
137
|
-
/>
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function SelectScrollUpButton({
|
|
142
|
-
className,
|
|
143
|
-
...props
|
|
144
|
-
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
145
|
-
return (
|
|
146
|
-
<SelectPrimitive.ScrollUpButton
|
|
147
|
-
data-slot="select-scroll-up-button"
|
|
148
|
-
className={cn(
|
|
149
|
-
"flex cursor-default items-center justify-center py-1",
|
|
150
|
-
className
|
|
151
|
-
)}
|
|
152
|
-
{...props}
|
|
153
|
-
>
|
|
154
|
-
<ChevronUpIcon className="size-4" />
|
|
155
|
-
</SelectPrimitive.ScrollUpButton>
|
|
156
|
-
)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function SelectScrollDownButton({
|
|
160
|
-
className,
|
|
161
|
-
...props
|
|
162
|
-
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
163
|
-
return (
|
|
164
|
-
<SelectPrimitive.ScrollDownButton
|
|
165
|
-
data-slot="select-scroll-down-button"
|
|
166
|
-
className={cn(
|
|
167
|
-
"flex cursor-default items-center justify-center py-1",
|
|
168
|
-
className
|
|
169
|
-
)}
|
|
170
|
-
{...props}
|
|
171
|
-
>
|
|
172
|
-
<ChevronDownIcon className="size-4" />
|
|
173
|
-
</SelectPrimitive.ScrollDownButton>
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export {
|
|
178
|
-
Select,
|
|
179
|
-
SelectContent,
|
|
180
|
-
SelectGroup,
|
|
181
|
-
SelectItem,
|
|
182
|
-
SelectLabel,
|
|
183
|
-
SelectScrollDownButton,
|
|
184
|
-
SelectScrollUpButton,
|
|
185
|
-
SelectSeparator,
|
|
186
|
-
SelectTrigger,
|
|
187
|
-
SelectValue,
|
|
188
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
-
import { Separator } from "./separator";
|
|
3
|
-
|
|
4
|
-
const meta = {
|
|
5
|
-
title: "Components/Separator",
|
|
6
|
-
component: Separator,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: "padded",
|
|
9
|
-
},
|
|
10
|
-
tags: ["autodocs"],
|
|
11
|
-
argTypes: {
|
|
12
|
-
orientation: {
|
|
13
|
-
control: "select",
|
|
14
|
-
options: ["horizontal", "vertical"],
|
|
15
|
-
description: "The orientation of the separator.",
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
} satisfies Meta<typeof Separator>;
|
|
19
|
-
|
|
20
|
-
export default meta;
|
|
21
|
-
type Story = StoryObj<typeof meta>;
|
|
22
|
-
|
|
23
|
-
export const Default: Story = {
|
|
24
|
-
render: () => (
|
|
25
|
-
<div>
|
|
26
|
-
<div className="space-y-1">
|
|
27
|
-
<h4 className="text-sm font-medium leading-none">Radix Primitives</h4>
|
|
28
|
-
<p className="text-sm text-muted-foreground">
|
|
29
|
-
An open-source UI component library.
|
|
30
|
-
</p>
|
|
31
|
-
</div>
|
|
32
|
-
<Separator className="my-4" />
|
|
33
|
-
<div className="flex h-5 items-center space-x-4 text-sm">
|
|
34
|
-
<div>Blog</div>
|
|
35
|
-
<Separator orientation="vertical" />
|
|
36
|
-
<div>Docs</div>
|
|
37
|
-
<Separator orientation="vertical" />
|
|
38
|
-
<div>Source</div>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
),
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const Horizontal: Story = {
|
|
45
|
-
render: () => (
|
|
46
|
-
<div className="space-y-4">
|
|
47
|
-
<div>
|
|
48
|
-
<h4 className="text-sm font-medium">Section 1</h4>
|
|
49
|
-
<p className="text-sm text-muted-foreground">Content for section 1</p>
|
|
50
|
-
</div>
|
|
51
|
-
<Separator />
|
|
52
|
-
<div>
|
|
53
|
-
<h4 className="text-sm font-medium">Section 2</h4>
|
|
54
|
-
<p className="text-sm text-muted-foreground">Content for section 2</p>
|
|
55
|
-
</div>
|
|
56
|
-
<Separator />
|
|
57
|
-
<div>
|
|
58
|
-
<h4 className="text-sm font-medium">Section 3</h4>
|
|
59
|
-
<p className="text-sm text-muted-foreground">Content for section 3</p>
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
),
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const Vertical: Story = {
|
|
66
|
-
render: () => (
|
|
67
|
-
<div className="flex h-20 items-center gap-4">
|
|
68
|
-
<div>Left</div>
|
|
69
|
-
<Separator orientation="vertical" />
|
|
70
|
-
<div>Center</div>
|
|
71
|
-
<Separator orientation="vertical" />
|
|
72
|
-
<div>Right</div>
|
|
73
|
-
</div>
|
|
74
|
-
),
|
|
75
|
-
};
|
|
76
|
-
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { render } from "@testing-library/react";
|
|
3
|
-
import { Separator } from "./separator";
|
|
4
|
-
|
|
5
|
-
describe("Separator", () => {
|
|
6
|
-
it("should render separator", () => {
|
|
7
|
-
const { container } = render(<Separator />);
|
|
8
|
-
const separator = container.querySelector('[data-slot="separator"]');
|
|
9
|
-
expect(separator).toBeInTheDocument();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it("should render horizontal separator by default", () => {
|
|
13
|
-
const { container } = render(<Separator />);
|
|
14
|
-
const separator = container.querySelector('[data-slot="separator"]');
|
|
15
|
-
expect(separator).toHaveAttribute("data-orientation", "horizontal");
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it("should render vertical separator when orientation is vertical", () => {
|
|
19
|
-
const { container } = render(<Separator orientation="vertical" />);
|
|
20
|
-
const separator = container.querySelector('[data-slot="separator"]');
|
|
21
|
-
expect(separator).toHaveAttribute("data-orientation", "vertical");
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils"
|
|
7
|
-
|
|
8
|
-
function Separator({
|
|
9
|
-
className,
|
|
10
|
-
orientation = "horizontal",
|
|
11
|
-
decorative = true,
|
|
12
|
-
...props
|
|
13
|
-
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
|
14
|
-
return (
|
|
15
|
-
<SeparatorPrimitive.Root
|
|
16
|
-
data-slot="separator"
|
|
17
|
-
decorative={decorative}
|
|
18
|
-
orientation={orientation}
|
|
19
|
-
className={cn(
|
|
20
|
-
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
21
|
-
className
|
|
22
|
-
)}
|
|
23
|
-
{...props}
|
|
24
|
-
/>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { Separator }
|