@suphark/ui 0.18.0 → 0.20.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/CHANGELOG.md +47 -0
- package/package.json +14 -13
- package/scripts/audit.mjs +0 -0
- package/src/components/app-shell/app-shell.tsx +15 -9
- package/src/components/app-shell/index.ts +1 -0
- package/src/components/app-shell/mobile-tab-bar.tsx +104 -0
- package/src/components/shared/action-menu.tsx +155 -0
- package/src/components/shared/confirm-dialog.tsx +41 -2
- package/src/components/shared/count-badge.tsx +41 -0
- package/src/components/shared/filter-bar.tsx +108 -0
- package/src/components/shared/form/slider-field.tsx +79 -0
- package/src/components/shared/form-dialog.tsx +43 -4
- package/src/components/shared/month-stepper.tsx +124 -0
- package/src/components/shared/save-status.tsx +99 -0
- package/src/components/shared/segmented-control.tsx +73 -0
- package/src/components/shared/settings-layout.tsx +170 -0
- package/src/components/shared/settings-row.tsx +118 -0
- package/src/components/shared/setup-checklist.tsx +104 -0
- package/src/components/shared/simple-dialog.tsx +172 -0
- package/src/components/shared/simple-pagination.tsx +109 -0
- package/src/components/shared/simple-table.tsx +93 -0
- package/src/components/shared/simple-tabs.tsx +118 -0
- package/src/components/shared/simple-tooltip.tsx +87 -0
- package/src/components/shared/skip-link.tsx +30 -0
- package/src/components/shared/stat.tsx +110 -6
- package/src/components/shared/ui-text.tsx +35 -0
- package/src/components/shared/user-identity.tsx +61 -0
- package/src/components/ui/accordion.tsx +2 -2
- package/src/components/ui/alert-dialog.tsx +4 -4
- package/src/components/ui/alert.tsx +2 -2
- package/src/components/ui/attachment.tsx +9 -9
- package/src/components/ui/avatar.tsx +4 -4
- package/src/components/ui/badge.tsx +1 -1
- package/src/components/ui/breadcrumb.tsx +1 -1
- package/src/components/ui/bubble.tsx +123 -0
- package/src/components/ui/button-group.tsx +2 -2
- package/src/components/ui/button.tsx +6 -6
- package/src/components/ui/calendar.tsx +9 -9
- package/src/components/ui/card.tsx +3 -3
- package/src/components/ui/chart.tsx +2 -2
- package/src/components/ui/checkbox.tsx +1 -1
- package/src/components/ui/combobox.tsx +6 -6
- package/src/components/ui/command.tsx +4 -4
- package/src/components/ui/context-menu.tsx +7 -7
- package/src/components/ui/dialog.tsx +4 -4
- package/src/components/ui/direction.tsx +6 -0
- package/src/components/ui/drawer.tsx +10 -10
- package/src/components/ui/dropdown-menu.tsx +8 -8
- package/src/components/ui/empty.tsx +4 -4
- package/src/components/ui/field.tsx +8 -8
- package/src/components/ui/hover-card.tsx +1 -2
- package/src/components/ui/input-group.tsx +3 -3
- package/src/components/ui/input-otp.tsx +1 -1
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/item.tsx +4 -4
- package/src/components/ui/kbd.tsx +1 -1
- package/src/components/ui/label.tsx +1 -1
- package/src/components/ui/marker.tsx +67 -0
- package/src/components/ui/menubar.tsx +9 -9
- package/src/components/ui/message-scroller.tsx +129 -0
- package/src/components/ui/message.tsx +84 -0
- package/src/components/ui/native-select.tsx +1 -1
- package/src/components/ui/navigation-menu.tsx +6 -6
- package/src/components/ui/popover.tsx +1 -1
- package/src/components/ui/progress.tsx +2 -3
- package/src/components/ui/questionnaire.tsx +314 -0
- package/src/components/ui/radio-group.tsx +1 -2
- package/src/components/ui/resizable.tsx +1 -1
- package/src/components/ui/select.tsx +4 -4
- package/src/components/ui/separator.tsx +0 -1
- package/src/components/ui/sheet.tsx +3 -3
- package/src/components/ui/sidebar.tsx +14 -14
- package/src/components/ui/switch.tsx +2 -3
- package/src/components/ui/textarea.tsx +1 -1
- package/src/components/ui/toast.tsx +221 -0
- package/src/components/ui/toggle-group.tsx +2 -2
- package/src/components/ui/toggle.tsx +1 -1
- package/src/components/ui/tooltip.tsx +0 -1
- package/src/hooks/use-confirm.tsx +2 -0
- package/src/index.ts +48 -1
- package/src/lib/month.ts +60 -0
- package/src/styles.css +10 -0
|
@@ -40,7 +40,7 @@ function SelectTrigger({
|
|
|
40
40
|
data-slot="select-trigger"
|
|
41
41
|
data-size={size}
|
|
42
42
|
className={cn(
|
|
43
|
-
"flex w-fit
|
|
43
|
+
"flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
44
44
|
className,
|
|
45
45
|
)}
|
|
46
46
|
{...props}
|
|
@@ -81,7 +81,7 @@ function SelectContent({
|
|
|
81
81
|
data-slot="select-content"
|
|
82
82
|
data-align-trigger={alignItemWithTrigger}
|
|
83
83
|
className={cn(
|
|
84
|
-
"data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:fade-in-0 data-open:zoom-in-95 data-closed:
|
|
84
|
+
"relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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",
|
|
85
85
|
className,
|
|
86
86
|
)}
|
|
87
87
|
{...props}
|
|
@@ -99,7 +99,7 @@ function SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props)
|
|
|
99
99
|
return (
|
|
100
100
|
<SelectPrimitive.GroupLabel
|
|
101
101
|
data-slot="select-label"
|
|
102
|
-
className={cn("px-1.5 py-1 text-muted-foreground
|
|
102
|
+
className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
|
|
103
103
|
{...props}
|
|
104
104
|
/>
|
|
105
105
|
);
|
|
@@ -110,7 +110,7 @@ function SelectItem({ className, children, ...props }: SelectPrimitive.Item.Prop
|
|
|
110
110
|
<SelectPrimitive.Item
|
|
111
111
|
data-slot="select-item"
|
|
112
112
|
className={cn(
|
|
113
|
-
"relative flex w-full cursor-default
|
|
113
|
+
"relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
114
114
|
className,
|
|
115
115
|
)}
|
|
116
116
|
{...props}
|
|
@@ -52,7 +52,7 @@ function SheetContent({
|
|
|
52
52
|
data-slot="sheet-content"
|
|
53
53
|
data-side={side}
|
|
54
54
|
className={cn(
|
|
55
|
-
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-popover-foreground
|
|
55
|
+
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
|
|
56
56
|
className,
|
|
57
57
|
)}
|
|
58
58
|
{...props}
|
|
@@ -96,7 +96,7 @@ function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
|
|
|
96
96
|
return (
|
|
97
97
|
<SheetPrimitive.Title
|
|
98
98
|
data-slot="sheet-title"
|
|
99
|
-
className={cn("font-medium text-
|
|
99
|
+
className={cn("text-base font-medium text-foreground", className)}
|
|
100
100
|
{...props}
|
|
101
101
|
/>
|
|
102
102
|
);
|
|
@@ -106,7 +106,7 @@ function SheetDescription({ className, ...props }: SheetPrimitive.Description.Pr
|
|
|
106
106
|
return (
|
|
107
107
|
<SheetPrimitive.Description
|
|
108
108
|
data-slot="sheet-description"
|
|
109
|
-
className={cn("text-muted-foreground
|
|
109
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
110
110
|
{...props}
|
|
111
111
|
/>
|
|
112
112
|
);
|
|
@@ -86,7 +86,7 @@ function SidebarProvider({
|
|
|
86
86
|
// Helper to toggle the sidebar.
|
|
87
87
|
const toggleSidebar = React.useCallback(() => {
|
|
88
88
|
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
89
|
-
}, [isMobile, setOpen]);
|
|
89
|
+
}, [isMobile, setOpen, setOpenMobile]);
|
|
90
90
|
|
|
91
91
|
// Adds a keyboard shortcut to toggle the sidebar.
|
|
92
92
|
React.useEffect(() => {
|
|
@@ -115,7 +115,7 @@ function SidebarProvider({
|
|
|
115
115
|
setOpenMobile,
|
|
116
116
|
toggleSidebar,
|
|
117
117
|
}),
|
|
118
|
-
[state, open, setOpen, isMobile, openMobile, toggleSidebar],
|
|
118
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
|
|
119
119
|
);
|
|
120
120
|
|
|
121
121
|
return (
|
|
@@ -222,7 +222,7 @@ function Sidebar({
|
|
|
222
222
|
data-slot="sidebar-container"
|
|
223
223
|
data-side={side}
|
|
224
224
|
className={cn(
|
|
225
|
-
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=
|
|
225
|
+
"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)] md:flex",
|
|
226
226
|
// Adjust the padding for floating and inset variants.
|
|
227
227
|
variant === "floating" || variant === "inset"
|
|
228
228
|
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
|
|
@@ -277,10 +277,10 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
|
|
277
277
|
onClick={toggleSidebar}
|
|
278
278
|
title="Toggle Sidebar"
|
|
279
279
|
className={cn(
|
|
280
|
-
"absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border
|
|
280
|
+
"absolute inset-y-0 z-20 hidden w-4 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2",
|
|
281
281
|
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
|
|
282
282
|
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
283
|
-
"group-data-[collapsible=offcanvas]:translate-x-0
|
|
283
|
+
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
|
|
284
284
|
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
|
285
285
|
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
|
286
286
|
className,
|
|
@@ -295,7 +295,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
|
|
295
295
|
<main
|
|
296
296
|
data-slot="sidebar-inset"
|
|
297
297
|
className={cn(
|
|
298
|
-
"relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:peer-data-[
|
|
298
|
+
"relative flex w-full flex-1 flex-col bg-background md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
|
|
299
299
|
className,
|
|
300
300
|
)}
|
|
301
301
|
{...props}
|
|
@@ -382,7 +382,7 @@ function SidebarGroupLabel({
|
|
|
382
382
|
props: mergeProps<"div">(
|
|
383
383
|
{
|
|
384
384
|
className: cn(
|
|
385
|
-
"flex h-8 shrink-0 items-center rounded-md px-2 font-medium text-sidebar-foreground/70
|
|
385
|
+
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 ring-sidebar-ring outline-hidden transition-[margin,opacity] duration-200 ease-linear group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0 focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
386
386
|
className,
|
|
387
387
|
),
|
|
388
388
|
},
|
|
@@ -406,7 +406,7 @@ function SidebarGroupAction({
|
|
|
406
406
|
props: mergeProps<"button">(
|
|
407
407
|
{
|
|
408
408
|
className: cn(
|
|
409
|
-
"absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground
|
|
409
|
+
"absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
|
|
410
410
|
className,
|
|
411
411
|
),
|
|
412
412
|
},
|
|
@@ -454,7 +454,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
const sidebarMenuButtonVariants = cva(
|
|
457
|
-
"peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm
|
|
457
|
+
"peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
|
|
458
458
|
{
|
|
459
459
|
variants: {
|
|
460
460
|
variant: {
|
|
@@ -543,9 +543,9 @@ function SidebarMenuAction({
|
|
|
543
543
|
props: mergeProps<"button">(
|
|
544
544
|
{
|
|
545
545
|
className: cn(
|
|
546
|
-
"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground
|
|
546
|
+
"absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 after:absolute after:-inset-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 md:after:hidden [&>svg]:size-4 [&>svg]:shrink-0",
|
|
547
547
|
showOnHover &&
|
|
548
|
-
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100
|
|
548
|
+
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-active/menu-button:text-sidebar-accent-foreground aria-expanded:opacity-100 md:opacity-0",
|
|
549
549
|
className,
|
|
550
550
|
),
|
|
551
551
|
},
|
|
@@ -565,7 +565,7 @@ function SidebarMenuBadge({ className, ...props }: React.ComponentProps<"div">)
|
|
|
565
565
|
data-slot="sidebar-menu-badge"
|
|
566
566
|
data-sidebar="menu-badge"
|
|
567
567
|
className={cn(
|
|
568
|
-
"pointer-events-none absolute right-1 flex h-5 min-w-5
|
|
568
|
+
"pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium text-sidebar-foreground tabular-nums select-none group-data-[collapsible=icon]:hidden peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 peer-data-[size=sm]/menu-button:top-1 peer-data-active/menu-button:text-sidebar-accent-foreground",
|
|
569
569
|
className,
|
|
570
570
|
)}
|
|
571
571
|
{...props}
|
|
@@ -612,7 +612,7 @@ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
|
|
|
612
612
|
data-slot="sidebar-menu-sub"
|
|
613
613
|
data-sidebar="menu-sub"
|
|
614
614
|
className={cn(
|
|
615
|
-
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-sidebar-border
|
|
615
|
+
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5 group-data-[collapsible=icon]:hidden",
|
|
616
616
|
className,
|
|
617
617
|
)}
|
|
618
618
|
{...props}
|
|
@@ -647,7 +647,7 @@ function SidebarMenuSubButton({
|
|
|
647
647
|
props: mergeProps<"a">(
|
|
648
648
|
{
|
|
649
649
|
className: cn(
|
|
650
|
-
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-hidden
|
|
650
|
+
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground ring-sidebar-ring outline-hidden group-data-[collapsible=icon]:hidden hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
|
|
651
651
|
className,
|
|
652
652
|
),
|
|
653
653
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
4
|
-
|
|
5
4
|
import { cn } from "@suphark/ui/lib/utils";
|
|
6
5
|
|
|
7
6
|
function Switch({
|
|
@@ -16,14 +15,14 @@ function Switch({
|
|
|
16
15
|
data-slot="switch"
|
|
17
16
|
data-size={size}
|
|
18
17
|
className={cn(
|
|
19
|
-
"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent outline-none
|
|
18
|
+
"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
20
19
|
className,
|
|
21
20
|
)}
|
|
22
21
|
{...props}
|
|
23
22
|
>
|
|
24
23
|
<SwitchPrimitive.Thumb
|
|
25
24
|
data-slot="switch-thumb"
|
|
26
|
-
className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=
|
|
25
|
+
className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
|
|
27
26
|
/>
|
|
28
27
|
</SwitchPrimitive.Root>
|
|
29
28
|
);
|
|
@@ -6,7 +6,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
|
6
6
|
<textarea
|
|
7
7
|
data-slot="textarea"
|
|
8
8
|
className={cn(
|
|
9
|
-
"field-sizing-content
|
|
9
|
+
"flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
10
10
|
className,
|
|
11
11
|
)}
|
|
12
12
|
{...props}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Toast as ToastPrimitive } from "@base-ui/react/toast";
|
|
4
|
+
import { Button } from "@suphark/ui/components/ui/button";
|
|
5
|
+
import { cn } from "@suphark/ui/lib/utils";
|
|
6
|
+
import {
|
|
7
|
+
CircleCheckIcon,
|
|
8
|
+
InfoIcon,
|
|
9
|
+
Loader2Icon,
|
|
10
|
+
OctagonXIcon,
|
|
11
|
+
TriangleAlertIcon,
|
|
12
|
+
XIcon,
|
|
13
|
+
} from "lucide-react";
|
|
14
|
+
import type * as React from "react";
|
|
15
|
+
|
|
16
|
+
const toast = ToastPrimitive.createToastManager();
|
|
17
|
+
|
|
18
|
+
function ToastProvider({ ...props }: ToastPrimitive.Provider.Props) {
|
|
19
|
+
return <ToastPrimitive.Provider {...props} />;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ToastPortal({ ...props }: ToastPrimitive.Portal.Props) {
|
|
23
|
+
return <ToastPrimitive.Portal data-slot="toast-portal" {...props} />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function ToastViewport({ className, ...props }: ToastPrimitive.Viewport.Props) {
|
|
27
|
+
return (
|
|
28
|
+
<ToastPrimitive.Viewport
|
|
29
|
+
data-slot="toast-viewport"
|
|
30
|
+
className={cn(
|
|
31
|
+
"pointer-events-none fixed inset-x-4 bottom-4 z-50 mx-auto w-auto max-w-sm outline-none sm:right-4 sm:left-auto sm:mx-0 sm:w-full",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function Toast({ className, ...props }: ToastPrimitive.Root.Props) {
|
|
40
|
+
return (
|
|
41
|
+
<ToastPrimitive.Root
|
|
42
|
+
data-slot="toast"
|
|
43
|
+
className={cn(
|
|
44
|
+
"group/toast pointer-events-auto absolute right-0 bottom-0 z-[calc(1000-var(--toast-index))] w-full origin-bottom rounded-2xl border bg-popover text-popover-foreground shadow-lg will-change-transform outline-none select-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
45
|
+
"[--gap:0.75rem] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))]",
|
|
46
|
+
"h-(--height) [transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))] [transition:transform_500ms_cubic-bezier(0.22,1,0.36,1),opacity_500ms,height_150ms]",
|
|
47
|
+
"after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']",
|
|
48
|
+
"data-expanded:h-(--toast-height) data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]",
|
|
49
|
+
"data-limited:opacity-0 data-starting-style:[transform:translateY(150%)]",
|
|
50
|
+
"[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]",
|
|
51
|
+
"data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
|
|
52
|
+
"data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
|
|
53
|
+
"data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
|
|
54
|
+
"data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
|
|
55
|
+
"data-expanded:data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]",
|
|
56
|
+
"data-expanded:data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]",
|
|
57
|
+
"data-expanded:data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]",
|
|
58
|
+
"data-expanded:data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]",
|
|
59
|
+
className,
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function ToastContent({ className, ...props }: ToastPrimitive.Content.Props) {
|
|
67
|
+
return (
|
|
68
|
+
<ToastPrimitive.Content
|
|
69
|
+
data-slot="toast-content"
|
|
70
|
+
className={cn(
|
|
71
|
+
"flex h-full items-center gap-3 overflow-hidden p-4 transition-opacity duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] data-behind:opacity-0 data-expanded:opacity-100",
|
|
72
|
+
className,
|
|
73
|
+
)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function ToastTitle({ className, ...props }: ToastPrimitive.Title.Props) {
|
|
80
|
+
return (
|
|
81
|
+
<ToastPrimitive.Title
|
|
82
|
+
data-slot="toast-title"
|
|
83
|
+
className={cn("text-sm font-medium", className)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function ToastDescription({ className, ...props }: ToastPrimitive.Description.Props) {
|
|
90
|
+
return (
|
|
91
|
+
<ToastPrimitive.Description
|
|
92
|
+
data-slot="toast-description"
|
|
93
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ToastAction({
|
|
100
|
+
className,
|
|
101
|
+
render = <Button variant="outline" size="sm" />,
|
|
102
|
+
...props
|
|
103
|
+
}: ToastPrimitive.Action.Props) {
|
|
104
|
+
return (
|
|
105
|
+
<ToastPrimitive.Action
|
|
106
|
+
data-slot="toast-action"
|
|
107
|
+
render={render}
|
|
108
|
+
className={cn("shrink-0", className)}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function ToastClose({
|
|
115
|
+
className,
|
|
116
|
+
children,
|
|
117
|
+
render = <Button variant="ghost" size="icon-sm" />,
|
|
118
|
+
...props
|
|
119
|
+
}: ToastPrimitive.Close.Props) {
|
|
120
|
+
return (
|
|
121
|
+
<ToastPrimitive.Close
|
|
122
|
+
data-slot="toast-close"
|
|
123
|
+
aria-label="Close toast"
|
|
124
|
+
render={render}
|
|
125
|
+
className={cn(
|
|
126
|
+
"relative shrink-0 text-muted-foreground after:absolute after:-inset-2 after:content-[''] hover:text-foreground",
|
|
127
|
+
className,
|
|
128
|
+
)}
|
|
129
|
+
{...props}
|
|
130
|
+
>
|
|
131
|
+
{children ?? <XIcon aria-hidden="true" />}
|
|
132
|
+
</ToastPrimitive.Close>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function ToastIcon({ type }: { type: string | undefined }) {
|
|
137
|
+
let icon: React.ReactNode = null;
|
|
138
|
+
|
|
139
|
+
if (type === "success") {
|
|
140
|
+
icon = <CircleCheckIcon aria-hidden="true" />;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (type === "info") {
|
|
144
|
+
icon = <InfoIcon aria-hidden="true" />;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (type === "warning") {
|
|
148
|
+
icon = <TriangleAlertIcon aria-hidden="true" />;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (type === "error") {
|
|
152
|
+
icon = <OctagonXIcon className="text-destructive" aria-hidden="true" />;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (type === "loading") {
|
|
156
|
+
icon = <Loader2Icon className="animate-spin" aria-hidden="true" />;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!icon) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<span
|
|
165
|
+
data-slot="toast-icon"
|
|
166
|
+
className="shrink-0 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4"
|
|
167
|
+
>
|
|
168
|
+
{icon}
|
|
169
|
+
</span>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function ToastList() {
|
|
174
|
+
const { toasts } = ToastPrimitive.useToastManager();
|
|
175
|
+
|
|
176
|
+
return toasts.map((toastItem) => (
|
|
177
|
+
<Toast key={toastItem.id} toast={toastItem}>
|
|
178
|
+
<ToastContent>
|
|
179
|
+
<ToastIcon type={toastItem.type} />
|
|
180
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
181
|
+
<ToastTitle />
|
|
182
|
+
<ToastDescription />
|
|
183
|
+
</div>
|
|
184
|
+
<ToastAction />
|
|
185
|
+
<ToastClose />
|
|
186
|
+
</ToastContent>
|
|
187
|
+
</Toast>
|
|
188
|
+
));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function Toaster({ children, toastManager = toast, ...props }: ToastPrimitive.Provider.Props) {
|
|
192
|
+
return (
|
|
193
|
+
<ToastProvider toastManager={toastManager} {...props}>
|
|
194
|
+
{children}
|
|
195
|
+
<ToastPortal>
|
|
196
|
+
<ToastViewport>
|
|
197
|
+
<ToastList />
|
|
198
|
+
</ToastViewport>
|
|
199
|
+
</ToastPortal>
|
|
200
|
+
</ToastProvider>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const createToastManager = ToastPrimitive.createToastManager;
|
|
205
|
+
const useToastManager = ToastPrimitive.useToastManager;
|
|
206
|
+
|
|
207
|
+
export {
|
|
208
|
+
createToastManager,
|
|
209
|
+
Toast,
|
|
210
|
+
ToastAction,
|
|
211
|
+
ToastClose,
|
|
212
|
+
ToastContent,
|
|
213
|
+
ToastDescription,
|
|
214
|
+
Toaster,
|
|
215
|
+
ToastPortal,
|
|
216
|
+
ToastProvider,
|
|
217
|
+
ToastTitle,
|
|
218
|
+
ToastViewport,
|
|
219
|
+
toast,
|
|
220
|
+
useToastManager,
|
|
221
|
+
};
|
|
@@ -41,7 +41,7 @@ function ToggleGroup({
|
|
|
41
41
|
data-orientation={orientation}
|
|
42
42
|
style={{ "--gap": spacing } as React.CSSProperties}
|
|
43
43
|
className={cn(
|
|
44
|
-
"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-
|
|
44
|
+
"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] rounded-lg data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-vertical:flex-col data-vertical:items-stretch",
|
|
45
45
|
className,
|
|
46
46
|
)}
|
|
47
47
|
{...props}
|
|
@@ -69,7 +69,7 @@ function ToggleGroupItem({
|
|
|
69
69
|
data-size={context.size || size}
|
|
70
70
|
data-spacing={context.spacing}
|
|
71
71
|
className={cn(
|
|
72
|
-
"shrink-0
|
|
72
|
+
"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-2 focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t",
|
|
73
73
|
toggleVariants({
|
|
74
74
|
variant: context.variant || variant,
|
|
75
75
|
size: context.size || size,
|
|
@@ -5,7 +5,7 @@ import { cn } from "@suphark/ui/lib/utils";
|
|
|
5
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
6
|
|
|
7
7
|
const toggleVariants = cva(
|
|
8
|
-
"group/toggle inline-flex items-center justify-center gap-1
|
|
8
|
+
"group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
variant: {
|
|
@@ -55,6 +55,8 @@ export function useConfirm(): {
|
|
|
55
55
|
confirmLabel={request.options.confirmLabel}
|
|
56
56
|
cancelLabel={request.options.cancelLabel}
|
|
57
57
|
destructive={request.options.destructive}
|
|
58
|
+
requireText={request.options.requireText}
|
|
59
|
+
requireTextLabel={request.options.requireTextLabel}
|
|
58
60
|
onConfirm={() => settle(true)}
|
|
59
61
|
/>
|
|
60
62
|
) : null;
|