@bearmenu/ui 0.1.1 → 0.5.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/{chunk-2CUFS5LF.js → chunk-2BMJRXQX.js} +1 -1
- package/dist/chunk-HLQ2IRE7.js +279 -0
- package/dist/chunk-IQASCH2V.js +25 -0
- package/dist/{chunk-UXAYXRFN.js → chunk-QJ54Z7TC.js} +15 -1
- package/dist/{chunk-X6GATUI2.js → chunk-UISA4CIG.js} +1 -0
- package/dist/components/alert-dialog.js +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/calendar.d.ts +9 -7
- package/dist/components/calendar.js +153 -39
- package/dist/components/card.d.ts +2 -1
- package/dist/components/card.js +1 -1
- package/dist/components/carousel.js +1 -1
- package/dist/components/checkbox.js +3 -25
- package/dist/components/dropdown-menu.js +1 -1
- package/dist/components/empty-state.js +1 -1
- package/dist/components/haptic-button.js +1 -1
- package/dist/components/link-button.js +1 -1
- package/dist/components/multi-select-combobox.js +1 -1
- package/dist/components/multi-select-menu.d.ts +26 -0
- package/dist/components/multi-select-menu.js +71 -0
- package/dist/components/pagination.js +1 -1
- package/dist/components/phone-frame.d.ts +17 -0
- package/dist/components/phone-frame.js +41 -0
- package/dist/components/place-about-tab.d.ts +17 -0
- package/dist/components/place-about-tab.js +6 -0
- package/dist/components/place-card.d.ts +17 -0
- package/dist/components/place-card.js +145 -0
- package/dist/components/place-details-mobile.d.ts +18 -0
- package/dist/components/place-details-mobile.js +187 -0
- package/dist/components/place-types.d.ts +145 -0
- package/dist/components/place-types.js +1 -0
- package/dist/components/search-bar.js +1 -1
- package/dist/components/searchable-select.js +1 -1
- package/dist/components/skeleton-card.js +1 -1
- package/dist/components/skeleton.js +1 -1
- package/dist/components/sliding-panels.js +1 -1
- package/dist/components/sonner.js +11 -2
- package/dist/components/tabs.js +1 -1
- package/dist/components/toaster.js +1 -1
- package/package.json +28 -9
- package/src/components/accordion.stories.tsx +51 -0
- package/src/components/alert-dialog.stories.tsx +45 -0
- package/src/components/alert.stories.tsx +85 -0
- package/src/components/aspect-ratio.stories.tsx +47 -0
- package/src/components/avatar.stories.tsx +66 -0
- package/src/components/badge.stories.tsx +60 -0
- package/src/components/breadcrumb.stories.tsx +63 -0
- package/src/components/button.stories.tsx +115 -0
- package/src/components/button.tsx +1 -1
- package/src/components/calendar.stories.tsx +47 -0
- package/src/components/calendar.tsx +160 -40
- package/src/components/card.stories.tsx +72 -0
- package/src/components/card.tsx +13 -1
- package/src/components/carousel.stories.tsx +62 -0
- package/src/components/checkbox.stories.tsx +54 -0
- package/src/components/checkbox.tsx +1 -1
- package/src/components/collapsible.stories.tsx +34 -0
- package/src/components/command.stories.tsx +64 -0
- package/src/components/currency-input.stories.tsx +50 -0
- package/src/components/dialog.stories.tsx +75 -0
- package/src/components/drawer.stories.tsx +47 -0
- package/src/components/dropdown-menu.stories.tsx +64 -0
- package/src/components/dropdown-menu.tsx +1 -1
- package/src/components/empty-state.stories.tsx +67 -0
- package/src/components/form.stories.tsx +73 -0
- package/src/components/haptic-button.stories.tsx +41 -0
- package/src/components/input-otp.stories.tsx +42 -0
- package/src/components/input.stories.tsx +41 -0
- package/src/components/label.stories.tsx +35 -0
- package/src/components/markdown-renderer.stories.tsx +45 -0
- package/src/components/multi-select-combobox.stories.tsx +78 -0
- package/src/components/multi-select-menu.tsx +96 -0
- package/src/components/pagination.stories.tsx +48 -0
- package/src/components/phone-frame.stories.tsx +51 -0
- package/src/components/phone-frame.test.tsx +82 -0
- package/src/components/phone-frame.tsx +59 -0
- package/src/components/place-about-tab.stories.tsx +164 -0
- package/src/components/place-about-tab.test.tsx +325 -0
- package/src/components/place-about-tab.tsx +474 -0
- package/src/components/place-card.stories.tsx +120 -0
- package/src/components/place-card.test.tsx +187 -0
- package/src/components/place-card.tsx +187 -0
- package/src/components/place-details-mobile.tsx +251 -0
- package/src/components/place-types.ts +127 -0
- package/src/components/popover.stories.tsx +42 -0
- package/src/components/progress.stories.tsx +35 -0
- package/src/components/radio-group.stories.tsx +46 -0
- package/src/components/rating.stories.tsx +45 -0
- package/src/components/scroll-area.stories.tsx +48 -0
- package/src/components/search-bar.stories.tsx +92 -0
- package/src/components/searchable-select.stories.tsx +55 -0
- package/src/components/select.stories.tsx +92 -0
- package/src/components/separator.stories.tsx +33 -0
- package/src/components/sheet.stories.tsx +95 -0
- package/src/components/skeleton-card.stories.tsx +53 -0
- package/src/components/skeleton.stories.tsx +42 -0
- package/src/components/skeleton.tsx +1 -0
- package/src/components/slider.stories.tsx +27 -0
- package/src/components/sliding-panels.stories.tsx +68 -0
- package/src/components/sonner.tsx +17 -2
- package/src/components/sticky-container.stories.tsx +33 -0
- package/src/components/switch.stories.tsx +35 -0
- package/src/components/table.stories.tsx +60 -0
- package/src/components/tabs.stories.tsx +53 -0
- package/src/components/tabs.tsx +1 -1
- package/src/components/text.stories.tsx +82 -0
- package/src/components/textarea.stories.tsx +35 -0
- package/src/components/toast.stories.tsx +63 -0
- package/src/components/toggle-group.stories.tsx +60 -0
- package/src/components/toggle.stories.tsx +48 -0
- package/src/components/tooltip.stories.tsx +71 -0
- package/src/globals.css +14 -2
- package/src/test/setup.ts +9 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Badge } from "./badge";
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: "Components/Badge",
|
|
6
|
+
component: Badge,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
argTypes: {
|
|
9
|
+
variant: {
|
|
10
|
+
control: "select",
|
|
11
|
+
options: ["default", "secondary", "destructive", "outline", "overlay", "glass", "success", "warning"],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta<typeof Badge>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: { children: "Badge" },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Secondary: Story = {
|
|
24
|
+
args: { children: "Secondary", variant: "secondary" },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Destructive: Story = {
|
|
28
|
+
args: { children: "Destructive", variant: "destructive" },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const Outline: Story = {
|
|
32
|
+
args: { children: "Outline", variant: "outline" },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Glass: Story = {
|
|
36
|
+
args: { children: "Glass", variant: "glass" },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Success: Story = {
|
|
40
|
+
args: { children: "Success", variant: "success" },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Warning: Story = {
|
|
44
|
+
args: { children: "Warning", variant: "warning" },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const AllVariants: Story = {
|
|
48
|
+
render: () => (
|
|
49
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
50
|
+
<Badge variant="default">Default</Badge>
|
|
51
|
+
<Badge variant="secondary">Secondary</Badge>
|
|
52
|
+
<Badge variant="destructive">Destructive</Badge>
|
|
53
|
+
<Badge variant="outline">Outline</Badge>
|
|
54
|
+
<Badge variant="overlay">Overlay</Badge>
|
|
55
|
+
<Badge variant="glass">Glass</Badge>
|
|
56
|
+
<Badge variant="success">Success</Badge>
|
|
57
|
+
<Badge variant="warning">Warning</Badge>
|
|
58
|
+
</div>
|
|
59
|
+
),
|
|
60
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
Breadcrumb,
|
|
4
|
+
BreadcrumbEllipsis,
|
|
5
|
+
BreadcrumbItem,
|
|
6
|
+
BreadcrumbLink,
|
|
7
|
+
BreadcrumbList,
|
|
8
|
+
BreadcrumbPage,
|
|
9
|
+
BreadcrumbSeparator,
|
|
10
|
+
} from "./breadcrumb";
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: "Components/Breadcrumb",
|
|
14
|
+
component: Breadcrumb,
|
|
15
|
+
tags: ["autodocs"],
|
|
16
|
+
} satisfies Meta<typeof Breadcrumb>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
export const Default: Story = {
|
|
22
|
+
render: () => (
|
|
23
|
+
<Breadcrumb>
|
|
24
|
+
<BreadcrumbList>
|
|
25
|
+
<BreadcrumbItem>
|
|
26
|
+
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
|
27
|
+
</BreadcrumbItem>
|
|
28
|
+
<BreadcrumbSeparator />
|
|
29
|
+
<BreadcrumbItem>
|
|
30
|
+
<BreadcrumbLink href="#">Products</BreadcrumbLink>
|
|
31
|
+
</BreadcrumbItem>
|
|
32
|
+
<BreadcrumbSeparator />
|
|
33
|
+
<BreadcrumbItem>
|
|
34
|
+
<BreadcrumbPage>Current Page</BreadcrumbPage>
|
|
35
|
+
</BreadcrumbItem>
|
|
36
|
+
</BreadcrumbList>
|
|
37
|
+
</Breadcrumb>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const WithEllipsis: Story = {
|
|
42
|
+
render: () => (
|
|
43
|
+
<Breadcrumb>
|
|
44
|
+
<BreadcrumbList>
|
|
45
|
+
<BreadcrumbItem>
|
|
46
|
+
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
|
47
|
+
</BreadcrumbItem>
|
|
48
|
+
<BreadcrumbSeparator />
|
|
49
|
+
<BreadcrumbItem>
|
|
50
|
+
<BreadcrumbEllipsis />
|
|
51
|
+
</BreadcrumbItem>
|
|
52
|
+
<BreadcrumbSeparator />
|
|
53
|
+
<BreadcrumbItem>
|
|
54
|
+
<BreadcrumbLink href="#">Category</BreadcrumbLink>
|
|
55
|
+
</BreadcrumbItem>
|
|
56
|
+
<BreadcrumbSeparator />
|
|
57
|
+
<BreadcrumbItem>
|
|
58
|
+
<BreadcrumbPage>Product</BreadcrumbPage>
|
|
59
|
+
</BreadcrumbItem>
|
|
60
|
+
</BreadcrumbList>
|
|
61
|
+
</Breadcrumb>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Button } from "./button";
|
|
3
|
+
import { Heart, Mail, Plus } from "lucide-react";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/Button",
|
|
7
|
+
component: Button,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
argTypes: {
|
|
10
|
+
variant: {
|
|
11
|
+
control: "select",
|
|
12
|
+
options: [
|
|
13
|
+
"default",
|
|
14
|
+
"destructive",
|
|
15
|
+
"outline",
|
|
16
|
+
"secondary",
|
|
17
|
+
"ghost",
|
|
18
|
+
"link",
|
|
19
|
+
"glass",
|
|
20
|
+
"brown",
|
|
21
|
+
"antagonist",
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
size: {
|
|
25
|
+
control: "select",
|
|
26
|
+
options: ["default", "sm", "lg", "icon"],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
} satisfies Meta<typeof Button>;
|
|
30
|
+
|
|
31
|
+
export default meta;
|
|
32
|
+
type Story = StoryObj<typeof meta>;
|
|
33
|
+
|
|
34
|
+
export const Default: Story = {
|
|
35
|
+
args: { children: "Button" },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Destructive: Story = {
|
|
39
|
+
args: { children: "Delete", variant: "destructive" },
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const Outline: Story = {
|
|
43
|
+
args: { children: "Outline", variant: "outline" },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Secondary: Story = {
|
|
47
|
+
args: { children: "Secondary", variant: "secondary" },
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const Ghost: Story = {
|
|
51
|
+
args: { children: "Ghost", variant: "ghost" },
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Link: Story = {
|
|
55
|
+
args: { children: "Link", variant: "link" },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Glass: Story = {
|
|
59
|
+
args: { children: "Glass", variant: "glass" },
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Brown: Story = {
|
|
63
|
+
args: { children: "Brown", variant: "brown" },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const Antagonist: Story = {
|
|
67
|
+
args: { children: "Antagonist", variant: "antagonist" },
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const Small: Story = {
|
|
71
|
+
args: { children: "Small", size: "sm" },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const Large: Story = {
|
|
75
|
+
args: { children: "Large", size: "lg" },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Icon: Story = {
|
|
79
|
+
args: { size: "icon", children: <Plus className="h-4 w-4" /> },
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const WithIcon: Story = {
|
|
83
|
+
args: { children: <><Mail className="h-4 w-4" /> Send Email</> },
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const Disabled: Story = {
|
|
87
|
+
args: { children: "Disabled", disabled: true },
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const AllVariants: Story = {
|
|
91
|
+
render: () => (
|
|
92
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
93
|
+
<Button variant="default">Default</Button>
|
|
94
|
+
<Button variant="destructive">Destructive</Button>
|
|
95
|
+
<Button variant="outline">Outline</Button>
|
|
96
|
+
<Button variant="secondary">Secondary</Button>
|
|
97
|
+
<Button variant="ghost">Ghost</Button>
|
|
98
|
+
<Button variant="link">Link</Button>
|
|
99
|
+
<Button variant="glass">Glass</Button>
|
|
100
|
+
<Button variant="brown">Brown</Button>
|
|
101
|
+
<Button variant="antagonist">Antagonist</Button>
|
|
102
|
+
</div>
|
|
103
|
+
),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const AllSizes: Story = {
|
|
107
|
+
render: () => (
|
|
108
|
+
<div className="flex items-center gap-4">
|
|
109
|
+
<Button size="sm">Small</Button>
|
|
110
|
+
<Button size="default">Default</Button>
|
|
111
|
+
<Button size="lg">Large</Button>
|
|
112
|
+
<Button size="icon"><Heart className="h-4 w-4" /></Button>
|
|
113
|
+
</div>
|
|
114
|
+
),
|
|
115
|
+
};
|
|
@@ -14,7 +14,7 @@ const buttonVariants = cva(
|
|
|
14
14
|
destructive:
|
|
15
15
|
"bg-destructive text-destructive-foreground shadow-lg hover:bg-destructive/90 hover:shadow-destructive/20 backdrop-blur-sm border border-destructive/20",
|
|
16
16
|
outline:
|
|
17
|
-
"border border-border bg-
|
|
17
|
+
"border border-border bg-sidebar backdrop-blur-md hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:border-sidebar-accent-foreground/20 hover:shadow-lg",
|
|
18
18
|
secondary:
|
|
19
19
|
"bg-secondary text-secondary-foreground shadow-lg hover:bg-secondary/90 hover:shadow-secondary/20 backdrop-blur-sm border border-secondary/20",
|
|
20
20
|
ghost: "hover:bg-foreground/10 hover:text-foreground transition-colors duration-200",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Calendar } from "./calendar";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Components/Calendar",
|
|
7
|
+
component: Calendar,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
} satisfies Meta<typeof Calendar>;
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
|
|
14
|
+
function CalendarDemo() {
|
|
15
|
+
const [date, setDate] = useState<Date | undefined>(new Date());
|
|
16
|
+
return (
|
|
17
|
+
<Calendar
|
|
18
|
+
mode="single"
|
|
19
|
+
selected={date}
|
|
20
|
+
onSelect={setDate}
|
|
21
|
+
className="rounded-md border"
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
render: () => <CalendarDemo />,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function CalendarRangeDemo() {
|
|
31
|
+
const [range, setRange] = useState<{ from: Date; to?: Date }>({
|
|
32
|
+
from: new Date(),
|
|
33
|
+
});
|
|
34
|
+
return (
|
|
35
|
+
<Calendar
|
|
36
|
+
mode="range"
|
|
37
|
+
selected={range}
|
|
38
|
+
onSelect={(r) => r && setRange(r as { from: Date; to?: Date })}
|
|
39
|
+
numberOfMonths={2}
|
|
40
|
+
className="rounded-md border"
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const Range: Story = {
|
|
46
|
+
render: () => <CalendarRangeDemo />,
|
|
47
|
+
};
|
|
@@ -1,60 +1,180 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { DayPicker } from "react-day-picker";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
5
|
+
import { DayPicker, getDefaultClassNames, type DayButton } from "react-day-picker";
|
|
6
|
+
|
|
6
7
|
import { cn } from "../lib/utils";
|
|
7
|
-
import { buttonVariants } from "./button";
|
|
8
|
+
import { Button, buttonVariants } from "./button";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
function Calendar({
|
|
11
|
+
className,
|
|
12
|
+
classNames,
|
|
13
|
+
showOutsideDays = true,
|
|
14
|
+
captionLayout = "label",
|
|
15
|
+
buttonVariant = "ghost",
|
|
16
|
+
formatters,
|
|
17
|
+
components,
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof DayPicker> & {
|
|
20
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
21
|
+
}) {
|
|
22
|
+
const defaultClassNames = getDefaultClassNames();
|
|
10
23
|
|
|
11
|
-
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
|
12
24
|
return (
|
|
13
25
|
<DayPicker
|
|
14
26
|
showOutsideDays={showOutsideDays}
|
|
15
|
-
className={cn(
|
|
27
|
+
className={cn(
|
|
28
|
+
"group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
|
29
|
+
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
30
|
+
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
31
|
+
className
|
|
32
|
+
)}
|
|
33
|
+
captionLayout={captionLayout}
|
|
34
|
+
formatters={{
|
|
35
|
+
formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
|
|
36
|
+
...formatters,
|
|
37
|
+
}}
|
|
16
38
|
classNames={{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
40
|
+
months: cn("relative flex flex-col gap-4 md:flex-row", defaultClassNames.months),
|
|
41
|
+
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
42
|
+
nav: cn(
|
|
43
|
+
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
44
|
+
defaultClassNames.nav
|
|
45
|
+
),
|
|
46
|
+
button_previous: cn(
|
|
47
|
+
buttonVariants({ variant: buttonVariant }),
|
|
48
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
49
|
+
defaultClassNames.button_previous
|
|
50
|
+
),
|
|
51
|
+
button_next: cn(
|
|
52
|
+
buttonVariants({ variant: buttonVariant }),
|
|
53
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
54
|
+
defaultClassNames.button_next
|
|
55
|
+
),
|
|
56
|
+
month_caption: cn(
|
|
57
|
+
"flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
|
|
58
|
+
defaultClassNames.month_caption
|
|
59
|
+
),
|
|
60
|
+
dropdowns: cn(
|
|
61
|
+
"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
|
|
62
|
+
defaultClassNames.dropdowns
|
|
63
|
+
),
|
|
64
|
+
dropdown_root: cn(
|
|
65
|
+
"relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
|
|
66
|
+
defaultClassNames.dropdown_root
|
|
67
|
+
),
|
|
68
|
+
dropdown: cn("absolute inset-0 bg-popover opacity-0", defaultClassNames.dropdown),
|
|
69
|
+
caption_label: cn(
|
|
70
|
+
"font-medium select-none",
|
|
71
|
+
captionLayout === "label"
|
|
72
|
+
? "text-sm"
|
|
73
|
+
: "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
|
|
74
|
+
defaultClassNames.caption_label
|
|
75
|
+
),
|
|
76
|
+
table: "w-full border-collapse",
|
|
77
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
78
|
+
weekday: cn(
|
|
79
|
+
"flex-1 rounded-md text-[0.8rem] font-normal text-muted-foreground select-none",
|
|
80
|
+
defaultClassNames.weekday
|
|
81
|
+
),
|
|
82
|
+
week: cn("mt-2 flex w-full", defaultClassNames.week),
|
|
83
|
+
week_number_header: cn("w-(--cell-size) select-none", defaultClassNames.week_number_header),
|
|
84
|
+
week_number: cn(
|
|
85
|
+
"text-[0.8rem] text-muted-foreground select-none",
|
|
86
|
+
defaultClassNames.week_number
|
|
87
|
+
),
|
|
33
88
|
day: cn(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
89
|
+
"group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
|
|
90
|
+
props.showWeekNumber
|
|
91
|
+
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
|
|
92
|
+
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
|
|
93
|
+
defaultClassNames.day
|
|
94
|
+
),
|
|
95
|
+
range_start: cn("rounded-l-md bg-accent", defaultClassNames.range_start),
|
|
96
|
+
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
|
97
|
+
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
|
|
98
|
+
today: cn(
|
|
99
|
+
"rounded-md bg-accent text-accent-foreground data-[selected=true]:rounded-none",
|
|
100
|
+
defaultClassNames.today
|
|
101
|
+
),
|
|
102
|
+
outside: cn(
|
|
103
|
+
"text-muted-foreground aria-selected:text-muted-foreground",
|
|
104
|
+
defaultClassNames.outside
|
|
105
|
+
),
|
|
106
|
+
disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
|
|
107
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
46
108
|
...classNames,
|
|
47
109
|
}}
|
|
48
110
|
components={{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
111
|
+
Root: ({ className, rootRef, ...props }) => {
|
|
112
|
+
return <div data-slot="calendar" ref={rootRef} className={cn(className)} {...props} />;
|
|
113
|
+
},
|
|
114
|
+
Chevron: ({ className, orientation, ...props }) => {
|
|
115
|
+
if (orientation === "left") {
|
|
116
|
+
return <ChevronLeftIcon className={cn("size-4", className)} {...props} />;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (orientation === "right") {
|
|
120
|
+
return <ChevronRightIcon className={cn("size-4", className)} {...props} />;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
|
|
52
124
|
},
|
|
125
|
+
DayButton: CalendarDayButton,
|
|
126
|
+
WeekNumber: ({ children, ...props }) => {
|
|
127
|
+
return (
|
|
128
|
+
<td {...props}>
|
|
129
|
+
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
|
130
|
+
{children}
|
|
131
|
+
</div>
|
|
132
|
+
</td>
|
|
133
|
+
);
|
|
134
|
+
},
|
|
135
|
+
...components,
|
|
53
136
|
}}
|
|
54
137
|
{...props}
|
|
55
138
|
/>
|
|
56
139
|
);
|
|
57
140
|
}
|
|
58
|
-
Calendar.displayName = "Calendar";
|
|
59
141
|
|
|
60
|
-
|
|
142
|
+
function CalendarDayButton({
|
|
143
|
+
className,
|
|
144
|
+
day,
|
|
145
|
+
modifiers,
|
|
146
|
+
...props
|
|
147
|
+
}: React.ComponentProps<typeof DayButton>) {
|
|
148
|
+
const defaultClassNames = getDefaultClassNames();
|
|
149
|
+
|
|
150
|
+
const ref = React.useRef<HTMLButtonElement>(null);
|
|
151
|
+
React.useEffect(() => {
|
|
152
|
+
if (modifiers.focused) ref.current?.focus();
|
|
153
|
+
}, [modifiers.focused]);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<Button
|
|
157
|
+
ref={ref}
|
|
158
|
+
variant="ghost"
|
|
159
|
+
size="icon"
|
|
160
|
+
data-day={day.date.toLocaleDateString()}
|
|
161
|
+
data-selected-single={
|
|
162
|
+
modifiers.selected &&
|
|
163
|
+
!modifiers.range_start &&
|
|
164
|
+
!modifiers.range_end &&
|
|
165
|
+
!modifiers.range_middle
|
|
166
|
+
}
|
|
167
|
+
data-range-start={modifiers.range_start}
|
|
168
|
+
data-range-end={modifiers.range_end}
|
|
169
|
+
data-range-middle={modifiers.range_middle}
|
|
170
|
+
className={cn(
|
|
171
|
+
"group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70",
|
|
172
|
+
defaultClassNames.day,
|
|
173
|
+
className
|
|
174
|
+
)}
|
|
175
|
+
{...props}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export { Calendar, CalendarDayButton };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./card";
|
|
3
|
+
import { Button } from "./button";
|
|
4
|
+
import { Input } from "./input";
|
|
5
|
+
import { Label } from "./label";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Components/Card",
|
|
9
|
+
component: Card,
|
|
10
|
+
tags: ["autodocs"],
|
|
11
|
+
argTypes: {
|
|
12
|
+
variant: {
|
|
13
|
+
control: "select",
|
|
14
|
+
options: ["glass", "surface"],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
} satisfies Meta<typeof Card>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
export const Glass: Story = {
|
|
23
|
+
render: () => (
|
|
24
|
+
<Card variant="glass" className="w-[350px]">
|
|
25
|
+
<CardHeader>
|
|
26
|
+
<CardTitle>Glass Card</CardTitle>
|
|
27
|
+
<CardDescription>A card with glass morphism effect.</CardDescription>
|
|
28
|
+
</CardHeader>
|
|
29
|
+
<CardContent>
|
|
30
|
+
<p className="text-sm text-muted-foreground">Card content goes here.</p>
|
|
31
|
+
</CardContent>
|
|
32
|
+
</Card>
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Surface: Story = {
|
|
37
|
+
render: () => (
|
|
38
|
+
<Card variant="surface" className="w-[350px]">
|
|
39
|
+
<CardHeader>
|
|
40
|
+
<CardTitle>Surface Card</CardTitle>
|
|
41
|
+
<CardDescription>A card with solid surface background.</CardDescription>
|
|
42
|
+
</CardHeader>
|
|
43
|
+
<CardContent>
|
|
44
|
+
<p className="text-sm text-muted-foreground">Card content goes here.</p>
|
|
45
|
+
</CardContent>
|
|
46
|
+
</Card>
|
|
47
|
+
),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const WithForm: Story = {
|
|
51
|
+
render: () => (
|
|
52
|
+
<Card className="w-[350px]">
|
|
53
|
+
<CardHeader>
|
|
54
|
+
<CardTitle>Create account</CardTitle>
|
|
55
|
+
<CardDescription>Enter your details below.</CardDescription>
|
|
56
|
+
</CardHeader>
|
|
57
|
+
<CardContent className="flex flex-col gap-4">
|
|
58
|
+
<div className="grid gap-1.5">
|
|
59
|
+
<Label htmlFor="name">Name</Label>
|
|
60
|
+
<Input id="name" placeholder="Your name" />
|
|
61
|
+
</div>
|
|
62
|
+
<div className="grid gap-1.5">
|
|
63
|
+
<Label htmlFor="email">Email</Label>
|
|
64
|
+
<Input id="email" type="email" placeholder="name@example.com" />
|
|
65
|
+
</div>
|
|
66
|
+
</CardContent>
|
|
67
|
+
<CardFooter>
|
|
68
|
+
<Button className="w-full">Sign up</Button>
|
|
69
|
+
</CardFooter>
|
|
70
|
+
</Card>
|
|
71
|
+
),
|
|
72
|
+
};
|
package/src/components/card.tsx
CHANGED
|
@@ -57,6 +57,18 @@ const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDi
|
|
|
57
57
|
);
|
|
58
58
|
CardContent.displayName = "CardContent";
|
|
59
59
|
|
|
60
|
+
const CardAction = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
61
|
+
({ className, ...props }, ref) => (
|
|
62
|
+
<div
|
|
63
|
+
ref={ref}
|
|
64
|
+
data-slot="card-action"
|
|
65
|
+
className={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
CardAction.displayName = "CardAction";
|
|
71
|
+
|
|
60
72
|
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
61
73
|
({ className, ...props }, ref) => (
|
|
62
74
|
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
|
|
@@ -64,4 +76,4 @@ const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDiv
|
|
|
64
76
|
);
|
|
65
77
|
CardFooter.displayName = "CardFooter";
|
|
66
78
|
|
|
67
|
-
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
|
79
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
Carousel,
|
|
4
|
+
CarouselContent,
|
|
5
|
+
CarouselItem,
|
|
6
|
+
CarouselNext,
|
|
7
|
+
CarouselPrevious,
|
|
8
|
+
} from "./carousel";
|
|
9
|
+
import { Card } from "./card";
|
|
10
|
+
|
|
11
|
+
const meta = {
|
|
12
|
+
title: "Components/Carousel",
|
|
13
|
+
component: Carousel,
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
} satisfies Meta<typeof Carousel>;
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
render: () => (
|
|
22
|
+
<div className="w-full max-w-xs mx-auto">
|
|
23
|
+
<Carousel>
|
|
24
|
+
<CarouselContent>
|
|
25
|
+
{Array.from({ length: 5 }).map((_, i) => (
|
|
26
|
+
<CarouselItem key={i}>
|
|
27
|
+
<Card className="p-6">
|
|
28
|
+
<div className="flex aspect-square items-center justify-center text-3xl font-semibold">
|
|
29
|
+
{i + 1}
|
|
30
|
+
</div>
|
|
31
|
+
</Card>
|
|
32
|
+
</CarouselItem>
|
|
33
|
+
))}
|
|
34
|
+
</CarouselContent>
|
|
35
|
+
<CarouselPrevious />
|
|
36
|
+
<CarouselNext />
|
|
37
|
+
</Carousel>
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const ThreePerView: Story = {
|
|
43
|
+
render: () => (
|
|
44
|
+
<div className="w-full max-w-sm mx-auto">
|
|
45
|
+
<Carousel opts={{ align: "start" }}>
|
|
46
|
+
<CarouselContent className="-ml-2">
|
|
47
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
48
|
+
<CarouselItem key={i} className="pl-2 basis-1/3">
|
|
49
|
+
<Card className="p-4">
|
|
50
|
+
<div className="flex aspect-square items-center justify-center text-lg font-semibold">
|
|
51
|
+
{i + 1}
|
|
52
|
+
</div>
|
|
53
|
+
</Card>
|
|
54
|
+
</CarouselItem>
|
|
55
|
+
))}
|
|
56
|
+
</CarouselContent>
|
|
57
|
+
<CarouselPrevious />
|
|
58
|
+
<CarouselNext />
|
|
59
|
+
</Carousel>
|
|
60
|
+
</div>
|
|
61
|
+
),
|
|
62
|
+
};
|