@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
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voila.dev/ui",
|
|
3
|
+
"version": "1.1.9",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "85 components, one convention. The floor everything else stands on.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://ui.voila.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/voila-voila-dev/ui.git",
|
|
11
|
+
"directory": "packages/ui"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"react",
|
|
15
|
+
"ui",
|
|
16
|
+
"components",
|
|
17
|
+
"tailwindcss",
|
|
18
|
+
"base-ui",
|
|
19
|
+
"design-system"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"src",
|
|
26
|
+
"!src/**/*.test.ts",
|
|
27
|
+
"!src/**/*.test.tsx",
|
|
28
|
+
"!src/**/*.stories.ts",
|
|
29
|
+
"!src/**/*.stories.tsx"
|
|
30
|
+
],
|
|
31
|
+
"sideEffects": [
|
|
32
|
+
"**/*.css"
|
|
33
|
+
],
|
|
34
|
+
"exports": {
|
|
35
|
+
"./styles.css": "./src/styles.css",
|
|
36
|
+
"./styles/globals.css": "./src/styles/globals.css",
|
|
37
|
+
"./lib/utils": "./src/lib/utils.ts",
|
|
38
|
+
"./lib/time-math": "./src/lib/time-math.ts",
|
|
39
|
+
"./cva": "./src/lib/cva.ts",
|
|
40
|
+
"./badge-variants": "./src/components/ui/badge-variants.ts",
|
|
41
|
+
"./button-variants": "./src/components/ui/button-variants.ts",
|
|
42
|
+
"./menu-variants": "./src/components/ui/menu-variants.ts",
|
|
43
|
+
"./components/*": "./src/components/ui/*.tsx",
|
|
44
|
+
"./hooks/*": "./src/hooks/*.ts"
|
|
45
|
+
},
|
|
46
|
+
"imports": {
|
|
47
|
+
"#/*": "./src/*"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"check": "biome check",
|
|
51
|
+
"check-types": "tsc --noEmit",
|
|
52
|
+
"format": "biome format",
|
|
53
|
+
"lint": "biome lint",
|
|
54
|
+
"test": "vitest run"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@base-ui/react": "^1.4.1",
|
|
58
|
+
"@phosphor-icons/react": "2.1.10",
|
|
59
|
+
"@voila.dev/ui-icon": "0.0.0",
|
|
60
|
+
"@voila.dev/ui-tokens": "0.0.0",
|
|
61
|
+
"clsx": "^2.1.1",
|
|
62
|
+
"cmdk": "^1.1.1",
|
|
63
|
+
"cva": "^1.0.0-beta.4",
|
|
64
|
+
"embla-carousel-react": "^8.6.0",
|
|
65
|
+
"input-otp": "^1.4.2",
|
|
66
|
+
"react-day-picker": "^10.0.1",
|
|
67
|
+
"react-resizable-panels": "^4.11.1",
|
|
68
|
+
"sonner": "^2.0.7",
|
|
69
|
+
"tailwind-merge": "^3.3.1",
|
|
70
|
+
"tw-animate-css": "^1.4.0",
|
|
71
|
+
"vaul": "^1.1.2"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"react": "^19.0.0",
|
|
75
|
+
"react-dom": "^19.0.0",
|
|
76
|
+
"tailwindcss": "^4.0.0"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
|
2
|
+
import { CaretDownIcon } from "@phosphor-icons/react";
|
|
3
|
+
import { cn, proseLinkClassName } from "#/lib/utils.ts";
|
|
4
|
+
|
|
5
|
+
function Accordion({
|
|
6
|
+
className,
|
|
7
|
+
// Deliberate kit default: one item open at a time. Pass `multiple` to opt out.
|
|
8
|
+
multiple = false,
|
|
9
|
+
...props
|
|
10
|
+
}: AccordionPrimitive.Root.Props) {
|
|
11
|
+
return (
|
|
12
|
+
<AccordionPrimitive.Root
|
|
13
|
+
data-slot="accordion"
|
|
14
|
+
className={cn("flex w-full flex-col", className)}
|
|
15
|
+
multiple={multiple}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
|
|
22
|
+
return (
|
|
23
|
+
<AccordionPrimitive.Item
|
|
24
|
+
data-slot="accordion-item"
|
|
25
|
+
className={cn("not-last:border-b", className)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AccordionTrigger({
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
34
|
+
...props
|
|
35
|
+
}: AccordionPrimitive.Trigger.Props) {
|
|
36
|
+
return (
|
|
37
|
+
<AccordionPrimitive.Header className="flex">
|
|
38
|
+
<AccordionPrimitive.Trigger
|
|
39
|
+
data-slot="accordion-trigger"
|
|
40
|
+
className={cn(
|
|
41
|
+
"group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
<CaretDownIcon
|
|
48
|
+
data-slot="accordion-trigger-icon"
|
|
49
|
+
className="pointer-events-none shrink-0 transition-transform duration-200 group-aria-expanded/accordion-trigger:rotate-180 motion-reduce:transition-none"
|
|
50
|
+
/>
|
|
51
|
+
</AccordionPrimitive.Trigger>
|
|
52
|
+
</AccordionPrimitive.Header>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function AccordionContent({
|
|
57
|
+
className,
|
|
58
|
+
children,
|
|
59
|
+
...props
|
|
60
|
+
}: AccordionPrimitive.Panel.Props) {
|
|
61
|
+
return (
|
|
62
|
+
<AccordionPrimitive.Panel
|
|
63
|
+
data-slot="accordion-content"
|
|
64
|
+
className={cn(
|
|
65
|
+
"h-(--accordion-panel-height) overflow-hidden text-sm transition-[height] duration-200 ease-out data-ending-style:h-0 data-starting-style:h-0 motion-reduce:transition-none",
|
|
66
|
+
className,
|
|
67
|
+
)}
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
<div
|
|
71
|
+
className={cn("pb-2.5 [&_p:not(:last-child)]:mb-4", proseLinkClassName)}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</div>
|
|
75
|
+
</AccordionPrimitive.Panel>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
import { Button } from "#/components/ui/button.tsx";
|
|
4
|
+
import { cn } from "#/lib/utils.ts";
|
|
5
|
+
|
|
6
|
+
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
|
|
7
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
|
|
11
|
+
return (
|
|
12
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
|
|
17
|
+
return (
|
|
18
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function AlertDialogClose({ ...props }: AlertDialogPrimitive.Close.Props) {
|
|
23
|
+
return (
|
|
24
|
+
<AlertDialogPrimitive.Close data-slot="alert-dialog-close" {...props} />
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function AlertDialogOverlay({
|
|
29
|
+
className,
|
|
30
|
+
...props
|
|
31
|
+
}: AlertDialogPrimitive.Backdrop.Props) {
|
|
32
|
+
return (
|
|
33
|
+
<AlertDialogPrimitive.Backdrop
|
|
34
|
+
data-slot="alert-dialog-overlay"
|
|
35
|
+
className={cn(
|
|
36
|
+
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 motion-reduce:animate-none",
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type AlertDialogContentSize = "default" | "sm";
|
|
45
|
+
|
|
46
|
+
function AlertDialogContent({
|
|
47
|
+
className,
|
|
48
|
+
size = "default",
|
|
49
|
+
...props
|
|
50
|
+
}: AlertDialogPrimitive.Popup.Props & {
|
|
51
|
+
size?: AlertDialogContentSize;
|
|
52
|
+
}) {
|
|
53
|
+
return (
|
|
54
|
+
<AlertDialogPortal>
|
|
55
|
+
<AlertDialogOverlay />
|
|
56
|
+
<AlertDialogPrimitive.Popup
|
|
57
|
+
data-slot="alert-dialog-content"
|
|
58
|
+
data-size={size}
|
|
59
|
+
className={cn(
|
|
60
|
+
"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full max-w-xs -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 motion-reduce:animate-none",
|
|
61
|
+
className,
|
|
62
|
+
)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
</AlertDialogPortal>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function AlertDialogHeader({
|
|
70
|
+
className,
|
|
71
|
+
...props
|
|
72
|
+
}: React.ComponentProps<"div">) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="alert-dialog-header"
|
|
76
|
+
className={cn(
|
|
77
|
+
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function AlertDialogFooter({
|
|
86
|
+
className,
|
|
87
|
+
...props
|
|
88
|
+
}: React.ComponentProps<"div">) {
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
data-slot="alert-dialog-footer"
|
|
92
|
+
className={cn(
|
|
93
|
+
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
|
|
94
|
+
className,
|
|
95
|
+
)}
|
|
96
|
+
{...props}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function AlertDialogMedia({
|
|
102
|
+
className,
|
|
103
|
+
...props
|
|
104
|
+
}: React.ComponentProps<"div">) {
|
|
105
|
+
return (
|
|
106
|
+
<div
|
|
107
|
+
data-slot="alert-dialog-media"
|
|
108
|
+
className={cn(
|
|
109
|
+
"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
|
|
110
|
+
className,
|
|
111
|
+
)}
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function AlertDialogTitle({
|
|
118
|
+
className,
|
|
119
|
+
...props
|
|
120
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
121
|
+
return (
|
|
122
|
+
<AlertDialogPrimitive.Title
|
|
123
|
+
data-slot="alert-dialog-title"
|
|
124
|
+
className={cn(
|
|
125
|
+
"text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
|
|
126
|
+
className,
|
|
127
|
+
)}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function AlertDialogDescription({
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
137
|
+
return (
|
|
138
|
+
<AlertDialogPrimitive.Description
|
|
139
|
+
data-slot="alert-dialog-description"
|
|
140
|
+
className={cn(
|
|
141
|
+
"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
142
|
+
className,
|
|
143
|
+
)}
|
|
144
|
+
{...props}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function AlertDialogAction({
|
|
150
|
+
className,
|
|
151
|
+
variant = "default",
|
|
152
|
+
size = "default",
|
|
153
|
+
...props
|
|
154
|
+
}: AlertDialogPrimitive.Close.Props &
|
|
155
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
156
|
+
return (
|
|
157
|
+
<AlertDialogPrimitive.Close
|
|
158
|
+
data-slot="alert-dialog-action"
|
|
159
|
+
className={className}
|
|
160
|
+
render={<Button variant={variant} size={size} />}
|
|
161
|
+
{...props}
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function AlertDialogCancel({
|
|
167
|
+
className,
|
|
168
|
+
variant = "outline",
|
|
169
|
+
size = "default",
|
|
170
|
+
...props
|
|
171
|
+
}: AlertDialogPrimitive.Close.Props &
|
|
172
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
173
|
+
return (
|
|
174
|
+
<AlertDialogPrimitive.Close
|
|
175
|
+
data-slot="alert-dialog-cancel"
|
|
176
|
+
className={className}
|
|
177
|
+
render={<Button variant={variant} size={size} />}
|
|
178
|
+
{...props}
|
|
179
|
+
/>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
AlertDialog,
|
|
185
|
+
AlertDialogAction,
|
|
186
|
+
AlertDialogCancel,
|
|
187
|
+
AlertDialogClose,
|
|
188
|
+
AlertDialogContent,
|
|
189
|
+
type AlertDialogContentSize,
|
|
190
|
+
AlertDialogDescription,
|
|
191
|
+
AlertDialogFooter,
|
|
192
|
+
AlertDialogHeader,
|
|
193
|
+
AlertDialogMedia,
|
|
194
|
+
AlertDialogOverlay,
|
|
195
|
+
AlertDialogPortal,
|
|
196
|
+
AlertDialogTitle,
|
|
197
|
+
AlertDialogTrigger,
|
|
198
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { XIcon } from "@phosphor-icons/react";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
import { buttonVariants } from "#/components/ui/button-variants.ts";
|
|
4
|
+
import { cva, type VariantProps } from "#/lib/cva.ts";
|
|
5
|
+
|
|
6
|
+
import { cn, proseLinkClassName } from "#/lib/utils.ts";
|
|
7
|
+
|
|
8
|
+
const alertVariants = cva({
|
|
9
|
+
base: "group/alert relative grid w-full grid-cols-1 gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-data-[slot=alert-action]:gap-x-2 has-[>svg]:has-data-[slot=alert-action]:grid-cols-[auto_1fr_auto] *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-card text-card-foreground",
|
|
13
|
+
destructive:
|
|
14
|
+
"bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
|
|
15
|
+
success:
|
|
16
|
+
"bg-card text-success *:data-[slot=alert-description]:text-success/90 *:[svg]:text-current",
|
|
17
|
+
warning:
|
|
18
|
+
"bg-card text-warning *:data-[slot=alert-description]:text-warning/90 *:[svg]:text-current",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: "default",
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function Alert({
|
|
27
|
+
className,
|
|
28
|
+
variant,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
data-slot="alert"
|
|
34
|
+
role="alert"
|
|
35
|
+
className={cn(alertVariants({ variant }), className)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
42
|
+
return (
|
|
43
|
+
<div
|
|
44
|
+
data-slot="alert-title"
|
|
45
|
+
className={cn(
|
|
46
|
+
"font-medium group-has-[>svg]/alert:col-start-2",
|
|
47
|
+
proseLinkClassName,
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function AlertDescription({
|
|
56
|
+
className,
|
|
57
|
+
...props
|
|
58
|
+
}: React.ComponentProps<"div">) {
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
data-slot="alert-description"
|
|
62
|
+
className={cn(
|
|
63
|
+
"text-sm text-balance text-muted-foreground md:text-pretty [&_p:not(:last-child)]:mb-4",
|
|
64
|
+
proseLinkClassName,
|
|
65
|
+
className,
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="alert-action"
|
|
76
|
+
className={cn(
|
|
77
|
+
"col-start-2 row-span-2 row-start-1 self-center group-has-[>svg]/alert:col-start-3",
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function AlertClose({ className, ...props }: React.ComponentProps<"button">) {
|
|
86
|
+
return (
|
|
87
|
+
<AlertAction>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
data-slot="alert-close"
|
|
91
|
+
aria-label="Dismiss"
|
|
92
|
+
className={cn(
|
|
93
|
+
buttonVariants({ variant: "ghost", size: "icon-xs" }),
|
|
94
|
+
"text-muted-foreground",
|
|
95
|
+
className,
|
|
96
|
+
)}
|
|
97
|
+
{...props}
|
|
98
|
+
>
|
|
99
|
+
<XIcon />
|
|
100
|
+
</button>
|
|
101
|
+
</AlertAction>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { Alert, AlertAction, AlertClose, AlertDescription, AlertTitle };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
import type * as React from "react";
|
|
4
|
+
import { cn } from "#/lib/utils.ts";
|
|
5
|
+
|
|
6
|
+
function AspectRatio({
|
|
7
|
+
ratio = 1,
|
|
8
|
+
className,
|
|
9
|
+
render,
|
|
10
|
+
...props
|
|
11
|
+
}: useRender.ComponentProps<"div"> & { ratio?: number | string }) {
|
|
12
|
+
return useRender({
|
|
13
|
+
defaultTagName: "div",
|
|
14
|
+
props: mergeProps<"div">(
|
|
15
|
+
{
|
|
16
|
+
className: cn("relative aspect-(--ratio)", className),
|
|
17
|
+
style: {
|
|
18
|
+
"--ratio": ratio,
|
|
19
|
+
} as React.CSSProperties,
|
|
20
|
+
},
|
|
21
|
+
props,
|
|
22
|
+
),
|
|
23
|
+
render,
|
|
24
|
+
state: {
|
|
25
|
+
slot: "aspect-ratio",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { AspectRatio };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "#/lib/utils.ts";
|
|
5
|
+
|
|
6
|
+
function Avatar({
|
|
7
|
+
className,
|
|
8
|
+
size = "default",
|
|
9
|
+
...props
|
|
10
|
+
}: AvatarPrimitive.Root.Props & {
|
|
11
|
+
size?: "default" | "sm" | "lg";
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<AvatarPrimitive.Root
|
|
15
|
+
data-slot="avatar"
|
|
16
|
+
data-size={size}
|
|
17
|
+
className={cn(
|
|
18
|
+
"group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) {
|
|
27
|
+
return (
|
|
28
|
+
<AvatarPrimitive.Image
|
|
29
|
+
data-slot="avatar-image"
|
|
30
|
+
className={cn(
|
|
31
|
+
"aspect-square size-full animate-in rounded-full object-cover duration-300 fade-in",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function AvatarFallback({
|
|
40
|
+
className,
|
|
41
|
+
...props
|
|
42
|
+
}: AvatarPrimitive.Fallback.Props) {
|
|
43
|
+
return (
|
|
44
|
+
<AvatarPrimitive.Fallback
|
|
45
|
+
data-slot="avatar-fallback"
|
|
46
|
+
className={cn(
|
|
47
|
+
"flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=lg]/avatar:text-base group-data-[size=sm]/avatar:text-xs",
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const avatarBadgeStatusClassNames = {
|
|
56
|
+
online: "bg-success text-success-foreground",
|
|
57
|
+
offline: "bg-muted-foreground text-muted",
|
|
58
|
+
busy: "bg-destructive text-destructive-foreground",
|
|
59
|
+
} as const;
|
|
60
|
+
|
|
61
|
+
function AvatarBadge({
|
|
62
|
+
className,
|
|
63
|
+
status,
|
|
64
|
+
...props
|
|
65
|
+
}: React.ComponentProps<"span"> & {
|
|
66
|
+
status?: "online" | "offline" | "busy";
|
|
67
|
+
}) {
|
|
68
|
+
return (
|
|
69
|
+
<span
|
|
70
|
+
data-slot="avatar-badge"
|
|
71
|
+
data-status={status}
|
|
72
|
+
className={cn(
|
|
73
|
+
"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground ring-2 ring-background select-none",
|
|
74
|
+
status && avatarBadgeStatusClassNames[status],
|
|
75
|
+
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden",
|
|
76
|
+
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
|
|
77
|
+
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
data-slot="avatar-group"
|
|
89
|
+
className={cn(
|
|
90
|
+
"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background",
|
|
91
|
+
className,
|
|
92
|
+
)}
|
|
93
|
+
{...props}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function AvatarGroupCount({
|
|
99
|
+
className,
|
|
100
|
+
size = "default",
|
|
101
|
+
...props
|
|
102
|
+
}: React.ComponentProps<"div"> & {
|
|
103
|
+
size?: "default" | "sm" | "lg";
|
|
104
|
+
}) {
|
|
105
|
+
return (
|
|
106
|
+
<div
|
|
107
|
+
data-slot="avatar-group-count"
|
|
108
|
+
data-size={size}
|
|
109
|
+
className={cn(
|
|
110
|
+
"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background data-[size=lg]:size-10 data-[size=sm]:size-6 data-[size=lg]:text-base data-[size=sm]:text-xs [&>svg]:size-4 data-[size=lg]:[&>svg]:size-5 data-[size=sm]:[&>svg]:size-3",
|
|
111
|
+
className,
|
|
112
|
+
)}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export {
|
|
119
|
+
Avatar,
|
|
120
|
+
AvatarBadge,
|
|
121
|
+
AvatarFallback,
|
|
122
|
+
AvatarGroup,
|
|
123
|
+
AvatarGroupCount,
|
|
124
|
+
AvatarImage,
|
|
125
|
+
};
|