@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,74 @@
1
+ /**
2
+ * Attachment — file attachment row with upload state, for chat messages and composers.
3
+ *
4
+ * A card-like row (or vertical tile) with a media/icon slot, title,
5
+ * description, and action buttons for one file. `state` drives the upload
6
+ * affordance: dashed border while idle, shimmering title while
7
+ * uploading/processing, destructive tint on error. AttachmentGroup lays out
8
+ * several as a horizontally-scrolling strip. AttachmentTrigger is an
9
+ * invisible full-cover button for drop-zone / file-picker interactions.
10
+ */
11
+ import * as React from "react";
12
+ import { type VariantProps } from "class-variance-authority";
13
+ import { Button, type TextButtonSize } from "../../components/ui/button";
14
+ declare const attachmentVariants: (props?: ({
15
+ size?: "sm" | "default" | "xs" | null | undefined;
16
+ orientation?: "horizontal" | "vertical" | null | undefined;
17
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
18
+ declare function Attachment({ className, state, size, orientation, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentVariants> & {
19
+ state?: "idle" | "uploading" | "processing" | "error" | "done";
20
+ }): React.JSX.Element;
21
+ declare const attachmentMediaVariants: (props?: ({
22
+ variant?: "image" | "icon" | null | undefined;
23
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
24
+ declare function AttachmentMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>): React.JSX.Element;
25
+ declare function AttachmentContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
26
+ declare function AttachmentTitle({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
27
+ declare function AttachmentDescription({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
28
+ declare function AttachmentActions({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
29
+ declare function AttachmentAction({ className, variant, size, ...props }: Omit<React.ComponentProps<typeof Button>, "size" | "aria-label" | "iconOnly" | "asChild"> & {
30
+ /** Height step of the icon-only button; it is always square (`iconOnly`). */
31
+ size?: TextButtonSize;
32
+ "aria-label": string;
33
+ }): React.JSX.Element;
34
+ declare function AttachmentTrigger({ className, asChild, type, ...props }: React.ComponentProps<"button"> & {
35
+ asChild?: boolean;
36
+ }): React.JSX.Element;
37
+ declare function AttachmentGroup({ className, tabIndex, ...props }: React.ComponentProps<"div">): React.JSX.Element;
38
+ export { Attachment, AttachmentGroup, AttachmentMedia, AttachmentContent, AttachmentTitle, AttachmentDescription, AttachmentActions, AttachmentAction, AttachmentTrigger, };
39
+ /**
40
+ * WHEN TO USE
41
+ * - Files attached to a chat message or composer
42
+ * - Upload queues that need per-file progress/state and a remove action
43
+ *
44
+ * NOT WHEN
45
+ * - A plain native file picker with no per-file UI — use Input type="file"
46
+ * - Image browsing meant as a gallery rather than an attachment list
47
+ * - Plain download links with no upload lifecycle
48
+ *
49
+ * KEY RULES
50
+ * - state: idle, uploading, processing, error, done (default "done") — "idle" renders a dashed border (drop-zone look)
51
+ * - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment
52
+ * - orientation: horizontal (default, row) or vertical (column tile, media fills the width)
53
+ * - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in "done"/"idle" states
54
+ * - AttachmentTitle shimmers automatically in "uploading"/"processing" states — no extra prop needed
55
+ * - AttachmentAction defaults to variant="ghost" size="xs" iconOnly — always pass aria-label, it's icon-only
56
+ * - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable
57
+ *
58
+ * USAGE
59
+ * <Attachment state="uploading">
60
+ * <AttachmentMedia variant="icon"><FileTextIcon /></AttachmentMedia>
61
+ * <AttachmentContent>
62
+ * <AttachmentTitle>theme.css</AttachmentTitle>
63
+ * <AttachmentDescription>6.3 KB</AttachmentDescription>
64
+ * </AttachmentContent>
65
+ * <AttachmentActions>
66
+ * <AttachmentAction aria-label="Remove attachment"><XIcon /></AttachmentAction>
67
+ * </AttachmentActions>
68
+ * </Attachment>
69
+ *
70
+ * <AttachmentGroup>
71
+ * {files.map((f) => <Attachment key={f.name}>...</Attachment>)}
72
+ * </AttachmentGroup>
73
+ */
74
+ //# sourceMappingURL=attachment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../../src/components/ui/attachment.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,OAAO,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEpE,QAAA,MAAM,kBAAkB;;;8EAgBvB,CAAA;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,KAAc,EACd,IAAgB,EAChB,WAA0B,EAC1B,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAC5B,YAAY,CAAC,OAAO,kBAAkB,CAAC,GAAG;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAA;CAC/D,qBAWF;AAED,QAAA,MAAM,uBAAuB;;8EAc5B,CAAA;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,OAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,OAAO,uBAAuB,CAAC,qBAS5E;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAW9B;AAED,iBAAS,qBAAqB,CAAC,EAC7B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAY9B;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,OAAO,EACP,IAAW,EACX,GAAG,KAAK,EACT,EAAE,IAAI,CACL,KAAK,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EACnC,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAC/C,GAAG;IACF,6EAA6E;IAC7E,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,qBAWA;AAED,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,OAAe,EACf,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAWA;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,QAAY,EACZ,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAc7B;AAED,OAAO,EACL,UAAU,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GAClB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG"}
@@ -0,0 +1,142 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { Button } from "./button.js";
3
+ import "react";
4
+ import { Slot } from "radix-ui";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import { cva } from "class-variance-authority";
7
+ //#region src/components/ui/attachment.tsx
8
+ var attachmentVariants = cva("group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-3 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed", { variants: {
9
+ size: {
10
+ default: "gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2",
11
+ sm: "gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5",
12
+ xs: "gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1"
13
+ },
14
+ orientation: {
15
+ horizontal: "min-w-40 items-center",
16
+ vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30"
17
+ }
18
+ } });
19
+ function Attachment({ className, state = "done", size = "default", orientation = "horizontal", ...props }) {
20
+ return /* @__PURE__ */ jsx("div", {
21
+ "data-slot": "attachment",
22
+ "data-state": state,
23
+ "data-size": size,
24
+ "data-orientation": orientation,
25
+ className: cn(attachmentVariants({
26
+ size,
27
+ orientation
28
+ }), className),
29
+ ...props
30
+ });
31
+ }
32
+ var attachmentMediaVariants = cva("relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5", {
33
+ variants: { variant: {
34
+ icon: "",
35
+ image: "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
36
+ } },
37
+ defaultVariants: { variant: "icon" }
38
+ });
39
+ function AttachmentMedia({ className, variant = "icon", ...props }) {
40
+ return /* @__PURE__ */ jsx("div", {
41
+ "data-slot": "attachment-media",
42
+ "data-variant": variant,
43
+ className: cn(attachmentMediaVariants({ variant }), className),
44
+ ...props
45
+ });
46
+ }
47
+ function AttachmentContent({ className, ...props }) {
48
+ return /* @__PURE__ */ jsx("div", {
49
+ "data-slot": "attachment-content",
50
+ className: cn("max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1", className),
51
+ ...props
52
+ });
53
+ }
54
+ function AttachmentTitle({ className, ...props }) {
55
+ return /* @__PURE__ */ jsx("span", {
56
+ "data-slot": "attachment-title",
57
+ className: cn("block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer", className),
58
+ ...props
59
+ });
60
+ }
61
+ function AttachmentDescription({ className, ...props }) {
62
+ return /* @__PURE__ */ jsx("span", {
63
+ "data-slot": "attachment-description",
64
+ className: cn("mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80", "max-w-full", className),
65
+ ...props
66
+ });
67
+ }
68
+ function AttachmentActions({ className, ...props }) {
69
+ return /* @__PURE__ */ jsx("div", {
70
+ "data-slot": "attachment-actions",
71
+ className: cn("relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1", className),
72
+ ...props
73
+ });
74
+ }
75
+ function AttachmentAction({ className, variant, size = "xs", ...props }) {
76
+ return /* @__PURE__ */ jsx(Button, {
77
+ "data-slot": "attachment-action",
78
+ variant: variant ?? "ghost",
79
+ size,
80
+ iconOnly: true,
81
+ className: cn(className),
82
+ ...props
83
+ });
84
+ }
85
+ function AttachmentTrigger({ className, asChild = false, type, ...props }) {
86
+ const Comp = asChild ? Slot.Root : "button";
87
+ return /* @__PURE__ */ jsx(Comp, {
88
+ "data-slot": "attachment-trigger",
89
+ type: asChild ? void 0 : type ?? "button",
90
+ className: cn("absolute inset-0 z-10 outline-none", className),
91
+ ...props
92
+ });
93
+ }
94
+ function AttachmentGroup({ className, tabIndex = 0, ...props }) {
95
+ return /* @__PURE__ */ jsx("div", {
96
+ "data-slot": "attachment-group",
97
+ role: "region",
98
+ "aria-label": "Attachments",
99
+ tabIndex,
100
+ className: cn("flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start", className),
101
+ ...props
102
+ });
103
+ }
104
+ /**
105
+ * WHEN TO USE
106
+ * - Files attached to a chat message or composer
107
+ * - Upload queues that need per-file progress/state and a remove action
108
+ *
109
+ * NOT WHEN
110
+ * - A plain native file picker with no per-file UI — use Input type="file"
111
+ * - Image browsing meant as a gallery rather than an attachment list
112
+ * - Plain download links with no upload lifecycle
113
+ *
114
+ * KEY RULES
115
+ * - state: idle, uploading, processing, error, done (default "done") — "idle" renders a dashed border (drop-zone look)
116
+ * - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment
117
+ * - orientation: horizontal (default, row) or vertical (column tile, media fills the width)
118
+ * - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in "done"/"idle" states
119
+ * - AttachmentTitle shimmers automatically in "uploading"/"processing" states — no extra prop needed
120
+ * - AttachmentAction defaults to variant="ghost" size="xs" iconOnly — always pass aria-label, it's icon-only
121
+ * - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable
122
+ *
123
+ * USAGE
124
+ * <Attachment state="uploading">
125
+ * <AttachmentMedia variant="icon"><FileTextIcon /></AttachmentMedia>
126
+ * <AttachmentContent>
127
+ * <AttachmentTitle>theme.css</AttachmentTitle>
128
+ * <AttachmentDescription>6.3 KB</AttachmentDescription>
129
+ * </AttachmentContent>
130
+ * <AttachmentActions>
131
+ * <AttachmentAction aria-label="Remove attachment"><XIcon /></AttachmentAction>
132
+ * </AttachmentActions>
133
+ * </Attachment>
134
+ *
135
+ * <AttachmentGroup>
136
+ * {files.map((f) => <Attachment key={f.name}>...</Attachment>)}
137
+ * </AttachmentGroup>
138
+ */
139
+ //#endregion
140
+ export { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger };
141
+
142
+ //# sourceMappingURL=attachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.js","names":[],"sources":["../../../src/components/ui/attachment.tsx"],"sourcesContent":["/**\n * Attachment — file attachment row with upload state, for chat messages and composers.\n *\n * A card-like row (or vertical tile) with a media/icon slot, title,\n * description, and action buttons for one file. `state` drives the upload\n * affordance: dashed border while idle, shimmering title while\n * uploading/processing, destructive tint on error. AttachmentGroup lays out\n * several as a horizontally-scrolling strip. AttachmentTrigger is an\n * invisible full-cover button for drop-zone / file-picker interactions.\n */\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button, type TextButtonSize } from \"@/components/ui/button\"\n\nconst attachmentVariants = cva(\n \"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-3 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed\",\n {\n variants: {\n size: {\n default:\n \"gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2\",\n sm: \"gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5\",\n xs: \"gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1\",\n },\n orientation: {\n horizontal: \"min-w-40 items-center\",\n vertical: \"w-24 flex-col has-data-[slot=attachment-content]:w-30\",\n },\n },\n }\n)\n\nfunction Attachment({\n className,\n state = \"done\",\n size = \"default\",\n orientation = \"horizontal\",\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof attachmentVariants> & {\n state?: \"idle\" | \"uploading\" | \"processing\" | \"error\" | \"done\"\n }) {\n return (\n <div\n data-slot=\"attachment\"\n data-state={state}\n data-size={size}\n data-orientation={orientation}\n className={cn(attachmentVariants({ size, orientation }), className)}\n {...props}\n />\n )\n}\n\nconst attachmentMediaVariants = cva(\n \"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5\",\n {\n variants: {\n variant: {\n icon: \"\",\n image:\n \"opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"icon\",\n },\n }\n)\n\nfunction AttachmentMedia({\n className,\n variant = \"icon\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof attachmentMediaVariants>) {\n return (\n <div\n data-slot=\"attachment-media\"\n data-variant={variant}\n className={cn(attachmentMediaVariants({ variant }), className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-content\"\n className={cn(\n \"max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentTitle({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-title\"\n className={cn(\n \"block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentDescription({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"attachment-description\"\n className={cn(\n \"mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80\",\n \"max-w-full\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentActions({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-actions\"\n className={cn(\n \"relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AttachmentAction({\n className,\n variant,\n size = \"xs\",\n ...props\n}: Omit<\n React.ComponentProps<typeof Button>,\n \"size\" | \"aria-label\" | \"iconOnly\" | \"asChild\"\n> & {\n /** Height step of the icon-only button; it is always square (`iconOnly`). */\n size?: TextButtonSize\n \"aria-label\": string\n}) {\n return (\n <Button\n data-slot=\"attachment-action\"\n variant={variant ?? \"ghost\"}\n size={size}\n iconOnly\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentTrigger({\n className,\n asChild = false,\n type,\n ...props\n}: React.ComponentProps<\"button\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"button\"\n\n return (\n <Comp\n data-slot=\"attachment-trigger\"\n type={asChild ? undefined : (type ?? \"button\")}\n className={cn(\"absolute inset-0 z-10 outline-none\", className)}\n {...props}\n />\n )\n}\n\nfunction AttachmentGroup({\n className,\n tabIndex = 0,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"attachment-group\"\n role=\"region\"\n aria-label=\"Attachments\"\n tabIndex={tabIndex}\n className={cn(\n \"flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Attachment,\n AttachmentGroup,\n AttachmentMedia,\n AttachmentContent,\n AttachmentTitle,\n AttachmentDescription,\n AttachmentActions,\n AttachmentAction,\n AttachmentTrigger,\n}\n\n/**\n * WHEN TO USE\n * - Files attached to a chat message or composer\n * - Upload queues that need per-file progress/state and a remove action\n *\n * NOT WHEN\n * - A plain native file picker with no per-file UI — use Input type=\"file\"\n * - Image browsing meant as a gallery rather than an attachment list\n * - Plain download links with no upload lifecycle\n *\n * KEY RULES\n * - state: idle, uploading, processing, error, done (default \"done\") — \"idle\" renders a dashed border (drop-zone look)\n * - size: default, sm, xs — scales padding/gap and AttachmentMedia icon size together; set once on Attachment\n * - orientation: horizontal (default, row) or vertical (column tile, media fills the width)\n * - AttachmentMedia variant: icon (default) or image — image dims to 60% opacity except in \"done\"/\"idle\" states\n * - AttachmentTitle shimmers automatically in \"uploading\"/\"processing\" states — no extra prop needed\n * - AttachmentAction defaults to variant=\"ghost\" size=\"xs\" iconOnly — always pass aria-label, it's icon-only\n * - AttachmentTrigger covers the whole card (inset-0, z-10) — put real buttons in AttachmentActions (z-20) so they stack above it and stay clickable\n *\n * USAGE\n * <Attachment state=\"uploading\">\n * <AttachmentMedia variant=\"icon\"><FileTextIcon /></AttachmentMedia>\n * <AttachmentContent>\n * <AttachmentTitle>theme.css</AttachmentTitle>\n * <AttachmentDescription>6.3 KB</AttachmentDescription>\n * </AttachmentContent>\n * <AttachmentActions>\n * <AttachmentAction aria-label=\"Remove attachment\"><XIcon /></AttachmentAction>\n * </AttachmentActions>\n * </Attachment>\n *\n * <AttachmentGroup>\n * {files.map((f) => <Attachment key={f.name}>...</Attachment>)}\n * </AttachmentGroup>\n */\n"],"mappings":";;;;;;;AAkBA,IAAM,qBAAqB,IACzB,ySACA,EACE,UAAU;CACR,MAAM;EACJ,SACE;EACF,IAAI;EACJ,IAAI;CACN;CACA,aAAa;EACX,YAAY;EACZ,UAAU;CACZ;AACF,EACF,CACF;AAEA,SAAS,WAAW,EAClB,WACA,QAAQ,QACR,OAAO,WACP,cAAc,cACd,GAAG,SAIA;CACH,OACE,oBAAC,OAAD;EACE,aAAU;EACV,cAAY;EACZ,aAAW;EACX,oBAAkB;EAClB,WAAW,GAAG,mBAAmB;GAAE;GAAM;EAAY,CAAC,GAAG,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAEA,IAAM,0BAA0B,IAC9B,orBACA;CACE,UAAU,EACR,SAAS;EACP,MAAM;EACN,OACE;CACJ,EACF;CACA,iBAAiB,EACf,SAAS,OACX;AACF,CACF;AAEA,SAAS,gBAAgB,EACvB,WACA,UAAU,QACV,GAAG,SAC0E;CAC7E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,GAAG,wBAAwB,EAAE,QAAQ,CAAC,GAAG,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,6FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,WACA,GAAG,SAC4B;CAC/B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,kJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4B;CAC/B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,uHACA,cACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,6PACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,SACA,OAAO,MACP,GAAG,SAQF;CACD,OACE,oBAAC,QAAD;EACE,aAAU;EACV,SAAS,WAAW;EACd;EACN,UAAA;EACA,WAAW,GAAG,SAAS;EACvB,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,kBAAkB,EACzB,WACA,UAAU,OACV,MACA,GAAG,SAGF;CACD,MAAM,OAAO,UAAU,KAAK,OAAO;CAEnC,OACE,oBAAC,MAAD;EACE,aAAU;EACV,MAAM,UAAU,KAAA,IAAa,QAAQ;EACrC,WAAW,GAAG,sCAAsC,SAAS;EAC7D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,WACA,WAAW,GACX,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,cAAW;EACD;EACV,WAAW,GACT,sMACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Avatar — person/entity image with initials fallback.
3
+ *
4
+ * Built on the Radix Avatar primitive. A `size` prop ("default" | "sm" |
5
+ * "lg") also rescales AvatarFallback text and AvatarBadge via a shared
6
+ * `data-size` attribute, so sizing never needs className overrides.
7
+ */
8
+ import * as React from "react";
9
+ import { Avatar as AvatarPrimitive } from "radix-ui";
10
+ declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof AvatarPrimitive.Root> & {
11
+ size?: "default" | "sm" | "lg";
12
+ }): React.JSX.Element;
13
+ declare function AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarPrimitive.Image>): React.JSX.Element;
14
+ declare function AvatarFallback({ className, colorSeed, children, ...props }: React.ComponentProps<typeof AvatarPrimitive.Fallback> & {
15
+ /**
16
+ * A stable identity string (name, user id, email) hashed to one of the
17
+ * 6 chart colors. Defaults to the fallback's own text (usually
18
+ * initials) when omitted, so a plain `<AvatarFallback>AL</AvatarFallback>`
19
+ * is already colored — there's no neutral/grey fallback for text content.
20
+ * Pass it explicitly when the visible text isn't a stable per-identity
21
+ * string (e.g. it's always "?"), or when it differs from the real identity
22
+ * key you want the color derived from.
23
+ */
24
+ colorSeed?: string;
25
+ }): React.JSX.Element;
26
+ declare function AvatarBadge({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
27
+ declare function AvatarGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
28
+ declare function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
29
+ export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge, };
30
+ /**
31
+ * WHEN TO USE
32
+ * - Representing a person or organization visually — profile pictures,
33
+ * comment authors, member lists.
34
+ * - AvatarGroup + AvatarGroupCount for a set of collaborators with a
35
+ * "+N" overflow count.
36
+ * - AvatarBadge for a presence dot (online/away/status) on the corner.
37
+ *
38
+ * NOT WHEN
39
+ * - Generic iconography with no identity meaning — use a Lucide icon.
40
+ * - Decorative or content imagery — Avatar is identity-specific.
41
+ * - A numeric unread/notification count — use CountBadge, not AvatarBadge
42
+ * (AvatarBadge is a plain dot with no built-in number formatting).
43
+ *
44
+ * KEY RULES
45
+ * - Prefer the `size` prop ("default" | "sm" | "lg") over a raw
46
+ * `size-*` className — it keeps AvatarFallback's text size and
47
+ * AvatarBadge's dot size in sync via `data-size`. A raw className
48
+ * override (e.g. `size-14`) changes only the Avatar's own dimensions,
49
+ * not its children's.
50
+ * - AvatarFallback renders only once AvatarImage fails or is still
51
+ * loading — always pair an AvatarImage with a fallback.
52
+ * - AvatarFallback hashes to one of 6 chart colors so each identity gets a
53
+ * stable, distinct fallback — never the flat neutral bg-muted. The hash
54
+ * seed defaults to the fallback's own text content (usually initials), so
55
+ * plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass
56
+ * `colorSeed` explicitly only when the visible text isn't a stable
57
+ * per-identity string, or should key off something other than itself
58
+ * - Avatar itself has no border/ring — that's AvatarGroup's job (a
59
+ * background-colored ring for overlap separation), not Avatar's
60
+ * - AvatarGroup expects each child to be a `data-slot="avatar"` element
61
+ * (i.e. an actual `<Avatar>`) — it styles overlap and ring via that
62
+ * attribute selector, not by wrapping arbitrary children.
63
+ *
64
+ * USAGE
65
+ * <Avatar>
66
+ * <AvatarImage src="/user.png" alt="Ada Lovelace" />
67
+ * <AvatarFallback>AL</AvatarFallback>
68
+ * </Avatar>
69
+ *
70
+ * <Avatar size="lg">
71
+ * <AvatarImage src="/user.png" alt="Ada Lovelace" />
72
+ * <AvatarFallback>AL</AvatarFallback>
73
+ * <AvatarBadge className="bg-success" />
74
+ * </Avatar>
75
+ *
76
+ * <AvatarGroup>
77
+ * <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>
78
+ * <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>
79
+ * <AvatarGroupCount>+4</AvatarGroupCount>
80
+ * </AvatarGroup>
81
+ */
82
+ //# sourceMappingURL=avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/components/ui/avatar.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,UAAU,CAAA;AAIpD,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,IAAgB,EAChB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,GAAG;IACrD,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAA;CAC/B,qBAYA;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAWpD;AA4CD,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,QAAQ,CAAC,GAAG;IACzD;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,qBAkBA;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAczE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAW7B;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,WAAW,GACZ,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG"}
@@ -0,0 +1,123 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import "react";
3
+ import { Avatar as Avatar$1 } from "radix-ui";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/ui/avatar.tsx
6
+ function Avatar({ className, size = "default", ...props }) {
7
+ return /* @__PURE__ */ jsx(Avatar$1.Root, {
8
+ "data-slot": "avatar",
9
+ "data-size": size,
10
+ className: cn("group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6", className),
11
+ ...props
12
+ });
13
+ }
14
+ function AvatarImage({ className, ...props }) {
15
+ return /* @__PURE__ */ jsx(Avatar$1.Image, {
16
+ "data-slot": "avatar-image",
17
+ className: cn("aspect-square size-full rounded-full object-cover", className),
18
+ ...props
19
+ });
20
+ }
21
+ var AVATAR_FALLBACK_COLOR_VARIANTS = [
22
+ "bg-[oklch(from_var(--color-chart-1)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-1)_0.88_calc(c*0.6)_h)]",
23
+ "bg-[oklch(from_var(--color-chart-3)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-3)_0.88_calc(c*0.6)_h)]",
24
+ "bg-[oklch(from_var(--color-chart-4)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-4)_0.88_calc(c*0.6)_h)]",
25
+ "bg-[oklch(from_var(--color-chart-6)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-6)_0.88_calc(c*0.6)_h)]",
26
+ "bg-[oklch(from_var(--color-chart-7)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-7)_0.88_calc(c*0.6)_h)]",
27
+ "bg-[oklch(from_var(--color-chart-8)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-8)_0.88_calc(c*0.6)_h)]"
28
+ ];
29
+ /** djb2-ish string hash — deterministic, so the same seed always lands on the same swatch. */
30
+ function hashSeedToColorIndex(seed) {
31
+ let hash = 0;
32
+ for (let i = 0; i < seed.length; i++) {
33
+ hash = (hash << 5) - hash + seed.charCodeAt(i);
34
+ hash |= 0;
35
+ }
36
+ return Math.abs(hash) % AVATAR_FALLBACK_COLOR_VARIANTS.length;
37
+ }
38
+ function AvatarFallback({ className, colorSeed, children, ...props }) {
39
+ const seed = colorSeed ?? (typeof children === "string" ? children : void 0);
40
+ return /* @__PURE__ */ jsx(Avatar$1.Fallback, {
41
+ "data-slot": "avatar-fallback",
42
+ className: cn("flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs", seed ? AVATAR_FALLBACK_COLOR_VARIANTS[hashSeedToColorIndex(seed)] : "bg-muted text-muted-foreground", className),
43
+ ...props,
44
+ children
45
+ });
46
+ }
47
+ function AvatarBadge({ className, ...props }) {
48
+ return /* @__PURE__ */ jsx("span", {
49
+ "data-slot": "avatar-badge",
50
+ className: cn("absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className),
51
+ ...props
52
+ });
53
+ }
54
+ function AvatarGroup({ className, ...props }) {
55
+ return /* @__PURE__ */ jsx("div", {
56
+ "data-slot": "avatar-group",
57
+ className: cn("group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", className),
58
+ ...props
59
+ });
60
+ }
61
+ function AvatarGroupCount({ className, ...props }) {
62
+ return /* @__PURE__ */ jsx("div", {
63
+ "data-slot": "avatar-group-count",
64
+ className: cn("relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className),
65
+ ...props
66
+ });
67
+ }
68
+ /**
69
+ * WHEN TO USE
70
+ * - Representing a person or organization visually — profile pictures,
71
+ * comment authors, member lists.
72
+ * - AvatarGroup + AvatarGroupCount for a set of collaborators with a
73
+ * "+N" overflow count.
74
+ * - AvatarBadge for a presence dot (online/away/status) on the corner.
75
+ *
76
+ * NOT WHEN
77
+ * - Generic iconography with no identity meaning — use a Lucide icon.
78
+ * - Decorative or content imagery — Avatar is identity-specific.
79
+ * - A numeric unread/notification count — use CountBadge, not AvatarBadge
80
+ * (AvatarBadge is a plain dot with no built-in number formatting).
81
+ *
82
+ * KEY RULES
83
+ * - Prefer the `size` prop ("default" | "sm" | "lg") over a raw
84
+ * `size-*` className — it keeps AvatarFallback's text size and
85
+ * AvatarBadge's dot size in sync via `data-size`. A raw className
86
+ * override (e.g. `size-14`) changes only the Avatar's own dimensions,
87
+ * not its children's.
88
+ * - AvatarFallback renders only once AvatarImage fails or is still
89
+ * loading — always pair an AvatarImage with a fallback.
90
+ * - AvatarFallback hashes to one of 6 chart colors so each identity gets a
91
+ * stable, distinct fallback — never the flat neutral bg-muted. The hash
92
+ * seed defaults to the fallback's own text content (usually initials), so
93
+ * plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass
94
+ * `colorSeed` explicitly only when the visible text isn't a stable
95
+ * per-identity string, or should key off something other than itself
96
+ * - Avatar itself has no border/ring — that's AvatarGroup's job (a
97
+ * background-colored ring for overlap separation), not Avatar's
98
+ * - AvatarGroup expects each child to be a `data-slot="avatar"` element
99
+ * (i.e. an actual `<Avatar>`) — it styles overlap and ring via that
100
+ * attribute selector, not by wrapping arbitrary children.
101
+ *
102
+ * USAGE
103
+ * <Avatar>
104
+ * <AvatarImage src="/user.png" alt="Ada Lovelace" />
105
+ * <AvatarFallback>AL</AvatarFallback>
106
+ * </Avatar>
107
+ *
108
+ * <Avatar size="lg">
109
+ * <AvatarImage src="/user.png" alt="Ada Lovelace" />
110
+ * <AvatarFallback>AL</AvatarFallback>
111
+ * <AvatarBadge className="bg-success" />
112
+ * </Avatar>
113
+ *
114
+ * <AvatarGroup>
115
+ * <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>
116
+ * <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>
117
+ * <AvatarGroupCount>+4</AvatarGroupCount>
118
+ * </AvatarGroup>
119
+ */
120
+ //#endregion
121
+ export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage };
122
+
123
+ //# sourceMappingURL=avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatar.js","names":[],"sources":["../../../src/components/ui/avatar.tsx"],"sourcesContent":["/**\n * Avatar — person/entity image with initials fallback.\n *\n * Built on the Radix Avatar primitive. A `size` prop (\"default\" | \"sm\" |\n * \"lg\") also rescales AvatarFallback text and AvatarBadge via a shared\n * `data-size` attribute, so sizing never needs className overrides.\n */\n\nimport * as React from \"react\"\nimport { Avatar as AvatarPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Avatar({\n className,\n size = \"default\",\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root> & {\n size?: \"default\" | \"sm\" | \"lg\"\n}) {\n return (\n <AvatarPrimitive.Root\n data-slot=\"avatar\"\n data-size={size}\n className={cn(\n \"group/avatar relative flex size-8 shrink-0 rounded-full select-none data-[size=lg]:size-10 data-[size=sm]:size-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarImage({\n className,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n return (\n <AvatarPrimitive.Image\n data-slot=\"avatar-image\"\n className={cn(\n \"aspect-square size-full rounded-full object-cover\",\n className\n )}\n {...props}\n />\n )\n}\n\n/*\n * One static class string per chart color, not a template literal — Tailwind's\n * scanner only picks up complete class names that appear literally in source.\n * bg: a subtle tint of the color; text: a dark shade of that SAME color,\n * not a flat neutral ink — via the same CSS relative-color trick Bubble's\n * \"tinted\" variant already uses: keep the chart color's hue, pull the\n * background toward a light pastel (dark mode: a dark pastel) and the text\n * toward a dark, moderately saturated shade of that hue (dark mode: a light\n * one) instead of full-strength swatch + neutral ink.\n *\n * Only 6 of the 8 chart hues, not all 8: chart-1/3/4/6/7/8 (orange, indigo,\n * lime, pink, teal, fuchsia) — dropping chart-2 (violet) and chart-5 (cyan),\n * the two that sit closest to a kept hue (violet is 20.8° from indigo; cyan\n * is 39.5° from teal) and are therefore the most redundant to cut. Worst gap\n * in the kept 6 is 36.8° (pink to fuchsia) — not the >=45° this used to\n * clear before chart-1..8 was reconstructed from the Accent 1-8 primitives\n * (see theme-tokens.css), but the best any 6-of-8 subset of these\n * particular hues can do; re-verified via brute force over all 28\n * combinations, not assumed. Once pulled this light and this desaturated\n * for an avatar fill, hue is nearly all that's left to tell colors apart,\n * so even a \"close enough\" pair here reads as more similar than it would\n * at chart's full saturation.\n */\nconst AVATAR_FALLBACK_COLOR_VARIANTS = [\n \"bg-[oklch(from_var(--color-chart-1)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-1)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-1)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-3)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-3)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-3)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-4)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-4)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-4)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-6)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-6)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-6)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-7)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-7)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-7)_0.88_calc(c*0.6)_h)]\",\n \"bg-[oklch(from_var(--color-chart-8)_0.93_calc(c*0.35)_h)] text-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.85)_h)] dark:bg-[oklch(from_var(--color-chart-8)_0.32_calc(c*0.35)_h)] dark:text-[oklch(from_var(--color-chart-8)_0.88_calc(c*0.6)_h)]\",\n]\n\n/** djb2-ish string hash — deterministic, so the same seed always lands on the same swatch. */\nfunction hashSeedToColorIndex(seed: string) {\n let hash = 0\n for (let i = 0; i < seed.length; i++) {\n hash = (hash << 5) - hash + seed.charCodeAt(i)\n hash |= 0\n }\n return Math.abs(hash) % AVATAR_FALLBACK_COLOR_VARIANTS.length\n}\n\nfunction AvatarFallback({\n className,\n colorSeed,\n children,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback> & {\n /**\n * A stable identity string (name, user id, email) hashed to one of the\n * 6 chart colors. Defaults to the fallback's own text (usually\n * initials) when omitted, so a plain `<AvatarFallback>AL</AvatarFallback>`\n * is already colored — there's no neutral/grey fallback for text content.\n * Pass it explicitly when the visible text isn't a stable per-identity\n * string (e.g. it's always \"?\"), or when it differs from the real identity\n * key you want the color derived from.\n */\n colorSeed?: string\n}) {\n const seed =\n colorSeed ?? (typeof children === \"string\" ? children : undefined)\n return (\n <AvatarPrimitive.Fallback\n data-slot=\"avatar-fallback\"\n className={cn(\n \"flex size-full items-center justify-center rounded-full text-sm group-data-[size=sm]/avatar:text-xs\",\n seed\n ? AVATAR_FALLBACK_COLOR_VARIANTS[hashSeedToColorIndex(seed)]\n : \"bg-muted text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n </AvatarPrimitive.Fallback>\n )\n}\n\nfunction AvatarBadge({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"avatar-badge\"\n className={cn(\n \"absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none\",\n \"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden\",\n \"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2\",\n \"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group\"\n className={cn(\n \"group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AvatarGroupCount({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"avatar-group-count\"\n className={cn(\n \"relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n Avatar,\n AvatarImage,\n AvatarFallback,\n AvatarGroup,\n AvatarGroupCount,\n AvatarBadge,\n}\n\n/**\n * WHEN TO USE\n * - Representing a person or organization visually — profile pictures,\n * comment authors, member lists.\n * - AvatarGroup + AvatarGroupCount for a set of collaborators with a\n * \"+N\" overflow count.\n * - AvatarBadge for a presence dot (online/away/status) on the corner.\n *\n * NOT WHEN\n * - Generic iconography with no identity meaning — use a Lucide icon.\n * - Decorative or content imagery — Avatar is identity-specific.\n * - A numeric unread/notification count — use CountBadge, not AvatarBadge\n * (AvatarBadge is a plain dot with no built-in number formatting).\n *\n * KEY RULES\n * - Prefer the `size` prop (\"default\" | \"sm\" | \"lg\") over a raw\n * `size-*` className — it keeps AvatarFallback's text size and\n * AvatarBadge's dot size in sync via `data-size`. A raw className\n * override (e.g. `size-14`) changes only the Avatar's own dimensions,\n * not its children's.\n * - AvatarFallback renders only once AvatarImage fails or is still\n * loading — always pair an AvatarImage with a fallback.\n * - AvatarFallback hashes to one of 6 chart colors so each identity gets a\n * stable, distinct fallback — never the flat neutral bg-muted. The hash\n * seed defaults to the fallback's own text content (usually initials), so\n * plain `<AvatarFallback>AL</AvatarFallback>` is already colored; pass\n * `colorSeed` explicitly only when the visible text isn't a stable\n * per-identity string, or should key off something other than itself\n * - Avatar itself has no border/ring — that's AvatarGroup's job (a\n * background-colored ring for overlap separation), not Avatar's\n * - AvatarGroup expects each child to be a `data-slot=\"avatar\"` element\n * (i.e. an actual `<Avatar>`) — it styles overlap and ring via that\n * attribute selector, not by wrapping arbitrary children.\n *\n * USAGE\n * <Avatar>\n * <AvatarImage src=\"/user.png\" alt=\"Ada Lovelace\" />\n * <AvatarFallback>AL</AvatarFallback>\n * </Avatar>\n *\n * <Avatar size=\"lg\">\n * <AvatarImage src=\"/user.png\" alt=\"Ada Lovelace\" />\n * <AvatarFallback>AL</AvatarFallback>\n * <AvatarBadge className=\"bg-success\" />\n * </Avatar>\n *\n * <AvatarGroup>\n * <Avatar><AvatarFallback>CN</AvatarFallback></Avatar>\n * <Avatar><AvatarFallback>AL</AvatarFallback></Avatar>\n * <AvatarGroupCount>+4</AvatarGroupCount>\n * </AvatarGroup>\n */\n"],"mappings":";;;;;AAaA,SAAS,OAAO,EACd,WACA,OAAO,WACP,GAAG,SAGF;CACD,OACE,oBAAC,SAAgB,MAAjB;EACE,aAAU;EACV,aAAW;EACX,WAAW,GACT,oHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EACnB,WACA,GAAG,SACkD;CACrD,OACE,oBAAC,SAAgB,OAAjB;EACE,aAAU;EACV,WAAW,GACT,qDACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAyBA,IAAM,iCAAiC;CACrC;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAS,qBAAqB,MAAc;CAC1C,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,QAAQ,QAAQ,KAAK,OAAO,KAAK,WAAW,CAAC;EAC7C,QAAQ;CACV;CACA,OAAO,KAAK,IAAI,IAAI,IAAI,+BAA+B;AACzD;AAEA,SAAS,eAAe,EACtB,WACA,WACA,UACA,GAAG,SAYF;CACD,MAAM,OACJ,cAAc,OAAO,aAAa,WAAW,WAAW,KAAA;CAC1D,OACE,oBAAC,SAAgB,UAAjB;EACE,aAAU;EACV,WAAW,GACT,uGACA,OACI,+BAA+B,qBAAqB,IAAI,KACxD,kCACJ,SACF;EACA,GAAI;EAEH;CACuB,CAAA;AAE9B;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAuC;CAC1E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,4KACA,iFACA,6FACA,iFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,uGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SAC2B;CAC9B,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,4VACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Badge — inline status/category/count label.
3
+ *
4
+ * cva-driven span, non-interactive by default. Styled on two axes — `tone`
5
+ * (what it means) × `emphasis` (how loudly it's drawn) — with the old single
6
+ * `variant` list kept as a deprecated alias.
7
+ */
8
+ import * as React from "react";
9
+ import { type VariantProps } from "class-variance-authority";
10
+ declare const badgeVariants: (props?: ({
11
+ tone?: "default" | "secondary" | "destructive" | null | undefined;
12
+ emphasis?: "outline" | "ghost" | "filled" | null | undefined;
13
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
14
+ type BadgeTone = NonNullable<VariantProps<typeof badgeVariants>["tone"]>;
15
+ type BadgeEmphasis = NonNullable<VariantProps<typeof badgeVariants>["emphasis"]>;
16
+ /**
17
+ * @deprecated The single `variant` list mixed two axes (what the badge means
18
+ * and how loudly it's drawn). Use `tone` + `emphasis` instead. Still accepted
19
+ * so existing consumers render unchanged: default -> filled default,
20
+ * secondary -> filled secondary, destructive -> filled destructive,
21
+ * outline -> outline default, ghost -> ghost default. `link` (an interaction
22
+ * affordance on a non-interactive label) has no new-axis equivalent and just
23
+ * keeps its old underline look.
24
+ */
25
+ type BadgeLegacyVariant = "default" | "secondary" | "destructive" | "outline" | "ghost" | "link";
26
+ declare function Badge({ className, tone, emphasis, variant, asChild, truncate, maxWidth, style, children, title, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
27
+ asChild?: boolean;
28
+ /** Cuts a label that's too long for its space off with an ellipsis instead of overflowing. Pair with `maxWidth` (or a width from the parent) — without one the badge just sizes to its text. Not applied with `asChild`. */
29
+ truncate?: boolean;
30
+ /** Caps the badge's width (a number is px, or any CSS size) and implies `truncate`. */
31
+ maxWidth?: number | string;
32
+ /** @deprecated use `tone` + `emphasis` */
33
+ variant?: BadgeLegacyVariant;
34
+ }): React.JSX.Element;
35
+ export { Badge, badgeVariants };
36
+ export type { BadgeTone, BadgeEmphasis };
37
+ /**
38
+ * WHEN TO USE
39
+ * - A status, category, count, or tag shown inline with other content
40
+ * (row status, list tag, small metadata chip).
41
+ * - An operational-status indicator (active, failed, expiring, pending) —
42
+ * emphasis="outline" with a small colored icon, not a filled badge. This
43
+ * is Badge's status-indicator convention; there's no separate component
44
+ * for it.
45
+ *
46
+ * NOT WHEN
47
+ * - Interactive filters or removable tags — those need their own
48
+ * click/remove handling, which Badge doesn't provide.
49
+ * - An action — use Button.
50
+ * - Long text — Badge is sized and padded for short labels only. When a user-supplied label might run long anyway (a role or tag name), cap it with `maxWidth` / `truncate`.
51
+ *
52
+ * KEY RULES
53
+ * - `truncate` / `maxWidth` ellipsize a long label and show the full text as a native `title`; icons are untouched. They don't apply with `asChild`.
54
+ * - Non-interactive by default; pass `asChild` to render as an `<a>` when
55
+ * the badge itself needs to link somewhere.
56
+ * - Two axes, not one list. tone: default | secondary | destructive — what the
57
+ * label means. emphasis: filled | outline | ghost — how loudly it's drawn.
58
+ * Every tone×emphasis pair is styled; omit both for a filled default badge.
59
+ * The old single `variant` prop (default, secondary, destructive, outline,
60
+ * ghost, link) still renders identically but is deprecated — it folded the
61
+ * two axes into one list. `link` has no new-axis equivalent: a Badge is
62
+ * non-interactive, so an underlined link look belongs on Button/anchor.
63
+ * - Custom semantic colors (success/warning/alert/info) aren't separate
64
+ * variants — apply the token utility directly, using each status's
65
+ * subtle `-light`/`-text` pair (not the solid `-foreground` pairing,
66
+ * which reads too loud for an inline tag), e.g. `className="bg-success-light
67
+ * text-success-text"`.
68
+ * - Status-indicator convention: emphasis="outline" + a leading icon colored
69
+ * with the matching semantic token, `data-icon="inline-start"`. Fixed
70
+ * icon/color pairing, don't substitute other icons for these:
71
+ * success -> CheckIcon text-success
72
+ * alert -> XIcon text-alert (text-destructive for a true error, not just "alert")
73
+ * warning -> TriangleAlertIcon text-warning
74
+ * info -> InfoIcon text-info
75
+ * default -> PenLineIcon text-muted-foreground
76
+ * - Flush status-indicator variant: the same icon/color pairing above, but
77
+ * `emphasis="ghost"` (no border, no fill) plus
78
+ * `className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"`
79
+ * — the padding overrides zero out what `emphasis="outline"` needs for
80
+ * its own chip look but this doesn't, and `hover:bg-transparent` drops
81
+ * `ghost`'s subtle hover highlight (meant for when Badge is `asChild` as
82
+ * a real link), which a flush, non-interactive status doesn't need. For
83
+ * a status that needs to sit flush against other plain content instead
84
+ * of reading as its own separate chip: a `KeyValuePairValue` slot, a
85
+ * table cell (especially one with a `MetaList` underneath, where a
86
+ * padded chip would misalign against the MetaList's own flush left/right
87
+ * edges), or right-aligned in a flex row next to one.
88
+ * - An AI-assigned status/tag is a plain composition, not a variant: keep the Badge exactly
89
+ * as the status calls for and put `AILabel` (size="sm" — never the opt-in icon-only "xs" by
90
+ * default) beside it in an `inline-flex` span. Never restyle the Badge itself
91
+ * with the AI gradient — that would be indistinguishable from Button's AI Chip
92
+ * (variant="ai" rounded-full), and the two must read apart: the Chip is an action, a Badge
93
+ * is not. See AI/Badge.
94
+ *
95
+ * USAGE
96
+ * <Badge>Default</Badge>
97
+ * <Badge tone="destructive">Overdue</Badge>
98
+ * <Badge tone="secondary" emphasis="ghost">Draft</Badge>
99
+ * <Badge className="bg-success-light text-success-text">Success</Badge>
100
+ * <Badge><CheckIcon />Verified</Badge>
101
+ * <Badge maxWidth={120}>Regional Clinical Operations Lead</Badge>
102
+ *
103
+ * // Status indicator convention
104
+ * <Badge emphasis="outline">
105
+ * <CheckIcon className="text-success" data-icon="inline-start" />
106
+ * Active
107
+ * </Badge>
108
+ * <Badge emphasis="outline">
109
+ * <XIcon className="text-alert" data-icon="inline-start" />
110
+ * Failed
111
+ * </Badge>
112
+ * <Badge emphasis="outline">
113
+ * <TriangleAlertIcon className="text-warning" data-icon="inline-start" />
114
+ * Expiring soon
115
+ * </Badge>
116
+ * <Badge emphasis="outline">
117
+ * <PenLineIcon className="text-muted-foreground" data-icon="inline-start" />
118
+ * Draft
119
+ * </Badge>
120
+ *
121
+ * // Flush status indicator — KVP value, table cell, or right-aligned next to a MetaList
122
+ * <Badge
123
+ * emphasis="ghost"
124
+ * className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"
125
+ * >
126
+ * <CheckIcon className="text-success" data-icon="inline-start" />
127
+ * Active
128
+ * </Badge>
129
+ */
130
+ //# sourceMappingURL=badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../../src/components/ui/badge.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAKjE,QAAA,MAAM,aAAa;;;8EA8ElB,CAAA;AAED,KAAK,SAAS,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AACxE,KAAK,aAAa,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;AAChF;;;;;;;;GAQG;AACH,KAAK,kBAAkB,GACrB,SAAS,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAaxE,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,OAAe,EACf,QAAgB,EAChB,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,GAC7B,YAAY,CAAC,OAAO,aAAa,CAAC,GAAG;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,4NAA4N;IAC5N,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC1B,0CAA0C;IAC1C,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAC7B,qBAiDF;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAA;AAC/B,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4FG"}