@inui/design-system 0.0.0-stage → 1.22.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.
Files changed (312) hide show
  1. package/README.md +360 -2
  2. package/dist/components/ui/accordion.d.ts +44 -0
  3. package/dist/components/ui/accordion.d.ts.map +1 -0
  4. package/dist/components/ui/accordion.js +86 -0
  5. package/dist/components/ui/accordion.js.map +1 -0
  6. package/dist/components/ui/ai-avatar.d.ts +46 -0
  7. package/dist/components/ui/ai-avatar.d.ts.map +1 -0
  8. package/dist/components/ui/ai-avatar.js +43 -0
  9. package/dist/components/ui/ai-avatar.js.map +1 -0
  10. package/dist/components/ui/ai-label.d.ts +118 -0
  11. package/dist/components/ui/ai-label.d.ts.map +1 -0
  12. package/dist/components/ui/ai-label.js +184 -0
  13. package/dist/components/ui/ai-label.js.map +1 -0
  14. package/dist/components/ui/ai-sparkle.d.ts +91 -0
  15. package/dist/components/ui/ai-sparkle.d.ts.map +1 -0
  16. package/dist/components/ui/ai-sparkle.js +200 -0
  17. package/dist/components/ui/ai-sparkle.js.map +1 -0
  18. package/dist/components/ui/alert-dialog.d.ts +79 -0
  19. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  20. package/dist/components/ui/alert-dialog.js +147 -0
  21. package/dist/components/ui/alert-dialog.js.map +1 -0
  22. package/dist/components/ui/alert.d.ts +71 -0
  23. package/dist/components/ui/alert.d.ts.map +1 -0
  24. package/dist/components/ui/alert.js +108 -0
  25. package/dist/components/ui/alert.js.map +1 -0
  26. package/dist/components/ui/aspect-ratio.d.ts +30 -0
  27. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  28. package/dist/components/ui/aspect-ratio.js +40 -0
  29. package/dist/components/ui/aspect-ratio.js.map +1 -0
  30. package/dist/components/ui/attachment.d.ts +74 -0
  31. package/dist/components/ui/attachment.d.ts.map +1 -0
  32. package/dist/components/ui/attachment.js +142 -0
  33. package/dist/components/ui/attachment.js.map +1 -0
  34. package/dist/components/ui/avatar.d.ts +82 -0
  35. package/dist/components/ui/avatar.d.ts.map +1 -0
  36. package/dist/components/ui/avatar.js +123 -0
  37. package/dist/components/ui/avatar.js.map +1 -0
  38. package/dist/components/ui/badge.d.ts +130 -0
  39. package/dist/components/ui/badge.d.ts.map +1 -0
  40. package/dist/components/ui/badge.js +226 -0
  41. package/dist/components/ui/badge.js.map +1 -0
  42. package/dist/components/ui/breadcrumb.d.ts +43 -0
  43. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  44. package/dist/components/ui/breadcrumb.js +98 -0
  45. package/dist/components/ui/breadcrumb.js.map +1 -0
  46. package/dist/components/ui/browser-tabs.d.ts +218 -0
  47. package/dist/components/ui/browser-tabs.d.ts.map +1 -0
  48. package/dist/components/ui/browser-tabs.js +528 -0
  49. package/dist/components/ui/browser-tabs.js.map +1 -0
  50. package/dist/components/ui/bubble.d.ts +80 -0
  51. package/dist/components/ui/bubble.d.ts.map +1 -0
  52. package/dist/components/ui/bubble.js +235 -0
  53. package/dist/components/ui/bubble.js.map +1 -0
  54. package/dist/components/ui/button-group.d.ts +60 -0
  55. package/dist/components/ui/button-group.d.ts.map +1 -0
  56. package/dist/components/ui/button-group.js +89 -0
  57. package/dist/components/ui/button-group.js.map +1 -0
  58. package/dist/components/ui/button.d.ts +157 -0
  59. package/dist/components/ui/button.d.ts.map +1 -0
  60. package/dist/components/ui/button.js +144 -0
  61. package/dist/components/ui/button.js.map +1 -0
  62. package/dist/components/ui/calendar.d.ts +57 -0
  63. package/dist/components/ui/calendar.d.ts.map +1 -0
  64. package/dist/components/ui/calendar.js +163 -0
  65. package/dist/components/ui/calendar.js.map +1 -0
  66. package/dist/components/ui/card.d.ts +96 -0
  67. package/dist/components/ui/card.d.ts.map +1 -0
  68. package/dist/components/ui/card.js +131 -0
  69. package/dist/components/ui/card.js.map +1 -0
  70. package/dist/components/ui/carousel.d.ts +86 -0
  71. package/dist/components/ui/carousel.d.ts.map +1 -0
  72. package/dist/components/ui/carousel.js +207 -0
  73. package/dist/components/ui/carousel.js.map +1 -0
  74. package/dist/components/ui/checkbox.d.ts +54 -0
  75. package/dist/components/ui/checkbox.d.ts.map +1 -0
  76. package/dist/components/ui/checkbox.js +78 -0
  77. package/dist/components/ui/checkbox.js.map +1 -0
  78. package/dist/components/ui/collapsible.d.ts +45 -0
  79. package/dist/components/ui/collapsible.d.ts.map +1 -0
  80. package/dist/components/ui/collapsible.js +65 -0
  81. package/dist/components/ui/collapsible.js.map +1 -0
  82. package/dist/components/ui/combobox.d.ts +111 -0
  83. package/dist/components/ui/combobox.d.ts.map +1 -0
  84. package/dist/components/ui/combobox.js +264 -0
  85. package/dist/components/ui/combobox.js.map +1 -0
  86. package/dist/components/ui/command.d.ts +71 -0
  87. package/dist/components/ui/command.d.ts.map +1 -0
  88. package/dist/components/ui/command.js +133 -0
  89. package/dist/components/ui/command.js.map +1 -0
  90. package/dist/components/ui/context-menu.d.ts +70 -0
  91. package/dist/components/ui/context-menu.d.ts.map +1 -0
  92. package/dist/components/ui/context-menu.js +163 -0
  93. package/dist/components/ui/context-menu.js.map +1 -0
  94. package/dist/components/ui/count-badge.d.ts +40 -0
  95. package/dist/components/ui/count-badge.d.ts.map +1 -0
  96. package/dist/components/ui/count-badge.js +43 -0
  97. package/dist/components/ui/count-badge.js.map +1 -0
  98. package/dist/components/ui/data-table.d.ts +1026 -0
  99. package/dist/components/ui/data-table.d.ts.map +1 -0
  100. package/dist/components/ui/data-table.js +3423 -0
  101. package/dist/components/ui/data-table.js.map +1 -0
  102. package/dist/components/ui/dialog.d.ts +73 -0
  103. package/dist/components/ui/dialog.d.ts.map +1 -0
  104. package/dist/components/ui/dialog.js +145 -0
  105. package/dist/components/ui/dialog.js.map +1 -0
  106. package/dist/components/ui/direction.d.ts +35 -0
  107. package/dist/components/ui/direction.d.ts.map +1 -0
  108. package/dist/components/ui/direction.js +35 -0
  109. package/dist/components/ui/direction.js.map +1 -0
  110. package/dist/components/ui/drawer.d.ts +53 -0
  111. package/dist/components/ui/drawer.d.ts.map +1 -0
  112. package/dist/components/ui/drawer.js +115 -0
  113. package/dist/components/ui/drawer.js.map +1 -0
  114. package/dist/components/ui/dropdown-menu.d.ts +75 -0
  115. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  116. package/dist/components/ui/dropdown-menu.js +173 -0
  117. package/dist/components/ui/dropdown-menu.js.map +1 -0
  118. package/dist/components/ui/dropzone.d.ts +141 -0
  119. package/dist/components/ui/dropzone.d.ts.map +1 -0
  120. package/dist/components/ui/dropzone.js +257 -0
  121. package/dist/components/ui/dropzone.js.map +1 -0
  122. package/dist/components/ui/empty.d.ts +94 -0
  123. package/dist/components/ui/empty.d.ts.map +1 -0
  124. package/dist/components/ui/empty.js +149 -0
  125. package/dist/components/ui/empty.js.map +1 -0
  126. package/dist/components/ui/field.d.ts +122 -0
  127. package/dist/components/ui/field.d.ts.map +1 -0
  128. package/dist/components/ui/field.js +254 -0
  129. package/dist/components/ui/field.js.map +1 -0
  130. package/dist/components/ui/hover-card.d.ts +51 -0
  131. package/dist/components/ui/hover-card.d.ts.map +1 -0
  132. package/dist/components/ui/hover-card.js +101 -0
  133. package/dist/components/ui/hover-card.js.map +1 -0
  134. package/dist/components/ui/input-group.d.ts +62 -0
  135. package/dist/components/ui/input-group.d.ts.map +1 -0
  136. package/dist/components/ui/input-group.js +115 -0
  137. package/dist/components/ui/input-group.js.map +1 -0
  138. package/dist/components/ui/input-otp.d.ts +52 -0
  139. package/dist/components/ui/input-otp.d.ts.map +1 -0
  140. package/dist/components/ui/input-otp.js +89 -0
  141. package/dist/components/ui/input-otp.js.map +1 -0
  142. package/dist/components/ui/input.d.ts +47 -0
  143. package/dist/components/ui/input.d.ts.map +1 -0
  144. package/dist/components/ui/input.js +47 -0
  145. package/dist/components/ui/input.js.map +1 -0
  146. package/dist/components/ui/item.d.ts +74 -0
  147. package/dist/components/ui/item.d.ts.map +1 -0
  148. package/dist/components/ui/item.js +176 -0
  149. package/dist/components/ui/item.js.map +1 -0
  150. package/dist/components/ui/kbd.d.ts +41 -0
  151. package/dist/components/ui/kbd.d.ts.map +1 -0
  152. package/dist/components/ui/kbd.js +58 -0
  153. package/dist/components/ui/kbd.js.map +1 -0
  154. package/dist/components/ui/key-value-pair.d.ts +56 -0
  155. package/dist/components/ui/key-value-pair.d.ts.map +1 -0
  156. package/dist/components/ui/key-value-pair.js +110 -0
  157. package/dist/components/ui/key-value-pair.js.map +1 -0
  158. package/dist/components/ui/label.d.ts +83 -0
  159. package/dist/components/ui/label.d.ts.map +1 -0
  160. package/dist/components/ui/label.js +85 -0
  161. package/dist/components/ui/label.js.map +1 -0
  162. package/dist/components/ui/marker.d.ts +54 -0
  163. package/dist/components/ui/marker.d.ts.map +1 -0
  164. package/dist/components/ui/marker.js +79 -0
  165. package/dist/components/ui/marker.js.map +1 -0
  166. package/dist/components/ui/menubar.d.ts +72 -0
  167. package/dist/components/ui/menubar.d.ts.map +1 -0
  168. package/dist/components/ui/menubar.js +174 -0
  169. package/dist/components/ui/menubar.js.map +1 -0
  170. package/dist/components/ui/message-scroller.d.ts +53 -0
  171. package/dist/components/ui/message-scroller.d.ts.map +1 -0
  172. package/dist/components/ui/message-scroller.js +95 -0
  173. package/dist/components/ui/message-scroller.js.map +1 -0
  174. package/dist/components/ui/message.d.ts +63 -0
  175. package/dist/components/ui/message.d.ts.map +1 -0
  176. package/dist/components/ui/message.js +92 -0
  177. package/dist/components/ui/message.js.map +1 -0
  178. package/dist/components/ui/meta-list.d.ts +55 -0
  179. package/dist/components/ui/meta-list.d.ts.map +1 -0
  180. package/dist/components/ui/meta-list.js +75 -0
  181. package/dist/components/ui/meta-list.js.map +1 -0
  182. package/dist/components/ui/native-select.d.ts +51 -0
  183. package/dist/components/ui/native-select.d.ts.map +1 -0
  184. package/dist/components/ui/native-select.js +75 -0
  185. package/dist/components/ui/native-select.js.map +1 -0
  186. package/dist/components/ui/navigation-menu.d.ts +56 -0
  187. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  188. package/dist/components/ui/navigation-menu.js +116 -0
  189. package/dist/components/ui/navigation-menu.js.map +1 -0
  190. package/dist/components/ui/page-header.d.ts +223 -0
  191. package/dist/components/ui/page-header.d.ts.map +1 -0
  192. package/dist/components/ui/page-header.js +233 -0
  193. package/dist/components/ui/page-header.js.map +1 -0
  194. package/dist/components/ui/pagination.d.ts +68 -0
  195. package/dist/components/ui/pagination.d.ts.map +1 -0
  196. package/dist/components/ui/pagination.js +145 -0
  197. package/dist/components/ui/pagination.js.map +1 -0
  198. package/dist/components/ui/popover.d.ts +61 -0
  199. package/dist/components/ui/popover.d.ts.map +1 -0
  200. package/dist/components/ui/popover.js +144 -0
  201. package/dist/components/ui/popover.js.map +1 -0
  202. package/dist/components/ui/progress.d.ts +35 -0
  203. package/dist/components/ui/progress.d.ts.map +1 -0
  204. package/dist/components/ui/progress.js +46 -0
  205. package/dist/components/ui/progress.js.map +1 -0
  206. package/dist/components/ui/questionnaire.d.ts +92 -0
  207. package/dist/components/ui/questionnaire.d.ts.map +1 -0
  208. package/dist/components/ui/questionnaire.js +277 -0
  209. package/dist/components/ui/questionnaire.js.map +1 -0
  210. package/dist/components/ui/radio-group.d.ts +50 -0
  211. package/dist/components/ui/radio-group.d.ts.map +1 -0
  212. package/dist/components/ui/radio-group.js +65 -0
  213. package/dist/components/ui/radio-group.js.map +1 -0
  214. package/dist/components/ui/resizable.d.ts +44 -0
  215. package/dist/components/ui/resizable.d.ts.map +1 -0
  216. package/dist/components/ui/resizable.js +73 -0
  217. package/dist/components/ui/resizable.js.map +1 -0
  218. package/dist/components/ui/scroll-area.d.ts +55 -0
  219. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  220. package/dist/components/ui/scroll-area.js +72 -0
  221. package/dist/components/ui/scroll-area.js.map +1 -0
  222. package/dist/components/ui/select.d.ts +274 -0
  223. package/dist/components/ui/select.d.ts.map +1 -0
  224. package/dist/components/ui/select.js +609 -0
  225. package/dist/components/ui/select.js.map +1 -0
  226. package/dist/components/ui/separator.d.ts +31 -0
  227. package/dist/components/ui/separator.d.ts.map +1 -0
  228. package/dist/components/ui/separator.js +38 -0
  229. package/dist/components/ui/separator.js.map +1 -0
  230. package/dist/components/ui/sheet.d.ts +59 -0
  231. package/dist/components/ui/sheet.d.ts.map +1 -0
  232. package/dist/components/ui/sheet.js +128 -0
  233. package/dist/components/ui/sheet.js.map +1 -0
  234. package/dist/components/ui/sidebar.d.ts +166 -0
  235. package/dist/components/ui/sidebar.d.ts.map +1 -0
  236. package/dist/components/ui/sidebar.js +512 -0
  237. package/dist/components/ui/sidebar.js.map +1 -0
  238. package/dist/components/ui/skeleton.d.ts +35 -0
  239. package/dist/components/ui/skeleton.d.ts.map +1 -0
  240. package/dist/components/ui/skeleton.js +46 -0
  241. package/dist/components/ui/skeleton.js.map +1 -0
  242. package/dist/components/ui/slider.d.ts +39 -0
  243. package/dist/components/ui/slider.d.ts.map +1 -0
  244. package/dist/components/ui/slider.js +75 -0
  245. package/dist/components/ui/slider.js.map +1 -0
  246. package/dist/components/ui/sonner.d.ts +56 -0
  247. package/dist/components/ui/sonner.d.ts.map +1 -0
  248. package/dist/components/ui/sonner.js +96 -0
  249. package/dist/components/ui/sonner.js.map +1 -0
  250. package/dist/components/ui/spinner.d.ts +37 -0
  251. package/dist/components/ui/spinner.d.ts.map +1 -0
  252. package/dist/components/ui/spinner.js +51 -0
  253. package/dist/components/ui/spinner.js.map +1 -0
  254. package/dist/components/ui/stepper.d.ts +84 -0
  255. package/dist/components/ui/stepper.d.ts.map +1 -0
  256. package/dist/components/ui/stepper.js +145 -0
  257. package/dist/components/ui/stepper.js.map +1 -0
  258. package/dist/components/ui/switch.d.ts +36 -0
  259. package/dist/components/ui/switch.d.ts.map +1 -0
  260. package/dist/components/ui/switch.js +44 -0
  261. package/dist/components/ui/switch.js.map +1 -0
  262. package/dist/components/ui/table.d.ts +80 -0
  263. package/dist/components/ui/table.d.ts.map +1 -0
  264. package/dist/components/ui/table.js +130 -0
  265. package/dist/components/ui/table.js.map +1 -0
  266. package/dist/components/ui/tabs.d.ts +87 -0
  267. package/dist/components/ui/tabs.d.ts.map +1 -0
  268. package/dist/components/ui/tabs.js +128 -0
  269. package/dist/components/ui/tabs.js.map +1 -0
  270. package/dist/components/ui/textarea.d.ts +35 -0
  271. package/dist/components/ui/textarea.d.ts.map +1 -0
  272. package/dist/components/ui/textarea.js +38 -0
  273. package/dist/components/ui/textarea.js.map +1 -0
  274. package/dist/components/ui/time-picker.d.ts +58 -0
  275. package/dist/components/ui/time-picker.d.ts.map +1 -0
  276. package/dist/components/ui/time-picker.js +188 -0
  277. package/dist/components/ui/time-picker.js.map +1 -0
  278. package/dist/components/ui/toggle-group.d.ts +52 -0
  279. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  280. package/dist/components/ui/toggle-group.js +94 -0
  281. package/dist/components/ui/toggle-group.js.map +1 -0
  282. package/dist/components/ui/toggle.d.ts +50 -0
  283. package/dist/components/ui/toggle.d.ts.map +1 -0
  284. package/dist/components/ui/toggle.js +70 -0
  285. package/dist/components/ui/toggle.js.map +1 -0
  286. package/dist/components/ui/tooltip.d.ts +51 -0
  287. package/dist/components/ui/tooltip.d.ts.map +1 -0
  288. package/dist/components/ui/tooltip.js +78 -0
  289. package/dist/components/ui/tooltip.js.map +1 -0
  290. package/dist/hooks/use-dark-mode.d.ts +2 -0
  291. package/dist/hooks/use-dark-mode.d.ts.map +1 -0
  292. package/dist/hooks/use-dark-mode.js +36 -0
  293. package/dist/hooks/use-dark-mode.js.map +1 -0
  294. package/dist/hooks/use-mobile.d.ts +2 -0
  295. package/dist/hooks/use-mobile.d.ts.map +1 -0
  296. package/dist/hooks/use-mobile.js +20 -0
  297. package/dist/hooks/use-mobile.js.map +1 -0
  298. package/dist/index.d.ts +88 -0
  299. package/dist/index.d.ts.map +1 -0
  300. package/dist/index.js +77 -0
  301. package/dist/lib/scope.d.ts +64 -0
  302. package/dist/lib/scope.d.ts.map +1 -0
  303. package/dist/lib/scope.js +74 -0
  304. package/dist/lib/scope.js.map +1 -0
  305. package/dist/lib/utils.d.ts +3 -0
  306. package/dist/lib/utils.d.ts.map +1 -0
  307. package/dist/lib/utils.js +11 -0
  308. package/dist/lib/utils.js.map +1 -0
  309. package/dist/styles.css +2 -0
  310. package/dist/theme-tokens.css +537 -0
  311. package/dist/theme.css +417 -0
  312. package/package.json +103 -3
@@ -0,0 +1,95 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { Button } from "./button.js";
3
+ import "react";
4
+ import { ArrowDownIcon } from "lucide-react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { MessageScroller as MessageScroller$1, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility } from "@shadcn/react/message-scroller";
7
+ //#region src/components/ui/message-scroller.tsx
8
+ function MessageScrollerProvider(props) {
9
+ return /* @__PURE__ */ jsx(MessageScroller$1.Provider, { ...props });
10
+ }
11
+ function MessageScroller({ className, ...props }) {
12
+ return /* @__PURE__ */ jsx(MessageScroller$1.Root, {
13
+ "data-slot": "message-scroller",
14
+ className: cn("group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden", className),
15
+ ...props
16
+ });
17
+ }
18
+ function MessageScrollerViewport({ className, ...props }) {
19
+ return /* @__PURE__ */ jsx(MessageScroller$1.Viewport, {
20
+ "data-slot": "message-scroller-viewport",
21
+ className: cn("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", className),
22
+ ...props
23
+ });
24
+ }
25
+ function MessageScrollerContent({ className, ...props }) {
26
+ return /* @__PURE__ */ jsx(MessageScroller$1.Content, {
27
+ "data-slot": "message-scroller-content",
28
+ className: cn("flex h-max min-h-full flex-col gap-6", className),
29
+ ...props
30
+ });
31
+ }
32
+ function MessageScrollerItem({ className, scrollAnchor = false, ...props }) {
33
+ return /* @__PURE__ */ jsx(MessageScroller$1.Item, {
34
+ "data-slot": "message-scroller-item",
35
+ scrollAnchor,
36
+ className: cn("min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]", className),
37
+ ...props
38
+ });
39
+ }
40
+ function MessageScrollerButton({ direction = "end", className, children, render, variant = "secondary", size = "sm", ...props }) {
41
+ return /* @__PURE__ */ jsx(MessageScroller$1.Button, {
42
+ "data-slot": "message-scroller-button",
43
+ "data-direction": direction,
44
+ "data-variant": variant,
45
+ "data-size": size,
46
+ direction,
47
+ className: cn("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 in-data-[slot=card-content]:bg-card in-data-[slot=dialog-content]:bg-popover in-data-[slot=popover-content]:bg-popover in-data-[slot=sheet-content]:bg-popover 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", className),
48
+ render: render ?? /* @__PURE__ */ jsx(Button, {
49
+ variant,
50
+ size,
51
+ iconOnly: true,
52
+ "aria-label": direction === "end" ? "Scroll to end" : "Scroll to start"
53
+ }),
54
+ ...props,
55
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ArrowDownIcon, {}), /* @__PURE__ */ jsx("span", {
56
+ className: "sr-only",
57
+ children: direction === "end" ? "Scroll to end" : "Scroll to start"
58
+ })] })
59
+ });
60
+ }
61
+ /**
62
+ * WHEN TO USE
63
+ * - Chat transcripts, live logs, or any list where new content should keep the newest item in view
64
+ * - Streaming or incrementally-appended content
65
+ *
66
+ * NOT WHEN
67
+ * - Static, non-growing lists — use ScrollArea
68
+ * - Feeds anchored to the top (e.g. paginated results) — this only pins to one end anchor
69
+ *
70
+ * KEY RULES
71
+ * - Requires MessageScrollerProvider as an ancestor — MessageScroller does nothing useful without it
72
+ * - Exactly one MessageScrollerItem should carry `scrollAnchor` (usually the last rendered item) — that's what the viewport pins to and what the jump button targets
73
+ * - MessageScrollerButton `direction`: "end" (default, jump to newest) or "start"
74
+ * - useMessageScroller / useMessageScrollerScrollable / useMessageScrollerVisibility expose scroll state for custom UI — reach for these before wiring a manual scroll listener
75
+ *
76
+ * USAGE
77
+ * <MessageScrollerProvider>
78
+ * <MessageScroller className="h-80 rounded-xl border">
79
+ * <MessageScrollerViewport>
80
+ * <MessageScrollerContent>
81
+ * {messages.map((m, i) => (
82
+ * <MessageScrollerItem key={m.id} scrollAnchor={i === messages.length - 1}>
83
+ * <Message align={m.align}>{m.body}</Message>
84
+ * </MessageScrollerItem>
85
+ * ))}
86
+ * </MessageScrollerContent>
87
+ * </MessageScrollerViewport>
88
+ * <MessageScrollerButton direction="end" />
89
+ * </MessageScroller>
90
+ * </MessageScrollerProvider>
91
+ */
92
+ //#endregion
93
+ export { MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility };
94
+
95
+ //# sourceMappingURL=message-scroller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-scroller.js","names":[],"sources":["../../../src/components/ui/message-scroller.tsx"],"sourcesContent":["/**\n * MessageScroller — auto-sticking scroll container for chat transcripts and log streams.\n *\n * Pins to the newest item by default and reveals a jump-to-latest\n * MessageScrollerButton once the user scrolls away from it. Wraps the\n * `@shadcn/react` message-scroller primitive. Render Message or Bubble\n * items inside MessageScrollerItem; mark the item the viewport should pin\n * to with `scrollAnchor` (typically the last item).\n */\n\nimport * as React from \"react\"\nimport {\n MessageScroller as MessageScrollerPrimitive,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n} from \"@shadcn/react/message-scroller\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button, type TextButtonSize } from \"@/components/ui/button\"\nimport { ArrowDownIcon } from \"lucide-react\"\n\nfunction MessageScrollerProvider(\n props: React.ComponentProps<typeof MessageScrollerPrimitive.Provider>\n) {\n return <MessageScrollerPrimitive.Provider {...props} />\n}\n\nfunction MessageScroller({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Root>) {\n return (\n <MessageScrollerPrimitive.Root\n data-slot=\"message-scroller\"\n className={cn(\n \"group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerViewport({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Viewport>) {\n return (\n <MessageScrollerPrimitive.Viewport\n data-slot=\"message-scroller-viewport\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerContent({\n className,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Content>) {\n return (\n <MessageScrollerPrimitive.Content\n data-slot=\"message-scroller-content\"\n className={cn(\"flex h-max min-h-full flex-col gap-6\", className)}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerItem({\n className,\n scrollAnchor = false,\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Item>) {\n return (\n <MessageScrollerPrimitive.Item\n data-slot=\"message-scroller-item\"\n scrollAnchor={scrollAnchor}\n className={cn(\n \"min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageScrollerButton({\n direction = \"end\",\n className,\n children,\n render,\n variant = \"secondary\",\n size = \"sm\",\n ...props\n}: React.ComponentProps<typeof MessageScrollerPrimitive.Button> &\n Pick<React.ComponentProps<typeof Button>, \"variant\"> & {\n size?: TextButtonSize\n }) {\n return (\n <MessageScrollerPrimitive.Button\n data-slot=\"message-scroller-button\"\n data-direction={direction}\n data-variant={variant}\n data-size={size}\n direction={direction}\n className={cn(\n \"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 in-data-[slot=card-content]:bg-card in-data-[slot=dialog-content]:bg-popover in-data-[slot=popover-content]:bg-popover in-data-[slot=sheet-content]:bg-popover 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\",\n className\n )}\n render={\n render ?? (\n <Button\n variant={variant}\n size={size}\n iconOnly\n aria-label={\n direction === \"end\" ? \"Scroll to end\" : \"Scroll to start\"\n }\n />\n )\n }\n {...props}\n >\n {children ?? (\n <>\n <ArrowDownIcon />\n <span className=\"sr-only\">\n {direction === \"end\" ? \"Scroll to end\" : \"Scroll to start\"}\n </span>\n </>\n )}\n </MessageScrollerPrimitive.Button>\n )\n}\n\nexport {\n MessageScrollerProvider,\n MessageScroller,\n MessageScrollerViewport,\n MessageScrollerContent,\n MessageScrollerItem,\n MessageScrollerButton,\n useMessageScroller,\n useMessageScrollerScrollable,\n useMessageScrollerVisibility,\n}\n\n/**\n * WHEN TO USE\n * - Chat transcripts, live logs, or any list where new content should keep the newest item in view\n * - Streaming or incrementally-appended content\n *\n * NOT WHEN\n * - Static, non-growing lists — use ScrollArea\n * - Feeds anchored to the top (e.g. paginated results) — this only pins to one end anchor\n *\n * KEY RULES\n * - Requires MessageScrollerProvider as an ancestor — MessageScroller does nothing useful without it\n * - Exactly one MessageScrollerItem should carry `scrollAnchor` (usually the last rendered item) — that's what the viewport pins to and what the jump button targets\n * - MessageScrollerButton `direction`: \"end\" (default, jump to newest) or \"start\"\n * - useMessageScroller / useMessageScrollerScrollable / useMessageScrollerVisibility expose scroll state for custom UI — reach for these before wiring a manual scroll listener\n *\n * USAGE\n * <MessageScrollerProvider>\n * <MessageScroller className=\"h-80 rounded-xl border\">\n * <MessageScrollerViewport>\n * <MessageScrollerContent>\n * {messages.map((m, i) => (\n * <MessageScrollerItem key={m.id} scrollAnchor={i === messages.length - 1}>\n * <Message align={m.align}>{m.body}</Message>\n * </MessageScrollerItem>\n * ))}\n * </MessageScrollerContent>\n * </MessageScrollerViewport>\n * <MessageScrollerButton direction=\"end\" />\n * </MessageScroller>\n * </MessageScrollerProvider>\n */\n"],"mappings":";;;;;;;AAsBA,SAAS,wBACP,OACA;CACA,OAAO,oBAAC,kBAAyB,UAA1B,EAAmC,GAAI,MAAQ,CAAA;AACxD;AAEA,SAAS,gBAAgB,EACvB,WACA,GAAG,SAC0D;CAC7D,OACE,oBAAC,kBAAyB,MAA1B;EACE,aAAU;EACV,WAAW,GACT,mFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,wBAAwB,EAC/B,WACA,GAAG,SAC8D;CACjE,OACE,oBAAC,kBAAyB,UAA1B;EACE,aAAU;EACV,WAAW,GACT,mOACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAAC,kBAAyB,SAA1B;EACE,aAAU;EACV,WAAW,GAAG,wCAAwC,SAAS;EAC/D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,WACA,eAAe,OACf,GAAG,SAC0D;CAC7D,OACE,oBAAC,kBAAyB,MAA1B;EACE,aAAU;EACI;EACd,WAAW,GACT,kFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,YAAY,OACZ,WACA,UACA,QACA,UAAU,aACV,OAAO,MACP,GAAG,SAIA;CACH,OACE,oBAAC,kBAAyB,QAA1B;EACE,aAAU;EACV,kBAAgB;EAChB,gBAAc;EACd,aAAW;EACA;EACX,WAAW,GACT,w4BACA,SACF;EACA,QACE,UACE,oBAAC,QAAD;GACW;GACH;GACN,UAAA;GACA,cACE,cAAc,QAAQ,kBAAkB;EAE3C,CAAA;EAGL,GAAI;EAEH,UAAA,YACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAChB,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,cAAc,QAAQ,kBAAkB;EACrC,CAAA,CACN,EAAA,CAAA;CAE2B,CAAA;AAErC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Message — structured chat message with avatar, author, and timestamp slots.
3
+ *
4
+ * MessageAvatar, MessageHeader (author), MessageContent (body), and
5
+ * MessageFooter (timestamp) compose around a shared `align` value.
6
+ * MessageGroup stacks a thread. MessageContent also self-aligns any direct
7
+ * data-slot child when `align="end"`, so a Bubble can be dropped inside it to
8
+ * get avatar/header/footer chrome around a colored bubble surface. For long
9
+ * or streaming threads that must stay pinned to the newest message, wrap the
10
+ * list in MessageScroller instead of a plain scrolling div.
11
+ */
12
+ import * as React from "react";
13
+ declare function MessageGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
14
+ declare function Message({ className, align, ...props }: React.ComponentProps<"div"> & {
15
+ align?: "start" | "end";
16
+ }): React.JSX.Element;
17
+ declare function MessageAvatar({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
18
+ declare function MessageContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
19
+ declare function MessageHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
20
+ declare function MessageFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
21
+ export { MessageGroup, Message, MessageAvatar, MessageContent, MessageFooter, MessageHeader, };
22
+ /**
23
+ * WHEN TO USE
24
+ * - Chat threads where each turn needs an avatar, author name, and/or timestamp
25
+ * - Multi-participant conversations where "who said this" must be visible
26
+ *
27
+ * NOT WHEN
28
+ * - Bare speech bubbles with no metadata — use Bubble
29
+ * - Long scrolling threads that must auto-stick to the newest message — wrap in MessageScroller rather than a plain overflow-y-auto container
30
+ *
31
+ * KEY RULES
32
+ * - align: "start" (default) or "end" — reverses the avatar/content order via flex-row-reverse
33
+ * - Every slot is optional: omit MessageAvatar/MessageHeader/MessageFooter freely per message
34
+ * - MessageAvatar is `self-start` — it aligns with the first content line (the bubble/text), not the last (a MessageFooter timestamp), regardless of gap or footer text length
35
+ * - MessageGroup only provides gap-2 stacking — no scrolling or auto-anchoring of its own
36
+ * - MessageAvatar is for group threads specifically — once there are 3+ possible senders,
37
+ * it's what says who's speaking. A 1:1 conversation doesn't need it: the container
38
+ * already tells the user who the other party is, and `align` alone already distinguishes
39
+ * your own messages from theirs — omit MessageAvatar (and MessageHeader) entirely there
40
+ * - Per-message hover actions (e.g. a "Copy"/feedback row under an AI reply) are a plain
41
+ * composition, not a dedicated slot: give the action row `opacity-0
42
+ * group-hover/message:opacity-100 group-focus-within/message:opacity-100` — Message's own
43
+ * root already carries `group/message`, so no extra wrapper is needed
44
+ *
45
+ * USAGE
46
+ * <MessageGroup>
47
+ * <Message align="start">
48
+ * <MessageAvatar><Avatar><AvatarFallback>AL</AvatarFallback></Avatar></MessageAvatar>
49
+ * <MessageContent>
50
+ * <MessageHeader>Ada Lovelace</MessageHeader>
51
+ * Where should brand overrides live?
52
+ * <MessageFooter>9:41 AM</MessageFooter>
53
+ * </MessageContent>
54
+ * </Message>
55
+ * <Message align="end">
56
+ * <MessageContent>
57
+ * <MessageHeader>You</MessageHeader>
58
+ * In theme.css — it is the single source of truth for the theme.
59
+ * </MessageContent>
60
+ * </Message>
61
+ * </MessageGroup>
62
+ */
63
+ //# sourceMappingURL=message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/components/ui/message.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQzE;AAED,iBAAS,OAAO,CAAC,EACf,SAAS,EACT,KAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,KAAK,CAAA;CAAE,qBAY3D;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAwB1E;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW3E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW1E;AAED,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW1E;AAED,OAAO,EACL,YAAY,EACZ,OAAO,EACP,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,GACd,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG"}
@@ -0,0 +1,92 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/components/ui/message.tsx
5
+ function MessageGroup({ className, ...props }) {
6
+ return /* @__PURE__ */ jsx("div", {
7
+ "data-slot": "message-group",
8
+ className: cn("flex min-w-0 flex-col gap-2", className),
9
+ ...props
10
+ });
11
+ }
12
+ function Message({ className, align = "start", ...props }) {
13
+ return /* @__PURE__ */ jsx("div", {
14
+ "data-slot": "message",
15
+ "data-align": align,
16
+ className: cn("group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse", className),
17
+ ...props
18
+ });
19
+ }
20
+ function MessageAvatar({ className, ...props }) {
21
+ return /* @__PURE__ */ jsx("div", {
22
+ "data-slot": "message-avatar",
23
+ className: cn("flex w-fit shrink-0 items-center justify-center self-start overflow-hidden rounded-full", className),
24
+ ...props
25
+ });
26
+ }
27
+ function MessageContent({ className, ...props }) {
28
+ return /* @__PURE__ */ jsx("div", {
29
+ "data-slot": "message-content",
30
+ className: cn("flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end", className),
31
+ ...props
32
+ });
33
+ }
34
+ function MessageHeader({ className, ...props }) {
35
+ return /* @__PURE__ */ jsx("div", {
36
+ "data-slot": "message-header",
37
+ className: cn("flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[emphasis=ghost]/message:px-0", className),
38
+ ...props
39
+ });
40
+ }
41
+ function MessageFooter({ className, ...props }) {
42
+ return /* @__PURE__ */ jsx("div", {
43
+ "data-slot": "message-footer",
44
+ className: cn("flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[emphasis=ghost]/message:px-0 group-data-[align=end]/message:justify-end", className),
45
+ ...props
46
+ });
47
+ }
48
+ /**
49
+ * WHEN TO USE
50
+ * - Chat threads where each turn needs an avatar, author name, and/or timestamp
51
+ * - Multi-participant conversations where "who said this" must be visible
52
+ *
53
+ * NOT WHEN
54
+ * - Bare speech bubbles with no metadata — use Bubble
55
+ * - Long scrolling threads that must auto-stick to the newest message — wrap in MessageScroller rather than a plain overflow-y-auto container
56
+ *
57
+ * KEY RULES
58
+ * - align: "start" (default) or "end" — reverses the avatar/content order via flex-row-reverse
59
+ * - Every slot is optional: omit MessageAvatar/MessageHeader/MessageFooter freely per message
60
+ * - MessageAvatar is `self-start` — it aligns with the first content line (the bubble/text), not the last (a MessageFooter timestamp), regardless of gap or footer text length
61
+ * - MessageGroup only provides gap-2 stacking — no scrolling or auto-anchoring of its own
62
+ * - MessageAvatar is for group threads specifically — once there are 3+ possible senders,
63
+ * it's what says who's speaking. A 1:1 conversation doesn't need it: the container
64
+ * already tells the user who the other party is, and `align` alone already distinguishes
65
+ * your own messages from theirs — omit MessageAvatar (and MessageHeader) entirely there
66
+ * - Per-message hover actions (e.g. a "Copy"/feedback row under an AI reply) are a plain
67
+ * composition, not a dedicated slot: give the action row `opacity-0
68
+ * group-hover/message:opacity-100 group-focus-within/message:opacity-100` — Message's own
69
+ * root already carries `group/message`, so no extra wrapper is needed
70
+ *
71
+ * USAGE
72
+ * <MessageGroup>
73
+ * <Message align="start">
74
+ * <MessageAvatar><Avatar><AvatarFallback>AL</AvatarFallback></Avatar></MessageAvatar>
75
+ * <MessageContent>
76
+ * <MessageHeader>Ada Lovelace</MessageHeader>
77
+ * Where should brand overrides live?
78
+ * <MessageFooter>9:41 AM</MessageFooter>
79
+ * </MessageContent>
80
+ * </Message>
81
+ * <Message align="end">
82
+ * <MessageContent>
83
+ * <MessageHeader>You</MessageHeader>
84
+ * In theme.css — it is the single source of truth for the theme.
85
+ * </MessageContent>
86
+ * </Message>
87
+ * </MessageGroup>
88
+ */
89
+ //#endregion
90
+ export { Message, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader };
91
+
92
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","names":[],"sources":["../../../src/components/ui/message.tsx"],"sourcesContent":["/**\n * Message — structured chat message with avatar, author, and timestamp slots.\n *\n * MessageAvatar, MessageHeader (author), MessageContent (body), and\n * MessageFooter (timestamp) compose around a shared `align` value.\n * MessageGroup stacks a thread. MessageContent also self-aligns any direct\n * data-slot child when `align=\"end\"`, so a Bubble can be dropped inside it to\n * get avatar/header/footer chrome around a colored bubble surface. For long\n * or streaming threads that must stay pinned to the newest message, wrap the\n * list in MessageScroller instead of a plain scrolling div.\n */\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction MessageGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-group\"\n className={cn(\"flex min-w-0 flex-col gap-2\", className)}\n {...props}\n />\n )\n}\n\nfunction Message({\n className,\n align = \"start\",\n ...props\n}: React.ComponentProps<\"div\"> & { align?: \"start\" | \"end\" }) {\n return (\n <div\n data-slot=\"message\"\n data-align={align}\n className={cn(\n \"group/message relative flex w-full min-w-0 gap-2 text-sm data-[align=end]:flex-row-reverse\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageAvatar({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-avatar\"\n // self-start, not self-end + a fixed -translate-y-8 correction — that\n // bottom-align-then-shift-up-by-a-magic-number approach only lined up\n // with the default MessageContent gap it was tuned against; tighten\n // that gap (e.g. a P2P chat's bubble-to-timestamp spacing) and the\n // fixed offset overshoots, pushing the avatar above the bubble's own\n // top. True top-alignment needs no calibration at all — it's correct\n // for any gap, any footer text length, any bubble height.\n // No min-w-8/bg-muted of its own — those were sized for the default\n // 32px Avatar specifically; a smaller Avatar (size=\"sm\", 24px) left\n // a visible gray halo, the wrapper's own fill and forced minimum\n // width showing past the smaller circle inside it. The Avatar\n // already carries its own size and fallback background — this is\n // purely a layout/alignment container, not a second surface.\n className={cn(\n \"flex w-fit shrink-0 items-center justify-center self-start overflow-hidden rounded-full\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-content\"\n className={cn(\n \"flex w-full min-w-0 flex-col gap-2.5 wrap-break-word group-data-[align=end]/message:*:data-slot:self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-header\"\n className={cn(\n \"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[emphasis=ghost]/message:px-0\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MessageFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"message-footer\"\n className={cn(\n \"flex max-w-full min-w-0 items-center px-3 text-xs font-medium text-muted-foreground group-has-data-[emphasis=ghost]/message:px-0 group-data-[align=end]/message:justify-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n MessageGroup,\n Message,\n MessageAvatar,\n MessageContent,\n MessageFooter,\n MessageHeader,\n}\n\n/**\n * WHEN TO USE\n * - Chat threads where each turn needs an avatar, author name, and/or timestamp\n * - Multi-participant conversations where \"who said this\" must be visible\n *\n * NOT WHEN\n * - Bare speech bubbles with no metadata — use Bubble\n * - Long scrolling threads that must auto-stick to the newest message — wrap in MessageScroller rather than a plain overflow-y-auto container\n *\n * KEY RULES\n * - align: \"start\" (default) or \"end\" — reverses the avatar/content order via flex-row-reverse\n * - Every slot is optional: omit MessageAvatar/MessageHeader/MessageFooter freely per message\n * - MessageAvatar is `self-start` — it aligns with the first content line (the bubble/text), not the last (a MessageFooter timestamp), regardless of gap or footer text length\n * - MessageGroup only provides gap-2 stacking — no scrolling or auto-anchoring of its own\n * - MessageAvatar is for group threads specifically — once there are 3+ possible senders,\n * it's what says who's speaking. A 1:1 conversation doesn't need it: the container\n * already tells the user who the other party is, and `align` alone already distinguishes\n * your own messages from theirs — omit MessageAvatar (and MessageHeader) entirely there\n * - Per-message hover actions (e.g. a \"Copy\"/feedback row under an AI reply) are a plain\n * composition, not a dedicated slot: give the action row `opacity-0\n * group-hover/message:opacity-100 group-focus-within/message:opacity-100` — Message's own\n * root already carries `group/message`, so no extra wrapper is needed\n *\n * USAGE\n * <MessageGroup>\n * <Message align=\"start\">\n * <MessageAvatar><Avatar><AvatarFallback>AL</AvatarFallback></Avatar></MessageAvatar>\n * <MessageContent>\n * <MessageHeader>Ada Lovelace</MessageHeader>\n * Where should brand overrides live?\n * <MessageFooter>9:41 AM</MessageFooter>\n * </MessageContent>\n * </Message>\n * <Message align=\"end\">\n * <MessageContent>\n * <MessageHeader>You</MessageHeader>\n * In theme.css — it is the single source of truth for the theme.\n * </MessageContent>\n * </Message>\n * </MessageGroup>\n */\n"],"mappings":";;;;AAgBA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAsC;CAC1E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,+BAA+B,SAAS;EACtD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,QAAQ,EACf,WACA,QAAQ,SACR,GAAG,SACyD;CAC5D,OACE,oBAAC,OAAD;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,8FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAsC;CAC3E,OACE,oBAAC,OAAD;EACE,aAAU;EAcV,WAAW,GACT,2FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAsC;CAC5E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,4GACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAsC;CAC3E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,oIACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAsC;CAC3E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,+KACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * MetaList — a short horizontal list of secondary/meta information, items
3
+ * separated by a dot.
4
+ *
5
+ * `MetaList` is the flex row;
6
+ * `MetaListItem` is one entry, auto-separated from the previous item by a
7
+ * `·` unless it's first. Plain text/nodes instead of `MetaListItem` render
8
+ * with no separator, which is how a consumer opts out of the dot.
9
+ */
10
+ import * as React from "react";
11
+ import { type VariantProps } from "class-variance-authority";
12
+ declare const metaListVariants: (props?: ({
13
+ size?: "sm" | "default" | null | undefined;
14
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
15
+ declare function MetaList({ className, size, ...props }: React.ComponentProps<"div"> & VariantProps<typeof metaListVariants>): React.JSX.Element;
16
+ declare function MetaListItem({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
17
+ declare function MetaListIcon({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
18
+ export { MetaList, MetaListItem, MetaListIcon, metaListVariants };
19
+ /**
20
+ * WHEN TO USE
21
+ * - Secondary information below a PageHeaderTitle or inside a table cell —
22
+ * e.g. "3 min read · 5 comments · Draft".
23
+ *
24
+ * NOT WHEN
25
+ * - Primary content or anything interactive — MetaList is a plain read-only
26
+ * row, not a set of links or actions.
27
+ * - A single piece of metadata with no list — just render the text.
28
+ *
29
+ * KEY RULES
30
+ * - size: default | sm (default "default") — regular is text-sm, sm is text-xs; both inherit
31
+ * text-muted-foreground.
32
+ * - Every MetaListItem after the first renders a `·` separator automatically — there's no
33
+ * separator prop. Mixing in plain children (not wrapped in MetaListItem) skips the dot for
34
+ * that entry.
35
+ * - MetaListIcon is an optional leading glyph inside an item, aria-hidden — pair it with real
36
+ * text in the item, not on its own.
37
+ * - No padding is baked in — this is a plain inline row; add spacing via the parent (e.g.
38
+ * PageHeaderContent's own gap) rather than on MetaList itself.
39
+ *
40
+ * USAGE
41
+ * <MetaList>
42
+ * <MetaListItem>3 min read</MetaListItem>
43
+ * <MetaListItem>5 comments</MetaListItem>
44
+ * <MetaListItem>Draft</MetaListItem>
45
+ * </MetaList>
46
+ *
47
+ * <MetaList size="sm">
48
+ * <MetaListItem>
49
+ * <MetaListIcon><ClockIcon /></MetaListIcon>
50
+ * Updated 2h ago
51
+ * </MetaListItem>
52
+ * <MetaListItem>James Wilson</MetaListItem>
53
+ * </MetaList>
54
+ */
55
+ //# sourceMappingURL=meta-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-list.d.ts","sourceRoot":"","sources":["../../../src/components/ui/meta-list.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,QAAA,MAAM,gBAAgB;;8EAarB,CAAA;AAED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,qBASrE;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAW1E;AAED,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAY1E;AAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG"}
@@ -0,0 +1,75 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+ //#region src/components/ui/meta-list.tsx
6
+ var metaListVariants = cva("flex flex-wrap items-center text-muted-foreground", {
7
+ variants: { size: {
8
+ default: "text-sm",
9
+ sm: "text-xs"
10
+ } },
11
+ defaultVariants: { size: "default" }
12
+ });
13
+ function MetaList({ className, size = "default", ...props }) {
14
+ return /* @__PURE__ */ jsx("div", {
15
+ "data-slot": "meta-list",
16
+ "data-size": size,
17
+ className: cn(metaListVariants({ size }), className),
18
+ ...props
19
+ });
20
+ }
21
+ function MetaListItem({ className, ...props }) {
22
+ return /* @__PURE__ */ jsx("span", {
23
+ "data-slot": "meta-list-item",
24
+ className: cn("inline-flex items-center gap-1 [&:not(:first-child)]:before:mx-1.5 [&:not(:first-child)]:before:content-['•']", className),
25
+ ...props
26
+ });
27
+ }
28
+ function MetaListIcon({ className, ...props }) {
29
+ return /* @__PURE__ */ jsx("span", {
30
+ "data-slot": "meta-list-icon",
31
+ "aria-hidden": "true",
32
+ className: cn("size-3.5 shrink-0 [&_svg:not([class*='size-'])]:size-3.5", className),
33
+ ...props
34
+ });
35
+ }
36
+ /**
37
+ * WHEN TO USE
38
+ * - Secondary information below a PageHeaderTitle or inside a table cell —
39
+ * e.g. "3 min read · 5 comments · Draft".
40
+ *
41
+ * NOT WHEN
42
+ * - Primary content or anything interactive — MetaList is a plain read-only
43
+ * row, not a set of links or actions.
44
+ * - A single piece of metadata with no list — just render the text.
45
+ *
46
+ * KEY RULES
47
+ * - size: default | sm (default "default") — regular is text-sm, sm is text-xs; both inherit
48
+ * text-muted-foreground.
49
+ * - Every MetaListItem after the first renders a `·` separator automatically — there's no
50
+ * separator prop. Mixing in plain children (not wrapped in MetaListItem) skips the dot for
51
+ * that entry.
52
+ * - MetaListIcon is an optional leading glyph inside an item, aria-hidden — pair it with real
53
+ * text in the item, not on its own.
54
+ * - No padding is baked in — this is a plain inline row; add spacing via the parent (e.g.
55
+ * PageHeaderContent's own gap) rather than on MetaList itself.
56
+ *
57
+ * USAGE
58
+ * <MetaList>
59
+ * <MetaListItem>3 min read</MetaListItem>
60
+ * <MetaListItem>5 comments</MetaListItem>
61
+ * <MetaListItem>Draft</MetaListItem>
62
+ * </MetaList>
63
+ *
64
+ * <MetaList size="sm">
65
+ * <MetaListItem>
66
+ * <MetaListIcon><ClockIcon /></MetaListIcon>
67
+ * Updated 2h ago
68
+ * </MetaListItem>
69
+ * <MetaListItem>James Wilson</MetaListItem>
70
+ * </MetaList>
71
+ */
72
+ //#endregion
73
+ export { MetaList, MetaListIcon, MetaListItem, metaListVariants };
74
+
75
+ //# sourceMappingURL=meta-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-list.js","names":[],"sources":["../../../src/components/ui/meta-list.tsx"],"sourcesContent":["/**\n * MetaList — a short horizontal list of secondary/meta information, items\n * separated by a dot.\n *\n * `MetaList` is the flex row;\n * `MetaListItem` is one entry, auto-separated from the previous item by a\n * `·` unless it's first. Plain text/nodes instead of `MetaListItem` render\n * with no separator, which is how a consumer opts out of the dot.\n */\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst metaListVariants = cva(\n \"flex flex-wrap items-center text-muted-foreground\",\n {\n variants: {\n size: {\n default: \"text-sm\",\n sm: \"text-xs\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n }\n)\n\nfunction MetaList({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof metaListVariants>) {\n return (\n <div\n data-slot=\"meta-list\"\n data-size={size}\n className={cn(metaListVariants({ size }), className)}\n {...props}\n />\n )\n}\n\nfunction MetaListItem({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"meta-list-item\"\n className={cn(\n \"inline-flex items-center gap-1 [&:not(:first-child)]:before:mx-1.5 [&:not(:first-child)]:before:content-['•']\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction MetaListIcon({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"meta-list-icon\"\n aria-hidden=\"true\"\n className={cn(\n \"size-3.5 shrink-0 [&_svg:not([class*='size-'])]:size-3.5\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport { MetaList, MetaListItem, MetaListIcon, metaListVariants }\n\n/**\n * WHEN TO USE\n * - Secondary information below a PageHeaderTitle or inside a table cell —\n * e.g. \"3 min read · 5 comments · Draft\".\n *\n * NOT WHEN\n * - Primary content or anything interactive — MetaList is a plain read-only\n * row, not a set of links or actions.\n * - A single piece of metadata with no list — just render the text.\n *\n * KEY RULES\n * - size: default | sm (default \"default\") — regular is text-sm, sm is text-xs; both inherit\n * text-muted-foreground.\n * - Every MetaListItem after the first renders a `·` separator automatically — there's no\n * separator prop. Mixing in plain children (not wrapped in MetaListItem) skips the dot for\n * that entry.\n * - MetaListIcon is an optional leading glyph inside an item, aria-hidden — pair it with real\n * text in the item, not on its own.\n * - No padding is baked in — this is a plain inline row; add spacing via the parent (e.g.\n * PageHeaderContent's own gap) rather than on MetaList itself.\n *\n * USAGE\n * <MetaList>\n * <MetaListItem>3 min read</MetaListItem>\n * <MetaListItem>5 comments</MetaListItem>\n * <MetaListItem>Draft</MetaListItem>\n * </MetaList>\n *\n * <MetaList size=\"sm\">\n * <MetaListItem>\n * <MetaListIcon><ClockIcon /></MetaListIcon>\n * Updated 2h ago\n * </MetaListItem>\n * <MetaListItem>James Wilson</MetaListItem>\n * </MetaList>\n */\n"],"mappings":";;;;;AAeA,IAAM,mBAAmB,IACvB,qDACA;CACE,UAAU,EACR,MAAM;EACJ,SAAS;EACT,IAAI;CACN,EACF;CACA,iBAAiB,EACf,MAAM,UACR;AACF,CACF;AAEA,SAAS,SAAS,EAChB,WACA,OAAO,WACP,GAAG,SACmE;CACtE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GAAG,iBAAiB,EAAE,KAAK,CAAC,GAAG,SAAS;EACnD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAuC;CAC3E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,iHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAuC;CAC3E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,eAAY;EACZ,WAAW,GACT,4DACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * NativeSelect — styled wrapper around the browser's native <select>.
3
+ *
4
+ * A plain <select> with a chevron icon overlay, not a Radix primitive.
5
+ * Sizes ("sm" | "default") are applied via a `data-size`
6
+ * attribute on both the wrapper and the <select>.
7
+ */
8
+ import * as React from "react";
9
+ type NativeSelectProps = Omit<React.ComponentProps<"select">, "size"> & {
10
+ size?: "sm" | "default";
11
+ };
12
+ declare function NativeSelect({ className, size, ...props }: NativeSelectProps): React.JSX.Element;
13
+ declare function NativeSelectOption({ className, ...props }: React.ComponentProps<"option">): React.JSX.Element;
14
+ declare function NativeSelectOptGroup({ className, ...props }: React.ComponentProps<"optgroup">): React.JSX.Element;
15
+ export { NativeSelect, NativeSelectOptGroup, NativeSelectOption };
16
+ /**
17
+ * WHEN TO USE
18
+ * - Simple option lists in dense forms where native OS picker behavior and zero extra JS are preferable.
19
+ * - Mobile-heavy flows — the OS supplies its own picker UI, which tends to be more reliable than a custom popover.
20
+ *
21
+ * NOT WHEN
22
+ * - Custom item rendering, icons, or grouped visual styling is required — use Select instead.
23
+ * - The list is long enough to need type-to-filter — use Combobox instead.
24
+ *
25
+ * KEY RULES
26
+ * - `size` is "sm" | "default" (default "default") — no other sizes exist.
27
+ * - Compose options with NativeSelectOption / NativeSelectOptGroup only — content is plain text, no custom item rendering.
28
+ * - Disabled state is native (`disabled` on the underlying <select>); the wrapper dims via has-[select:disabled]:opacity-50.
29
+ *
30
+ * USAGE
31
+ * <NativeSelect defaultValue="cardamom">
32
+ * <NativeSelectOption value="turmeric">Turmeric</NativeSelectOption>
33
+ * <NativeSelectOption value="cardamom">Cardamom</NativeSelectOption>
34
+ * </NativeSelect>
35
+ *
36
+ * // Grouped
37
+ * <NativeSelect defaultValue="cumin">
38
+ * <NativeSelectOptGroup label="Whole">
39
+ * <NativeSelectOption value="cardamom">Cardamom pod</NativeSelectOption>
40
+ * </NativeSelectOptGroup>
41
+ * <NativeSelectOptGroup label="Ground">
42
+ * <NativeSelectOption value="cumin">Cumin</NativeSelectOption>
43
+ * </NativeSelectOptGroup>
44
+ * </NativeSelect>
45
+ *
46
+ * // Small size
47
+ * <NativeSelect size="sm" defaultValue="turmeric">
48
+ * <NativeSelectOption value="turmeric">Turmeric</NativeSelectOption>
49
+ * </NativeSelect>
50
+ */
51
+ //# sourceMappingURL=native-select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/native-select.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,KAAK,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,GAAG;IACtE,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CACxB,CAAA;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,iBAAiB,qBAuBnB;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,qBAQhC;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,qBAQlC;AAED,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG"}
@@ -0,0 +1,75 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import "react";
3
+ import { ChevronDownIcon } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/ui/native-select.tsx
6
+ function NativeSelect({ className, size = "default", ...props }) {
7
+ return /* @__PURE__ */ jsxs("div", {
8
+ className: cn("group/native-select relative w-fit has-[select:disabled]:opacity-50", className),
9
+ "data-slot": "native-select-wrapper",
10
+ "data-size": size,
11
+ children: [/* @__PURE__ */ jsx("select", {
12
+ "data-slot": "native-select",
13
+ "data-size": size,
14
+ className: "h-8 w-full min-w-0 appearance-none rounded-lg border border-input bg-transparent py-1 pr-8 pl-2.5 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-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 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md,0.375rem),10px)] data-[size=sm]:py-0.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
15
+ ...props
16
+ }), /* @__PURE__ */ jsx(ChevronDownIcon, {
17
+ className: "pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none",
18
+ "aria-hidden": "true",
19
+ "data-slot": "native-select-icon"
20
+ })]
21
+ });
22
+ }
23
+ function NativeSelectOption({ className, ...props }) {
24
+ return /* @__PURE__ */ jsx("option", {
25
+ "data-slot": "native-select-option",
26
+ className: cn("bg-[Canvas] text-[CanvasText]", className),
27
+ ...props
28
+ });
29
+ }
30
+ function NativeSelectOptGroup({ className, ...props }) {
31
+ return /* @__PURE__ */ jsx("optgroup", {
32
+ "data-slot": "native-select-optgroup",
33
+ className: cn("bg-[Canvas] text-[CanvasText]", className),
34
+ ...props
35
+ });
36
+ }
37
+ /**
38
+ * WHEN TO USE
39
+ * - Simple option lists in dense forms where native OS picker behavior and zero extra JS are preferable.
40
+ * - Mobile-heavy flows — the OS supplies its own picker UI, which tends to be more reliable than a custom popover.
41
+ *
42
+ * NOT WHEN
43
+ * - Custom item rendering, icons, or grouped visual styling is required — use Select instead.
44
+ * - The list is long enough to need type-to-filter — use Combobox instead.
45
+ *
46
+ * KEY RULES
47
+ * - `size` is "sm" | "default" (default "default") — no other sizes exist.
48
+ * - Compose options with NativeSelectOption / NativeSelectOptGroup only — content is plain text, no custom item rendering.
49
+ * - Disabled state is native (`disabled` on the underlying <select>); the wrapper dims via has-[select:disabled]:opacity-50.
50
+ *
51
+ * USAGE
52
+ * <NativeSelect defaultValue="cardamom">
53
+ * <NativeSelectOption value="turmeric">Turmeric</NativeSelectOption>
54
+ * <NativeSelectOption value="cardamom">Cardamom</NativeSelectOption>
55
+ * </NativeSelect>
56
+ *
57
+ * // Grouped
58
+ * <NativeSelect defaultValue="cumin">
59
+ * <NativeSelectOptGroup label="Whole">
60
+ * <NativeSelectOption value="cardamom">Cardamom pod</NativeSelectOption>
61
+ * </NativeSelectOptGroup>
62
+ * <NativeSelectOptGroup label="Ground">
63
+ * <NativeSelectOption value="cumin">Cumin</NativeSelectOption>
64
+ * </NativeSelectOptGroup>
65
+ * </NativeSelect>
66
+ *
67
+ * // Small size
68
+ * <NativeSelect size="sm" defaultValue="turmeric">
69
+ * <NativeSelectOption value="turmeric">Turmeric</NativeSelectOption>
70
+ * </NativeSelect>
71
+ */
72
+ //#endregion
73
+ export { NativeSelect, NativeSelectOptGroup, NativeSelectOption };
74
+
75
+ //# sourceMappingURL=native-select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-select.js","names":[],"sources":["../../../src/components/ui/native-select.tsx"],"sourcesContent":["/**\n * NativeSelect — styled wrapper around the browser's native <select>.\n *\n * A plain <select> with a chevron icon overlay, not a Radix primitive.\n * Sizes (\"sm\" | \"default\") are applied via a `data-size`\n * attribute on both the wrapper and the <select>.\n */\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\ntype NativeSelectProps = Omit<React.ComponentProps<\"select\">, \"size\"> & {\n size?: \"sm\" | \"default\"\n}\n\nfunction NativeSelect({\n className,\n size = \"default\",\n ...props\n}: NativeSelectProps) {\n return (\n <div\n className={cn(\n \"group/native-select relative w-fit has-[select:disabled]:opacity-50\",\n className\n )}\n data-slot=\"native-select-wrapper\"\n data-size={size}\n >\n <select\n data-slot=\"native-select\"\n data-size={size}\n className=\"h-8 w-full min-w-0 appearance-none rounded-lg border border-input bg-transparent py-1 pr-8 pl-2.5 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-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 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md,0.375rem),10px)] data-[size=sm]:py-0.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\"\n {...props}\n />\n <ChevronDownIcon\n className=\"pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none\"\n aria-hidden=\"true\"\n data-slot=\"native-select-icon\"\n />\n </div>\n )\n}\n\nfunction NativeSelectOption({\n className,\n ...props\n}: React.ComponentProps<\"option\">) {\n return (\n <option\n data-slot=\"native-select-option\"\n className={cn(\"bg-[Canvas] text-[CanvasText]\", className)}\n {...props}\n />\n )\n}\n\nfunction NativeSelectOptGroup({\n className,\n ...props\n}: React.ComponentProps<\"optgroup\">) {\n return (\n <optgroup\n data-slot=\"native-select-optgroup\"\n className={cn(\"bg-[Canvas] text-[CanvasText]\", className)}\n {...props}\n />\n )\n}\n\nexport { NativeSelect, NativeSelectOptGroup, NativeSelectOption }\n\n/**\n * WHEN TO USE\n * - Simple option lists in dense forms where native OS picker behavior and zero extra JS are preferable.\n * - Mobile-heavy flows — the OS supplies its own picker UI, which tends to be more reliable than a custom popover.\n *\n * NOT WHEN\n * - Custom item rendering, icons, or grouped visual styling is required — use Select instead.\n * - The list is long enough to need type-to-filter — use Combobox instead.\n *\n * KEY RULES\n * - `size` is \"sm\" | \"default\" (default \"default\") — no other sizes exist.\n * - Compose options with NativeSelectOption / NativeSelectOptGroup only — content is plain text, no custom item rendering.\n * - Disabled state is native (`disabled` on the underlying <select>); the wrapper dims via has-[select:disabled]:opacity-50.\n *\n * USAGE\n * <NativeSelect defaultValue=\"cardamom\">\n * <NativeSelectOption value=\"turmeric\">Turmeric</NativeSelectOption>\n * <NativeSelectOption value=\"cardamom\">Cardamom</NativeSelectOption>\n * </NativeSelect>\n *\n * // Grouped\n * <NativeSelect defaultValue=\"cumin\">\n * <NativeSelectOptGroup label=\"Whole\">\n * <NativeSelectOption value=\"cardamom\">Cardamom pod</NativeSelectOption>\n * </NativeSelectOptGroup>\n * <NativeSelectOptGroup label=\"Ground\">\n * <NativeSelectOption value=\"cumin\">Cumin</NativeSelectOption>\n * </NativeSelectOptGroup>\n * </NativeSelect>\n *\n * // Small size\n * <NativeSelect size=\"sm\" defaultValue=\"turmeric\">\n * <NativeSelectOption value=\"turmeric\">Turmeric</NativeSelectOption>\n * </NativeSelect>\n */\n"],"mappings":";;;;;AAiBA,SAAS,aAAa,EACpB,WACA,OAAO,WACP,GAAG,SACiB;CACpB,OACE,qBAAC,OAAD;EACE,WAAW,GACT,uEACA,SACF;EACA,aAAU;EACV,aAAW;EANb,UAAA,CAQE,oBAAC,UAAD;GACE,aAAU;GACV,aAAW;GACX,WAAU;GACV,GAAI;EACL,CAAA,GACD,oBAAC,iBAAD;GACE,WAAU;GACV,eAAY;GACZ,aAAU;EACX,CAAA,CACE;;AAET;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SAC8B;CACjC,OACE,oBAAC,UAAD;EACE,aAAU;EACV,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,qBAAqB,EAC5B,WACA,GAAG,SACgC;CACnC,OACE,oBAAC,YAAD;EACE,aAAU;EACV,WAAW,GAAG,iCAAiC,SAAS;EACxD,GAAI;CACL,CAAA;AAEL"}