@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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
MessageScroller as MessageScrollerPrimitive,
|
|
5
|
+
useMessageScroller,
|
|
6
|
+
useMessageScrollerScrollable,
|
|
7
|
+
useMessageScrollerVisibility,
|
|
8
|
+
} from "@shadcn/react/message-scroller";
|
|
9
|
+
import { Button } from "@suphark/ui/components/ui/button";
|
|
10
|
+
import { cn } from "@suphark/ui/lib/utils";
|
|
11
|
+
import { ArrowDownIcon } from "lucide-react";
|
|
12
|
+
import type * as React from "react";
|
|
13
|
+
|
|
14
|
+
function MessageScrollerProvider(
|
|
15
|
+
props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>,
|
|
16
|
+
) {
|
|
17
|
+
return <MessageScrollerPrimitive.Provider {...props} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function MessageScroller({
|
|
21
|
+
className,
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {
|
|
24
|
+
return (
|
|
25
|
+
<MessageScrollerPrimitive.Root
|
|
26
|
+
data-slot="message-scroller"
|
|
27
|
+
className={cn(
|
|
28
|
+
"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden",
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function MessageScrollerViewport({
|
|
37
|
+
className,
|
|
38
|
+
...props
|
|
39
|
+
}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {
|
|
40
|
+
return (
|
|
41
|
+
<MessageScrollerPrimitive.Viewport
|
|
42
|
+
data-slot="message-scroller-viewport"
|
|
43
|
+
className={cn(
|
|
44
|
+
"size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent data-pending-scroll:invisible",
|
|
45
|
+
className,
|
|
46
|
+
)}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function MessageScrollerContent({
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
55
|
+
}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {
|
|
56
|
+
return (
|
|
57
|
+
<MessageScrollerPrimitive.Content
|
|
58
|
+
data-slot="message-scroller-content"
|
|
59
|
+
className={cn("flex h-max min-h-full flex-col gap-6", className)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function MessageScrollerItem({
|
|
66
|
+
className,
|
|
67
|
+
scrollAnchor = false,
|
|
68
|
+
...props
|
|
69
|
+
}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {
|
|
70
|
+
return (
|
|
71
|
+
<MessageScrollerPrimitive.Item
|
|
72
|
+
data-slot="message-scroller-item"
|
|
73
|
+
scrollAnchor={scrollAnchor}
|
|
74
|
+
className={cn(
|
|
75
|
+
"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]",
|
|
76
|
+
className,
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function MessageScrollerButton({
|
|
84
|
+
direction = "end",
|
|
85
|
+
className,
|
|
86
|
+
children,
|
|
87
|
+
render,
|
|
88
|
+
variant = "secondary",
|
|
89
|
+
size = "icon-sm",
|
|
90
|
+
...props
|
|
91
|
+
}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &
|
|
92
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
93
|
+
return (
|
|
94
|
+
<MessageScrollerPrimitive.Button
|
|
95
|
+
data-slot="message-scroller-button"
|
|
96
|
+
data-direction={direction}
|
|
97
|
+
data-variant={variant}
|
|
98
|
+
data-size={size}
|
|
99
|
+
direction={direction}
|
|
100
|
+
className={cn(
|
|
101
|
+
"absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
|
|
102
|
+
className,
|
|
103
|
+
)}
|
|
104
|
+
render={render ?? <Button variant={variant} size={size} />}
|
|
105
|
+
{...props}
|
|
106
|
+
>
|
|
107
|
+
{children ?? (
|
|
108
|
+
<>
|
|
109
|
+
<ArrowDownIcon />
|
|
110
|
+
<span className="sr-only">
|
|
111
|
+
{direction === "end" ? "Scroll to end" : "Scroll to start"}
|
|
112
|
+
</span>
|
|
113
|
+
</>
|
|
114
|
+
)}
|
|
115
|
+
</MessageScrollerPrimitive.Button>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
MessageScroller,
|
|
121
|
+
MessageScrollerButton,
|
|
122
|
+
MessageScrollerContent,
|
|
123
|
+
MessageScrollerItem,
|
|
124
|
+
MessageScrollerProvider,
|
|
125
|
+
MessageScrollerViewport,
|
|
126
|
+
useMessageScroller,
|
|
127
|
+
useMessageScrollerScrollable,
|
|
128
|
+
useMessageScrollerVisibility,
|
|
129
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { cn } from "@suphark/ui/lib/utils";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
|
|
4
|
+
function MessageGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
data-slot="message-group"
|
|
8
|
+
className={cn("flex min-w-0 flex-col gap-2", className)}
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function Message({
|
|
15
|
+
className,
|
|
16
|
+
align = "start",
|
|
17
|
+
...props
|
|
18
|
+
}: React.ComponentProps<"div"> & { align?: "start" | "end" }) {
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
data-slot="message"
|
|
22
|
+
data-align={align}
|
|
23
|
+
className={cn(
|
|
24
|
+
"group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse",
|
|
25
|
+
className,
|
|
26
|
+
)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function MessageAvatar({ className, ...props }: React.ComponentProps<"div">) {
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
data-slot="message-avatar"
|
|
36
|
+
className={cn(
|
|
37
|
+
"flex w-fit min-w-8 shrink-0 items-center justify-center self-end overflow-hidden rounded-full bg-muted group-has-data-[slot=message-footer]/message:-translate-y-8",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function MessageContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
data-slot="message-content"
|
|
49
|
+
className={cn(
|
|
50
|
+
"flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end",
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function MessageHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
59
|
+
return (
|
|
60
|
+
<div
|
|
61
|
+
data-slot="message-header"
|
|
62
|
+
className={cn(
|
|
63
|
+
"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0",
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function MessageFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
data-slot="message-footer"
|
|
75
|
+
className={cn(
|
|
76
|
+
"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[variant=ghost]/message:px-0 group-data-[align=end]/message:justify-end",
|
|
77
|
+
className,
|
|
78
|
+
)}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { Message, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader };
|
|
@@ -51,7 +51,7 @@ function NavigationMenuItem({
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const navigationMenuTriggerStyle = cva(
|
|
54
|
-
"group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 font-medium
|
|
54
|
+
"group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted",
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
function NavigationMenuTrigger({
|
|
@@ -67,7 +67,7 @@ function NavigationMenuTrigger({
|
|
|
67
67
|
>
|
|
68
68
|
{children}{" "}
|
|
69
69
|
<ChevronDownIcon
|
|
70
|
-
className="relative top-px ml-1 size-3 transition duration-300 group-data-open/navigation-menu-trigger:rotate-180 group-data-
|
|
70
|
+
className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180"
|
|
71
71
|
aria-hidden="true"
|
|
72
72
|
/>
|
|
73
73
|
</NavigationMenuPrimitive.Trigger>
|
|
@@ -79,7 +79,7 @@ function NavigationMenuContent({ className, ...props }: NavigationMenuPrimitive.
|
|
|
79
79
|
<NavigationMenuPrimitive.Content
|
|
80
80
|
data-slot="navigation-menu-content"
|
|
81
81
|
className={cn(
|
|
82
|
-
"data-
|
|
82
|
+
"data-ending-style:data-activation-direction=left:translate-x-[50%] data-ending-style:data-activation-direction=right:translate-x-[-50%] data-starting-style:data-activation-direction=left:translate-x-[-50%] data-starting-style:data-activation-direction=right:translate-x-[50%] h-full w-auto p-1 transition-[opacity,transform,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95",
|
|
83
83
|
className,
|
|
84
84
|
)}
|
|
85
85
|
{...props}
|
|
@@ -108,7 +108,7 @@ function NavigationMenuPositioner({
|
|
|
108
108
|
)}
|
|
109
109
|
{...props}
|
|
110
110
|
>
|
|
111
|
-
<NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease]
|
|
111
|
+
<NavigationMenuPrimitive.Popup className="data-[ending-style]:easing-[ease] xs:w-(--popup-width) relative h-(--popup-height) w-(--popup-width) origin-(--transform-origin) rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 transition-[opacity,transform,width,height,scale,translate] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] outline-none data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:scale-90 data-starting-style:opacity-0">
|
|
112
112
|
<NavigationMenuPrimitive.Viewport className="relative size-full overflow-hidden" />
|
|
113
113
|
</NavigationMenuPrimitive.Popup>
|
|
114
114
|
</NavigationMenuPrimitive.Positioner>
|
|
@@ -121,7 +121,7 @@ function NavigationMenuLink({ className, ...props }: NavigationMenuPrimitive.Lin
|
|
|
121
121
|
<NavigationMenuPrimitive.Link
|
|
122
122
|
data-slot="navigation-menu-link"
|
|
123
123
|
className={cn(
|
|
124
|
-
"flex items-center gap-2
|
|
124
|
+
"flex items-center gap-2 rounded-lg p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*='size-'])]:size-4",
|
|
125
125
|
className,
|
|
126
126
|
)}
|
|
127
127
|
{...props}
|
|
@@ -137,7 +137,7 @@ function NavigationMenuIndicator({
|
|
|
137
137
|
<NavigationMenuPrimitive.Icon
|
|
138
138
|
data-slot="navigation-menu-indicator"
|
|
139
139
|
className={cn(
|
|
140
|
-
"
|
|
140
|
+
"top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in",
|
|
141
141
|
className,
|
|
142
142
|
)}
|
|
143
143
|
{...props}
|
|
@@ -33,7 +33,7 @@ function PopoverContent({
|
|
|
33
33
|
<PopoverPrimitive.Popup
|
|
34
34
|
data-slot="popover-content"
|
|
35
35
|
className={cn(
|
|
36
|
-
"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:
|
|
36
|
+
"z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 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",
|
|
37
37
|
className,
|
|
38
38
|
)}
|
|
39
39
|
{...props}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Progress as ProgressPrimitive } from "@base-ui/react/progress";
|
|
4
|
-
|
|
5
4
|
import { cn } from "@suphark/ui/lib/utils";
|
|
6
5
|
|
|
7
6
|
function Progress({ className, children, value, ...props }: ProgressPrimitive.Root.Props) {
|
|
@@ -46,7 +45,7 @@ function ProgressIndicator({ className, ...props }: ProgressPrimitive.Indicator.
|
|
|
46
45
|
function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
|
|
47
46
|
return (
|
|
48
47
|
<ProgressPrimitive.Label
|
|
49
|
-
className={cn("font-medium
|
|
48
|
+
className={cn("text-sm font-medium", className)}
|
|
50
49
|
data-slot="progress-label"
|
|
51
50
|
{...props}
|
|
52
51
|
/>
|
|
@@ -56,7 +55,7 @@ function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
|
|
|
56
55
|
function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
|
|
57
56
|
return (
|
|
58
57
|
<ProgressPrimitive.Value
|
|
59
|
-
className={cn("ml-auto text-muted-foreground
|
|
58
|
+
className={cn("ml-auto text-sm text-muted-foreground tabular-nums", className)}
|
|
60
59
|
data-slot="progress-value"
|
|
61
60
|
{...props}
|
|
62
61
|
/>
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Questionnaire as QuestionnairePrimitive } from "@shadcn/react/questionnaire";
|
|
4
|
+
import { type Button, buttonVariants } from "@suphark/ui/components/ui/button";
|
|
5
|
+
import { cn } from "@suphark/ui/lib/utils";
|
|
6
|
+
import { CheckIcon } from "lucide-react";
|
|
7
|
+
import type * as React from "react";
|
|
8
|
+
|
|
9
|
+
function Questionnaire({
|
|
10
|
+
className,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Root>) {
|
|
13
|
+
return (
|
|
14
|
+
<QuestionnairePrimitive.Root
|
|
15
|
+
data-slot="questionnaire"
|
|
16
|
+
className={cn("flex w-full min-w-0 flex-col gap-4", className)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function QuestionnaireProgress({
|
|
23
|
+
className,
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Progress>) {
|
|
26
|
+
return (
|
|
27
|
+
<QuestionnairePrimitive.Progress
|
|
28
|
+
data-slot="questionnaire-progress"
|
|
29
|
+
className={cn(
|
|
30
|
+
"min-h-[1lh] w-fit min-w-[14ch] text-xs font-medium text-muted-foreground tabular-nums",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function QuestionnaireItem({
|
|
39
|
+
className,
|
|
40
|
+
...props
|
|
41
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Item>) {
|
|
42
|
+
return (
|
|
43
|
+
<QuestionnairePrimitive.Item
|
|
44
|
+
data-slot="questionnaire-item"
|
|
45
|
+
className={cn("flex min-w-0 flex-col gap-4 border-0 p-0 outline-none", className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function QuestionnaireTitle({
|
|
52
|
+
className,
|
|
53
|
+
...props
|
|
54
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Title>) {
|
|
55
|
+
return (
|
|
56
|
+
<QuestionnairePrimitive.Title
|
|
57
|
+
data-slot="questionnaire-title"
|
|
58
|
+
className={cn(
|
|
59
|
+
"text-base leading-snug font-medium text-pretty [&:not(:has(~[data-slot=questionnaire-description]))]:mb-4",
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function QuestionnaireDescription({
|
|
68
|
+
className,
|
|
69
|
+
...props
|
|
70
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Description>) {
|
|
71
|
+
return (
|
|
72
|
+
<QuestionnairePrimitive.Description
|
|
73
|
+
data-slot="questionnaire-description"
|
|
74
|
+
className={cn("text-sm text-pretty text-muted-foreground", className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function QuestionnaireChoices({
|
|
81
|
+
className,
|
|
82
|
+
...props
|
|
83
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Choices>) {
|
|
84
|
+
return (
|
|
85
|
+
<QuestionnairePrimitive.Choices
|
|
86
|
+
data-slot="questionnaire-choices"
|
|
87
|
+
className={cn("group/questionnaire-choices grid min-w-0 gap-2", className)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function QuestionnaireChoice({
|
|
94
|
+
children,
|
|
95
|
+
className,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Choice>) {
|
|
98
|
+
return (
|
|
99
|
+
<QuestionnairePrimitive.Choice
|
|
100
|
+
data-slot="questionnaire-choice"
|
|
101
|
+
className={cn(
|
|
102
|
+
"group/questionnaire-choice relative flex min-h-11 cursor-pointer items-start gap-2.5 rounded-lg border border-input bg-transparent px-3 py-2.5 text-start text-sm transition-colors outline-none select-none hover:bg-muted/50 has-[>input:focus-visible]:border-ring has-[>input:focus-visible]:ring-3 has-[>input:focus-visible]:ring-ring/50 data-invalid:border-destructive dark:bg-input/20 data-checked:border-primary/40 data-checked:bg-muted dark:data-checked:bg-muted",
|
|
103
|
+
"data-disabled:pointer-events-none data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
104
|
+
className,
|
|
105
|
+
)}
|
|
106
|
+
{...props}
|
|
107
|
+
>
|
|
108
|
+
<QuestionnairePrimitive.ChoiceInput
|
|
109
|
+
data-slot="questionnaire-choice-input"
|
|
110
|
+
className="absolute inset-0 z-10 size-full cursor-pointer opacity-0"
|
|
111
|
+
/>
|
|
112
|
+
<span
|
|
113
|
+
aria-hidden="true"
|
|
114
|
+
data-slot="questionnaire-choice-indicator"
|
|
115
|
+
className="pointer-events-none relative flex size-4 shrink-0 translate-y-[--spacing(0.45)] items-center justify-center rounded-[4px] border border-input group-has-data-[slot=questionnaire-choice-description]/questionnaire-choice:translate-y-0.5 group-data-[type=radio]/questionnaire-choice:rounded-full group-data-checked/questionnaire-choice:border-primary group-data-checked/questionnaire-choice:bg-primary group-data-checked/questionnaire-choice:text-primary-foreground dark:bg-input/30 dark:group-data-checked/questionnaire-choice:bg-primary"
|
|
116
|
+
>
|
|
117
|
+
<span
|
|
118
|
+
data-slot="questionnaire-choice-indicator-dot"
|
|
119
|
+
className="hidden size-2 rounded-full bg-primary-foreground group-data-[type=checkbox]/questionnaire-choice:hidden group-data-checked/questionnaire-choice:block"
|
|
120
|
+
/>
|
|
121
|
+
<CheckIcon
|
|
122
|
+
data-slot="questionnaire-choice-indicator-check"
|
|
123
|
+
className="hidden size-3.5 group-data-[type=radio]/questionnaire-choice:hidden group-data-checked/questionnaire-choice:block"
|
|
124
|
+
/>
|
|
125
|
+
</span>
|
|
126
|
+
<QuestionnairePrimitive.ChoiceLabel
|
|
127
|
+
data-slot="questionnaire-choice-label"
|
|
128
|
+
className="flex min-w-0 flex-1 flex-col gap-0.5 leading-snug"
|
|
129
|
+
>
|
|
130
|
+
{children}
|
|
131
|
+
</QuestionnairePrimitive.ChoiceLabel>
|
|
132
|
+
<QuestionnairePrimitive.ChoiceShortcut
|
|
133
|
+
data-slot="questionnaire-choice-shortcut"
|
|
134
|
+
className="pointer-events-none ms-auto hidden size-5 shrink-0 translate-y-[--spacing(0.45)] items-center justify-center rounded-md border border-input bg-background font-mono text-[0.625rem] leading-none font-medium text-muted-foreground group-has-data-[slot=questionnaire-choice-description]/questionnaire-choice:translate-y-0.5 group-data-[shortcut]/questionnaire-choice:inline-flex"
|
|
135
|
+
/>
|
|
136
|
+
</QuestionnairePrimitive.Choice>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function QuestionnaireChoiceDescription({ className, ...props }: React.ComponentProps<"span">) {
|
|
141
|
+
return (
|
|
142
|
+
<span
|
|
143
|
+
data-slot="questionnaire-choice-description"
|
|
144
|
+
className={cn("text-muted-foreground", className)}
|
|
145
|
+
{...props}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function QuestionnaireInput({
|
|
151
|
+
className,
|
|
152
|
+
...props
|
|
153
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Input>) {
|
|
154
|
+
return (
|
|
155
|
+
<div
|
|
156
|
+
data-slot="questionnaire-input-wrapper"
|
|
157
|
+
className="group/questionnaire-input relative w-full min-w-0"
|
|
158
|
+
>
|
|
159
|
+
<QuestionnairePrimitive.Input
|
|
160
|
+
data-slot="questionnaire-input"
|
|
161
|
+
className={cn(
|
|
162
|
+
"h-8 min-h-11 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-[color,box-shadow,background-color] outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 sm:min-h-0 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
163
|
+
"selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground",
|
|
164
|
+
className,
|
|
165
|
+
)}
|
|
166
|
+
{...props}
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function QuestionnaireError({
|
|
173
|
+
className,
|
|
174
|
+
...props
|
|
175
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Error>) {
|
|
176
|
+
return (
|
|
177
|
+
<QuestionnairePrimitive.Error
|
|
178
|
+
data-slot="questionnaire-error"
|
|
179
|
+
className={cn("mt-2 text-sm text-destructive", className)}
|
|
180
|
+
{...props}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function QuestionnaireActions({ className, ...props }: React.ComponentProps<"div">) {
|
|
186
|
+
return (
|
|
187
|
+
<div
|
|
188
|
+
data-slot="questionnaire-actions"
|
|
189
|
+
className={cn(
|
|
190
|
+
"grid min-h-11 w-full grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-2 sm:min-h-8",
|
|
191
|
+
className,
|
|
192
|
+
)}
|
|
193
|
+
{...props}
|
|
194
|
+
/>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function QuestionnairePrevious({
|
|
199
|
+
children,
|
|
200
|
+
className,
|
|
201
|
+
size = "default",
|
|
202
|
+
variant = "outline",
|
|
203
|
+
...props
|
|
204
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Previous> &
|
|
205
|
+
Pick<React.ComponentProps<typeof Button>, "size" | "variant">) {
|
|
206
|
+
return (
|
|
207
|
+
<QuestionnairePrimitive.Previous
|
|
208
|
+
data-slot="questionnaire-previous"
|
|
209
|
+
data-size={size}
|
|
210
|
+
data-variant={variant}
|
|
211
|
+
className={cn(
|
|
212
|
+
buttonVariants({ size, variant }),
|
|
213
|
+
"col-start-1 row-start-1 min-h-11 justify-self-start sm:min-h-0",
|
|
214
|
+
className,
|
|
215
|
+
)}
|
|
216
|
+
{...props}
|
|
217
|
+
>
|
|
218
|
+
{children ?? "Previous"}
|
|
219
|
+
</QuestionnairePrimitive.Previous>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function QuestionnaireSkip({
|
|
224
|
+
children,
|
|
225
|
+
className,
|
|
226
|
+
size = "default",
|
|
227
|
+
variant = "outline",
|
|
228
|
+
...props
|
|
229
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Skip> &
|
|
230
|
+
Pick<React.ComponentProps<typeof Button>, "size" | "variant">) {
|
|
231
|
+
return (
|
|
232
|
+
<QuestionnairePrimitive.Skip
|
|
233
|
+
data-slot="questionnaire-skip"
|
|
234
|
+
data-size={size}
|
|
235
|
+
data-variant={variant}
|
|
236
|
+
className={cn(
|
|
237
|
+
buttonVariants({ size, variant }),
|
|
238
|
+
"col-start-2 row-start-1 min-h-11 justify-self-end sm:min-h-0",
|
|
239
|
+
className,
|
|
240
|
+
)}
|
|
241
|
+
{...props}
|
|
242
|
+
>
|
|
243
|
+
{children ?? "Skip"}
|
|
244
|
+
</QuestionnairePrimitive.Skip>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function QuestionnaireNext({
|
|
249
|
+
children,
|
|
250
|
+
className,
|
|
251
|
+
size = "default",
|
|
252
|
+
variant = "default",
|
|
253
|
+
...props
|
|
254
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Next> &
|
|
255
|
+
Pick<React.ComponentProps<typeof Button>, "size" | "variant">) {
|
|
256
|
+
return (
|
|
257
|
+
<QuestionnairePrimitive.Next
|
|
258
|
+
data-slot="questionnaire-next"
|
|
259
|
+
data-size={size}
|
|
260
|
+
data-variant={variant}
|
|
261
|
+
className={cn(
|
|
262
|
+
buttonVariants({ size, variant }),
|
|
263
|
+
"col-start-3 row-start-1 min-h-11 justify-self-end sm:min-h-0",
|
|
264
|
+
className,
|
|
265
|
+
)}
|
|
266
|
+
{...props}
|
|
267
|
+
>
|
|
268
|
+
{children ?? "Next"}
|
|
269
|
+
</QuestionnairePrimitive.Next>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function QuestionnaireSubmit({
|
|
274
|
+
children,
|
|
275
|
+
className,
|
|
276
|
+
size = "default",
|
|
277
|
+
variant = "default",
|
|
278
|
+
...props
|
|
279
|
+
}: React.ComponentProps<typeof QuestionnairePrimitive.Submit> &
|
|
280
|
+
Pick<React.ComponentProps<typeof Button>, "size" | "variant">) {
|
|
281
|
+
return (
|
|
282
|
+
<QuestionnairePrimitive.Submit
|
|
283
|
+
data-slot="questionnaire-submit"
|
|
284
|
+
data-size={size}
|
|
285
|
+
data-variant={variant}
|
|
286
|
+
className={cn(
|
|
287
|
+
buttonVariants({ size, variant }),
|
|
288
|
+
"col-start-3 row-start-1 min-h-11 justify-self-end sm:min-h-0",
|
|
289
|
+
className,
|
|
290
|
+
)}
|
|
291
|
+
{...props}
|
|
292
|
+
>
|
|
293
|
+
{children ?? "Submit"}
|
|
294
|
+
</QuestionnairePrimitive.Submit>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export {
|
|
299
|
+
Questionnaire,
|
|
300
|
+
QuestionnaireActions,
|
|
301
|
+
QuestionnaireChoice,
|
|
302
|
+
QuestionnaireChoiceDescription,
|
|
303
|
+
QuestionnaireChoices,
|
|
304
|
+
QuestionnaireDescription,
|
|
305
|
+
QuestionnaireError,
|
|
306
|
+
QuestionnaireInput,
|
|
307
|
+
QuestionnaireItem,
|
|
308
|
+
QuestionnaireNext,
|
|
309
|
+
QuestionnairePrevious,
|
|
310
|
+
QuestionnaireProgress,
|
|
311
|
+
QuestionnaireSkip,
|
|
312
|
+
QuestionnaireSubmit,
|
|
313
|
+
QuestionnaireTitle,
|
|
314
|
+
};
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { Radio as RadioPrimitive } from "@base-ui/react/radio";
|
|
4
4
|
import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
|
|
5
|
-
|
|
6
5
|
import { cn } from "@suphark/ui/lib/utils";
|
|
7
6
|
|
|
8
7
|
function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
|
|
@@ -20,7 +19,7 @@ function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
|
|
|
20
19
|
<RadioPrimitive.Root
|
|
21
20
|
data-slot="radio-group-item"
|
|
22
21
|
className={cn(
|
|
23
|
-
"group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50
|
|
22
|
+
"group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 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 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary",
|
|
24
23
|
className,
|
|
25
24
|
)}
|
|
26
25
|
{...props}
|
|
@@ -28,7 +28,7 @@ function ResizableHandle({
|
|
|
28
28
|
<ResizablePrimitive.Separator
|
|
29
29
|
data-slot="resizable-handle"
|
|
30
30
|
className={cn(
|
|
31
|
-
"relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:
|
|
31
|
+
"relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
|
|
32
32
|
className,
|
|
33
33
|
)}
|
|
34
34
|
{...props}
|