@voila.dev/ui 1.1.9
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/package.json +78 -0
- package/src/components/ui/accordion.tsx +79 -0
- package/src/components/ui/alert-dialog.tsx +198 -0
- package/src/components/ui/alert.tsx +105 -0
- package/src/components/ui/aspect-ratio.tsx +30 -0
- package/src/components/ui/avatar.tsx +125 -0
- package/src/components/ui/badge-variants.ts +166 -0
- package/src/components/ui/badge.tsx +45 -0
- package/src/components/ui/banner.tsx +84 -0
- package/src/components/ui/breadcrumb.tsx +127 -0
- package/src/components/ui/button-group.tsx +99 -0
- package/src/components/ui/button-variants.ts +108 -0
- package/src/components/ui/button.tsx +54 -0
- package/src/components/ui/calendar.tsx +266 -0
- package/src/components/ui/card.tsx +155 -0
- package/src/components/ui/carousel.tsx +319 -0
- package/src/components/ui/chat.tsx +896 -0
- package/src/components/ui/checkbox-group.tsx +44 -0
- package/src/components/ui/checkbox.tsx +34 -0
- package/src/components/ui/chip.tsx +60 -0
- package/src/components/ui/collapsible.tsx +44 -0
- package/src/components/ui/color-picker.tsx +191 -0
- package/src/components/ui/combobox.tsx +317 -0
- package/src/components/ui/command.tsx +187 -0
- package/src/components/ui/confirm-dialog.tsx +125 -0
- package/src/components/ui/context-menu.tsx +254 -0
- package/src/components/ui/copyable-text.tsx +65 -0
- package/src/components/ui/date-picker.tsx +316 -0
- package/src/components/ui/date-time-picker.tsx +1071 -0
- package/src/components/ui/dialog.tsx +176 -0
- package/src/components/ui/direction.tsx +15 -0
- package/src/components/ui/drawer.tsx +178 -0
- package/src/components/ui/dropdown-menu.tsx +247 -0
- package/src/components/ui/empty.tsx +131 -0
- package/src/components/ui/field.tsx +257 -0
- package/src/components/ui/formatted-input.tsx +219 -0
- package/src/components/ui/gallery.tsx +161 -0
- package/src/components/ui/hover-card.tsx +77 -0
- package/src/components/ui/icon-picker.tsx +193 -0
- package/src/components/ui/image-cropper.tsx +787 -0
- package/src/components/ui/image-upload-field.tsx +344 -0
- package/src/components/ui/input-group.tsx +175 -0
- package/src/components/ui/input-otp.tsx +83 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/item.tsx +212 -0
- package/src/components/ui/kbd.tsx +62 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/list.tsx +46 -0
- package/src/components/ui/menu-variants.ts +71 -0
- package/src/components/ui/menubar.tsx +226 -0
- package/src/components/ui/money-input.tsx +96 -0
- package/src/components/ui/native-date-picker.tsx +120 -0
- package/src/components/ui/native-select.tsx +74 -0
- package/src/components/ui/navigation-menu.tsx +183 -0
- package/src/components/ui/pagination.tsx +150 -0
- package/src/components/ui/popover.tsx +104 -0
- package/src/components/ui/profile-header.tsx +196 -0
- package/src/components/ui/progress.tsx +71 -0
- package/src/components/ui/radio-group.tsx +115 -0
- package/src/components/ui/rating.tsx +200 -0
- package/src/components/ui/resizable.tsx +61 -0
- package/src/components/ui/responsive-dialog.tsx +278 -0
- package/src/components/ui/responsive-select.tsx +289 -0
- package/src/components/ui/responsive-sheet.tsx +225 -0
- package/src/components/ui/scroll-area.tsx +51 -0
- package/src/components/ui/section.tsx +106 -0
- package/src/components/ui/segmented-control.tsx +148 -0
- package/src/components/ui/select.tsx +216 -0
- package/src/components/ui/separator.tsx +69 -0
- package/src/components/ui/sheet.tsx +154 -0
- package/src/components/ui/shortcut.tsx +41 -0
- package/src/components/ui/sidebar.tsx +739 -0
- package/src/components/ui/skeleton.tsx +23 -0
- package/src/components/ui/slider.tsx +74 -0
- package/src/components/ui/sonner.tsx +64 -0
- package/src/components/ui/spinner.tsx +19 -0
- package/src/components/ui/stat-card.tsx +138 -0
- package/src/components/ui/stepper.tsx +181 -0
- package/src/components/ui/sticky-action-bar.tsx +42 -0
- package/src/components/ui/switch.tsx +30 -0
- package/src/components/ui/table.tsx +132 -0
- package/src/components/ui/tabs.tsx +77 -0
- package/src/components/ui/textarea.tsx +24 -0
- package/src/components/ui/time-picker.tsx +221 -0
- package/src/components/ui/toggle-group.tsx +86 -0
- package/src/components/ui/toggle.tsx +43 -0
- package/src/components/ui/tooltip.tsx +79 -0
- package/src/components/ui/translation-input.tsx +126 -0
- package/src/components/ui/user-avatar.tsx +74 -0
- package/src/css-modules.d.ts +4 -0
- package/src/hooks/use-command-palette.ts +28 -0
- package/src/hooks/use-mobile.ts +21 -0
- package/src/hooks/use-pagination.ts +81 -0
- package/src/hooks/use-picker-state.ts +44 -0
- package/src/lib/cva.ts +18 -0
- package/src/lib/time-math.ts +62 -0
- package/src/lib/utils.ts +14 -0
- package/src/styles/globals.css +36 -0
- package/src/styles.css +10 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CaretDownIcon,
|
|
3
|
+
CaretLeftIcon,
|
|
4
|
+
CaretRightIcon,
|
|
5
|
+
} from "@phosphor-icons/react";
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import {
|
|
8
|
+
type DayButton,
|
|
9
|
+
DayPicker,
|
|
10
|
+
getDefaultClassNames,
|
|
11
|
+
} from "react-day-picker";
|
|
12
|
+
import { Button, buttonVariants } from "#/components/ui/button.tsx";
|
|
13
|
+
import { cn } from "#/lib/utils.ts";
|
|
14
|
+
|
|
15
|
+
// DayPicker's props are a union over `mode` (single | range | multiple); omitting a
|
|
16
|
+
// key must distribute so each member keeps its own `selected`/`onSelect` shape.
|
|
17
|
+
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
18
|
+
? Omit<T, K>
|
|
19
|
+
: never;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* First day of the week for a BCP-47 locale (react-day-picker's `weekStartsOn`,
|
|
23
|
+
* 0 = Sunday), read from the native `Intl.Locale` week info: `en-US` → Sunday,
|
|
24
|
+
* `fr-FR` → Monday. Returns undefined (react-day-picker's default) when the
|
|
25
|
+
* runtime lacks the API or the locale is omitted.
|
|
26
|
+
*/
|
|
27
|
+
function weekStartFromLocale(
|
|
28
|
+
locale: string | undefined,
|
|
29
|
+
): 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined {
|
|
30
|
+
if (!locale) return undefined;
|
|
31
|
+
try {
|
|
32
|
+
const intlLocale = new Intl.Locale(locale) as Intl.Locale & {
|
|
33
|
+
getWeekInfo?: () => { firstDay: number };
|
|
34
|
+
weekInfo?: { firstDay: number };
|
|
35
|
+
};
|
|
36
|
+
const info = intlLocale.getWeekInfo?.() ?? intlLocale.weekInfo;
|
|
37
|
+
// Intl reports 1 = Monday … 7 = Sunday; map Sunday (7) to 0 for the picker.
|
|
38
|
+
if (info) return (info.firstDay % 7) as 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
39
|
+
} catch {
|
|
40
|
+
// Older runtimes lack Intl week info; fall back to the picker default.
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function Calendar({
|
|
46
|
+
className,
|
|
47
|
+
classNames,
|
|
48
|
+
showOutsideDays = true,
|
|
49
|
+
captionLayout = "label",
|
|
50
|
+
navButtonVariant = "ghost",
|
|
51
|
+
locale,
|
|
52
|
+
weekStartsOn,
|
|
53
|
+
formatters,
|
|
54
|
+
components,
|
|
55
|
+
...props
|
|
56
|
+
}: DistributiveOmit<React.ComponentProps<typeof DayPicker>, "locale"> & {
|
|
57
|
+
navButtonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
58
|
+
/** BCP-47 locale (e.g. "fr-FR") applied to the month, weekday, and day labels. */
|
|
59
|
+
locale?: string;
|
|
60
|
+
}) {
|
|
61
|
+
const defaultClassNames = getDefaultClassNames();
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<DayPicker
|
|
65
|
+
showOutsideDays={showOutsideDays}
|
|
66
|
+
className={cn(
|
|
67
|
+
"group/calendar bg-background p-2 [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
|
|
68
|
+
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
69
|
+
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
70
|
+
className,
|
|
71
|
+
)}
|
|
72
|
+
captionLayout={captionLayout}
|
|
73
|
+
weekStartsOn={weekStartsOn ?? weekStartFromLocale(locale)}
|
|
74
|
+
formatters={{
|
|
75
|
+
// Localize every visible label through the native Intl formatters so the
|
|
76
|
+
// calendar carries no date-fns locale object.
|
|
77
|
+
formatCaption: (date) =>
|
|
78
|
+
new Intl.DateTimeFormat(locale, {
|
|
79
|
+
month: "long",
|
|
80
|
+
year: "numeric",
|
|
81
|
+
}).format(date),
|
|
82
|
+
formatMonthDropdown: (date) =>
|
|
83
|
+
new Intl.DateTimeFormat(locale, { month: "short" }).format(date),
|
|
84
|
+
formatYearDropdown: (date) =>
|
|
85
|
+
new Intl.DateTimeFormat(locale, { year: "numeric" }).format(date),
|
|
86
|
+
formatWeekdayName: (date) =>
|
|
87
|
+
new Intl.DateTimeFormat(locale, { weekday: "short" }).format(date),
|
|
88
|
+
...formatters,
|
|
89
|
+
}}
|
|
90
|
+
classNames={{
|
|
91
|
+
root: cn("w-fit", defaultClassNames.root),
|
|
92
|
+
months: cn(
|
|
93
|
+
"relative flex flex-col gap-4 md:flex-row",
|
|
94
|
+
defaultClassNames.months,
|
|
95
|
+
),
|
|
96
|
+
month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
|
|
97
|
+
nav: cn(
|
|
98
|
+
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
99
|
+
defaultClassNames.nav,
|
|
100
|
+
),
|
|
101
|
+
button_previous: cn(
|
|
102
|
+
buttonVariants({ variant: navButtonVariant }),
|
|
103
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
104
|
+
defaultClassNames.button_previous,
|
|
105
|
+
),
|
|
106
|
+
button_next: cn(
|
|
107
|
+
buttonVariants({ variant: navButtonVariant }),
|
|
108
|
+
"size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
|
|
109
|
+
defaultClassNames.button_next,
|
|
110
|
+
),
|
|
111
|
+
month_caption: cn(
|
|
112
|
+
"flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
|
|
113
|
+
defaultClassNames.month_caption,
|
|
114
|
+
),
|
|
115
|
+
dropdowns: cn(
|
|
116
|
+
"flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
|
|
117
|
+
defaultClassNames.dropdowns,
|
|
118
|
+
),
|
|
119
|
+
dropdown_root: cn(
|
|
120
|
+
"relative rounded-(--cell-radius)",
|
|
121
|
+
defaultClassNames.dropdown_root,
|
|
122
|
+
),
|
|
123
|
+
dropdown: cn(
|
|
124
|
+
"absolute inset-0 bg-popover opacity-0",
|
|
125
|
+
defaultClassNames.dropdown,
|
|
126
|
+
),
|
|
127
|
+
caption_label: cn(
|
|
128
|
+
"font-medium select-none",
|
|
129
|
+
captionLayout === "label"
|
|
130
|
+
? "text-sm"
|
|
131
|
+
: "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
|
|
132
|
+
defaultClassNames.caption_label,
|
|
133
|
+
),
|
|
134
|
+
month_grid: cn("w-full border-collapse", defaultClassNames.month_grid),
|
|
135
|
+
weekdays: cn("flex", defaultClassNames.weekdays),
|
|
136
|
+
// text-[0.8rem]: shared with Button `sm` (button-variants.ts); keep in sync.
|
|
137
|
+
weekday: cn(
|
|
138
|
+
"flex-1 rounded-(--cell-radius) text-[0.8rem] font-normal text-muted-foreground select-none",
|
|
139
|
+
defaultClassNames.weekday,
|
|
140
|
+
),
|
|
141
|
+
week: cn("mt-2 flex w-full", defaultClassNames.week),
|
|
142
|
+
week_number_header: cn(
|
|
143
|
+
"w-(--cell-size) select-none",
|
|
144
|
+
defaultClassNames.week_number_header,
|
|
145
|
+
),
|
|
146
|
+
week_number: cn(
|
|
147
|
+
"text-[0.8rem] text-muted-foreground select-none",
|
|
148
|
+
defaultClassNames.week_number,
|
|
149
|
+
),
|
|
150
|
+
day: cn(
|
|
151
|
+
"group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
|
|
152
|
+
props.showWeekNumber
|
|
153
|
+
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)"
|
|
154
|
+
: "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
|
|
155
|
+
defaultClassNames.day,
|
|
156
|
+
),
|
|
157
|
+
range_start: cn(
|
|
158
|
+
"relative isolate z-0 rounded-l-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:right-0 after:w-4 after:bg-muted",
|
|
159
|
+
defaultClassNames.range_start,
|
|
160
|
+
),
|
|
161
|
+
range_middle: cn("rounded-none", defaultClassNames.range_middle),
|
|
162
|
+
range_end: cn(
|
|
163
|
+
"relative isolate z-0 rounded-r-(--cell-radius) bg-muted after:absolute after:inset-y-0 after:left-0 after:w-4 after:bg-muted",
|
|
164
|
+
defaultClassNames.range_end,
|
|
165
|
+
),
|
|
166
|
+
today: cn(
|
|
167
|
+
"rounded-(--cell-radius) bg-muted text-foreground data-[selected=true]:rounded-none",
|
|
168
|
+
defaultClassNames.today,
|
|
169
|
+
),
|
|
170
|
+
outside: cn(
|
|
171
|
+
"text-muted-foreground aria-selected:text-muted-foreground",
|
|
172
|
+
defaultClassNames.outside,
|
|
173
|
+
),
|
|
174
|
+
disabled: cn(
|
|
175
|
+
"text-muted-foreground opacity-50",
|
|
176
|
+
defaultClassNames.disabled,
|
|
177
|
+
),
|
|
178
|
+
hidden: cn("invisible", defaultClassNames.hidden),
|
|
179
|
+
...classNames,
|
|
180
|
+
}}
|
|
181
|
+
components={{
|
|
182
|
+
Root: ({ className, rootRef, ...props }) => {
|
|
183
|
+
return (
|
|
184
|
+
<div
|
|
185
|
+
data-slot="calendar"
|
|
186
|
+
ref={rootRef}
|
|
187
|
+
className={className}
|
|
188
|
+
{...props}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
Chevron: ({ className, orientation, ...props }) => {
|
|
193
|
+
if (orientation === "left") {
|
|
194
|
+
return (
|
|
195
|
+
<CaretLeftIcon className={cn("size-4", className)} {...props} />
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (orientation === "right") {
|
|
200
|
+
return (
|
|
201
|
+
<CaretRightIcon className={cn("size-4", className)} {...props} />
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<CaretDownIcon className={cn("size-4", className)} {...props} />
|
|
207
|
+
);
|
|
208
|
+
},
|
|
209
|
+
DayButton: ({ ...props }) => (
|
|
210
|
+
<CalendarDayButton locale={locale} {...props} />
|
|
211
|
+
),
|
|
212
|
+
WeekNumber: ({ children, ...props }) => {
|
|
213
|
+
return (
|
|
214
|
+
<td {...props}>
|
|
215
|
+
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
|
216
|
+
{children}
|
|
217
|
+
</div>
|
|
218
|
+
</td>
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
...components,
|
|
222
|
+
}}
|
|
223
|
+
{...props}
|
|
224
|
+
/>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function CalendarDayButton({
|
|
229
|
+
className,
|
|
230
|
+
day,
|
|
231
|
+
modifiers,
|
|
232
|
+
locale,
|
|
233
|
+
...props
|
|
234
|
+
}: React.ComponentProps<typeof DayButton> & { locale?: string }) {
|
|
235
|
+
const defaultClassNames = getDefaultClassNames();
|
|
236
|
+
|
|
237
|
+
const ref = React.useRef<HTMLButtonElement>(null);
|
|
238
|
+
React.useEffect(() => {
|
|
239
|
+
if (modifiers.focused) ref.current?.focus();
|
|
240
|
+
}, [modifiers.focused]);
|
|
241
|
+
|
|
242
|
+
return (
|
|
243
|
+
<Button
|
|
244
|
+
variant="ghost"
|
|
245
|
+
size="icon"
|
|
246
|
+
data-day={day.date.toLocaleDateString(locale)}
|
|
247
|
+
data-selected-single={
|
|
248
|
+
modifiers.selected &&
|
|
249
|
+
!modifiers.range_start &&
|
|
250
|
+
!modifiers.range_end &&
|
|
251
|
+
!modifiers.range_middle
|
|
252
|
+
}
|
|
253
|
+
data-range-start={modifiers.range_start}
|
|
254
|
+
data-range-end={modifiers.range_end}
|
|
255
|
+
data-range-middle={modifiers.range_middle}
|
|
256
|
+
className={cn(
|
|
257
|
+
"relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-3 group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) 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-foreground [&>span]:text-xs [&>span]:opacity-70",
|
|
258
|
+
defaultClassNames.day,
|
|
259
|
+
className,
|
|
260
|
+
)}
|
|
261
|
+
{...props}
|
|
262
|
+
/>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export { Calendar, CalendarDayButton };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
|
|
4
|
+
import { cn } from "#/lib/utils.ts";
|
|
5
|
+
|
|
6
|
+
type CardSize = "default" | "sm";
|
|
7
|
+
|
|
8
|
+
function Card({
|
|
9
|
+
className,
|
|
10
|
+
size = "default",
|
|
11
|
+
render,
|
|
12
|
+
...props
|
|
13
|
+
}: useRender.ComponentProps<"div"> & { size?: CardSize }) {
|
|
14
|
+
return useRender({
|
|
15
|
+
defaultTagName: "div",
|
|
16
|
+
props: mergeProps<"div">(
|
|
17
|
+
{
|
|
18
|
+
className: cn(
|
|
19
|
+
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
|
20
|
+
className,
|
|
21
|
+
),
|
|
22
|
+
},
|
|
23
|
+
props,
|
|
24
|
+
),
|
|
25
|
+
render,
|
|
26
|
+
state: { slot: "card", size },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function CardHeader({
|
|
31
|
+
className,
|
|
32
|
+
render,
|
|
33
|
+
...props
|
|
34
|
+
}: useRender.ComponentProps<"div">) {
|
|
35
|
+
return useRender({
|
|
36
|
+
defaultTagName: "div",
|
|
37
|
+
props: mergeProps<"div">(
|
|
38
|
+
{
|
|
39
|
+
className: cn(
|
|
40
|
+
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
|
|
41
|
+
className,
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
props,
|
|
45
|
+
),
|
|
46
|
+
render,
|
|
47
|
+
state: { slot: "card-header" },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function CardTitle({
|
|
52
|
+
className,
|
|
53
|
+
render,
|
|
54
|
+
...props
|
|
55
|
+
}: useRender.ComponentProps<"div">) {
|
|
56
|
+
return useRender({
|
|
57
|
+
defaultTagName: "div",
|
|
58
|
+
props: mergeProps<"div">(
|
|
59
|
+
{
|
|
60
|
+
className: cn(
|
|
61
|
+
"text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
|
|
62
|
+
className,
|
|
63
|
+
),
|
|
64
|
+
},
|
|
65
|
+
props,
|
|
66
|
+
),
|
|
67
|
+
render,
|
|
68
|
+
state: { slot: "card-title" },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function CardDescription({
|
|
73
|
+
className,
|
|
74
|
+
render,
|
|
75
|
+
...props
|
|
76
|
+
}: useRender.ComponentProps<"div">) {
|
|
77
|
+
return useRender({
|
|
78
|
+
defaultTagName: "div",
|
|
79
|
+
props: mergeProps<"div">(
|
|
80
|
+
{ className: cn("text-sm text-muted-foreground", className) },
|
|
81
|
+
props,
|
|
82
|
+
),
|
|
83
|
+
render,
|
|
84
|
+
state: { slot: "card-description" },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function CardAction({
|
|
89
|
+
className,
|
|
90
|
+
render,
|
|
91
|
+
...props
|
|
92
|
+
}: useRender.ComponentProps<"div">) {
|
|
93
|
+
return useRender({
|
|
94
|
+
defaultTagName: "div",
|
|
95
|
+
props: mergeProps<"div">(
|
|
96
|
+
{
|
|
97
|
+
className: cn(
|
|
98
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
99
|
+
className,
|
|
100
|
+
),
|
|
101
|
+
},
|
|
102
|
+
props,
|
|
103
|
+
),
|
|
104
|
+
render,
|
|
105
|
+
state: { slot: "card-action" },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function CardContent({
|
|
110
|
+
className,
|
|
111
|
+
render,
|
|
112
|
+
...props
|
|
113
|
+
}: useRender.ComponentProps<"div">) {
|
|
114
|
+
return useRender({
|
|
115
|
+
defaultTagName: "div",
|
|
116
|
+
props: mergeProps<"div">(
|
|
117
|
+
{ className: cn("px-4 group-data-[size=sm]/card:px-3", className) },
|
|
118
|
+
props,
|
|
119
|
+
),
|
|
120
|
+
render,
|
|
121
|
+
state: { slot: "card-content" },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function CardFooter({
|
|
126
|
+
className,
|
|
127
|
+
render,
|
|
128
|
+
...props
|
|
129
|
+
}: useRender.ComponentProps<"div">) {
|
|
130
|
+
return useRender({
|
|
131
|
+
defaultTagName: "div",
|
|
132
|
+
props: mergeProps<"div">(
|
|
133
|
+
{
|
|
134
|
+
className: cn(
|
|
135
|
+
"flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
|
|
136
|
+
className,
|
|
137
|
+
),
|
|
138
|
+
},
|
|
139
|
+
props,
|
|
140
|
+
),
|
|
141
|
+
render,
|
|
142
|
+
state: { slot: "card-footer" },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export {
|
|
147
|
+
Card,
|
|
148
|
+
CardAction,
|
|
149
|
+
CardContent,
|
|
150
|
+
CardDescription,
|
|
151
|
+
CardFooter,
|
|
152
|
+
CardHeader,
|
|
153
|
+
type CardSize,
|
|
154
|
+
CardTitle,
|
|
155
|
+
};
|