@a2v2ai/uikit 0.0.1 → 0.0.3
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/Alert/Alert.stories.tsx +121 -0
- package/Alert/Alert.tsx +71 -0
- package/AlertDialog/AlertDialog.stories.tsx +665 -0
- package/AlertDialog/AlertDialog.tsx +241 -0
- package/Avatar/Avatar.stories.tsx +128 -0
- package/Avatar/Avatar.tsx +71 -0
- package/Badge/Badge.stories.tsx +76 -0
- package/Badge/Badge.tsx +39 -0
- package/Breadcrumb/Breadcrumb.stories.tsx +231 -0
- package/Breadcrumb/Breadcrumb.tsx +114 -0
- package/Button/Button.stories.tsx +684 -0
- package/Button/Button.tsx +90 -0
- package/Calendar/Calendar.stories.tsx +207 -0
- package/Calendar/Calendar.tsx +232 -0
- package/Card/Card.stories.tsx +136 -0
- package/Card/Card.tsx +96 -0
- package/ChatBubble/ChatBubble.stories.tsx +307 -0
- package/ChatBubble/ChatBubble.tsx +167 -0
- package/Checkbox/Checkbox.stories.tsx +137 -0
- package/Checkbox/Checkbox.tsx +53 -0
- package/Drawer/Drawer.stories.tsx +721 -0
- package/Drawer/Drawer.tsx +201 -0
- package/DropdownMenu/DropdownMenu.stories.tsx +251 -0
- package/DropdownMenu/DropdownMenu.tsx +199 -0
- package/ErrorMessage/ErrorMessage.stories.tsx +159 -0
- package/ErrorMessage/ErrorMessage.tsx +55 -0
- package/Flex/Flex.tsx +102 -0
- package/IconButton/IconButton.stories.tsx +566 -0
- package/IconButton/IconButton.tsx +95 -0
- package/Input/Input.stories.tsx +456 -0
- package/Input/Input.tsx +129 -0
- package/InputOTP/InputOTP.stories.tsx +246 -0
- package/InputOTP/InputOTP.tsx +127 -0
- package/Label/Label.stories.tsx +105 -0
- package/Label/Label.tsx +43 -0
- package/Loader/Loader.stories.tsx +170 -0
- package/Loader/Loader.tsx +62 -0
- package/Popover/Popover.stories.tsx +133 -0
- package/Popover/Popover.tsx +31 -0
- package/Progress/Progress.stories.tsx +146 -0
- package/Progress/Progress.tsx +67 -0
- package/README.md +12 -12
- package/RadioGroup/RadioGroup.stories.tsx +159 -0
- package/RadioGroup/RadioGroup.tsx +68 -0
- package/ScrollArea/ScrollArea.stories.tsx +136 -0
- package/ScrollArea/ScrollArea.tsx +46 -0
- package/Select/Select.stories.tsx +242 -0
- package/Select/Select.tsx +180 -0
- package/Separator/Separator.stories.tsx +110 -0
- package/Separator/Separator.tsx +29 -0
- package/Skeleton/Skeleton.stories.tsx +117 -0
- package/Skeleton/Skeleton.tsx +16 -0
- package/Spinner/Spinner.stories.tsx +210 -0
- package/Spinner/Spinner.tsx +78 -0
- package/Switch/Switch.stories.tsx +146 -0
- package/Switch/Switch.tsx +59 -0
- package/Tabs/Tabs.stories.tsx +197 -0
- package/Tabs/Tabs.tsx +74 -0
- package/Textarea/Textarea.stories.tsx +170 -0
- package/Textarea/Textarea.tsx +51 -0
- package/Toast/Toast.stories.tsx +285 -0
- package/Toast/Toast.tsx +59 -0
- package/Tooltip/Tooltip.stories.tsx +463 -0
- package/Tooltip/Tooltip.tsx +96 -0
- package/Typography/Typography.stories.tsx +235 -0
- package/Typography/Typography.tsx +171 -0
- package/helpers.ts +5 -0
- package/icons.ts +2 -0
- package/index.ts +136 -0
- package/lib/utils.ts +15 -0
- package/package.json +4 -1
- package/tsconfig.json +24 -0
- package/Alert/Alert.d.ts +0 -11
- package/Alert/Alert.js +0 -64
- package/AlertDialog/AlertDialog.d.ts +0 -35
- package/AlertDialog/AlertDialog.js +0 -121
- package/Avatar/Avatar.d.ts +0 -12
- package/Avatar/Avatar.js +0 -64
- package/Badge/Badge.d.ts +0 -9
- package/Badge/Badge.js +0 -26
- package/Breadcrumb/Breadcrumb.d.ts +0 -19
- package/Breadcrumb/Breadcrumb.js +0 -65
- package/Button/Button.d.ts +0 -14
- package/Button/Button.js +0 -75
- package/Calendar/Calendar.d.ts +0 -16
- package/Calendar/Calendar.js +0 -113
- package/Card/Card.d.ts +0 -14
- package/Card/Card.js +0 -70
- package/ChatBubble/ChatBubble.d.ts +0 -29
- package/ChatBubble/ChatBubble.js +0 -133
- package/Checkbox/Checkbox.d.ts +0 -10
- package/Checkbox/Checkbox.js +0 -57
- package/Dialog/Dialog.d.ts +0 -35
- package/Dialog/Dialog.js +0 -130
- package/Drawer/Drawer.d.ts +0 -31
- package/Drawer/Drawer.js +0 -69
- package/DropdownMenu/DropdownMenu.d.ts +0 -27
- package/DropdownMenu/DropdownMenu.js +0 -85
- package/ErrorMessage/ErrorMessage.d.ts +0 -27
- package/ErrorMessage/ErrorMessage.js +0 -15
- package/Flex/Flex.d.ts +0 -23
- package/Flex/Flex.js +0 -101
- package/IconButton/IconButton.d.ts +0 -17
- package/IconButton/IconButton.js +0 -85
- package/Input/Input.d.ts +0 -16
- package/Input/Input.js +0 -75
- package/InputOTP/InputOTP.d.ts +0 -18
- package/InputOTP/InputOTP.js +0 -85
- package/Label/Label.d.ts +0 -10
- package/Label/Label.js +0 -57
- package/Loader/Loader.d.ts +0 -18
- package/Loader/Loader.js +0 -67
- package/Popover/Popover.d.ts +0 -7
- package/Popover/Popover.js +0 -49
- package/Progress/Progress.d.ts +0 -13
- package/Progress/Progress.js +0 -71
- package/RadioGroup/RadioGroup.d.ts +0 -11
- package/RadioGroup/RadioGroup.js +0 -64
- package/ScrollArea/ScrollArea.d.ts +0 -5
- package/ScrollArea/ScrollArea.js +0 -48
- package/Select/Select.d.ts +0 -19
- package/Select/Select.js +0 -85
- package/Separator/Separator.d.ts +0 -4
- package/Separator/Separator.js +0 -43
- package/Skeleton/Skeleton.d.ts +0 -4
- package/Skeleton/Skeleton.js +0 -8
- package/Spinner/Spinner.d.ts +0 -15
- package/Spinner/Spinner.js +0 -68
- package/Switch/Switch.d.ts +0 -10
- package/Switch/Switch.js +0 -67
- package/Tabs/Tabs.d.ts +0 -13
- package/Tabs/Tabs.js +0 -64
- package/Textarea/Textarea.d.ts +0 -10
- package/Textarea/Textarea.js +0 -64
- package/Toast/Toast.d.ts +0 -10
- package/Toast/Toast.js +0 -29
- package/Tooltip/Tooltip.d.ts +0 -15
- package/Tooltip/Tooltip.js +0 -68
- package/Typography/Typography.d.ts +0 -15
- package/Typography/Typography.js +0 -125
- package/helpers.d.ts +0 -4
- package/helpers.js +0 -13
- package/icons.d.ts +0 -1
- package/icons.js +0 -18
- package/index.d.ts +0 -35
- package/index.js +0 -183
- package/lib/utils.d.ts +0 -3
- package/lib/utils.js +0 -18
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/utils"
|
|
6
|
+
|
|
7
|
+
type ButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "ghost-muted" | "destructive"
|
|
8
|
+
type ButtonSize = "mini" | "small" | "regular" | "large"
|
|
9
|
+
type ButtonRoundness = "default" | "round"
|
|
10
|
+
|
|
11
|
+
const buttonVariants = cva(
|
|
12
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap font-normal font-sans cursor-pointer transition-colors focus-visible:outline-none focus-visible:shadow-[0_0_0_3px_#d4d4d4] disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
13
|
+
{
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
primary:
|
|
17
|
+
"bg-main-950 text-main-50 hover:bg-main-800",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-main-100 text-main-950 hover:bg-main-200",
|
|
20
|
+
outline:
|
|
21
|
+
"border border-main-300 bg-transparent text-main-950 hover:bg-main-100",
|
|
22
|
+
ghost:
|
|
23
|
+
"bg-transparent text-main-600 hover:bg-main-100 hover:text-main-950",
|
|
24
|
+
"ghost-muted":
|
|
25
|
+
"bg-transparent text-main-400 hover:bg-main-100 hover:text-main-600",
|
|
26
|
+
destructive:
|
|
27
|
+
"bg-error-600 text-white hover:bg-error-700",
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
mini: "h-6 px-3 text-xs rounded-md [&_svg]:size-3",
|
|
31
|
+
small: "h-8 px-3 text-sm rounded-md [&_svg]:size-3.5",
|
|
32
|
+
regular: "h-9 px-4 text-sm rounded-lg [&_svg]:size-4",
|
|
33
|
+
large: "h-10 px-4 text-base rounded-lg [&_svg]:size-5",
|
|
34
|
+
},
|
|
35
|
+
roundness: {
|
|
36
|
+
default: "",
|
|
37
|
+
round: "!rounded-full",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
variant: "primary",
|
|
42
|
+
size: "regular",
|
|
43
|
+
roundness: "default",
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export interface ButtonProps
|
|
49
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
50
|
+
variant?: ButtonVariant
|
|
51
|
+
size?: ButtonSize
|
|
52
|
+
roundness?: ButtonRoundness
|
|
53
|
+
asChild?: boolean
|
|
54
|
+
leftIcon?: React.ReactNode
|
|
55
|
+
rightIcon?: React.ReactNode
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
59
|
+
(
|
|
60
|
+
{
|
|
61
|
+
className,
|
|
62
|
+
variant,
|
|
63
|
+
size,
|
|
64
|
+
roundness,
|
|
65
|
+
asChild = false,
|
|
66
|
+
leftIcon,
|
|
67
|
+
rightIcon,
|
|
68
|
+
children,
|
|
69
|
+
...props
|
|
70
|
+
},
|
|
71
|
+
ref
|
|
72
|
+
) => {
|
|
73
|
+
const Comp = asChild ? Slot : "button"
|
|
74
|
+
return (
|
|
75
|
+
<Comp
|
|
76
|
+
className={cn(buttonVariants({ variant, size, roundness, className }))}
|
|
77
|
+
ref={ref}
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
{leftIcon && <span className="shrink-0">{leftIcon}</span>}
|
|
81
|
+
{children}
|
|
82
|
+
{rightIcon && <span className="shrink-0">{rightIcon}</span>}
|
|
83
|
+
</Comp>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
Button.displayName = "Button"
|
|
88
|
+
|
|
89
|
+
export { Button, buttonVariants }
|
|
90
|
+
export type { ButtonVariant, ButtonSize, ButtonRoundness }
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
import * as React from "react"
|
|
3
|
+
import type { DateRange } from "react-day-picker"
|
|
4
|
+
import { Calendar } from "./Calendar"
|
|
5
|
+
import { Flex } from "../Flex/Flex"
|
|
6
|
+
import { Typography } from "../Typography/Typography"
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Calendar> = {
|
|
9
|
+
title: "Components/Calendar",
|
|
10
|
+
component: Calendar,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: "centered",
|
|
13
|
+
},
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
argTypes: {
|
|
16
|
+
mode: {
|
|
17
|
+
control: "select",
|
|
18
|
+
options: ["single", "multiple", "range"],
|
|
19
|
+
description: "Selection mode for the calendar",
|
|
20
|
+
},
|
|
21
|
+
showOutsideDays: {
|
|
22
|
+
control: "boolean",
|
|
23
|
+
description: "Show days from adjacent months",
|
|
24
|
+
},
|
|
25
|
+
showWeekNumber: {
|
|
26
|
+
control: "boolean",
|
|
27
|
+
description: "Show week numbers",
|
|
28
|
+
},
|
|
29
|
+
captionLayout: {
|
|
30
|
+
control: "select",
|
|
31
|
+
options: ["label", "dropdown", "dropdown-months", "dropdown-years"],
|
|
32
|
+
description: "Layout of the caption (month/year selector)",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default meta
|
|
38
|
+
type Story = StoryObj<typeof Calendar>
|
|
39
|
+
|
|
40
|
+
export const Default: Story = {
|
|
41
|
+
render: () => {
|
|
42
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
43
|
+
return (
|
|
44
|
+
<Calendar
|
|
45
|
+
mode="single"
|
|
46
|
+
selected={date}
|
|
47
|
+
onSelect={setDate}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const SingleSelection: Story = {
|
|
54
|
+
render: () => {
|
|
55
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
56
|
+
return (
|
|
57
|
+
<Flex direction="column" gap={4} align="center">
|
|
58
|
+
<Calendar
|
|
59
|
+
mode="single"
|
|
60
|
+
selected={date}
|
|
61
|
+
onSelect={setDate}
|
|
62
|
+
/>
|
|
63
|
+
<Typography variant="body2" color="main-600">
|
|
64
|
+
Selected: {date ? date.toLocaleDateString() : "None"}
|
|
65
|
+
</Typography>
|
|
66
|
+
</Flex>
|
|
67
|
+
)
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const MultipleSelection: Story = {
|
|
72
|
+
render: () => {
|
|
73
|
+
const [dates, setDates] = React.useState<Date[] | undefined>([])
|
|
74
|
+
return (
|
|
75
|
+
<Flex direction="column" gap={4} align="center">
|
|
76
|
+
<Calendar
|
|
77
|
+
mode="multiple"
|
|
78
|
+
selected={dates}
|
|
79
|
+
onSelect={setDates}
|
|
80
|
+
/>
|
|
81
|
+
<Typography variant="body2" color="main-600">
|
|
82
|
+
Selected: {dates && dates.length > 0
|
|
83
|
+
? dates.map(d => d.toLocaleDateString()).join(", ")
|
|
84
|
+
: "None"}
|
|
85
|
+
</Typography>
|
|
86
|
+
</Flex>
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const RangeSelection: Story = {
|
|
92
|
+
render: () => {
|
|
93
|
+
const [range, setRange] = React.useState<DateRange | undefined>()
|
|
94
|
+
return (
|
|
95
|
+
<Flex direction="column" gap={4} align="center">
|
|
96
|
+
<Calendar
|
|
97
|
+
mode="range"
|
|
98
|
+
selected={range}
|
|
99
|
+
onSelect={setRange}
|
|
100
|
+
numberOfMonths={2}
|
|
101
|
+
/>
|
|
102
|
+
<Typography variant="body2" color="main-600">
|
|
103
|
+
{range?.from && range?.to
|
|
104
|
+
? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()}`
|
|
105
|
+
: range?.from
|
|
106
|
+
? `${range.from.toLocaleDateString()} - Select end date`
|
|
107
|
+
: "Select a date range"}
|
|
108
|
+
</Typography>
|
|
109
|
+
</Flex>
|
|
110
|
+
)
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const WithWeekNumbers: Story = {
|
|
115
|
+
render: () => {
|
|
116
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
117
|
+
return (
|
|
118
|
+
<Calendar
|
|
119
|
+
mode="single"
|
|
120
|
+
selected={date}
|
|
121
|
+
onSelect={setDate}
|
|
122
|
+
showWeekNumber
|
|
123
|
+
/>
|
|
124
|
+
)
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const WithDropdowns: Story = {
|
|
129
|
+
render: () => {
|
|
130
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
131
|
+
return (
|
|
132
|
+
<Calendar
|
|
133
|
+
mode="single"
|
|
134
|
+
selected={date}
|
|
135
|
+
onSelect={setDate}
|
|
136
|
+
captionLayout="dropdown"
|
|
137
|
+
fromYear={2020}
|
|
138
|
+
toYear={2030}
|
|
139
|
+
/>
|
|
140
|
+
)
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const DisabledDates: Story = {
|
|
145
|
+
render: () => {
|
|
146
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
147
|
+
|
|
148
|
+
// Disable weekends
|
|
149
|
+
const disabledDays = [
|
|
150
|
+
{ dayOfWeek: [0, 6] }, // Sunday and Saturday
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Flex direction="column" gap={4} align="center">
|
|
155
|
+
<Typography variant="body2" color="main-600">
|
|
156
|
+
Weekends are disabled
|
|
157
|
+
</Typography>
|
|
158
|
+
<Calendar
|
|
159
|
+
mode="single"
|
|
160
|
+
selected={date}
|
|
161
|
+
onSelect={setDate}
|
|
162
|
+
disabled={disabledDays}
|
|
163
|
+
/>
|
|
164
|
+
</Flex>
|
|
165
|
+
)
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const LimitedDateRange: Story = {
|
|
170
|
+
render: () => {
|
|
171
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
172
|
+
|
|
173
|
+
// Only allow dates in the next 30 days
|
|
174
|
+
const today = new Date()
|
|
175
|
+
const thirtyDaysFromNow = new Date()
|
|
176
|
+
thirtyDaysFromNow.setDate(today.getDate() + 30)
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<Flex direction="column" gap={4} align="center">
|
|
180
|
+
<Typography variant="body2" color="main-600">
|
|
181
|
+
Only next 30 days selectable
|
|
182
|
+
</Typography>
|
|
183
|
+
<Calendar
|
|
184
|
+
mode="single"
|
|
185
|
+
selected={date}
|
|
186
|
+
onSelect={setDate}
|
|
187
|
+
fromDate={today}
|
|
188
|
+
toDate={thirtyDaysFromNow}
|
|
189
|
+
/>
|
|
190
|
+
</Flex>
|
|
191
|
+
)
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const TwoMonths: Story = {
|
|
196
|
+
render: () => {
|
|
197
|
+
const [date, setDate] = React.useState<Date | undefined>(new Date())
|
|
198
|
+
return (
|
|
199
|
+
<Calendar
|
|
200
|
+
mode="single"
|
|
201
|
+
selected={date}
|
|
202
|
+
onSelect={setDate}
|
|
203
|
+
numberOfMonths={2}
|
|
204
|
+
/>
|
|
205
|
+
)
|
|
206
|
+
},
|
|
207
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import {
|
|
5
|
+
ChevronDownIcon,
|
|
6
|
+
ChevronLeftIcon,
|
|
7
|
+
ChevronRightIcon,
|
|
8
|
+
} from "lucide-react"
|
|
9
|
+
import { DayButton, DayPicker, getDefaultClassNames } from "react-day-picker"
|
|
10
|
+
|
|
11
|
+
import { cn } from "../lib/utils"
|
|
12
|
+
import { Button, buttonVariants } from "../Button/Button"
|
|
13
|
+
|
|
14
|
+
export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
|
|
15
|
+
/**
|
|
16
|
+
* Variant for navigation buttons
|
|
17
|
+
* @default "ghost"
|
|
18
|
+
*/
|
|
19
|
+
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function Calendar({
|
|
23
|
+
className,
|
|
24
|
+
classNames,
|
|
25
|
+
showOutsideDays = true,
|
|
26
|
+
captionLayout = "label",
|
|
27
|
+
buttonVariant = "ghost",
|
|
28
|
+
formatters,
|
|
29
|
+
components,
|
|
30
|
+
...props
|
|
31
|
+
}: CalendarProps) {
|
|
32
|
+
const defaultClassNames = getDefaultClassNames()
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<DayPicker
|
|
36
|
+
showOutsideDays={showOutsideDays}
|
|
37
|
+
className={cn(
|
|
38
|
+
"bg-white group/calendar p-3 rounded-lg border border-grey-200",
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
|
+
captionLayout={captionLayout}
|
|
42
|
+
formatters={{
|
|
43
|
+
formatMonthDropdown: (date) =>
|
|
44
|
+
date.toLocaleString("default", { month: "short" }),
|
|
45
|
+
...formatters,
|
|
46
|
+
}}
|
|
47
|
+
classNames={{
|
|
48
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
49
|
+
months: cn(
|
|
50
|
+
"flex gap-4 flex-col md:flex-row relative",
|
|
51
|
+
defaultClassNames.months
|
|
52
|
+
),
|
|
53
|
+
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
|
|
54
|
+
nav: cn(
|
|
55
|
+
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
|
|
56
|
+
defaultClassNames.nav
|
|
57
|
+
),
|
|
58
|
+
button_previous: cn(
|
|
59
|
+
buttonVariants({ variant: buttonVariant, size: "small" }),
|
|
60
|
+
"size-8 aria-disabled:opacity-50 p-0 select-none",
|
|
61
|
+
defaultClassNames.button_previous
|
|
62
|
+
),
|
|
63
|
+
button_next: cn(
|
|
64
|
+
buttonVariants({ variant: buttonVariant, size: "small" }),
|
|
65
|
+
"size-8 aria-disabled:opacity-50 p-0 select-none",
|
|
66
|
+
defaultClassNames.button_next
|
|
67
|
+
),
|
|
68
|
+
month_caption: cn(
|
|
69
|
+
"flex items-center justify-center h-8 w-full px-8",
|
|
70
|
+
defaultClassNames.month_caption
|
|
71
|
+
),
|
|
72
|
+
dropdowns: cn(
|
|
73
|
+
"w-full flex items-center text-sm font-medium justify-center h-8 gap-1.5",
|
|
74
|
+
defaultClassNames.dropdowns
|
|
75
|
+
),
|
|
76
|
+
dropdown_root: cn(
|
|
77
|
+
"relative has-focus:border-grey-400 border border-grey-300 shadow-xs has-focus:ring-grey-300/50 has-focus:ring-[3px] rounded-md",
|
|
78
|
+
defaultClassNames.dropdown_root
|
|
79
|
+
),
|
|
80
|
+
dropdown: cn(
|
|
81
|
+
"absolute bg-white inset-0 opacity-0",
|
|
82
|
+
defaultClassNames.dropdown
|
|
83
|
+
),
|
|
84
|
+
caption_label: cn(
|
|
85
|
+
"select-none font-medium text-main-900",
|
|
86
|
+
captionLayout === "label"
|
|
87
|
+
? "text-sm"
|
|
88
|
+
: "rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-main-400 [&>svg]:size-3.5",
|
|
89
|
+
defaultClassNames.caption_label
|
|
90
|
+
),
|
|
91
|
+
table: "w-full border-collapse",
|
|
92
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
93
|
+
weekday: cn(
|
|
94
|
+
"text-main-500 rounded-md flex-1 font-normal text-[0.8rem] select-none w-8 h-8 flex items-center justify-center",
|
|
95
|
+
defaultClassNames.weekday
|
|
96
|
+
),
|
|
97
|
+
week: cn("flex w-full mt-2", defaultClassNames.week),
|
|
98
|
+
week_number_header: cn(
|
|
99
|
+
"select-none w-8",
|
|
100
|
+
defaultClassNames.week_number_header
|
|
101
|
+
),
|
|
102
|
+
week_number: cn(
|
|
103
|
+
"text-[0.8rem] select-none text-main-400",
|
|
104
|
+
defaultClassNames.week_number
|
|
105
|
+
),
|
|
106
|
+
day: cn(
|
|
107
|
+
"relative w-8 h-8 p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-md group/day select-none",
|
|
108
|
+
props.showWeekNumber
|
|
109
|
+
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
|
|
110
|
+
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
|
|
111
|
+
defaultClassNames.day
|
|
112
|
+
),
|
|
113
|
+
range_start: cn(
|
|
114
|
+
"rounded-l-md bg-main-100",
|
|
115
|
+
defaultClassNames.range_start
|
|
116
|
+
),
|
|
117
|
+
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
|
118
|
+
range_end: cn("rounded-r-md bg-main-100", defaultClassNames.range_end),
|
|
119
|
+
today: cn(
|
|
120
|
+
"bg-main-100 text-main-900 rounded-md data-[selected=true]:rounded-none",
|
|
121
|
+
defaultClassNames.today
|
|
122
|
+
),
|
|
123
|
+
outside: cn(
|
|
124
|
+
"text-main-300 aria-selected:text-main-400",
|
|
125
|
+
defaultClassNames.outside
|
|
126
|
+
),
|
|
127
|
+
disabled: cn(
|
|
128
|
+
"text-main-300 opacity-50",
|
|
129
|
+
defaultClassNames.disabled
|
|
130
|
+
),
|
|
131
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
132
|
+
...classNames,
|
|
133
|
+
}}
|
|
134
|
+
components={{
|
|
135
|
+
Root: ({ className, rootRef, ...props }) => {
|
|
136
|
+
return (
|
|
137
|
+
<div
|
|
138
|
+
data-slot="calendar"
|
|
139
|
+
ref={rootRef}
|
|
140
|
+
className={cn(className)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
},
|
|
145
|
+
Chevron: ({ className, orientation, ...props }) => {
|
|
146
|
+
if (orientation === "left") {
|
|
147
|
+
return (
|
|
148
|
+
<ChevronLeftIcon className={cn("size-4", className)} {...props} />
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (orientation === "right") {
|
|
153
|
+
return (
|
|
154
|
+
<ChevronRightIcon
|
|
155
|
+
className={cn("size-4", className)}
|
|
156
|
+
{...props}
|
|
157
|
+
/>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<ChevronDownIcon className={cn("size-4", className)} {...props} />
|
|
163
|
+
)
|
|
164
|
+
},
|
|
165
|
+
DayButton: CalendarDayButton,
|
|
166
|
+
WeekNumber: ({ children, ...props }) => {
|
|
167
|
+
return (
|
|
168
|
+
<td {...props}>
|
|
169
|
+
<div className="flex size-8 items-center justify-center text-center">
|
|
170
|
+
{children}
|
|
171
|
+
</div>
|
|
172
|
+
</td>
|
|
173
|
+
)
|
|
174
|
+
},
|
|
175
|
+
...components,
|
|
176
|
+
}}
|
|
177
|
+
{...props}
|
|
178
|
+
/>
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function CalendarDayButton({
|
|
183
|
+
className,
|
|
184
|
+
day,
|
|
185
|
+
modifiers,
|
|
186
|
+
...props
|
|
187
|
+
}: React.ComponentProps<typeof DayButton>) {
|
|
188
|
+
const defaultClassNames = getDefaultClassNames()
|
|
189
|
+
|
|
190
|
+
const ref = React.useRef<HTMLButtonElement>(null)
|
|
191
|
+
React.useEffect(() => {
|
|
192
|
+
if (modifiers.focused) ref.current?.focus()
|
|
193
|
+
}, [modifiers.focused])
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<Button
|
|
197
|
+
ref={ref}
|
|
198
|
+
variant="ghost"
|
|
199
|
+
size="small"
|
|
200
|
+
data-day={day.date.toLocaleDateString()}
|
|
201
|
+
data-selected-single={
|
|
202
|
+
modifiers.selected &&
|
|
203
|
+
!modifiers.range_start &&
|
|
204
|
+
!modifiers.range_end &&
|
|
205
|
+
!modifiers.range_middle
|
|
206
|
+
}
|
|
207
|
+
data-range-start={modifiers.range_start}
|
|
208
|
+
data-range-end={modifiers.range_end}
|
|
209
|
+
data-range-middle={modifiers.range_middle}
|
|
210
|
+
className={cn(
|
|
211
|
+
"size-8 p-0 font-normal",
|
|
212
|
+
"data-[selected-single=true]:bg-main-900 data-[selected-single=true]:text-white",
|
|
213
|
+
"data-[range-middle=true]:bg-main-100 data-[range-middle=true]:text-main-900",
|
|
214
|
+
"data-[range-start=true]:bg-main-900 data-[range-start=true]:text-white",
|
|
215
|
+
"data-[range-end=true]:bg-main-900 data-[range-end=true]:text-white",
|
|
216
|
+
"group-data-[focused=true]/day:border-grey-400 group-data-[focused=true]/day:ring-grey-300/50",
|
|
217
|
+
"hover:bg-main-100 hover:text-main-900",
|
|
218
|
+
"group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px]",
|
|
219
|
+
"data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md",
|
|
220
|
+
"data-[range-middle=true]:rounded-none",
|
|
221
|
+
"data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md",
|
|
222
|
+
defaultClassNames.day,
|
|
223
|
+
className
|
|
224
|
+
)}
|
|
225
|
+
{...props}
|
|
226
|
+
/>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
Calendar.displayName = "Calendar"
|
|
231
|
+
|
|
232
|
+
export { Calendar, CalendarDayButton }
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
+
|
|
3
|
+
import { Button } from "../Button/Button"
|
|
4
|
+
import { Input } from "../Input/Input"
|
|
5
|
+
import { Label } from "../Label/Label"
|
|
6
|
+
import { Flex } from "../Flex/Flex"
|
|
7
|
+
import { Typography } from "../Typography/Typography"
|
|
8
|
+
import { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from "./Card"
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof Card> = {
|
|
11
|
+
title: "Components/Card",
|
|
12
|
+
component: Card,
|
|
13
|
+
parameters: {
|
|
14
|
+
layout: "centered",
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
variant: {
|
|
18
|
+
control: "select",
|
|
19
|
+
options: ["default", "outline"],
|
|
20
|
+
description: "The visual variant of the card",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
tags: ["autodocs"],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default meta
|
|
27
|
+
type Story = StoryObj<typeof meta>
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<Card className="w-[350px]">
|
|
32
|
+
<CardHeader>
|
|
33
|
+
<CardTitle>Card Title</CardTitle>
|
|
34
|
+
<CardDescription>Card Description</CardDescription>
|
|
35
|
+
</CardHeader>
|
|
36
|
+
<CardContent>
|
|
37
|
+
<p>Card Content</p>
|
|
38
|
+
</CardContent>
|
|
39
|
+
<CardFooter>
|
|
40
|
+
<p>Card Footer</p>
|
|
41
|
+
</CardFooter>
|
|
42
|
+
</Card>
|
|
43
|
+
),
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Outline: Story = {
|
|
47
|
+
render: () => (
|
|
48
|
+
<Card variant="outline" className="w-[350px]">
|
|
49
|
+
<CardHeader>
|
|
50
|
+
<CardTitle>Outline Card</CardTitle>
|
|
51
|
+
<CardDescription>This card has no shadow</CardDescription>
|
|
52
|
+
</CardHeader>
|
|
53
|
+
<CardContent>
|
|
54
|
+
<p>Card content goes here.</p>
|
|
55
|
+
</CardContent>
|
|
56
|
+
</Card>
|
|
57
|
+
),
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const WithForm: Story = {
|
|
61
|
+
render: () => (
|
|
62
|
+
<Card className="w-[350px]">
|
|
63
|
+
<CardHeader>
|
|
64
|
+
<CardTitle>Create project</CardTitle>
|
|
65
|
+
<CardDescription>Deploy your new project in one-click.</CardDescription>
|
|
66
|
+
</CardHeader>
|
|
67
|
+
<CardContent>
|
|
68
|
+
<form>
|
|
69
|
+
<Flex direction="column" gap={4}>
|
|
70
|
+
<Flex direction="column" gap={2}>
|
|
71
|
+
<Label htmlFor="name">Name</Label>
|
|
72
|
+
<Input id="name" placeholder="Name of your project" />
|
|
73
|
+
</Flex>
|
|
74
|
+
<Flex direction="column" gap={2}>
|
|
75
|
+
<Label htmlFor="framework">Framework</Label>
|
|
76
|
+
<Input id="framework" placeholder="Select a framework" />
|
|
77
|
+
</Flex>
|
|
78
|
+
</Flex>
|
|
79
|
+
</form>
|
|
80
|
+
</CardContent>
|
|
81
|
+
<CardFooter className="flex justify-between">
|
|
82
|
+
<Button variant="outline">Cancel</Button>
|
|
83
|
+
<Button>Deploy</Button>
|
|
84
|
+
</CardFooter>
|
|
85
|
+
</Card>
|
|
86
|
+
),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const SimpleCard: Story = {
|
|
90
|
+
render: () => (
|
|
91
|
+
<Card className="w-[350px] p-6">
|
|
92
|
+
<Flex direction="column" gap={2}>
|
|
93
|
+
<Typography variant="h4">Notifications</Typography>
|
|
94
|
+
<Typography variant="body2" color="grey-500">
|
|
95
|
+
You have 3 unread messages.
|
|
96
|
+
</Typography>
|
|
97
|
+
</Flex>
|
|
98
|
+
</Card>
|
|
99
|
+
),
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const AllVariants: Story = {
|
|
103
|
+
render: () => (
|
|
104
|
+
<Flex direction="column" gap={6}>
|
|
105
|
+
<Typography variant="h4" className="text-white">Card Variants</Typography>
|
|
106
|
+
|
|
107
|
+
<Flex gap={4} wrap="wrap">
|
|
108
|
+
<Card className="w-[300px]">
|
|
109
|
+
<CardHeader>
|
|
110
|
+
<CardTitle>Default Card</CardTitle>
|
|
111
|
+
<CardDescription>With shadow</CardDescription>
|
|
112
|
+
</CardHeader>
|
|
113
|
+
<CardContent>
|
|
114
|
+
<p>This is the default card style with a subtle shadow.</p>
|
|
115
|
+
</CardContent>
|
|
116
|
+
<CardFooter>
|
|
117
|
+
<Button size="small">Action</Button>
|
|
118
|
+
</CardFooter>
|
|
119
|
+
</Card>
|
|
120
|
+
|
|
121
|
+
<Card variant="outline" className="w-[300px]">
|
|
122
|
+
<CardHeader>
|
|
123
|
+
<CardTitle>Outline Card</CardTitle>
|
|
124
|
+
<CardDescription>Without shadow</CardDescription>
|
|
125
|
+
</CardHeader>
|
|
126
|
+
<CardContent>
|
|
127
|
+
<p>This card has an outline border but no shadow.</p>
|
|
128
|
+
</CardContent>
|
|
129
|
+
<CardFooter>
|
|
130
|
+
<Button size="small" variant="outline">Action</Button>
|
|
131
|
+
</CardFooter>
|
|
132
|
+
</Card>
|
|
133
|
+
</Flex>
|
|
134
|
+
</Flex>
|
|
135
|
+
),
|
|
136
|
+
}
|