@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,173 @@
1
+ "use client";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { getPortalContainer } from "../../lib/scope.js";
4
+ import "react";
5
+ import { DropdownMenu as DropdownMenu$1 } from "radix-ui";
6
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/ui/dropdown-menu.tsx
9
+ function DropdownMenu({ ...props }) {
10
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Root, {
11
+ "data-slot": "dropdown-menu",
12
+ ...props
13
+ });
14
+ }
15
+ function DropdownMenuPortal({ ...props }) {
16
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, {
17
+ "data-slot": "dropdown-menu-portal",
18
+ container: getPortalContainer(),
19
+ ...props
20
+ });
21
+ }
22
+ function DropdownMenuTrigger({ ...props }) {
23
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Trigger, {
24
+ "data-slot": "dropdown-menu-trigger",
25
+ ...props
26
+ });
27
+ }
28
+ function DropdownMenuContent({ className, align = "start", sideOffset = 4, ...props }) {
29
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, {
30
+ container: getPortalContainer(),
31
+ children: /* @__PURE__ */ jsx(DropdownMenu$1.Content, {
32
+ "data-slot": "dropdown-menu-content",
33
+ sideOffset,
34
+ align,
35
+ className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-popover ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", className),
36
+ ...props
37
+ })
38
+ });
39
+ }
40
+ function DropdownMenuGroup({ ...props }) {
41
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Group, {
42
+ "data-slot": "dropdown-menu-group",
43
+ ...props
44
+ });
45
+ }
46
+ function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
47
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Item, {
48
+ "data-slot": "dropdown-menu-item",
49
+ "data-inset": inset,
50
+ "data-variant": variant,
51
+ className: cn("group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive", className),
52
+ ...props
53
+ });
54
+ }
55
+ function DropdownMenuCheckboxItem({ className, children, checked, inset, ...props }) {
56
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.CheckboxItem, {
57
+ "data-slot": "dropdown-menu-checkbox-item",
58
+ "data-inset": inset,
59
+ className: cn("relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
60
+ checked,
61
+ ...props,
62
+ children: [/* @__PURE__ */ jsx("span", {
63
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
64
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
65
+ children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) })
66
+ }), children]
67
+ });
68
+ }
69
+ function DropdownMenuRadioGroup({ ...props }) {
70
+ return /* @__PURE__ */ jsx(DropdownMenu$1.RadioGroup, {
71
+ "data-slot": "dropdown-menu-radio-group",
72
+ ...props
73
+ });
74
+ }
75
+ function DropdownMenuRadioItem({ className, children, inset, ...props }) {
76
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.RadioItem, {
77
+ "data-slot": "dropdown-menu-radio-item",
78
+ "data-inset": inset,
79
+ className: cn("relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
80
+ ...props,
81
+ children: [/* @__PURE__ */ jsx("span", {
82
+ className: "pointer-events-none absolute right-2 flex items-center justify-center",
83
+ "data-slot": "dropdown-menu-radio-item-indicator",
84
+ children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) })
85
+ }), children]
86
+ });
87
+ }
88
+ function DropdownMenuLabel({ className, inset, ...props }) {
89
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Label, {
90
+ "data-slot": "dropdown-menu-label",
91
+ "data-inset": inset,
92
+ className: cn("px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7", className),
93
+ ...props
94
+ });
95
+ }
96
+ function DropdownMenuSeparator({ className, ...props }) {
97
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Separator, {
98
+ "data-slot": "dropdown-menu-separator",
99
+ className: cn("-mx-1 my-1 h-px bg-border", className),
100
+ ...props
101
+ });
102
+ }
103
+ function DropdownMenuShortcut({ className, ...props }) {
104
+ return /* @__PURE__ */ jsx("span", {
105
+ "data-slot": "dropdown-menu-shortcut",
106
+ className: cn("ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground", className),
107
+ ...props
108
+ });
109
+ }
110
+ function DropdownMenuSub({ ...props }) {
111
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Sub, {
112
+ "data-slot": "dropdown-menu-sub",
113
+ ...props
114
+ });
115
+ }
116
+ function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
117
+ return /* @__PURE__ */ jsxs(DropdownMenu$1.SubTrigger, {
118
+ "data-slot": "dropdown-menu-sub-trigger",
119
+ "data-inset": inset,
120
+ className: cn("flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
121
+ ...props,
122
+ children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto" })]
123
+ });
124
+ }
125
+ function DropdownMenuSubContent({ className, ...props }) {
126
+ return /* @__PURE__ */ jsx(DropdownMenu$1.SubContent, {
127
+ "data-slot": "dropdown-menu-sub-content",
128
+ className: cn("z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-popover ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", className),
129
+ ...props
130
+ });
131
+ }
132
+ /**
133
+ * WHEN TO USE
134
+ * - Secondary or tertiary actions on a row or entity, behind a "..." overflow trigger
135
+ * - View/appearance toggles via DropdownMenuCheckboxItem, or a single-select list via
136
+ * DropdownMenuRadioGroup + DropdownMenuRadioItem
137
+ * - Actions that benefit from grouping (DropdownMenuGroup/Label/Separator), keyboard shortcut
138
+ * hints (DropdownMenuShortcut), or nested submenus (DropdownMenuSub)
139
+ *
140
+ * NOT WHEN
141
+ * - The action is a page's primary action — use Button directly
142
+ * - The user is picking a value for a form field — use Select
143
+ * - The menu opens on right-click rather than a click trigger — use ContextMenu
144
+ *
145
+ * KEY RULES
146
+ * - DropdownMenuItem accepts variant="default" | "destructive"; use "destructive" for
147
+ * irreversible entries (delete, log out, remove) instead of custom text-color classes
148
+ * - Wrap DropdownMenuTrigger's child in asChild so the trigger renders as that element
149
+ * (e.g. a Button) rather than being wrapped in an extra <button>
150
+ * - DropdownMenuContent defaults to align="start" and sideOffset={4}; width is controlled
151
+ * via className (e.g. "w-56"), not a prop
152
+ * - DropdownMenuCheckboxItem/RadioItem are controlled — checked/value and their onChange
153
+ * handlers must be wired by the caller, they hold no internal state
154
+ *
155
+ * USAGE
156
+ * <DropdownMenu>
157
+ * <DropdownMenuTrigger asChild><Button variant="outline">Open menu</Button></DropdownMenuTrigger>
158
+ * <DropdownMenuContent className="w-56">
159
+ * <DropdownMenuLabel>My account</DropdownMenuLabel>
160
+ * <DropdownMenuSeparator />
161
+ * <DropdownMenuItem><UserIcon />Profile<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut></DropdownMenuItem>
162
+ * <DropdownMenuItem variant="destructive"><LogOutIcon />Log out</DropdownMenuItem>
163
+ * </DropdownMenuContent>
164
+ * </DropdownMenu>
165
+ *
166
+ * <DropdownMenuCheckboxItem checked={showStatus} onCheckedChange={setShowStatus}>
167
+ * Status bar
168
+ * </DropdownMenuCheckboxItem>
169
+ */
170
+ //#endregion
171
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger };
172
+
173
+ //# sourceMappingURL=dropdown-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdown-menu.js","names":[],"sources":["../../../src/components/ui/dropdown-menu.tsx"],"sourcesContent":["\"use client\"\n\n/**\n * DropdownMenu — menu of actions or options opened from a trigger element\n *\n * Built on the Radix DropdownMenu primitive (Root/Trigger/Content/Item/...),\n * styled with MMDS popover/accent tokens, with a `variant=\"destructive\"`\n * styling hook on DropdownMenuItem for dangerous entries.\n */\n\nimport * as React from \"react\"\nimport { DropdownMenu as DropdownMenuPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\nimport { getPortalContainer } from \"@/lib/scope\"\nimport { CheckIcon, ChevronRightIcon } from \"lucide-react\"\n\nfunction DropdownMenu({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return (\n <DropdownMenuPrimitive.Portal\n data-slot=\"dropdown-menu-portal\"\n container={getPortalContainer()}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuContent({\n className,\n align = \"start\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal container={getPortalContainer()}>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n align={align}\n className={cn(\n \"z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-popover ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return (\n <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-checkbox-item-indicator\"\n >\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return (\n <DropdownMenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-radio-item-indicator\"\n >\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto\" />\n </DropdownMenuPrimitive.SubTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"z-50 min-w-[96px] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-lg bg-popover p-1 text-popover-foreground shadow-popover ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n\n/**\n * WHEN TO USE\n * - Secondary or tertiary actions on a row or entity, behind a \"...\" overflow trigger\n * - View/appearance toggles via DropdownMenuCheckboxItem, or a single-select list via\n * DropdownMenuRadioGroup + DropdownMenuRadioItem\n * - Actions that benefit from grouping (DropdownMenuGroup/Label/Separator), keyboard shortcut\n * hints (DropdownMenuShortcut), or nested submenus (DropdownMenuSub)\n *\n * NOT WHEN\n * - The action is a page's primary action — use Button directly\n * - The user is picking a value for a form field — use Select\n * - The menu opens on right-click rather than a click trigger — use ContextMenu\n *\n * KEY RULES\n * - DropdownMenuItem accepts variant=\"default\" | \"destructive\"; use \"destructive\" for\n * irreversible entries (delete, log out, remove) instead of custom text-color classes\n * - Wrap DropdownMenuTrigger's child in asChild so the trigger renders as that element\n * (e.g. a Button) rather than being wrapped in an extra <button>\n * - DropdownMenuContent defaults to align=\"start\" and sideOffset={4}; width is controlled\n * via className (e.g. \"w-56\"), not a prop\n * - DropdownMenuCheckboxItem/RadioItem are controlled — checked/value and their onChange\n * handlers must be wired by the caller, they hold no internal state\n *\n * USAGE\n * <DropdownMenu>\n * <DropdownMenuTrigger asChild><Button variant=\"outline\">Open menu</Button></DropdownMenuTrigger>\n * <DropdownMenuContent className=\"w-56\">\n * <DropdownMenuLabel>My account</DropdownMenuLabel>\n * <DropdownMenuSeparator />\n * <DropdownMenuItem><UserIcon />Profile<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut></DropdownMenuItem>\n * <DropdownMenuItem variant=\"destructive\"><LogOutIcon />Log out</DropdownMenuItem>\n * </DropdownMenuContent>\n * </DropdownMenu>\n *\n * <DropdownMenuCheckboxItem checked={showStatus} onCheckedChange={setShowStatus}>\n * Status bar\n * </DropdownMenuCheckboxItem>\n */\n"],"mappings":";;;;;;;;AAiBA,SAAS,aAAa,EACpB,GAAG,SACuD;CAC1D,OAAO,oBAAC,eAAsB,MAAvB;EAA4B,aAAU;EAAgB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,mBAAmB,EAC1B,GAAG,SACyD;CAC5D,OACE,oBAAC,eAAsB,QAAvB;EACE,aAAU;EACV,WAAW,mBAAmB;EAC9B,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,GAAG,SAC0D;CAC7D,OACE,oBAAC,eAAsB,SAAvB;EACE,aAAU;EACV,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,WACA,QAAQ,SACR,aAAa,GACb,GAAG,SAC0D;CAC7D,OACE,oBAAC,eAAsB,QAAvB;EAA8B,WAAW,mBAAmB;EAC1D,UAAA,oBAAC,eAAsB,SAAvB;GACE,aAAU;GACE;GACL;GACP,WAAW,GACT,uqBACA,SACF;GACA,GAAI;EACL,CAAA;CAC2B,CAAA;AAElC;AAEA,SAAS,kBAAkB,EACzB,GAAG,SACwD;CAC3D,OACE,oBAAC,eAAsB,OAAvB;EAA6B,aAAU;EAAsB,GAAI;CAAQ,CAAA;AAE7E;AAEA,SAAS,iBAAiB,EACxB,WACA,OACA,UAAU,WACV,GAAG,SAIF;CACD,OACE,oBAAC,eAAsB,MAAvB;EACE,aAAU;EACV,cAAY;EACZ,gBAAc;EACd,WAAW,GACT,8oBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,yBAAyB,EAChC,WACA,UACA,SACA,OACA,GAAG,SAGF;CACD,OACE,qBAAC,eAAsB,cAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,8VACA,SACF;EACS;EACT,GAAI;EARN,UAAA,CAUE,oBAAC,QAAD;GACE,WAAU;GACV,aAAU;GAEV,UAAA,oBAAC,eAAsB,eAAvB,EAAA,UACE,oBAAC,WAAD,CAAY,CAAA,EACuB,CAAA;EACjC,CAAA,GACL,QACiC;;AAExC;AAEA,SAAS,uBAAuB,EAC9B,GAAG,SAC6D;CAChE,OACE,oBAAC,eAAsB,YAAvB;EACE,aAAU;EACV,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,WACA,UACA,OACA,GAAG,SAGF;CACD,OACE,qBAAC,eAAsB,WAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,8VACA,SACF;EACA,GAAI;EAPN,UAAA,CASE,oBAAC,QAAD;GACE,WAAU;GACV,aAAU;GAEV,UAAA,oBAAC,eAAsB,eAAvB,EAAA,UACE,oBAAC,WAAD,CAAY,CAAA,EACuB,CAAA;EACjC,CAAA,GACL,QAC8B;;AAErC;AAEA,SAAS,kBAAkB,EACzB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAAC,eAAsB,OAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,yEACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,sBAAsB,EAC7B,WACA,GAAG,SAC4D;CAC/D,OACE,oBAAC,eAAsB,WAAvB;EACE,aAAU;EACV,WAAW,GAAG,6BAA6B,SAAS;EACpD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,qBAAqB,EAC5B,WACA,GAAG,SAC4B;CAC/B,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GACT,+GACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EACvB,GAAG,SACsD;CACzD,OAAO,oBAAC,eAAsB,KAAvB;EAA2B,aAAU;EAAoB,GAAI;CAAQ,CAAA;AAC9E;AAEA,SAAS,uBAAuB,EAC9B,WACA,OACA,UACA,GAAG,SAGF;CACD,OACE,qBAAC,eAAsB,YAAvB;EACE,aAAU;EACV,cAAY;EACZ,WAAW,GACT,yXACA,SACF;EACA,GAAI;EAPN,UAAA,CASG,UACD,oBAAC,kBAAD,EAAkB,WAAU,UAAW,CAAA,CACP;;AAEtC;AAEA,SAAS,uBAAuB,EAC9B,WACA,GAAG,SAC6D;CAChE,OACE,oBAAC,eAAsB,YAAvB;EACE,aAAU;EACV,WAAW,GACT,shBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Dropzone — click-or-drag target that hands files to the caller.
3
+ *
4
+ * A composite over Attachment, not a new primitive: it's Attachment's
5
+ * `state="idle"` dashed-border look wired up with a native hidden file
6
+ * input plus drag-and-drop handlers. Selected files themselves aren't
7
+ * rendered here — map them to a stack of Attachment rows below the
8
+ * dropzone (state="uploading"/"error"/"done" per file, AttachmentAction
9
+ * for retry/remove) the same way any other Attachment list works.
10
+ * FileTypeIcon (below) gives each row a colored icon circle per file type,
11
+ * as an AttachmentMedia composition.
12
+ */
13
+ import * as React from "react";
14
+ import { AttachmentMedia } from "../../components/ui/attachment";
15
+ type FileTypeFamily = "video" | "image" | "document" | "audio" | "other";
16
+ /** Derives a file-type family from a File or a plain MIME-type string. */
17
+ declare function getFileTypeFamily(file: File | string): FileTypeFamily;
18
+ /**
19
+ * FileTypeIcon — colored icon-circle, per file type.
20
+ *
21
+ * A thin AttachmentMedia composition, not a new primitive: swaps its default
22
+ * square muted-bg look for a `rounded-full` circle tinted per file-type
23
+ * family (derived from `file`'s MIME type, or pass `family` directly).
24
+ */
25
+ declare function FileTypeIcon({ file, family, className, ...props }: Omit<React.ComponentProps<typeof AttachmentMedia>, "variant" | "children"> & {
26
+ file?: File | string;
27
+ family?: FileTypeFamily;
28
+ }): React.JSX.Element;
29
+ declare function Dropzone({ className, onFilesSelected, accept, multiple, disabled, size, state, activeContent, errorContent, children, id, "aria-describedby": ariaDescribedby, "aria-invalid": ariaInvalid, inputRef, ...props }: Omit<React.ComponentProps<"label">, "onDrop" | "onDragOver" | "onDragLeave"> & {
30
+ onFilesSelected: (files: File[]) => void;
31
+ accept?: string;
32
+ multiple?: boolean;
33
+ disabled?: boolean;
34
+ size?: "default" | "sm" | "xs";
35
+ /** Overrides the drag-derived visual state — mainly for demos; leave unset for real drag-and-drop. */
36
+ state?: "default" | "active" | "error";
37
+ /** Overrides the built-in "active" feedback content (icon + "Drag your files here"). */
38
+ activeContent?: React.ReactNode;
39
+ /** Overrides the built-in "error" feedback content (icon + "File format not accepted"). */
40
+ errorContent?: React.ReactNode;
41
+ /** Ref to the underlying (visually-hidden) `<input type="file">` — the actual control `id`/`aria-describedby`/`aria-invalid` land on, not the outer `<label>`. */
42
+ inputRef?: React.Ref<HTMLInputElement>;
43
+ }): React.JSX.Element;
44
+ export { Dropzone, FileTypeIcon, getFileTypeFamily };
45
+ /**
46
+ * WHEN TO USE
47
+ * - A drag-and-drop or click-to-browse target for picking one or more files
48
+ * - Paired with a list of Attachment rows below it, one per selected file,
49
+ * for per-file progress/error/remove — this is Dropzone's job, not the
50
+ * list's; there's no dedicated list component, just Attachment rows
51
+ * - FileTypeIcon on each row's AttachmentMedia slot for colored, per-type
52
+ * icon circles (video/image/document/audio/other)
53
+ *
54
+ * NOT WHEN
55
+ * - A plain, unstyled file input with no drop target or preview — use Input type="file"
56
+ * - Files are already attached and just need to be displayed — use Attachment/AttachmentGroup directly
57
+ *
58
+ * KEY RULES
59
+ * - `onFilesSelected(files: File[])` fires from both the native picker (click) and drag-and-drop —
60
+ * handle it once, not twice
61
+ * - `size`: "default" | "sm" | "xs" — controls LAYOUT (Dropzone owns this via `dropzoneVariants`,
62
+ * not just padding/icon-size): "default" stacks the icon above the text, "sm" puts the icon on
63
+ * the left instead (row, not stacked — the format/size hint stays, it's not optional info, just
64
+ * repositioned), "xs" drops the icon entirely down to one compact text line — same rule every
65
+ * other xs UI state in this library follows (see Empty). The children themselves (icon, hint
66
+ * text) are still fully custom — Dropzone only dictates the flex direction and whether there's
67
+ * room to show a leading icon; get the actual "which size shows what" split from a real example
68
+ * like the Sizes story, don't just eyeball it from this list.
69
+ * - `state` is normally left unset — Dropzone derives "active" (valid drag-over) and "error"
70
+ * (drag-over with a file type `accept` would reject) from real drag events by inspecting
71
+ * `dataTransfer.items[].type`, which browsers expose pre-drop. Pass `state` explicitly only
72
+ * to force a look for a demo; a real Dropzone should let this stay derived.
73
+ * - Unlike the idle look, "active"/"error" REPLACE `children` with built-in feedback (a filled
74
+ * icon + a short line — "Drag your files here" / "File format not accepted", no icon at
75
+ * `size="xs"` same as everywhere else) — override via `activeContent`/`errorContent` if the
76
+ * defaults don't fit; this is deliberate, not something to fight with children-based tricks.
77
+ * - The drag-over "error" look is a file-type warning ONLY, and it does not block the drop —
78
+ * the file still reaches `onFilesSelected`. File size can't be checked before drop (browsers
79
+ * don't expose it until then), so "file too large" is always a file-list-level error — render
80
+ * that file's Attachment with `state="error"` and the reason in AttachmentDescription, not
81
+ * as a Dropzone state.
82
+ * - The dropzone renders as a `label` wrapping a visually-hidden `<input type="file">`, so
83
+ * clicking anywhere in it opens the OS file picker with zero extra JS
84
+ * - `accept`/`multiple`/`disabled` map straight to the underlying input's attributes
85
+ * - `id`/`aria-describedby`/`aria-invalid` land on the underlying `<input type="file">`, not the
86
+ * outer `<label>` — a label only passes its accessible *name* through, not these relationships —
87
+ * so wire hint/error text (e.g. a rejection reason) through `aria-describedby`/`aria-invalid`
88
+ * rather than assuming label-wrapping is enough. `id` falls back to a generated one if unset.
89
+ * `inputRef` reaches the same underlying input if you need the ref itself.
90
+ * - Idle-state content (icon, "Drag files here or browse", format/size hints, an optional sample-
91
+ * file link) is fully custom via children — nothing is hardcoded, this component only owns the
92
+ * interaction wiring, the idle-state look, and the active/error feedback swap above
93
+ * - FileTypeIcon derives its color+icon from `file`'s MIME type (or pass `family` directly) — it's
94
+ * an AttachmentMedia composition (`rounded-full` + a per-family tint), not a new component tree
95
+ * - Attachment defaults to `w-fit` (sized to its own content, right for a horizontal chip strip) —
96
+ * for a vertical file list where every row should line up at the same width, pass
97
+ * `className="w-full"` on each Attachment row
98
+ * - AttachmentAction covers both retry and remove — render two of them (retry then remove) on an
99
+ * error row, one (remove) otherwise
100
+ *
101
+ * USAGE
102
+ * const [files, setFiles] = React.useState<Array<{ file: File; state: "uploading" | "error" | "done" }>>([])
103
+ * <div className="grid gap-3">
104
+ * <Dropzone
105
+ * accept="image/png,image/jpeg"
106
+ * onFilesSelected={(picked) =>
107
+ * setFiles((prev) => [...prev, ...picked.map((file) => ({ file, state: "uploading" as const }))])
108
+ * }
109
+ * >
110
+ * <UploadIcon className="text-muted-foreground" />
111
+ * <p className="text-sm font-medium">Drag your files here or <span className="text-primary">browse</span></p>
112
+ * <p className="text-xs text-muted-foreground">PNG or JPEG, up to 25MB</p>
113
+ * </Dropzone>
114
+ *
115
+ * {files.map(({ file, state }) => (
116
+ * <Attachment key={file.name} state={state} className="w-full">
117
+ * <FileTypeIcon file={file} />
118
+ * <AttachmentContent>
119
+ * <AttachmentTitle>{file.name}</AttachmentTitle>
120
+ * <AttachmentDescription>
121
+ * {state === "error" ? "File exceeds the 25MB limit" : `${(file.size / 1024).toFixed(1)} KB`}
122
+ * </AttachmentDescription>
123
+ * </AttachmentContent>
124
+ * <AttachmentActions>
125
+ * {state === "error" && (
126
+ * <AttachmentAction aria-label={`Retry ${file.name}`} onClick={() => retry(file)}>
127
+ * <RefreshCwIcon />
128
+ * </AttachmentAction>
129
+ * )}
130
+ * <AttachmentAction
131
+ * aria-label={`Remove ${file.name}`}
132
+ * onClick={() => setFiles((prev) => prev.filter((f) => f.file !== file))}
133
+ * >
134
+ * <XIcon />
135
+ * </AttachmentAction>
136
+ * </AttachmentActions>
137
+ * </Attachment>
138
+ * ))}
139
+ * </div>
140
+ */
141
+ //# sourceMappingURL=dropzone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropzone.d.ts","sourceRoot":"","sources":["../../../src/components/ui/dropzone.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAY9B,OAAO,EAAc,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAExE,KAAK,cAAc,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAA;AAExE,0EAA0E;AAC1E,iBAAS,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,cAAc,CAO9D;AAkDD;;;;;;GAMG;AACH,iBAAS,YAAY,CAAC,EACpB,IAAI,EACJ,MAAM,EACN,SAAS,EACT,GAAG,KAAK,EACT,EAAE,IAAI,CACL,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,EAC5C,SAAS,GAAG,UAAU,CACvB,GAAG;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB,qBAaA;AA4ED,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,eAAe,EACf,MAAM,EACN,QAAe,EACf,QAAQ,EACR,IAAgB,EAChB,KAAK,EACL,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,EAAE,EACF,kBAAkB,EAAE,eAAe,EACnC,cAAc,EAAE,WAAW,EAC3B,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,IAAI,CACL,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAC7B,QAAQ,GAAG,YAAY,GAAG,aAAa,CACxC,GAAG;IACF,eAAe,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAA;IAC9B,sGAAsG;IACtG,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;IACtC,wFAAwF;IACxF,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B,2FAA2F;IAC3F,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,kKAAkK;IAClK,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;CACvC,qBAyEA;AAED,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAA;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+FG"}
@@ -0,0 +1,257 @@
1
+ import { cn } from "../../lib/utils.js";
2
+ import { Attachment, AttachmentMedia } from "./attachment.js";
3
+ import * as React from "react";
4
+ import { ArrowDownToLineIcon, FileAudioIcon, FileIcon, FileTextIcon, FileVideoIcon, ImageIcon } from "lucide-react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { cva } from "class-variance-authority";
7
+ //#region src/components/ui/dropzone.tsx
8
+ /**
9
+ * Dropzone — click-or-drag target that hands files to the caller.
10
+ *
11
+ * A composite over Attachment, not a new primitive: it's Attachment's
12
+ * `state="idle"` dashed-border look wired up with a native hidden file
13
+ * input plus drag-and-drop handlers. Selected files themselves aren't
14
+ * rendered here — map them to a stack of Attachment rows below the
15
+ * dropzone (state="uploading"/"error"/"done" per file, AttachmentAction
16
+ * for retry/remove) the same way any other Attachment list works.
17
+ * FileTypeIcon (below) gives each row a colored icon circle per file type,
18
+ * as an AttachmentMedia composition.
19
+ */
20
+ /** Derives a file-type family from a File or a plain MIME-type string. */
21
+ function getFileTypeFamily(file) {
22
+ const type = typeof file === "string" ? file : file.type;
23
+ if (type.startsWith("video/")) return "video";
24
+ if (type.startsWith("image/")) return "image";
25
+ if (type.startsWith("audio/")) return "audio";
26
+ if (type.startsWith("application/")) return "document";
27
+ return "other";
28
+ }
29
+ /** Whether a dragged item's MIME type matches an `accept` list (comma-separated, wildcards like "image/*" supported). */
30
+ function matchesAccept(type, accept) {
31
+ if (!type) return true;
32
+ return accept.split(",").map((entry) => entry.trim()).filter(Boolean).some((entry) => entry.endsWith("/*") ? type.startsWith(entry.slice(0, -1)) : type === entry);
33
+ }
34
+ var fileTypeIcons = {
35
+ video: FileVideoIcon,
36
+ image: ImageIcon,
37
+ document: FileTextIcon,
38
+ audio: FileAudioIcon,
39
+ other: FileIcon
40
+ };
41
+ var fileTypeAccents = {
42
+ video: "!bg-chart-2/15 !text-chart-2",
43
+ image: "!bg-chart-6/15 !text-chart-6",
44
+ document: "!bg-chart-3/15 !text-chart-3",
45
+ audio: "!bg-chart-1/15 !text-chart-1",
46
+ other: "!bg-chart-4/15 !text-chart-4"
47
+ };
48
+ /**
49
+ * FileTypeIcon — colored icon-circle, per file type.
50
+ *
51
+ * A thin AttachmentMedia composition, not a new primitive: swaps its default
52
+ * square muted-bg look for a `rounded-full` circle tinted per file-type
53
+ * family (derived from `file`'s MIME type, or pass `family` directly).
54
+ */
55
+ function FileTypeIcon({ file, family, className, ...props }) {
56
+ const resolvedFamily = family ?? (file ? getFileTypeFamily(file) : "other");
57
+ const Icon = fileTypeIcons[resolvedFamily];
58
+ return /* @__PURE__ */ jsx(AttachmentMedia, {
59
+ variant: "icon",
60
+ className: cn("rounded-full", fileTypeAccents[resolvedFamily], className),
61
+ ...props,
62
+ children: /* @__PURE__ */ jsx(Icon, {})
63
+ });
64
+ }
65
+ var dropzoneVariants = cva("group/dropzone w-full cursor-pointer items-center justify-center transition-colors", {
66
+ variants: { size: {
67
+ default: "flex-col gap-1.5 p-6 text-center [&_svg:not([class*='size-'])]:size-8",
68
+ sm: "flex-row gap-3 p-4 text-left [&_svg:not([class*='size-'])]:size-6",
69
+ xs: "flex-row gap-2 p-2.5 text-left [&_svg:not([class*='size-'])]:size-5"
70
+ } },
71
+ defaultVariants: { size: "default" }
72
+ });
73
+ var dropzoneFeedbackIconVariants = cva("flex shrink-0 items-center justify-center [&_svg]:pointer-events-none", {
74
+ variants: { size: {
75
+ default: "size-10 [&_svg:not([class*='size-'])]:size-5",
76
+ sm: "size-9 [&_svg:not([class*='size-'])]:size-4",
77
+ xs: "size-7 [&_svg:not([class*='size-'])]:size-4"
78
+ } },
79
+ defaultVariants: { size: "default" }
80
+ });
81
+ /** Default "active" (valid drag-over) feedback — a filled icon plus a short instruction, replacing `children` entirely while dragging. No icon at xs, same as everywhere else in this file. */
82
+ function DropzoneActiveContent({ size }) {
83
+ return /* @__PURE__ */ jsxs(Fragment, { children: [size !== "xs" && /* @__PURE__ */ jsx("div", {
84
+ className: cn(dropzoneFeedbackIconVariants({ size }), "rounded-lg bg-primary text-primary-foreground"),
85
+ children: /* @__PURE__ */ jsx(ArrowDownToLineIcon, {})
86
+ }), /* @__PURE__ */ jsx("p", {
87
+ className: "font-medium text-primary",
88
+ children: "Drag your files here"
89
+ })] });
90
+ }
91
+ /** Default "error" (rejected file type on drag-over) feedback — a filled "!" plus a short reason, replacing `children` entirely while dragging. No icon at xs, same as everywhere else in this file. */
92
+ function DropzoneErrorContent({ size }) {
93
+ return /* @__PURE__ */ jsxs(Fragment, { children: [size !== "xs" && /* @__PURE__ */ jsx("div", {
94
+ className: cn(dropzoneFeedbackIconVariants({ size }), "rounded-full bg-destructive text-destructive-foreground"),
95
+ children: /* @__PURE__ */ jsx("span", {
96
+ className: "text-base leading-none font-bold",
97
+ children: "!"
98
+ })
99
+ }), /* @__PURE__ */ jsx("p", {
100
+ className: "font-medium text-destructive",
101
+ children: "File format not accepted"
102
+ })] });
103
+ }
104
+ function Dropzone({ className, onFilesSelected, accept, multiple = true, disabled, size = "default", state, activeContent, errorContent, children, id, "aria-describedby": ariaDescribedby, "aria-invalid": ariaInvalid, inputRef, ...props }) {
105
+ const [dragState, setDragState] = React.useState("default");
106
+ const resolvedState = state ?? dragState;
107
+ const generatedId = React.useId();
108
+ const inputId = id ?? generatedId;
109
+ return /* @__PURE__ */ jsxs("label", {
110
+ "data-slot": "dropzone",
111
+ "data-state": resolvedState,
112
+ className: cn("block", disabled && "cursor-not-allowed"),
113
+ ...props,
114
+ children: [/* @__PURE__ */ jsx("input", {
115
+ ref: inputRef,
116
+ type: "file",
117
+ id: inputId,
118
+ "data-slot": "dropzone-input",
119
+ className: "sr-only",
120
+ accept,
121
+ multiple,
122
+ disabled,
123
+ "aria-describedby": ariaDescribedby,
124
+ "aria-invalid": ariaInvalid,
125
+ onChange: (e) => {
126
+ const files = Array.from(e.target.files ?? []);
127
+ e.target.value = "";
128
+ if (files.length) onFilesSelected(files);
129
+ }
130
+ }), /* @__PURE__ */ jsxs(Attachment, {
131
+ "data-slot": "dropzone-target",
132
+ state: "idle",
133
+ orientation: "vertical",
134
+ onDragOver: (e) => {
135
+ e.preventDefault();
136
+ if (disabled) return;
137
+ const items = Array.from(e.dataTransfer.items ?? []);
138
+ const allAccepted = !accept || items.every((item) => matchesAccept(item.type, accept));
139
+ setDragState(allAccepted ? "active" : "error");
140
+ },
141
+ onDragLeave: () => setDragState("default"),
142
+ onDrop: (e) => {
143
+ e.preventDefault();
144
+ setDragState("default");
145
+ if (disabled) return;
146
+ const files = Array.from(e.dataTransfer.files ?? []);
147
+ if (files.length) onFilesSelected(files);
148
+ },
149
+ className: cn(dropzoneVariants({ size }), resolvedState === "active" && "border-primary bg-primary/10", resolvedState === "error" && "border-destructive bg-destructive/10", disabled && "pointer-events-none opacity-50", className),
150
+ children: [
151
+ resolvedState === "default" && children,
152
+ resolvedState === "active" && (activeContent ?? /* @__PURE__ */ jsx(DropzoneActiveContent, { size })),
153
+ resolvedState === "error" && (errorContent ?? /* @__PURE__ */ jsx(DropzoneErrorContent, { size }))
154
+ ]
155
+ })]
156
+ });
157
+ }
158
+ /**
159
+ * WHEN TO USE
160
+ * - A drag-and-drop or click-to-browse target for picking one or more files
161
+ * - Paired with a list of Attachment rows below it, one per selected file,
162
+ * for per-file progress/error/remove — this is Dropzone's job, not the
163
+ * list's; there's no dedicated list component, just Attachment rows
164
+ * - FileTypeIcon on each row's AttachmentMedia slot for colored, per-type
165
+ * icon circles (video/image/document/audio/other)
166
+ *
167
+ * NOT WHEN
168
+ * - A plain, unstyled file input with no drop target or preview — use Input type="file"
169
+ * - Files are already attached and just need to be displayed — use Attachment/AttachmentGroup directly
170
+ *
171
+ * KEY RULES
172
+ * - `onFilesSelected(files: File[])` fires from both the native picker (click) and drag-and-drop —
173
+ * handle it once, not twice
174
+ * - `size`: "default" | "sm" | "xs" — controls LAYOUT (Dropzone owns this via `dropzoneVariants`,
175
+ * not just padding/icon-size): "default" stacks the icon above the text, "sm" puts the icon on
176
+ * the left instead (row, not stacked — the format/size hint stays, it's not optional info, just
177
+ * repositioned), "xs" drops the icon entirely down to one compact text line — same rule every
178
+ * other xs UI state in this library follows (see Empty). The children themselves (icon, hint
179
+ * text) are still fully custom — Dropzone only dictates the flex direction and whether there's
180
+ * room to show a leading icon; get the actual "which size shows what" split from a real example
181
+ * like the Sizes story, don't just eyeball it from this list.
182
+ * - `state` is normally left unset — Dropzone derives "active" (valid drag-over) and "error"
183
+ * (drag-over with a file type `accept` would reject) from real drag events by inspecting
184
+ * `dataTransfer.items[].type`, which browsers expose pre-drop. Pass `state` explicitly only
185
+ * to force a look for a demo; a real Dropzone should let this stay derived.
186
+ * - Unlike the idle look, "active"/"error" REPLACE `children` with built-in feedback (a filled
187
+ * icon + a short line — "Drag your files here" / "File format not accepted", no icon at
188
+ * `size="xs"` same as everywhere else) — override via `activeContent`/`errorContent` if the
189
+ * defaults don't fit; this is deliberate, not something to fight with children-based tricks.
190
+ * - The drag-over "error" look is a file-type warning ONLY, and it does not block the drop —
191
+ * the file still reaches `onFilesSelected`. File size can't be checked before drop (browsers
192
+ * don't expose it until then), so "file too large" is always a file-list-level error — render
193
+ * that file's Attachment with `state="error"` and the reason in AttachmentDescription, not
194
+ * as a Dropzone state.
195
+ * - The dropzone renders as a `label` wrapping a visually-hidden `<input type="file">`, so
196
+ * clicking anywhere in it opens the OS file picker with zero extra JS
197
+ * - `accept`/`multiple`/`disabled` map straight to the underlying input's attributes
198
+ * - `id`/`aria-describedby`/`aria-invalid` land on the underlying `<input type="file">`, not the
199
+ * outer `<label>` — a label only passes its accessible *name* through, not these relationships —
200
+ * so wire hint/error text (e.g. a rejection reason) through `aria-describedby`/`aria-invalid`
201
+ * rather than assuming label-wrapping is enough. `id` falls back to a generated one if unset.
202
+ * `inputRef` reaches the same underlying input if you need the ref itself.
203
+ * - Idle-state content (icon, "Drag files here or browse", format/size hints, an optional sample-
204
+ * file link) is fully custom via children — nothing is hardcoded, this component only owns the
205
+ * interaction wiring, the idle-state look, and the active/error feedback swap above
206
+ * - FileTypeIcon derives its color+icon from `file`'s MIME type (or pass `family` directly) — it's
207
+ * an AttachmentMedia composition (`rounded-full` + a per-family tint), not a new component tree
208
+ * - Attachment defaults to `w-fit` (sized to its own content, right for a horizontal chip strip) —
209
+ * for a vertical file list where every row should line up at the same width, pass
210
+ * `className="w-full"` on each Attachment row
211
+ * - AttachmentAction covers both retry and remove — render two of them (retry then remove) on an
212
+ * error row, one (remove) otherwise
213
+ *
214
+ * USAGE
215
+ * const [files, setFiles] = React.useState<Array<{ file: File; state: "uploading" | "error" | "done" }>>([])
216
+ * <div className="grid gap-3">
217
+ * <Dropzone
218
+ * accept="image/png,image/jpeg"
219
+ * onFilesSelected={(picked) =>
220
+ * setFiles((prev) => [...prev, ...picked.map((file) => ({ file, state: "uploading" as const }))])
221
+ * }
222
+ * >
223
+ * <UploadIcon className="text-muted-foreground" />
224
+ * <p className="text-sm font-medium">Drag your files here or <span className="text-primary">browse</span></p>
225
+ * <p className="text-xs text-muted-foreground">PNG or JPEG, up to 25MB</p>
226
+ * </Dropzone>
227
+ *
228
+ * {files.map(({ file, state }) => (
229
+ * <Attachment key={file.name} state={state} className="w-full">
230
+ * <FileTypeIcon file={file} />
231
+ * <AttachmentContent>
232
+ * <AttachmentTitle>{file.name}</AttachmentTitle>
233
+ * <AttachmentDescription>
234
+ * {state === "error" ? "File exceeds the 25MB limit" : `${(file.size / 1024).toFixed(1)} KB`}
235
+ * </AttachmentDescription>
236
+ * </AttachmentContent>
237
+ * <AttachmentActions>
238
+ * {state === "error" && (
239
+ * <AttachmentAction aria-label={`Retry ${file.name}`} onClick={() => retry(file)}>
240
+ * <RefreshCwIcon />
241
+ * </AttachmentAction>
242
+ * )}
243
+ * <AttachmentAction
244
+ * aria-label={`Remove ${file.name}`}
245
+ * onClick={() => setFiles((prev) => prev.filter((f) => f.file !== file))}
246
+ * >
247
+ * <XIcon />
248
+ * </AttachmentAction>
249
+ * </AttachmentActions>
250
+ * </Attachment>
251
+ * ))}
252
+ * </div>
253
+ */
254
+ //#endregion
255
+ export { Dropzone, FileTypeIcon, getFileTypeFamily };
256
+
257
+ //# sourceMappingURL=dropzone.js.map