@suphark/ui 0.19.0 → 0.20.1

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/package.json +14 -13
  3. package/scripts/audit.mjs +0 -0
  4. package/src/components/app-shell/app-shell.tsx +12 -0
  5. package/src/components/app-shell/index.ts +1 -0
  6. package/src/components/app-shell/mobile-tab-bar.tsx +104 -0
  7. package/src/components/shared/action-menu.tsx +157 -0
  8. package/src/components/shared/button/confirm-action-button.tsx +2 -0
  9. package/src/components/shared/filter-bar.tsx +108 -0
  10. package/src/components/shared/month-stepper.tsx +124 -0
  11. package/src/components/shared/row-actions.tsx +2 -0
  12. package/src/components/shared/segmented-control.tsx +73 -0
  13. package/src/components/shared/settings-layout.tsx +170 -0
  14. package/src/components/shared/setup-checklist.tsx +104 -0
  15. package/src/components/shared/simple-dialog.tsx +172 -0
  16. package/src/components/shared/simple-pagination.tsx +109 -0
  17. package/src/components/shared/simple-table.tsx +93 -0
  18. package/src/components/shared/simple-tabs.tsx +118 -0
  19. package/src/components/shared/simple-tooltip.tsx +87 -0
  20. package/src/components/shared/ui-text.tsx +28 -0
  21. package/src/components/ui/accordion.tsx +2 -2
  22. package/src/components/ui/alert-dialog.tsx +4 -4
  23. package/src/components/ui/alert.tsx +2 -2
  24. package/src/components/ui/attachment.tsx +9 -9
  25. package/src/components/ui/avatar.tsx +4 -4
  26. package/src/components/ui/badge.tsx +1 -1
  27. package/src/components/ui/breadcrumb.tsx +1 -1
  28. package/src/components/ui/bubble.tsx +123 -0
  29. package/src/components/ui/button-group.tsx +2 -2
  30. package/src/components/ui/button.tsx +6 -6
  31. package/src/components/ui/calendar.tsx +9 -9
  32. package/src/components/ui/card.tsx +3 -3
  33. package/src/components/ui/chart.tsx +2 -2
  34. package/src/components/ui/checkbox.tsx +1 -1
  35. package/src/components/ui/combobox.tsx +6 -6
  36. package/src/components/ui/command.tsx +4 -4
  37. package/src/components/ui/context-menu.tsx +7 -7
  38. package/src/components/ui/dialog.tsx +4 -4
  39. package/src/components/ui/direction.tsx +6 -0
  40. package/src/components/ui/drawer.tsx +10 -10
  41. package/src/components/ui/dropdown-menu.tsx +8 -8
  42. package/src/components/ui/empty.tsx +4 -4
  43. package/src/components/ui/field.tsx +8 -8
  44. package/src/components/ui/hover-card.tsx +1 -2
  45. package/src/components/ui/input-group.tsx +3 -3
  46. package/src/components/ui/input-otp.tsx +1 -1
  47. package/src/components/ui/input.tsx +1 -1
  48. package/src/components/ui/item.tsx +4 -4
  49. package/src/components/ui/kbd.tsx +1 -1
  50. package/src/components/ui/label.tsx +1 -1
  51. package/src/components/ui/marker.tsx +67 -0
  52. package/src/components/ui/menubar.tsx +9 -9
  53. package/src/components/ui/message-scroller.tsx +129 -0
  54. package/src/components/ui/message.tsx +84 -0
  55. package/src/components/ui/native-select.tsx +1 -1
  56. package/src/components/ui/navigation-menu.tsx +6 -6
  57. package/src/components/ui/popover.tsx +1 -1
  58. package/src/components/ui/progress.tsx +2 -3
  59. package/src/components/ui/questionnaire.tsx +314 -0
  60. package/src/components/ui/radio-group.tsx +1 -2
  61. package/src/components/ui/resizable.tsx +1 -1
  62. package/src/components/ui/select.tsx +4 -4
  63. package/src/components/ui/separator.tsx +0 -1
  64. package/src/components/ui/sheet.tsx +3 -3
  65. package/src/components/ui/sidebar.tsx +14 -14
  66. package/src/components/ui/switch.tsx +2 -3
  67. package/src/components/ui/textarea.tsx +1 -1
  68. package/src/components/ui/toast.tsx +221 -0
  69. package/src/components/ui/toggle-group.tsx +2 -2
  70. package/src/components/ui/toggle.tsx +1 -1
  71. package/src/components/ui/tooltip.tsx +0 -1
  72. package/src/index.ts +41 -0
  73. package/src/lib/month.ts +60 -0
  74. package/src/styles.css +10 -0
@@ -38,7 +38,7 @@ function DropdownMenuContent({
38
38
  <MenuPrimitive.Popup
39
39
  data-slot="dropdown-menu-content"
40
40
  className={cn(
41
- "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:fade-out-0 data-closed:zoom-out-95 z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-y-auto overflow-x-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-md outline-none ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-open:animate-in data-closed:overflow-hidden",
41
+ "z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-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:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95",
42
42
  className,
43
43
  )}
44
44
  {...props}
@@ -64,7 +64,7 @@ function DropdownMenuLabel({
64
64
  data-slot="dropdown-menu-label"
65
65
  data-inset={inset}
66
66
  className={cn(
67
- "px-1.5 py-1 font-medium text-muted-foreground text-xs data-inset:pl-7",
67
+ "px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
68
68
  className,
69
69
  )}
70
70
  {...props}
@@ -87,7 +87,7 @@ function DropdownMenuItem({
87
87
  data-inset={inset}
88
88
  data-variant={variant}
89
89
  className={cn(
90
- "group/dropdown-menu-item relative flex cursor-default select-none items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-[variant=destructive]:text-destructive data-disabled:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 data-[variant=destructive]:*:[svg]:text-destructive",
90
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
91
91
  className,
92
92
  )}
93
93
  {...props}
@@ -112,7 +112,7 @@ function DropdownMenuSubTrigger({
112
112
  data-slot="dropdown-menu-sub-trigger"
113
113
  data-inset={inset}
114
114
  className={cn(
115
- "flex cursor-default select-none items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-open:bg-accent data-popup-open:bg-accent data-inset:pl-7 data-open:text-accent-foreground data-popup-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
115
+ "flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
116
116
  className,
117
117
  )}
118
118
  {...props}
@@ -135,7 +135,7 @@ function DropdownMenuSubContent({
135
135
  <DropdownMenuContent
136
136
  data-slot="dropdown-menu-sub-content"
137
137
  className={cn(
138
- "data-[side=bottom]:slide-in-from-top-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:fade-out-0 data-closed:zoom-out-95 w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-open:animate-in",
138
+ "w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-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",
139
139
  className,
140
140
  )}
141
141
  align={align}
@@ -161,7 +161,7 @@ function DropdownMenuCheckboxItem({
161
161
  data-slot="dropdown-menu-checkbox-item"
162
162
  data-inset={inset}
163
163
  className={cn(
164
- "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
164
+ "relative flex 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 focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
165
165
  className,
166
166
  )}
167
167
  checked={checked}
@@ -197,7 +197,7 @@ function DropdownMenuRadioItem({
197
197
  data-slot="dropdown-menu-radio-item"
198
198
  data-inset={inset}
199
199
  className={cn(
200
- "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
200
+ "relative flex 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 focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
201
201
  className,
202
202
  )}
203
203
  {...props}
@@ -230,7 +230,7 @@ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"spa
230
230
  <span
231
231
  data-slot="dropdown-menu-shortcut"
232
232
  className={cn(
233
- "ml-auto text-muted-foreground text-xs tracking-widest group-focus/dropdown-menu-item:text-accent-foreground",
233
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
234
234
  className,
235
235
  )}
236
236
  {...props}
@@ -6,7 +6,7 @@ function Empty({ className, ...props }: React.ComponentProps<"div">) {
6
6
  <div
7
7
  data-slot="empty"
8
8
  className={cn(
9
- "flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 text-balance rounded-xl border-dashed p-6 text-center",
9
+ "flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance",
10
10
  className,
11
11
  )}
12
12
  {...props}
@@ -58,7 +58,7 @@ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
58
58
  return (
59
59
  <div
60
60
  data-slot="empty-title"
61
- className={cn("font-medium text-sm tracking-tight", className)}
61
+ className={cn("text-sm font-medium tracking-tight", className)}
62
62
  {...props}
63
63
  />
64
64
  );
@@ -69,7 +69,7 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
69
69
  <div
70
70
  data-slot="empty-description"
71
71
  className={cn(
72
- "text-muted-foreground text-sm/relaxed [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
72
+ "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
73
73
  className,
74
74
  )}
75
75
  {...props}
@@ -82,7 +82,7 @@ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) {
82
82
  <div
83
83
  data-slot="empty-content"
84
84
  className={cn(
85
- "flex w-full min-w-0 max-w-sm flex-col items-center gap-2.5 text-balance text-sm",
85
+ "flex w-full max-w-sm min-w-0 flex-col items-center gap-2.5 text-sm text-balance",
86
86
  className,
87
87
  )}
88
88
  {...props}
@@ -57,7 +57,7 @@ const fieldVariants = cva("group/field flex w-full gap-2 data-[invalid=true]:tex
57
57
  horizontal:
58
58
  "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
59
59
  responsive:
60
- "@md/field-group:flex-row flex-col @md/field-group:items-center *:w-full @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
60
+ "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
61
61
  },
62
62
  },
63
63
  defaultVariants: {
@@ -96,7 +96,7 @@ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)
96
96
  <Label
97
97
  data-slot="field-label"
98
98
  className={cn(
99
- "group/field-label peer/field-label flex w-fit gap-2 leading-snug has-[>[data-slot=field]]:has-[:focus-visible]:border-ring has-[>[data-slot=field]]:has-[:focus-visible]:ring-3 has-[>[data-slot=field]]:has-[:focus-visible]:ring-ring/50 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:not-has-[:disabled,[data-disabled]]:hover:bg-muted/50 *:data-[slot=field]:p-2.5 group-data-[disabled=true]/field:opacity-50 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
99
+ "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-[>[data-slot=field]]:not-has-[:disabled,[data-disabled]]:hover:bg-muted/50 has-[>[data-slot=field]]:has-[:focus-visible]:border-ring has-[>[data-slot=field]]:has-[:focus-visible]:ring-3 has-[>[data-slot=field]]:has-[:focus-visible]:ring-ring/50 *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
100
100
  "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
101
101
  className,
102
102
  )}
@@ -110,7 +110,7 @@ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
110
110
  <div
111
111
  data-slot="field-label"
112
112
  className={cn(
113
- "flex w-fit items-center gap-2 font-medium text-sm group-data-[disabled=true]/field:opacity-50",
113
+ "flex w-fit items-center gap-2 text-sm font-medium group-data-[disabled=true]/field:opacity-50",
114
114
  className,
115
115
  )}
116
116
  {...props}
@@ -123,9 +123,9 @@ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
123
123
  <p
124
124
  data-slot="field-description"
125
125
  className={cn(
126
- "text-left font-normal text-muted-foreground text-sm leading-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5",
127
- "nth-last-2:-mt-1 last:mt-0",
128
- "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
126
+ "text-left text-sm leading-normal font-normal text-muted-foreground group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5",
127
+ "last:mt-0 nth-last-2:-mt-1",
128
+ "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
129
129
  className,
130
130
  )}
131
131
  {...props}
@@ -182,7 +182,7 @@ function FieldError({
182
182
 
183
183
  const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()];
184
184
 
185
- if (uniqueErrors?.length === 1) {
185
+ if (uniqueErrors?.length == 1) {
186
186
  return uniqueErrors[0]?.message;
187
187
  }
188
188
 
@@ -201,7 +201,7 @@ function FieldError({
201
201
  <div
202
202
  role="alert"
203
203
  data-slot="field-error"
204
- className={cn("font-normal text-destructive text-sm", className)}
204
+ className={cn("text-sm font-normal text-destructive", className)}
205
205
  {...props}
206
206
  >
207
207
  {content}
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
 
3
3
  import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card";
4
-
5
4
  import { cn } from "@suphark/ui/lib/utils";
6
5
 
7
6
  function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
@@ -33,7 +32,7 @@ function HoverCardContent({
33
32
  <PreviewCardPrimitive.Popup
34
33
  data-slot="hover-card-content"
35
34
  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:fade-out-0 data-closed:zoom-out-95 z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-2.5 text-popover-foreground text-sm shadow-md outline-hidden ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-open:animate-in",
35
+ "z-50 w-64 origin-(--transform-origin) 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
36
  className,
38
37
  )}
39
38
  {...props}
@@ -13,7 +13,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
13
13
  data-slot="input-group"
14
14
  role="group"
15
15
  className={cn(
16
- "group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input outline-none transition-colors in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-start]]:h-auto has-[>textarea]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:flex-col has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot][aria-invalid=true]]:border-destructive has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
16
+ "group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
17
17
  className,
18
18
  )}
19
19
  {...props}
@@ -22,7 +22,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
22
22
  }
23
23
 
24
24
  const inputGroupAddonVariants = cva(
25
- "flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 font-medium text-muted-foreground text-sm group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
25
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
26
26
  {
27
27
  variants: {
28
28
  align: {
@@ -101,7 +101,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
101
101
  return (
102
102
  <span
103
103
  className={cn(
104
- "flex items-center gap-2 text-muted-foreground text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
104
+ "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
105
105
  className,
106
106
  )}
107
107
  {...props}
@@ -54,7 +54,7 @@ function InputOTPSlot({
54
54
  data-slot="input-otp-slot"
55
55
  data-active={isActive}
56
56
  className={cn(
57
- "relative flex size-8 items-center justify-center border-input border-y border-r text-sm outline-none transition-all first:rounded-l-lg first:border-l last:rounded-r-lg aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-3 data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
57
+ "relative flex size-8 items-center justify-center border-y border-r border-input text-sm transition-all outline-none first:rounded-l-lg first:border-l last:rounded-r-lg aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-3 data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
58
58
  className,
59
59
  )}
60
60
  {...props}
@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
8
8
  type={type}
9
9
  data-slot="input"
10
10
  className={cn(
11
- "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base outline-none transition-colors file:inline-flex file:h-6 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground 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 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 dark:disabled:bg-input/80",
11
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground 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 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
12
12
  className,
13
13
  )}
14
14
  {...props}
@@ -31,7 +31,7 @@ function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Sepa
31
31
  }
32
32
 
33
33
  const itemVariants = cva(
34
- "group/item flex w-full flex-wrap items-center rounded-lg border text-sm outline-none transition-colors duration-100 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
34
+ "group/item flex w-full flex-wrap items-center rounded-lg border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
35
35
  {
36
36
  variants: {
37
37
  variant: {
@@ -42,7 +42,7 @@ const itemVariants = cva(
42
42
  size: {
43
43
  default: "gap-2.5 px-3 py-2.5",
44
44
  sm: "gap-2.5 px-3 py-2.5",
45
- xs: "gap-2 in-data-[slot=dropdown-menu-content]:p-0 px-2.5 py-2",
45
+ xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0",
46
46
  },
47
47
  },
48
48
  defaultVariants: {
@@ -126,7 +126,7 @@ function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
126
126
  <div
127
127
  data-slot="item-title"
128
128
  className={cn(
129
- "line-clamp-1 flex w-fit items-center gap-2 font-medium text-sm leading-snug underline-offset-4",
129
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
130
130
  className,
131
131
  )}
132
132
  {...props}
@@ -139,7 +139,7 @@ function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
139
139
  <p
140
140
  data-slot="item-description"
141
141
  className={cn(
142
- "line-clamp-2 text-left font-normal text-muted-foreground text-sm leading-normal group-data-[size=xs]/item:text-xs [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
142
+ "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
143
143
  className,
144
144
  )}
145
145
  {...props}
@@ -5,7 +5,7 @@ function Kbd({ className, ...props }: React.ComponentProps<"kbd">) {
5
5
  <kbd
6
6
  data-slot="kbd"
7
7
  className={cn(
8
- "pointer-events-none inline-flex h-5 w-fit min-w-5 select-none items-center justify-center gap-1 rounded-sm bg-muted in-data-[slot=tooltip-content]:bg-background/20 px-1 font-medium font-sans in-data-[slot=tooltip-content]:text-background text-muted-foreground text-xs dark:in-data-[slot=tooltip-content]:bg-background/10 [&_svg:not([class*='size-'])]:size-3",
8
+ "pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none in-data-[slot=tooltip-content]:bg-background/20 in-data-[slot=tooltip-content]:text-background dark:in-data-[slot=tooltip-content]:bg-background/10 [&_svg:not([class*='size-'])]:size-3",
9
9
  className,
10
10
  )}
11
11
  {...props}
@@ -8,7 +8,7 @@ function Label({ className, ...props }: React.ComponentProps<"label">) {
8
8
  <label
9
9
  data-slot="label"
10
10
  className={cn(
11
- "flex select-none items-center gap-2 font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50",
11
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
12
12
  className,
13
13
  )}
14
14
  {...props}
@@ -0,0 +1,67 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cn } from "@suphark/ui/lib/utils";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+ import type * as React from "react";
6
+
7
+ const markerVariants = cva(
8
+ "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "",
13
+ separator:
14
+ "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border",
15
+ border: "border-b border-border pb-2",
16
+ },
17
+ },
18
+ },
19
+ );
20
+
21
+ function Marker({
22
+ className,
23
+ variant = "default",
24
+ render,
25
+ ...props
26
+ }: useRender.ComponentProps<"div"> & VariantProps<typeof markerVariants>) {
27
+ return useRender({
28
+ defaultTagName: "div",
29
+ props: mergeProps<"div">(
30
+ {
31
+ className: cn(markerVariants({ variant, className })),
32
+ },
33
+ props,
34
+ ),
35
+ render,
36
+ state: {
37
+ slot: "marker",
38
+ variant,
39
+ },
40
+ });
41
+ }
42
+
43
+ function MarkerIcon({ className, ...props }: React.ComponentProps<"span">) {
44
+ return (
45
+ <span
46
+ data-slot="marker-icon"
47
+ aria-hidden="true"
48
+ className={cn("size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4", className)}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+
54
+ function MarkerContent({ className, ...props }: React.ComponentProps<"span">) {
55
+ return (
56
+ <span
57
+ data-slot="marker-content"
58
+ className={cn(
59
+ "min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
60
+ className,
61
+ )}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ export { Marker, MarkerContent, MarkerIcon, markerVariants };
@@ -48,7 +48,7 @@ function MenubarTrigger({ className, ...props }: React.ComponentProps<typeof Dro
48
48
  <DropdownMenuTrigger
49
49
  data-slot="menubar-trigger"
50
50
  className={cn(
51
- "flex select-none items-center rounded-sm px-1.5 py-[2px] font-medium text-sm outline-hidden hover:bg-muted aria-expanded:bg-muted",
51
+ "flex items-center rounded-sm px-1.5 py-[2px] text-sm font-medium outline-hidden select-none hover:bg-muted aria-expanded:bg-muted",
52
52
  className,
53
53
  )}
54
54
  {...props}
@@ -70,7 +70,7 @@ function MenubarContent({
70
70
  alignOffset={alignOffset}
71
71
  sideOffset={sideOffset}
72
72
  className={cn(
73
- "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 min-w-36 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-open:animate-in",
73
+ "min-w-36 rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 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",
74
74
  className,
75
75
  )}
76
76
  {...props}
@@ -90,7 +90,7 @@ function MenubarItem({
90
90
  data-inset={inset}
91
91
  data-variant={variant}
92
92
  className={cn(
93
- "group/menubar-item gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-disabled:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive!",
93
+ "group/menubar-item gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive!",
94
94
  className,
95
95
  )}
96
96
  {...props}
@@ -112,7 +112,7 @@ function MenubarCheckboxItem({
112
112
  data-slot="menubar-checkbox-item"
113
113
  data-inset={inset}
114
114
  className={cn(
115
- "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
115
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
116
116
  className,
117
117
  )}
118
118
  checked={checked}
@@ -145,7 +145,7 @@ function MenubarRadioItem({
145
145
  data-slot="menubar-radio-item"
146
146
  data-inset={inset}
147
147
  className={cn(
148
- "relative flex cursor-default select-none items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-7 data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
148
+ "relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-1.5 pl-7 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
149
149
  className,
150
150
  )}
151
151
  {...props}
@@ -171,7 +171,7 @@ function MenubarLabel({
171
171
  <DropdownMenuLabel
172
172
  data-slot="menubar-label"
173
173
  data-inset={inset}
174
- className={cn("px-1.5 py-1 font-medium text-sm data-inset:pl-7", className)}
174
+ className={cn("px-1.5 py-1 text-sm font-medium data-inset:pl-7", className)}
175
175
  {...props}
176
176
  />
177
177
  );
@@ -198,7 +198,7 @@ function MenubarShortcut({
198
198
  <DropdownMenuShortcut
199
199
  data-slot="menubar-shortcut"
200
200
  className={cn(
201
- "ml-auto text-muted-foreground text-xs tracking-widest group-focus/menubar-item:text-accent-foreground",
201
+ "ml-auto text-xs tracking-widest text-muted-foreground group-focus/menubar-item:text-accent-foreground",
202
202
  className,
203
203
  )}
204
204
  {...props}
@@ -222,7 +222,7 @@ function MenubarSubTrigger({
222
222
  data-slot="menubar-sub-trigger"
223
223
  data-inset={inset}
224
224
  className={cn(
225
- "gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-inset:pl-7 data-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4",
225
+ "gap-1.5 rounded-md px-1.5 py-1 text-sm focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg:not([class*='size-'])]:size-4",
226
226
  className,
227
227
  )}
228
228
  {...props}
@@ -238,7 +238,7 @@ function MenubarSubContent({
238
238
  <DropdownMenuSubContent
239
239
  data-slot="menubar-sub-content"
240
240
  className={cn(
241
- "data-[side=bottom]:slide-in-from-top-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:fade-out-0 data-closed:zoom-out-95 min-w-32 rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-open:animate-in",
241
+ "min-w-32 rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-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",
242
242
  className,
243
243
  )}
244
244
  {...props}
@@ -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
+ };