@customafk/lunas-ui 0.2.7 → 0.2.9

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 (267) hide show
  1. package/dist/{alert-DIC1_ymv.cjs → alert-BqJVf4wD.cjs} +1 -1
  2. package/dist/{alert-DIC1_ymv.cjs.map → alert-BqJVf4wD.cjs.map} +1 -1
  3. package/dist/{alert-CA1RS1CG.d.cts → alert-D3OOxNtK.d.mts} +6 -6
  4. package/dist/{alert-VP3giy31.mjs → alert-DQHE-pdI.mjs} +1 -1
  5. package/dist/{alert-VP3giy31.mjs.map → alert-DQHE-pdI.mjs.map} +1 -1
  6. package/dist/{alert-DDL82_U3.d.mts → alert-W_Q1Gsld.d.cts} +7 -7
  7. package/dist/{badge-BFTGDsBm.d.cts → badge-Dm1IEgtT.d.cts} +5 -5
  8. package/dist/{badge-Cg0e-djv.d.mts → badge-YFen8D8o.d.mts} +5 -5
  9. package/dist/{button-C76drZpd.d.mts → button-BnbtzQAN.d.mts} +5 -5
  10. package/dist/{button-Bn54lPVz.d.cts → button-Ckjev2AT.d.cts} +3 -3
  11. package/dist/{calendar-CyAPpT2m.cjs → calendar-B2V4Lv0T.cjs} +1 -1
  12. package/dist/{calendar-CyAPpT2m.cjs.map → calendar-B2V4Lv0T.cjs.map} +1 -1
  13. package/dist/{calendar-JKxWM6AF.mjs → calendar-Cw1G0sVL.mjs} +1 -1
  14. package/dist/{calendar-JKxWM6AF.mjs.map → calendar-Cw1G0sVL.mjs.map} +1 -1
  15. package/dist/{checkbox-RZrRNYP2.cjs → checkbox-Di7ACavC.cjs} +1 -1
  16. package/dist/{checkbox-RZrRNYP2.cjs.map → checkbox-Di7ACavC.cjs.map} +1 -1
  17. package/dist/{checkbox-DJEdYOjA.mjs → checkbox-Dzo6oI4y.mjs} +1 -1
  18. package/dist/{checkbox-DJEdYOjA.mjs.map → checkbox-Dzo6oI4y.mjs.map} +1 -1
  19. package/dist/{cms-layout-HfnOQS16.mjs → cms-layout-Bp6rU_of.mjs} +2 -2
  20. package/dist/{cms-layout-HfnOQS16.mjs.map → cms-layout-Bp6rU_of.mjs.map} +1 -1
  21. package/dist/{cms-layout-Dc4moos1.cjs → cms-layout-r9TmK6hi.cjs} +2 -2
  22. package/dist/{cms-layout-Dc4moos1.cjs.map → cms-layout-r9TmK6hi.cjs.map} +1 -1
  23. package/dist/data-display/country.d.mts +1 -1
  24. package/dist/data-display/role-badge.d.mts +1 -1
  25. package/dist/data-display/statistic.d.cts +2 -2
  26. package/dist/data-display/statistic.d.mts +4 -4
  27. package/dist/{dialog-D6ygAOSV.d.mts → dialog-DTtlGouy.d.mts} +12 -12
  28. package/dist/{dialog-CNhwBcEl.d.cts → dialog-DW1Axqio.d.cts} +12 -12
  29. package/dist/dialogs/detail-dialog/components/sidebar.d.cts +1 -1
  30. package/dist/dialogs/detail-dialog/components/sidebar.d.mts +26 -26
  31. package/dist/features/descriptions/index.d.cts +1 -1
  32. package/dist/features/descriptions/index.d.mts +1 -1
  33. package/dist/features/search-modal/index.d.cts +2 -2
  34. package/dist/features/search-modal/index.d.mts +2 -2
  35. package/dist/features/tables/index.cjs +1 -1
  36. package/dist/features/tables/index.d.cts +156 -6
  37. package/dist/features/tables/index.d.mts +157 -7
  38. package/dist/features/tables/index.mjs +1 -1
  39. package/dist/features/tanstack-form/index.cjs +1 -1
  40. package/dist/features/tanstack-form/index.d.cts +1 -1
  41. package/dist/features/tanstack-form/index.d.mts +1 -1
  42. package/dist/features/tanstack-form/index.mjs +1 -1
  43. package/dist/{field-CppNvoxV.cjs → field-C51eJ6QN.cjs} +2 -2
  44. package/dist/{field-CppNvoxV.cjs.map → field-C51eJ6QN.cjs.map} +1 -1
  45. package/dist/{field-CXVnw75a.mjs → field-DfsTE4Ie.mjs} +2 -2
  46. package/dist/{field-CXVnw75a.mjs.map → field-DfsTE4Ie.mjs.map} +1 -1
  47. package/dist/{index-75nSAiSe.d.mts → index-BIT9bkka.d.mts} +106 -106
  48. package/dist/{index-aTMCQQms.d.cts → index-CO4_ENw7.d.cts} +291 -291
  49. package/dist/index.cjs +1 -1
  50. package/dist/index.d.cts +8 -8
  51. package/dist/index.d.mts +8 -8
  52. package/dist/index.mjs +1 -1
  53. package/dist/{input-Cd0G5y-9.mjs → input-6f9JTc79.mjs} +1 -1
  54. package/dist/{input-Cd0G5y-9.mjs.map → input-6f9JTc79.mjs.map} +1 -1
  55. package/dist/{input-Cl5VkKQh.cjs → input-BMOYFJYM.cjs} +1 -1
  56. package/dist/{input-Cl5VkKQh.cjs.map → input-BMOYFJYM.cjs.map} +1 -1
  57. package/dist/{input-D5dtkW6g.d.mts → input-BrM6EExy.d.mts} +6 -6
  58. package/dist/{input-t2hpPP2K.d.cts → input-CigimPoX.d.cts} +4 -4
  59. package/dist/{label-OmlGaZ5h.mjs → label-3vAlNtF9.mjs} +1 -1
  60. package/dist/{label-OmlGaZ5h.mjs.map → label-3vAlNtF9.mjs.map} +1 -1
  61. package/dist/{label-DkMTQ3Ch.cjs → label-zyBJYydC.cjs} +1 -1
  62. package/dist/{label-DkMTQ3Ch.cjs.map → label-zyBJYydC.cjs.map} +1 -1
  63. package/dist/layouts/cms-layout/index.cjs +1 -1
  64. package/dist/layouts/cms-layout/index.mjs +1 -1
  65. package/dist/layouts/flex.d.cts +4 -4
  66. package/dist/layouts/flex.d.mts +4 -4
  67. package/dist/layouts/payment-layout/index.cjs +1 -1
  68. package/dist/layouts/payment-layout/index.mjs +1 -1
  69. package/dist/pages/FeatureDeveloping.d.cts +2 -2
  70. package/dist/pages/FeatureDeveloping.d.mts +2 -2
  71. package/dist/pages/FeatureFixing.d.cts +2 -2
  72. package/dist/pages/FeatureFixing.d.mts +2 -2
  73. package/dist/pages/NotAuthorized.d.cts +2 -2
  74. package/dist/pages/NotAuthorized.d.mts +2 -2
  75. package/dist/pages/NotFound.d.cts +2 -2
  76. package/dist/pages/NotFound.d.mts +2 -2
  77. package/dist/{payment-layout-Da29dHJe.cjs → payment-layout-C9pP5HdT.cjs} +1 -1
  78. package/dist/{payment-layout-Da29dHJe.cjs.map → payment-layout-C9pP5HdT.cjs.map} +1 -1
  79. package/dist/{payment-layout-wN5c7MCM.mjs → payment-layout-D-69gOPJ.mjs} +1 -1
  80. package/dist/{payment-layout-wN5c7MCM.mjs.map → payment-layout-D-69gOPJ.mjs.map} +1 -1
  81. package/dist/{popover-OJXFbqJi.mjs → popover-BFJhuzW3.mjs} +1 -1
  82. package/dist/{popover-OJXFbqJi.mjs.map → popover-BFJhuzW3.mjs.map} +1 -1
  83. package/dist/{popover-AEt-aSy3.cjs → popover-CmoqhK17.cjs} +1 -1
  84. package/dist/{popover-AEt-aSy3.cjs.map → popover-CmoqhK17.cjs.map} +1 -1
  85. package/dist/progress-0cpDwgAJ.mjs +2 -0
  86. package/dist/progress-0cpDwgAJ.mjs.map +1 -0
  87. package/dist/progress-DE1FdQ1J.cjs +2 -0
  88. package/dist/progress-DE1FdQ1J.cjs.map +1 -0
  89. package/dist/{radio-group-CAgfOr7-.mjs → radio-group-D5OurBIG.mjs} +1 -1
  90. package/dist/{radio-group-CAgfOr7-.mjs.map → radio-group-D5OurBIG.mjs.map} +1 -1
  91. package/dist/{radio-group-BWLdQw7M.cjs → radio-group-DAv2EU3F.cjs} +1 -1
  92. package/dist/{radio-group-BWLdQw7M.cjs.map → radio-group-DAv2EU3F.cjs.map} +1 -1
  93. package/dist/{resizable-DWh_mp5P.mjs → resizable-C2Zl-iLF.mjs} +1 -1
  94. package/dist/{resizable-DWh_mp5P.mjs.map → resizable-C2Zl-iLF.mjs.map} +1 -1
  95. package/dist/{resizable-D6UKwvFa.cjs → resizable-DDPMwd28.cjs} +1 -1
  96. package/dist/{resizable-D6UKwvFa.cjs.map → resizable-DDPMwd28.cjs.map} +1 -1
  97. package/dist/{select-Ze8Fq88G.mjs → select-DRCKwnTV.mjs} +1 -1
  98. package/dist/{select-Ze8Fq88G.mjs.map → select-DRCKwnTV.mjs.map} +1 -1
  99. package/dist/{select-Py_t2nX1.cjs → select-DfvSMRUq.cjs} +1 -1
  100. package/dist/{select-Py_t2nX1.cjs.map → select-DfvSMRUq.cjs.map} +1 -1
  101. package/dist/{spinner-EgMJOaQi.mjs → spinner-B3F9W53l.mjs} +1 -1
  102. package/dist/{spinner-EgMJOaQi.mjs.map → spinner-B3F9W53l.mjs.map} +1 -1
  103. package/dist/{spinner-MKXqwF9G.cjs → spinner-rA8pMY6v.cjs} +1 -1
  104. package/dist/{spinner-MKXqwF9G.cjs.map → spinner-rA8pMY6v.cjs.map} +1 -1
  105. package/dist/tables-D1JyNmcV.cjs +2 -0
  106. package/dist/tables-D1JyNmcV.cjs.map +1 -0
  107. package/dist/tables-DTazQIyy.mjs +2 -0
  108. package/dist/tables-DTazQIyy.mjs.map +1 -0
  109. package/dist/{tanstack-form-BmV2BXDz.cjs → tanstack-form-Bb9JXuEq.cjs} +2 -2
  110. package/dist/{tanstack-form-BmV2BXDz.cjs.map → tanstack-form-Bb9JXuEq.cjs.map} +1 -1
  111. package/dist/{tanstack-form-CJ43hVb_.mjs → tanstack-form-BwyHENeF.mjs} +2 -2
  112. package/dist/{tanstack-form-CJ43hVb_.mjs.map → tanstack-form-BwyHENeF.mjs.map} +1 -1
  113. package/dist/{textarea-CdGSEkZB.mjs → textarea-5RD9ToTV.mjs} +1 -1
  114. package/dist/{textarea-CdGSEkZB.mjs.map → textarea-5RD9ToTV.mjs.map} +1 -1
  115. package/dist/{textarea-BsgmN4jy.cjs → textarea-CvoBIPlJ.cjs} +1 -1
  116. package/dist/{textarea-BsgmN4jy.cjs.map → textarea-CvoBIPlJ.cjs.map} +1 -1
  117. package/dist/{types-B_32Ieia.d.mts → types-CkRjAQZ2.d.mts} +1 -1
  118. package/dist/typography/paragraph.d.cts +4 -4
  119. package/dist/typography/paragraph.d.mts +4 -4
  120. package/dist/typography/title.d.cts +2 -2
  121. package/dist/typography/title.d.mts +2 -2
  122. package/dist/ui/alert-dialog.d.cts +12 -12
  123. package/dist/ui/alert-dialog.d.mts +12 -12
  124. package/dist/ui/alert.cjs +1 -1
  125. package/dist/ui/alert.d.cts +1 -1
  126. package/dist/ui/alert.d.mts +1 -1
  127. package/dist/ui/alert.mjs +1 -1
  128. package/dist/ui/aspect-ratio.d.cts +2 -2
  129. package/dist/ui/aspect-ratio.d.mts +2 -2
  130. package/dist/ui/avatar.d.cts +4 -4
  131. package/dist/ui/avatar.d.mts +4 -4
  132. package/dist/ui/badge.d.cts +1 -1
  133. package/dist/ui/badge.d.mts +1 -1
  134. package/dist/ui/breadcrumb.d.cts +8 -8
  135. package/dist/ui/breadcrumb.d.mts +8 -8
  136. package/dist/ui/button-group.d.cts +6 -6
  137. package/dist/ui/button-group.d.mts +6 -6
  138. package/dist/ui/button.d.cts +1 -1
  139. package/dist/ui/button.d.mts +1 -1
  140. package/dist/ui/calendar.cjs +1 -1
  141. package/dist/ui/calendar.d.cts +4 -4
  142. package/dist/ui/calendar.d.mts +4 -4
  143. package/dist/ui/calendar.mjs +1 -1
  144. package/dist/ui/card.d.cts +8 -8
  145. package/dist/ui/card.d.mts +8 -8
  146. package/dist/ui/carousel.d.cts +7 -7
  147. package/dist/ui/carousel.d.mts +7 -7
  148. package/dist/ui/checkbox.cjs +1 -1
  149. package/dist/ui/checkbox.d.cts +2 -2
  150. package/dist/ui/checkbox.d.mts +2 -2
  151. package/dist/ui/checkbox.mjs +1 -1
  152. package/dist/ui/collapsible.d.cts +4 -4
  153. package/dist/ui/collapsible.d.mts +4 -4
  154. package/dist/ui/command.d.cts +11 -11
  155. package/dist/ui/command.d.mts +11 -11
  156. package/dist/ui/context-menu.d.cts +16 -16
  157. package/dist/ui/context-menu.d.mts +16 -16
  158. package/dist/ui/dialog.d.cts +1 -1
  159. package/dist/ui/dialog.d.mts +1 -1
  160. package/dist/ui/drawer.d.cts +11 -11
  161. package/dist/ui/drawer.d.mts +11 -11
  162. package/dist/ui/dropdown-menu.d.cts +16 -16
  163. package/dist/ui/dropdown-menu.d.mts +16 -16
  164. package/dist/ui/empty.d.cts +7 -7
  165. package/dist/ui/empty.d.mts +9 -9
  166. package/dist/ui/field.cjs +1 -1
  167. package/dist/ui/field.d.cts +24 -24
  168. package/dist/ui/field.d.mts +24 -24
  169. package/dist/ui/field.mjs +1 -1
  170. package/dist/ui/file-uploader.cjs +2 -2
  171. package/dist/ui/file-uploader.cjs.map +1 -1
  172. package/dist/ui/file-uploader.d.cts +2 -2
  173. package/dist/ui/file-uploader.d.mts +2 -2
  174. package/dist/ui/file-uploader.mjs +1 -1
  175. package/dist/ui/file-uploader.mjs.map +1 -1
  176. package/dist/ui/form.cjs +1 -1
  177. package/dist/ui/form.d.cts +11 -11
  178. package/dist/ui/form.d.mts +11 -11
  179. package/dist/ui/form.mjs +1 -1
  180. package/dist/ui/hover-card.d.cts +4 -4
  181. package/dist/ui/hover-card.d.mts +4 -4
  182. package/dist/ui/input-otp.d.cts +5 -5
  183. package/dist/ui/input-otp.d.mts +5 -5
  184. package/dist/ui/input.cjs +1 -1
  185. package/dist/ui/input.d.cts +1 -1
  186. package/dist/ui/input.d.mts +1 -1
  187. package/dist/ui/input.mjs +1 -1
  188. package/dist/ui/inputs/search-input.cjs +1 -1
  189. package/dist/ui/inputs/search-input.d.cts +3 -3
  190. package/dist/ui/inputs/search-input.d.mts +3 -3
  191. package/dist/ui/inputs/search-input.mjs +1 -1
  192. package/dist/ui/item.d.cts +14 -14
  193. package/dist/ui/item.d.mts +11 -11
  194. package/dist/ui/label.cjs +1 -1
  195. package/dist/ui/label.d.cts +2 -2
  196. package/dist/ui/label.d.mts +2 -2
  197. package/dist/ui/label.mjs +1 -1
  198. package/dist/ui/menubar.d.cts +17 -17
  199. package/dist/ui/multi-select.d.cts +2 -2
  200. package/dist/ui/multi-select.d.mts +3 -3
  201. package/dist/ui/navigation-menu.d.cts +11 -11
  202. package/dist/ui/navigation-menu.d.mts +9 -9
  203. package/dist/ui/pagination.d.cts +9 -9
  204. package/dist/ui/pagination.d.mts +9 -9
  205. package/dist/ui/popover.cjs +1 -1
  206. package/dist/ui/popover.d.cts +6 -6
  207. package/dist/ui/popover.d.mts +6 -6
  208. package/dist/ui/popover.mjs +1 -1
  209. package/dist/ui/progress.cjs +1 -2
  210. package/dist/ui/progress.d.cts +2 -2
  211. package/dist/ui/progress.d.mts +2 -2
  212. package/dist/ui/progress.mjs +1 -2
  213. package/dist/ui/radio-group.cjs +1 -1
  214. package/dist/ui/radio-group.d.cts +3 -3
  215. package/dist/ui/radio-group.d.mts +3 -3
  216. package/dist/ui/radio-group.mjs +1 -1
  217. package/dist/ui/resizable.cjs +1 -1
  218. package/dist/ui/resizable.d.cts +9 -9
  219. package/dist/ui/resizable.d.mts +9 -9
  220. package/dist/ui/resizable.mjs +1 -1
  221. package/dist/ui/scroll-area.d.cts +6 -6
  222. package/dist/ui/scroll-area.d.mts +6 -6
  223. package/dist/ui/select.cjs +1 -1
  224. package/dist/ui/select.d.cts +9 -9
  225. package/dist/ui/select.d.mts +9 -9
  226. package/dist/ui/select.mjs +1 -1
  227. package/dist/ui/separator.d.cts +2 -2
  228. package/dist/ui/separator.d.mts +2 -2
  229. package/dist/ui/sheet.d.cts +9 -9
  230. package/dist/ui/sheet.d.mts +9 -9
  231. package/dist/ui/sidebar.cjs +1 -1
  232. package/dist/ui/sidebar.d.cts +28 -28
  233. package/dist/ui/sidebar.d.mts +26 -26
  234. package/dist/ui/sidebar.mjs +1 -1
  235. package/dist/ui/skeleton.d.cts +2 -2
  236. package/dist/ui/skeleton.d.mts +2 -2
  237. package/dist/ui/slider.d.cts +2 -2
  238. package/dist/ui/slider.d.mts +2 -2
  239. package/dist/ui/sonner.d.cts +2 -2
  240. package/dist/ui/sonner.d.mts +2 -2
  241. package/dist/ui/spinner.cjs +1 -1
  242. package/dist/ui/spinner.d.cts +2 -2
  243. package/dist/ui/spinner.d.mts +2 -2
  244. package/dist/ui/spinner.mjs +1 -1
  245. package/dist/ui/switch.d.cts +2 -2
  246. package/dist/ui/switch.d.mts +2 -2
  247. package/dist/ui/table.d.cts +18 -18
  248. package/dist/ui/table.d.mts +9 -9
  249. package/dist/ui/tabs.d.cts +5 -5
  250. package/dist/ui/tabs.d.mts +5 -5
  251. package/dist/ui/textarea.cjs +1 -1
  252. package/dist/ui/textarea.d.cts +2 -2
  253. package/dist/ui/textarea.d.mts +2 -2
  254. package/dist/ui/textarea.mjs +1 -1
  255. package/dist/ui/toggle-group.d.cts +3 -3
  256. package/dist/ui/toggle-group.d.mts +3 -3
  257. package/dist/ui/toggle.d.cts +4 -4
  258. package/dist/ui/toggle.d.mts +2 -2
  259. package/dist/ui/tooltip.d.cts +5 -5
  260. package/dist/ui/tooltip.d.mts +5 -5
  261. package/package.json +1 -1
  262. package/dist/tables-Cc3Wik4i.cjs +0 -2
  263. package/dist/tables-Cc3Wik4i.cjs.map +0 -1
  264. package/dist/tables-DrJKQPsT.mjs +0 -2
  265. package/dist/tables-DrJKQPsT.mjs.map +0 -1
  266. package/dist/ui/progress.cjs.map +0 -1
  267. package/dist/ui/progress.mjs.map +0 -1
@@ -1,57 +1,57 @@
1
1
  import { Label } from "./label.cjs";
2
- import * as react_jsx_runtime124 from "react/jsx-runtime";
3
- import * as class_variance_authority_types5 from "class-variance-authority/types";
4
- import * as react1 from "react";
2
+ import * as react_jsx_runtime181 from "react/jsx-runtime";
3
+ import * as class_variance_authority_types10 from "class-variance-authority/types";
4
+ import * as react5 from "react";
5
5
  import { VariantProps } from "class-variance-authority";
6
6
 
7
7
  //#region packages/components/ui/field.d.ts
8
- declare const FieldSet: react1.MemoExoticComponent<({
8
+ declare const FieldSet: react5.MemoExoticComponent<({
9
9
  className,
10
10
  ...props
11
- }: React.ComponentProps<"fieldset">) => react_jsx_runtime124.JSX.Element>;
12
- declare const FieldLegend: react1.MemoExoticComponent<({
11
+ }: React.ComponentProps<"fieldset">) => react_jsx_runtime181.JSX.Element>;
12
+ declare const FieldLegend: react5.MemoExoticComponent<({
13
13
  className,
14
14
  variant,
15
15
  ...props
16
16
  }: React.ComponentProps<"legend"> & {
17
17
  variant?: "legend" | "label";
18
- }) => react_jsx_runtime124.JSX.Element>;
19
- declare const FieldGroup: react1.MemoExoticComponent<({
18
+ }) => react_jsx_runtime181.JSX.Element>;
19
+ declare const FieldGroup: react5.MemoExoticComponent<({
20
20
  className,
21
21
  ...props
22
- }: React.ComponentProps<"div">) => react_jsx_runtime124.JSX.Element>;
22
+ }: React.ComponentProps<"div">) => react_jsx_runtime181.JSX.Element>;
23
23
  declare const fieldVariants: (props?: ({
24
24
  orientation?: "vertical" | "horizontal" | "responsive" | null | undefined;
25
- } & class_variance_authority_types5.ClassProp) | undefined) => string;
26
- declare const Field: react1.MemoExoticComponent<({
25
+ } & class_variance_authority_types10.ClassProp) | undefined) => string;
26
+ declare const Field: react5.MemoExoticComponent<({
27
27
  className,
28
28
  orientation,
29
29
  ...props
30
- }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) => react_jsx_runtime124.JSX.Element>;
31
- declare const FieldContent: react1.MemoExoticComponent<({
30
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) => react_jsx_runtime181.JSX.Element>;
31
+ declare const FieldContent: react5.MemoExoticComponent<({
32
32
  className,
33
33
  ...props
34
- }: React.ComponentProps<"div">) => react_jsx_runtime124.JSX.Element>;
35
- declare const FieldLabel: react1.MemoExoticComponent<({
34
+ }: React.ComponentProps<"div">) => react_jsx_runtime181.JSX.Element>;
35
+ declare const FieldLabel: react5.MemoExoticComponent<({
36
36
  className,
37
37
  ...props
38
- }: React.ComponentProps<typeof Label>) => react_jsx_runtime124.JSX.Element>;
39
- declare const FieldTitle: react1.MemoExoticComponent<({
38
+ }: React.ComponentProps<typeof Label>) => react_jsx_runtime181.JSX.Element>;
39
+ declare const FieldTitle: react5.MemoExoticComponent<({
40
40
  className,
41
41
  ...props
42
- }: React.ComponentProps<"div">) => react_jsx_runtime124.JSX.Element>;
43
- declare const FieldDescription: react1.MemoExoticComponent<({
42
+ }: React.ComponentProps<"div">) => react_jsx_runtime181.JSX.Element>;
43
+ declare const FieldDescription: react5.MemoExoticComponent<({
44
44
  className,
45
45
  ...props
46
- }: React.ComponentProps<"p">) => react_jsx_runtime124.JSX.Element>;
47
- declare const FieldSeparator: react1.MemoExoticComponent<({
46
+ }: React.ComponentProps<"p">) => react_jsx_runtime181.JSX.Element>;
47
+ declare const FieldSeparator: react5.MemoExoticComponent<({
48
48
  children,
49
49
  className,
50
50
  ...props
51
51
  }: React.ComponentProps<"div"> & {
52
52
  children?: React.ReactNode;
53
- }) => react_jsx_runtime124.JSX.Element>;
54
- declare const FieldError: react1.MemoExoticComponent<({
53
+ }) => react_jsx_runtime181.JSX.Element>;
54
+ declare const FieldError: react5.MemoExoticComponent<({
55
55
  className,
56
56
  children,
57
57
  errors,
@@ -60,7 +60,7 @@ declare const FieldError: react1.MemoExoticComponent<({
60
60
  errors?: Array<{
61
61
  message?: string;
62
62
  } | undefined>;
63
- }) => react_jsx_runtime124.JSX.Element | null>;
63
+ }) => react_jsx_runtime181.JSX.Element | null>;
64
64
  //#endregion
65
65
  export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle };
66
66
  //# sourceMappingURL=field.d.cts.map
@@ -1,57 +1,57 @@
1
1
  import { Label } from "./label.mjs";
2
- import * as react1 from "react";
3
- import * as react_jsx_runtime130 from "react/jsx-runtime";
2
+ import * as react4 from "react";
3
+ import * as react_jsx_runtime125 from "react/jsx-runtime";
4
4
  import { VariantProps } from "class-variance-authority";
5
- import * as class_variance_authority_types6 from "class-variance-authority/types";
5
+ import * as class_variance_authority_types5 from "class-variance-authority/types";
6
6
 
7
7
  //#region packages/components/ui/field.d.ts
8
- declare const FieldSet: react1.MemoExoticComponent<({
8
+ declare const FieldSet: react4.MemoExoticComponent<({
9
9
  className,
10
10
  ...props
11
- }: React.ComponentProps<"fieldset">) => react_jsx_runtime130.JSX.Element>;
12
- declare const FieldLegend: react1.MemoExoticComponent<({
11
+ }: React.ComponentProps<"fieldset">) => react_jsx_runtime125.JSX.Element>;
12
+ declare const FieldLegend: react4.MemoExoticComponent<({
13
13
  className,
14
14
  variant,
15
15
  ...props
16
16
  }: React.ComponentProps<"legend"> & {
17
17
  variant?: "legend" | "label";
18
- }) => react_jsx_runtime130.JSX.Element>;
19
- declare const FieldGroup: react1.MemoExoticComponent<({
18
+ }) => react_jsx_runtime125.JSX.Element>;
19
+ declare const FieldGroup: react4.MemoExoticComponent<({
20
20
  className,
21
21
  ...props
22
- }: React.ComponentProps<"div">) => react_jsx_runtime130.JSX.Element>;
22
+ }: React.ComponentProps<"div">) => react_jsx_runtime125.JSX.Element>;
23
23
  declare const fieldVariants: (props?: ({
24
24
  orientation?: "vertical" | "horizontal" | "responsive" | null | undefined;
25
- } & class_variance_authority_types6.ClassProp) | undefined) => string;
26
- declare const Field: react1.MemoExoticComponent<({
25
+ } & class_variance_authority_types5.ClassProp) | undefined) => string;
26
+ declare const Field: react4.MemoExoticComponent<({
27
27
  className,
28
28
  orientation,
29
29
  ...props
30
- }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) => react_jsx_runtime130.JSX.Element>;
31
- declare const FieldContent: react1.MemoExoticComponent<({
30
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) => react_jsx_runtime125.JSX.Element>;
31
+ declare const FieldContent: react4.MemoExoticComponent<({
32
32
  className,
33
33
  ...props
34
- }: React.ComponentProps<"div">) => react_jsx_runtime130.JSX.Element>;
35
- declare const FieldLabel: react1.MemoExoticComponent<({
34
+ }: React.ComponentProps<"div">) => react_jsx_runtime125.JSX.Element>;
35
+ declare const FieldLabel: react4.MemoExoticComponent<({
36
36
  className,
37
37
  ...props
38
- }: React.ComponentProps<typeof Label>) => react_jsx_runtime130.JSX.Element>;
39
- declare const FieldTitle: react1.MemoExoticComponent<({
38
+ }: React.ComponentProps<typeof Label>) => react_jsx_runtime125.JSX.Element>;
39
+ declare const FieldTitle: react4.MemoExoticComponent<({
40
40
  className,
41
41
  ...props
42
- }: React.ComponentProps<"div">) => react_jsx_runtime130.JSX.Element>;
43
- declare const FieldDescription: react1.MemoExoticComponent<({
42
+ }: React.ComponentProps<"div">) => react_jsx_runtime125.JSX.Element>;
43
+ declare const FieldDescription: react4.MemoExoticComponent<({
44
44
  className,
45
45
  ...props
46
- }: React.ComponentProps<"p">) => react_jsx_runtime130.JSX.Element>;
47
- declare const FieldSeparator: react1.MemoExoticComponent<({
46
+ }: React.ComponentProps<"p">) => react_jsx_runtime125.JSX.Element>;
47
+ declare const FieldSeparator: react4.MemoExoticComponent<({
48
48
  children,
49
49
  className,
50
50
  ...props
51
51
  }: React.ComponentProps<"div"> & {
52
52
  children?: React.ReactNode;
53
- }) => react_jsx_runtime130.JSX.Element>;
54
- declare const FieldError: react1.MemoExoticComponent<({
53
+ }) => react_jsx_runtime125.JSX.Element>;
54
+ declare const FieldError: react4.MemoExoticComponent<({
55
55
  className,
56
56
  children,
57
57
  errors,
@@ -60,7 +60,7 @@ declare const FieldError: react1.MemoExoticComponent<({
60
60
  errors?: Array<{
61
61
  message?: string;
62
62
  } | undefined>;
63
- }) => react_jsx_runtime130.JSX.Element | null>;
63
+ }) => react_jsx_runtime125.JSX.Element | null>;
64
64
  //#endregion
65
65
  export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle };
66
66
  //# sourceMappingURL=field.d.mts.map
package/dist/ui/field.mjs CHANGED
@@ -1 +1 @@
1
- "use client";import"../separator-BMsbHAVt.mjs";import"../label-OmlGaZ5h.mjs";import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c,u as l}from"../field-CXVnw75a.mjs";export{c as Field,i as FieldContent,o as FieldDescription,n as FieldError,e as FieldGroup,a as FieldLabel,s as FieldLegend,t as FieldSeparator,r as FieldSet,l as FieldTitle};
1
+ "use client";import"../separator-BMsbHAVt.mjs";import"../label-3vAlNtF9.mjs";import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c,u as l}from"../field-DfsTE4Ie.mjs";export{c as Field,i as FieldContent,o as FieldDescription,n as FieldError,e as FieldGroup,a as FieldLabel,s as FieldLegend,t as FieldSeparator,r as FieldSet,l as FieldTitle};
@@ -1,3 +1,3 @@
1
- "use client";const e=require(`../chunk-Bmb41Sf3.cjs`);require(`../button.variants-tnhb123u.cjs`);const t=require(`../button-CwDT3m4m.cjs`),n=require(`./progress.cjs`);let r=require(`lucide-react`),i=require(`react`),a=require(`react/jsx-runtime`),o=require(`@customafk/react-toolkit/utils`),s=require(`react-dropzone`);s=e.t(s);let c=require(`@customafk/react-toolkit/hooks/useControllableState`),l=require(`sonner`);function u(e){let{value:t,onValueChange:n,onUpload:u,progresses:p,accept:m={"image/*":[]},maxSize:h=1024*1024*2,maxFileCount:g=1,multiple:_=!1,disabled:v=!1,showText:y=!0,iconSize:b,className:x,...S}=e,[C,w]=(0,c.useControllableState)({prop:t,onChange:n}),T=(0,i.useCallback)((e,t)=>{if(!_&&g===1&&e.length>1){l.toast.error(`Cannot upload more than 1 file at a time`);return}if((C?.length??0)+e.length>g){l.toast.error(`Cannot upload more than ${g} files`);return}let n=e.map(e=>Object.assign(e,{preview:URL.createObjectURL(e)})),r=C?[...C,...n]:n;if(w(r),t.length>0&&t.forEach(({file:e})=>{l.toast.error(`File ${e.name} was rejected`)}),u&&r.length>0&&r.length<=g){let e=r.length>0?`${r.length} files`:`file`;u(r).then(()=>{w([]),(0,l.toast)(`${e} uploaded`)})}},[C,g,_,u,w]);function E(e){if(!C)return;f(C[e])&&URL.revokeObjectURL(C[e].preview);let t=C.filter((t,n)=>n!==e);w(t),n?.(t)}(0,i.useEffect)(()=>()=>{C&&C.forEach(e=>{f(e)&&URL.revokeObjectURL(e.preview)})},[]);let D=v||(C?.length??0)>=g;return(0,a.jsxs)(`div`,{className:`relative flex w-full flex-col gap-6`,children:[(0,a.jsx)(s.default,{onDrop:T,accept:m,maxSize:h,maxFiles:g,multiple:g>1||_,disabled:D,children:({getRootProps:e,getInputProps:t,isDragActive:n})=>(0,a.jsxs)(`div`,{...e(),className:(0,o.cn)(`group`,`border-border-weak`,`hover:bg-border-weak/20`,`relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition`,`ring-offset-background`,`focus-visible:ring-primary-weak`,`focus-visible:ring-2`,`focus-visible:ring-offset-2`,`focus-visible:outline-hidden`,n&&`border-border-primary-strong bg-border-weak/40`,D&&`pointer-events-none opacity-60`,x),...S,children:[(0,a.jsx)(`input`,{...t()}),n?(0,a.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[(0,a.jsx)(`div`,{className:`rounded-full border border-dashed p-3`,children:(0,a.jsx)(r.Upload,{className:`text-text-positive-muted size-7`,"aria-hidden":`true`})}),(0,a.jsx)(`p`,{className:`text-text-positive-muted font-medium`,children:`Drop the files here`})]}):(0,a.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[(0,a.jsx)(`div`,{className:`rounded-full border border-dashed p-3`,children:(0,a.jsx)(r.Upload,{size:b||24,className:`text-muted-foreground`,"aria-hidden":`true`})}),y&&(0,a.jsxs)(`div`,{className:`flex flex-col gap-px`,children:[(0,a.jsxs)(`p`,{className:`text-text-positive-weak text-xs font-medium`,children:[`Drag `,`'n'`,` drop files here, or click to select files`]}),(0,a.jsxs)(`p`,{className:`text-text-positive-muted text-xs`,children:[`You can upload`,g>1?` ${g===1/0?`multiple`:g}
2
- files (up to ${(0,o.formatBytes)(h)} each)`:` a file with ${(0,o.formatBytes)(h)}`]})]})]})]})}),C?.length?(0,a.jsxs)(`div`,{className:`h-fit w-full overflow-y-auto`,children:[(0,a.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2.5`,children:[(0,a.jsxs)(`div`,{className:`text-text-positive-weak flex items-center gap-1`,children:[(0,a.jsx)(r.Image,{size:16,"aria-hidden":`true`}),(0,a.jsxs)(`p`,{className:`text-sm`,children:[`Ảnh đã tải lên (`,C.length,`)`]})]}),(0,a.jsxs)(`button`,{className:`hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200`,onClick:()=>{C&&(C.forEach(e=>{f(e)&&URL.revokeObjectURL(e.preview)}),w([]),n?.([]))},children:[(0,a.jsx)(r.Trash2,{size:16,"aria-hidden":`true`}),(0,a.jsx)(`p`,{className:`text-sm`,children:`Xóa tất cả`})]})]}),(0,a.jsx)(`div`,{className:`flex flex-col gap-2.5`,children:C?.map((e,t)=>(0,a.jsx)(d,{file:e,onRemove:()=>E(t),progress:p?.[e.name]},t))})]}):null]})}function d({file:e,progress:i,onRemove:s}){return(0,a.jsxs)(`div`,{className:`border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors`,children:[(0,a.jsxs)(`div`,{className:`flex flex-1 gap-2.5`,children:[f(e)?(0,a.jsx)(p,{file:e}):null,(0,a.jsxs)(`div`,{className:`flex w-full flex-col gap-2`,children:[(0,a.jsxs)(`div`,{className:`flex flex-col gap-y-0.5`,children:[(0,a.jsx)(`p`,{className:`text-text-positive line-clamp-1 text-sm`,children:e.name}),(0,a.jsx)(`p`,{className:`text-text-positive-muted text-xs`,children:(0,o.formatBytes)(e.size)})]}),i?(0,a.jsx)(n.Progress,{value:i}):null]})]}),(0,a.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,a.jsxs)(t.t,{type:`button`,variant:`ghost`,color:`secondary`,size:`icon`,className:`size-7`,onClick:s,children:[(0,a.jsx)(r.Trash2,{size:16,className:`text-text-positive-muted`,"aria-hidden":`true`}),(0,a.jsx)(`span`,{className:`sr-only`,children:`Remove file`})]})})]})}function f(e){return`preview`in e&&typeof e.preview==`string`}function p({file:e}){return e.type.startsWith(`image/`)?(0,a.jsx)(`img`,{src:e.preview,className:`border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm`}):(0,a.jsx)(r.FileText,{className:`text-text-positive-muted size-10 border`,"aria-hidden":`true`})}exports.FileUploader=u;
1
+ "use client";const e=require(`../chunk-Bmb41Sf3.cjs`);require(`../button.variants-tnhb123u.cjs`);const t=require(`../button-CwDT3m4m.cjs`),n=require(`../progress-DE1FdQ1J.cjs`);let r=require(`lucide-react`),i=require(`react`),a=require(`react/jsx-runtime`),o=require(`@customafk/react-toolkit/utils`),s=require(`react-dropzone`);s=e.t(s);let c=require(`@customafk/react-toolkit/hooks/useControllableState`),l=require(`sonner`);function u(e){let{value:t,onValueChange:n,onUpload:u,progresses:p,accept:m={"image/*":[]},maxSize:h=1024*1024*2,maxFileCount:g=1,multiple:_=!1,disabled:v=!1,showText:y=!0,iconSize:b,className:x,...S}=e,[C,w]=(0,c.useControllableState)({prop:t,onChange:n}),T=(0,i.useCallback)((e,t)=>{if(!_&&g===1&&e.length>1){l.toast.error(`Cannot upload more than 1 file at a time`);return}if((C?.length??0)+e.length>g){l.toast.error(`Cannot upload more than ${g} files`);return}let n=e.map(e=>Object.assign(e,{preview:URL.createObjectURL(e)})),r=C?[...C,...n]:n;if(w(r),t.length>0&&t.forEach(({file:e})=>{l.toast.error(`File ${e.name} was rejected`)}),u&&r.length>0&&r.length<=g){let e=r.length>0?`${r.length} files`:`file`;u(r).then(()=>{w([]),(0,l.toast)(`${e} uploaded`)})}},[C,g,_,u,w]);function E(e){if(!C)return;f(C[e])&&URL.revokeObjectURL(C[e].preview);let t=C.filter((t,n)=>n!==e);w(t),n?.(t)}(0,i.useEffect)(()=>()=>{C&&C.forEach(e=>{f(e)&&URL.revokeObjectURL(e.preview)})},[]);let D=v||(C?.length??0)>=g;return(0,a.jsxs)(`div`,{className:`relative flex w-full flex-col gap-6`,children:[(0,a.jsx)(s.default,{onDrop:T,accept:m,maxSize:h,maxFiles:g,multiple:g>1||_,disabled:D,children:({getRootProps:e,getInputProps:t,isDragActive:n})=>(0,a.jsxs)(`div`,{...e(),className:(0,o.cn)(`group`,`border-border-weak`,`hover:bg-border-weak/20`,`relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition`,`ring-offset-background`,`focus-visible:ring-primary-weak`,`focus-visible:ring-2`,`focus-visible:ring-offset-2`,`focus-visible:outline-hidden`,n&&`border-border-primary-strong bg-border-weak/40`,D&&`pointer-events-none opacity-60`,x),...S,children:[(0,a.jsx)(`input`,{...t()}),n?(0,a.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[(0,a.jsx)(`div`,{className:`rounded-full border border-dashed p-3`,children:(0,a.jsx)(r.Upload,{className:`text-text-positive-muted size-7`,"aria-hidden":`true`})}),(0,a.jsx)(`p`,{className:`text-text-positive-muted font-medium`,children:`Drop the files here`})]}):(0,a.jsxs)(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[(0,a.jsx)(`div`,{className:`rounded-full border border-dashed p-3`,children:(0,a.jsx)(r.Upload,{size:b||24,className:`text-muted-foreground`,"aria-hidden":`true`})}),y&&(0,a.jsxs)(`div`,{className:`flex flex-col gap-px`,children:[(0,a.jsxs)(`p`,{className:`text-text-positive-weak text-xs font-medium`,children:[`Drag `,`'n'`,` drop files here, or click to select files`]}),(0,a.jsxs)(`p`,{className:`text-text-positive-muted text-xs`,children:[`You can upload`,g>1?` ${g===1/0?`multiple`:g}
2
+ files (up to ${(0,o.formatBytes)(h)} each)`:` a file with ${(0,o.formatBytes)(h)}`]})]})]})]})}),C?.length?(0,a.jsxs)(`div`,{className:`h-fit w-full overflow-y-auto`,children:[(0,a.jsxs)(`div`,{className:`flex items-center justify-between px-3 py-2.5`,children:[(0,a.jsxs)(`div`,{className:`text-text-positive-weak flex items-center gap-1`,children:[(0,a.jsx)(r.Image,{size:16,"aria-hidden":`true`}),(0,a.jsxs)(`p`,{className:`text-sm`,children:[`Ảnh đã tải lên (`,C.length,`)`]})]}),(0,a.jsxs)(`button`,{className:`hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200`,onClick:()=>{C&&(C.forEach(e=>{f(e)&&URL.revokeObjectURL(e.preview)}),w([]),n?.([]))},children:[(0,a.jsx)(r.Trash2,{size:16,"aria-hidden":`true`}),(0,a.jsx)(`p`,{className:`text-sm`,children:`Xóa tất cả`})]})]}),(0,a.jsx)(`div`,{className:`flex flex-col gap-2.5`,children:C?.map((e,t)=>(0,a.jsx)(d,{file:e,onRemove:()=>E(t),progress:p?.[e.name]},t))})]}):null]})}function d({file:e,progress:i,onRemove:s}){return(0,a.jsxs)(`div`,{className:`border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors`,children:[(0,a.jsxs)(`div`,{className:`flex flex-1 gap-2.5`,children:[f(e)?(0,a.jsx)(p,{file:e}):null,(0,a.jsxs)(`div`,{className:`flex w-full flex-col gap-2`,children:[(0,a.jsxs)(`div`,{className:`flex flex-col gap-y-0.5`,children:[(0,a.jsx)(`p`,{className:`text-text-positive line-clamp-1 text-sm`,children:e.name}),(0,a.jsx)(`p`,{className:`text-text-positive-muted text-xs`,children:(0,o.formatBytes)(e.size)})]}),i?(0,a.jsx)(n.t,{value:i}):null]})]}),(0,a.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,a.jsxs)(t.t,{type:`button`,variant:`ghost`,color:`secondary`,size:`icon`,className:`size-7`,onClick:s,children:[(0,a.jsx)(r.Trash2,{size:16,className:`text-text-positive-muted`,"aria-hidden":`true`}),(0,a.jsx)(`span`,{className:`sr-only`,children:`Remove file`})]})})]})}function f(e){return`preview`in e&&typeof e.preview==`string`}function p({file:e}){return e.type.startsWith(`image/`)?(0,a.jsx)(`img`,{src:e.preview,className:`border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm`}):(0,a.jsx)(r.FileText,{className:`text-text-positive-muted size-10 border`,"aria-hidden":`true`})}exports.FileUploader=u;
3
3
  //# sourceMappingURL=file-uploader.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-uploader.cjs","names":["Dropzone","Upload","Image","Trash2","Progress","Button","FileText"],"sources":["../../packages/components/ui/file-uploader.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useEffect } from 'react';\nimport Dropzone, { type DropzoneProps, type FileRejection } from 'react-dropzone';\nimport { useControllableState } from '@customafk/react-toolkit/hooks/useControllableState';\nimport { cn, formatBytes } from '@customafk/react-toolkit/utils';\n\nimport { FileText, Image, Trash2, Upload } from 'lucide-react';\nimport { toast } from 'sonner';\n\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\n/**\n * Props for the FileUploader component.\n *\n * @example\n * ```tsx\n * import { FileUploader } from '@customafk/lunas-ui/ui/file-uploader';\n *\n * <FileUploader\n * accept={{ 'image/*': [] }}\n * maxSize={1024 * 1024 * 5}\n * maxFileCount={3}\n * multiple\n * onUpload={async (files) => { await uploadFiles(files); }}\n * />\n * ```\n */\ninterface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Value of the uploader.\n * @type File[]\n * @default undefined\n * @example value={files}\n */\n value?: File[];\n\n /**\n * Function to be called when the value changes.\n * @type (files: File[]) => void\n * @default undefined\n * @example onValueChange={(files) => setFiles(files)}\n */\n onValueChange?: (files: File[]) => void;\n\n /**\n * Function to be called when files are uploaded.\n * @type (files: File[]) => Promise<void>\n * @default undefined\n * @example onUpload={(files) => uploadFiles(files)}\n */\n onUpload?: (files: File[]) => Promise<void>;\n\n /**\n * Progress of the uploaded files.\n * @type Record<string, number> | undefined\n * @default undefined\n * @example progresses={{ \"file1.png\": 50 }}\n */\n progresses?: Record<string, number>;\n\n /**\n * Accepted file types for the uploader.\n * @type { [key: string]: string[]}\n * @default\n * ```ts\n * { \"image/*\": [] }\n * ```\n * @example accept={[\"image/png\", \"image/jpeg\"]}\n */\n accept?: DropzoneProps['accept'];\n\n /**\n * Maximum file size for the uploader.\n * @type number | undefined\n * @default 1024 * 1024 * 2 // 2MB\n * @example maxSize={1024 * 1024 * 2} // 2MB\n */\n maxSize?: DropzoneProps['maxSize'];\n\n /**\n * Maximum number of files for the uploader.\n * @type number | undefined\n * @default 1\n * @example maxFileCount={4}\n */\n maxFileCount?: DropzoneProps['maxFiles'];\n\n /**\n * Whether the uploader should accept multiple files.\n * @type boolean\n * @default false\n * @example multiple\n */\n multiple?: boolean;\n\n /**\n * Whether the uploader is disabled.\n * @type boolean\n * @default false\n * @example disabled\n */\n disabled?: boolean;\n\n /**\n * Whether to show the instructional drag-and-drop text inside the drop zone.\n * @default true\n */\n showText?: boolean;\n /** Size in pixels for the upload icon. */\n iconSize?: number;\n}\n\n/**\n * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.\n */\nexport function FileUploader(props: FileUploaderProps) {\n const {\n value: valueProp,\n onValueChange,\n onUpload,\n progresses,\n accept = {\n 'image/*': [],\n },\n maxSize = 1024 * 1024 * 2,\n maxFileCount = 1,\n multiple = false,\n disabled = false,\n showText = true,\n iconSize,\n className,\n ...dropzoneProps\n } = props;\n\n const [files, setFiles] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n });\n\n const onDrop = useCallback(\n (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {\n if (!multiple && maxFileCount === 1 && acceptedFiles.length > 1) {\n toast.error('Cannot upload more than 1 file at a time');\n\n return;\n }\n\n if ((files?.length ?? 0) + acceptedFiles.length > maxFileCount) {\n toast.error(`Cannot upload more than ${maxFileCount} files`);\n return;\n }\n\n const newFiles = acceptedFiles.map(file =>\n Object.assign(file, {\n preview: URL.createObjectURL(file),\n })\n );\n\n const updatedFiles = files ? [...files, ...newFiles] : newFiles;\n\n setFiles(updatedFiles);\n\n if (rejectedFiles.length > 0) {\n rejectedFiles.forEach(({ file }) => {\n toast.error(`File ${file.name} was rejected`);\n });\n }\n\n if (onUpload && updatedFiles.length > 0 && updatedFiles.length <= maxFileCount) {\n const target = updatedFiles.length > 0 ? `${updatedFiles.length} files` : `file`;\n\n onUpload(updatedFiles).then(() => {\n setFiles([]);\n toast(`${target} uploaded`);\n });\n }\n },\n\n [files, maxFileCount, multiple, onUpload, setFiles]\n );\n\n function onRemove(index: number) {\n if (!files) return;\n\n if (isFileWithPreview(files[index])) {\n URL.revokeObjectURL(files[index].preview);\n }\n\n const newFiles = files.filter((_, i) => i !== index);\n setFiles(newFiles);\n onValueChange?.(newFiles);\n }\n\n // Revoke preview url when component unmounts\n useEffect(() => {\n return () => {\n if (!files) return;\n files.forEach(file => {\n if (isFileWithPreview(file)) {\n URL.revokeObjectURL(file.preview);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;\n\n return (\n <div className=\"relative flex w-full flex-col gap-6\">\n <Dropzone onDrop={onDrop} accept={accept} maxSize={maxSize} maxFiles={maxFileCount} multiple={maxFileCount > 1 || multiple} disabled={isDisabled}>\n {({ getRootProps, getInputProps, isDragActive }) => (\n <div\n {...getRootProps()}\n className={cn(\n 'group',\n 'border-border-weak',\n 'hover:bg-border-weak/20',\n 'relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition',\n 'ring-offset-background',\n 'focus-visible:ring-primary-weak',\n 'focus-visible:ring-2',\n 'focus-visible:ring-offset-2',\n 'focus-visible:outline-hidden',\n isDragActive && 'border-border-primary-strong bg-border-weak/40',\n isDisabled && 'pointer-events-none opacity-60',\n className\n )}\n {...dropzoneProps}\n >\n <input {...getInputProps()} />\n {isDragActive ? (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload className=\"text-text-positive-muted size-7\" aria-hidden=\"true\" />\n </div>\n <p className=\"text-text-positive-muted font-medium\">Drop the files here</p>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload size={iconSize || 24} className=\"text-muted-foreground\" aria-hidden=\"true\" />\n </div>\n {showText && (\n <div className=\"flex flex-col gap-px\">\n <p className=\"text-text-positive-weak text-xs font-medium\">Drag {`'n'`} drop files here, or click to select files</p>\n <p className=\"text-text-positive-muted text-xs\">\n You can upload\n {maxFileCount > 1\n ? ` ${maxFileCount === Infinity ? 'multiple' : maxFileCount}\n files (up to ${formatBytes(maxSize)} each)`\n : ` a file with ${formatBytes(maxSize)}`}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </Dropzone>\n {files?.length ? (\n <div className=\"h-fit w-full overflow-y-auto\">\n <div className=\"flex items-center justify-between px-3 py-2.5\">\n <div className=\"text-text-positive-weak flex items-center gap-1\">\n <Image size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Ảnh đã tải lên ({files.length})</p>\n </div>\n <button\n className=\"hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200\"\n onClick={() => {\n if (!files) return;\n files.forEach(file => {\n if (!isFileWithPreview(file)) return;\n URL.revokeObjectURL(file.preview);\n });\n setFiles([]);\n onValueChange?.([]);\n }}\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Xóa tất cả</p>\n </button>\n </div>\n <div className=\"flex flex-col gap-2.5\">\n {files?.map((file, index) => (\n <FileCard key={index} file={file} onRemove={() => onRemove(index)} progress={progresses?.[file.name]} />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface FileCardProps {\n file: File;\n onRemove: () => void;\n progress?: number;\n}\n\nfunction FileCard({ file, progress, onRemove }: FileCardProps) {\n return (\n <div className=\"border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors\">\n <div className=\"flex flex-1 gap-2.5\">\n {isFileWithPreview(file) ? <FilePreview file={file} /> : null}\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex flex-col gap-y-0.5\">\n <p className=\"text-text-positive line-clamp-1 text-sm\">{file.name}</p>\n <p className=\"text-text-positive-muted text-xs\">{formatBytes(file.size)}</p>\n </div>\n {progress ? <Progress value={progress} /> : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"ghost\" color=\"secondary\" size=\"icon\" className=\"size-7\" onClick={onRemove}>\n <Trash2 size={16} className=\"text-text-positive-muted\" aria-hidden=\"true\" />\n <span className=\"sr-only\">Remove file</span>\n </Button>\n </div>\n </div>\n );\n}\n\nfunction isFileWithPreview(file: File): file is File & { preview: string } {\n return 'preview' in file && typeof file.preview === 'string';\n}\n\ninterface FilePreviewProps {\n file: File & { preview: string };\n}\n\nfunction FilePreview({ file }: FilePreviewProps) {\n if (file.type.startsWith('image/')) {\n return <img src={file.preview} className=\"border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm\" />;\n }\n\n return <FileText className=\"text-text-positive-muted size-10 border\" aria-hidden=\"true\" />;\n}\n"],"mappings":"iaAoHA,SAAgB,EAAa,EAA0B,CACrD,GAAM,CACJ,MAAO,EACP,gBACA,WACA,aACA,SAAS,CACP,UAAW,EAAE,CACd,CACD,UAAU,KAAO,KAAO,EACxB,eAAe,EACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,WACA,YACA,GAAG,GACD,EAEE,CAAC,EAAO,IAAA,EAAA,EAAA,sBAAiC,CAC7C,KAAM,EACN,SAAU,EACX,CAAC,CAEI,GAAA,EAAA,EAAA,cACH,EAAuB,IAAmC,CACzD,GAAI,CAAC,GAAY,IAAiB,GAAK,EAAc,OAAS,EAAG,CAC/D,EAAA,MAAM,MAAM,2CAA2C,CAEvD,OAGF,IAAK,GAAO,QAAU,GAAK,EAAc,OAAS,EAAc,CAC9D,EAAA,MAAM,MAAM,2BAA2B,EAAa,QAAQ,CAC5D,OAGF,IAAM,EAAW,EAAc,IAAI,GACjC,OAAO,OAAO,EAAM,CAClB,QAAS,IAAI,gBAAgB,EAAK,CACnC,CAAC,CACH,CAEK,EAAe,EAAQ,CAAC,GAAG,EAAO,GAAG,EAAS,CAAG,EAUvD,GARA,EAAS,EAAa,CAElB,EAAc,OAAS,GACzB,EAAc,SAAS,CAAE,UAAW,CAClC,EAAA,MAAM,MAAM,QAAQ,EAAK,KAAK,eAAe,EAC7C,CAGA,GAAY,EAAa,OAAS,GAAK,EAAa,QAAU,EAAc,CAC9E,IAAM,EAAS,EAAa,OAAS,EAAI,GAAG,EAAa,OAAO,QAAU,OAE1E,EAAS,EAAa,CAAC,SAAW,CAChC,EAAS,EAAE,CAAC,EACZ,EAAA,EAAA,OAAM,GAAG,EAAO,WAAW,EAC3B,GAIN,CAAC,EAAO,EAAc,EAAU,EAAU,EAAS,CACpD,CAED,SAAS,EAAS,EAAe,CAC/B,GAAI,CAAC,EAAO,OAER,EAAkB,EAAM,GAAO,EACjC,IAAI,gBAAgB,EAAM,GAAO,QAAQ,CAG3C,IAAM,EAAW,EAAM,QAAQ,EAAG,IAAM,IAAM,EAAM,CACpD,EAAS,EAAS,CAClB,IAAgB,EAAS,EAI3B,EAAA,EAAA,mBACe,CACN,GACL,EAAM,QAAQ,GAAQ,CAChB,EAAkB,EAAK,EACzB,IAAI,gBAAgB,EAAK,QAAQ,EAEnC,EAGH,EAAE,CAAC,CAEN,IAAM,EAAa,IAAa,GAAO,QAAU,IAAM,EAEvD,OACE,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,iDACb,EAAA,EAAA,KAACA,EAAAA,QAAAA,CAAiB,SAAgB,SAAiB,UAAS,SAAU,EAAc,SAAU,EAAe,GAAK,EAAU,SAAU,YAClI,CAAE,eAAc,gBAAe,mBAC/B,EAAA,EAAA,MAAC,MAAA,CACC,GAAI,GAAc,CAClB,WAAA,EAAA,EAAA,IACE,QACA,qBACA,0BACA,mIACA,yBACA,kCACA,uBACA,8BACA,+BACA,GAAgB,iDAChB,GAAc,iCACd,EACD,CACD,GAAI,aAEJ,EAAA,EAAA,KAAC,QAAA,CAAM,GAAI,GAAe,CAAA,CAAI,CAC7B,GACC,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,qEACb,EAAA,EAAA,KAAC,MAAA,CAAI,UAAU,kDACb,EAAA,EAAA,KAACC,EAAAA,OAAAA,CAAO,UAAU,kCAAkC,cAAY,QAAS,EACrE,EACN,EAAA,EAAA,KAAC,IAAA,CAAE,UAAU,gDAAuC,uBAAuB,CAAA,EACvE,EAEN,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,qEACb,EAAA,EAAA,KAAC,MAAA,CAAI,UAAU,kDACb,EAAA,EAAA,KAACA,EAAAA,OAAAA,CAAO,KAAM,GAAY,GAAI,UAAU,wBAAwB,cAAY,QAAS,EACjF,CACL,IACC,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,kCACb,EAAA,EAAA,MAAC,IAAA,CAAE,UAAU,wDAA8C,QAAM,MAAM,+CAA8C,EACrH,EAAA,EAAA,MAAC,IAAA,CAAE,UAAU,6CAAmC,iBAE7C,EAAe,EACZ,IAAI,IAAiB,IAAW,WAAa,EAAa;uDACnC,EAAQ,CAAC,QAChC,iBAAA,EAAA,EAAA,aAA4B,EAAQ,GAAA,EACtC,CAAA,EACA,CAAA,EAEJ,CAAA,EAEJ,EAEC,CACV,GAAO,QACN,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,0CACb,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,2DACb,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,6DACb,EAAA,EAAA,KAACC,EAAAA,MAAAA,CAAM,KAAM,GAAI,cAAY,QAAS,EACtC,EAAA,EAAA,MAAC,IAAA,CAAE,UAAU,oBAAU,mBAAiB,EAAM,OAAO,MAAK,CAAA,EACtD,EACN,EAAA,EAAA,MAAC,SAAA,CACC,UAAU,0HACV,YAAe,CACR,IACL,EAAM,QAAQ,GAAQ,CACf,EAAkB,EAAK,EAC5B,IAAI,gBAAgB,EAAK,QAAQ,EACjC,CACF,EAAS,EAAE,CAAC,CACZ,IAAgB,EAAE,CAAC,cAGrB,EAAA,EAAA,KAACC,EAAAA,OAAAA,CAAO,KAAM,GAAI,cAAY,QAAS,EACvC,EAAA,EAAA,KAAC,IAAA,CAAE,UAAU,mBAAU,cAAc,CAAA,EAC9B,CAAA,EACL,EACN,EAAA,EAAA,KAAC,MAAA,CAAI,UAAU,iCACZ,GAAO,KAAK,EAAM,KACjB,EAAA,EAAA,KAAC,EAAA,CAA2B,OAAM,aAAgB,EAAS,EAAM,CAAE,SAAU,IAAa,EAAK,OAAhF,EAAyF,CACxG,EACE,CAAA,EACF,CACJ,KAAA,EACA,CAUV,SAAS,EAAS,CAAE,OAAM,WAAU,YAA2B,CAC7D,OACE,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,kJACb,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,gCACZ,EAAkB,EAAK,EAAG,EAAA,EAAA,KAAC,EAAA,CAAkB,OAAA,CAAQ,CAAG,MACzD,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,wCACb,EAAA,EAAA,MAAC,MAAA,CAAI,UAAU,qCACb,EAAA,EAAA,KAAC,IAAA,CAAE,UAAU,mDAA2C,EAAK,MAAS,EACtE,EAAA,EAAA,KAAC,IAAA,CAAE,UAAU,8DAAgD,EAAK,KAAK,EAAK,CAAA,EACxE,CACL,GAAW,EAAA,EAAA,KAACC,EAAAA,SAAAA,CAAS,MAAO,EAAA,CAAY,CAAG,KAAA,EACxC,CAAA,EACF,EACN,EAAA,EAAA,KAAC,MAAA,CAAI,UAAU,oCACb,EAAA,EAAA,MAACC,EAAAA,EAAAA,CAAO,KAAK,SAAS,QAAQ,QAAQ,MAAM,YAAY,KAAK,OAAO,UAAU,SAAS,QAAS,aAC9F,EAAA,EAAA,KAACF,EAAAA,OAAAA,CAAO,KAAM,GAAI,UAAU,2BAA2B,cAAY,QAAS,EAC5E,EAAA,EAAA,KAAC,OAAA,CAAK,UAAU,mBAAU,eAAkB,CAAA,EACrC,EACL,CAAA,EACF,CAIV,SAAS,EAAkB,EAAgD,CACzE,MAAO,YAAa,GAAQ,OAAO,EAAK,SAAY,SAOtD,SAAS,EAAY,CAAE,QAA0B,CAK/C,OAJI,EAAK,KAAK,WAAW,SAAS,EACzB,EAAA,EAAA,KAAC,MAAA,CAAI,IAAK,EAAK,QAAS,UAAU,iGAAkG,EAGtI,EAAA,EAAA,KAACG,EAAAA,SAAAA,CAAS,UAAU,0CAA0C,cAAY,QAAS"}
1
+ {"version":3,"file":"file-uploader.cjs","names":["Dropzone","Upload","Image","Trash2","Progress","Button","FileText"],"sources":["../../packages/components/ui/file-uploader.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useEffect } from 'react';\nimport Dropzone, { type DropzoneProps, type FileRejection } from 'react-dropzone';\nimport { useControllableState } from '@customafk/react-toolkit/hooks/useControllableState';\nimport { cn, formatBytes } from '@customafk/react-toolkit/utils';\n\nimport { FileText, Image, Trash2, Upload } from 'lucide-react';\nimport { toast } from 'sonner';\n\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\n/**\n * Props for the FileUploader component.\n *\n * @example\n * ```tsx\n * import { FileUploader } from '@customafk/lunas-ui/ui/file-uploader';\n *\n * <FileUploader\n * accept={{ 'image/*': [] }}\n * maxSize={1024 * 1024 * 5}\n * maxFileCount={3}\n * multiple\n * onUpload={async (files) => { await uploadFiles(files); }}\n * />\n * ```\n */\ninterface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Value of the uploader.\n * @type File[]\n * @default undefined\n * @example value={files}\n */\n value?: File[];\n\n /**\n * Function to be called when the value changes.\n * @type (files: File[]) => void\n * @default undefined\n * @example onValueChange={(files) => setFiles(files)}\n */\n onValueChange?: (files: File[]) => void;\n\n /**\n * Function to be called when files are uploaded.\n * @type (files: File[]) => Promise<void>\n * @default undefined\n * @example onUpload={(files) => uploadFiles(files)}\n */\n onUpload?: (files: File[]) => Promise<void>;\n\n /**\n * Progress of the uploaded files.\n * @type Record<string, number> | undefined\n * @default undefined\n * @example progresses={{ \"file1.png\": 50 }}\n */\n progresses?: Record<string, number>;\n\n /**\n * Accepted file types for the uploader.\n * @type { [key: string]: string[]}\n * @default\n * ```ts\n * { \"image/*\": [] }\n * ```\n * @example accept={[\"image/png\", \"image/jpeg\"]}\n */\n accept?: DropzoneProps['accept'];\n\n /**\n * Maximum file size for the uploader.\n * @type number | undefined\n * @default 1024 * 1024 * 2 // 2MB\n * @example maxSize={1024 * 1024 * 2} // 2MB\n */\n maxSize?: DropzoneProps['maxSize'];\n\n /**\n * Maximum number of files for the uploader.\n * @type number | undefined\n * @default 1\n * @example maxFileCount={4}\n */\n maxFileCount?: DropzoneProps['maxFiles'];\n\n /**\n * Whether the uploader should accept multiple files.\n * @type boolean\n * @default false\n * @example multiple\n */\n multiple?: boolean;\n\n /**\n * Whether the uploader is disabled.\n * @type boolean\n * @default false\n * @example disabled\n */\n disabled?: boolean;\n\n /**\n * Whether to show the instructional drag-and-drop text inside the drop zone.\n * @default true\n */\n showText?: boolean;\n /** Size in pixels for the upload icon. */\n iconSize?: number;\n}\n\n/**\n * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.\n */\nexport function FileUploader(props: FileUploaderProps) {\n const {\n value: valueProp,\n onValueChange,\n onUpload,\n progresses,\n accept = {\n 'image/*': [],\n },\n maxSize = 1024 * 1024 * 2,\n maxFileCount = 1,\n multiple = false,\n disabled = false,\n showText = true,\n iconSize,\n className,\n ...dropzoneProps\n } = props;\n\n const [files, setFiles] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n });\n\n const onDrop = useCallback(\n (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {\n if (!multiple && maxFileCount === 1 && acceptedFiles.length > 1) {\n toast.error('Cannot upload more than 1 file at a time');\n\n return;\n }\n\n if ((files?.length ?? 0) + acceptedFiles.length > maxFileCount) {\n toast.error(`Cannot upload more than ${maxFileCount} files`);\n return;\n }\n\n const newFiles = acceptedFiles.map(file =>\n Object.assign(file, {\n preview: URL.createObjectURL(file),\n })\n );\n\n const updatedFiles = files ? [...files, ...newFiles] : newFiles;\n\n setFiles(updatedFiles);\n\n if (rejectedFiles.length > 0) {\n rejectedFiles.forEach(({ file }) => {\n toast.error(`File ${file.name} was rejected`);\n });\n }\n\n if (onUpload && updatedFiles.length > 0 && updatedFiles.length <= maxFileCount) {\n const target = updatedFiles.length > 0 ? `${updatedFiles.length} files` : `file`;\n\n onUpload(updatedFiles).then(() => {\n setFiles([]);\n toast(`${target} uploaded`);\n });\n }\n },\n\n [files, maxFileCount, multiple, onUpload, setFiles]\n );\n\n function onRemove(index: number) {\n if (!files) return;\n\n if (isFileWithPreview(files[index])) {\n URL.revokeObjectURL(files[index].preview);\n }\n\n const newFiles = files.filter((_, i) => i !== index);\n setFiles(newFiles);\n onValueChange?.(newFiles);\n }\n\n // Revoke preview url when component unmounts\n useEffect(() => {\n return () => {\n if (!files) return;\n files.forEach(file => {\n if (isFileWithPreview(file)) {\n URL.revokeObjectURL(file.preview);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;\n\n return (\n <div className=\"relative flex w-full flex-col gap-6\">\n <Dropzone onDrop={onDrop} accept={accept} maxSize={maxSize} maxFiles={maxFileCount} multiple={maxFileCount > 1 || multiple} disabled={isDisabled}>\n {({ getRootProps, getInputProps, isDragActive }) => (\n <div\n {...getRootProps()}\n className={cn(\n 'group',\n 'border-border-weak',\n 'hover:bg-border-weak/20',\n 'relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition',\n 'ring-offset-background',\n 'focus-visible:ring-primary-weak',\n 'focus-visible:ring-2',\n 'focus-visible:ring-offset-2',\n 'focus-visible:outline-hidden',\n isDragActive && 'border-border-primary-strong bg-border-weak/40',\n isDisabled && 'pointer-events-none opacity-60',\n className\n )}\n {...dropzoneProps}\n >\n <input {...getInputProps()} />\n {isDragActive ? (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload className=\"text-text-positive-muted size-7\" aria-hidden=\"true\" />\n </div>\n <p className=\"text-text-positive-muted font-medium\">Drop the files here</p>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload size={iconSize || 24} className=\"text-muted-foreground\" aria-hidden=\"true\" />\n </div>\n {showText && (\n <div className=\"flex flex-col gap-px\">\n <p className=\"text-text-positive-weak text-xs font-medium\">Drag {`'n'`} drop files here, or click to select files</p>\n <p className=\"text-text-positive-muted text-xs\">\n You can upload\n {maxFileCount > 1\n ? ` ${maxFileCount === Infinity ? 'multiple' : maxFileCount}\n files (up to ${formatBytes(maxSize)} each)`\n : ` a file with ${formatBytes(maxSize)}`}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </Dropzone>\n {files?.length ? (\n <div className=\"h-fit w-full overflow-y-auto\">\n <div className=\"flex items-center justify-between px-3 py-2.5\">\n <div className=\"text-text-positive-weak flex items-center gap-1\">\n <Image size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Ảnh đã tải lên ({files.length})</p>\n </div>\n <button\n className=\"hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200\"\n onClick={() => {\n if (!files) return;\n files.forEach(file => {\n if (!isFileWithPreview(file)) return;\n URL.revokeObjectURL(file.preview);\n });\n setFiles([]);\n onValueChange?.([]);\n }}\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Xóa tất cả</p>\n </button>\n </div>\n <div className=\"flex flex-col gap-2.5\">\n {files?.map((file, index) => (\n <FileCard key={index} file={file} onRemove={() => onRemove(index)} progress={progresses?.[file.name]} />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface FileCardProps {\n file: File;\n onRemove: () => void;\n progress?: number;\n}\n\nfunction FileCard({ file, progress, onRemove }: FileCardProps) {\n return (\n <div className=\"border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors\">\n <div className=\"flex flex-1 gap-2.5\">\n {isFileWithPreview(file) ? <FilePreview file={file} /> : null}\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex flex-col gap-y-0.5\">\n <p className=\"text-text-positive line-clamp-1 text-sm\">{file.name}</p>\n <p className=\"text-text-positive-muted text-xs\">{formatBytes(file.size)}</p>\n </div>\n {progress ? <Progress value={progress} /> : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"ghost\" color=\"secondary\" size=\"icon\" className=\"size-7\" onClick={onRemove}>\n <Trash2 size={16} className=\"text-text-positive-muted\" aria-hidden=\"true\" />\n <span className=\"sr-only\">Remove file</span>\n </Button>\n </div>\n </div>\n );\n}\n\nfunction isFileWithPreview(file: File): file is File & { preview: string } {\n return 'preview' in file && typeof file.preview === 'string';\n}\n\ninterface FilePreviewProps {\n file: File & { preview: string };\n}\n\nfunction FilePreview({ file }: FilePreviewProps) {\n if (file.type.startsWith('image/')) {\n return <img src={file.preview} className=\"border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm\" />;\n }\n\n return <FileText className=\"text-text-positive-muted size-10 border\" aria-hidden=\"true\" />;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime167 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime258 from "react/jsx-runtime";
2
2
  import { DropzoneProps } from "react-dropzone";
3
3
 
4
4
  //#region packages/components/ui/file-uploader.d.ts
@@ -97,7 +97,7 @@ interface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {
97
97
  /**
98
98
  * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.
99
99
  */
100
- declare function FileUploader(props: FileUploaderProps): react_jsx_runtime167.JSX.Element;
100
+ declare function FileUploader(props: FileUploaderProps): react_jsx_runtime258.JSX.Element;
101
101
  //#endregion
102
102
  export { FileUploader };
103
103
  //# sourceMappingURL=file-uploader.d.cts.map
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime155 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime150 from "react/jsx-runtime";
2
2
  import { DropzoneProps } from "react-dropzone";
3
3
 
4
4
  //#region packages/components/ui/file-uploader.d.ts
@@ -97,7 +97,7 @@ interface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {
97
97
  /**
98
98
  * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.
99
99
  */
100
- declare function FileUploader(props: FileUploaderProps): react_jsx_runtime155.JSX.Element;
100
+ declare function FileUploader(props: FileUploaderProps): react_jsx_runtime150.JSX.Element;
101
101
  //#endregion
102
102
  export { FileUploader };
103
103
  //# sourceMappingURL=file-uploader.d.mts.map
@@ -1,3 +1,3 @@
1
- "use client";import"../button.variants-DeCyas1F.mjs";import{t as e}from"../button-C6ybzxxj.mjs";import{Progress as t}from"./progress.mjs";import{FileText as n,Image as r,Trash2 as i,Upload as a}from"lucide-react";import{useCallback as o,useEffect as s}from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";import{cn as u,formatBytes as d}from"@customafk/react-toolkit/utils";import f from"react-dropzone";import{useControllableState as p}from"@customafk/react-toolkit/hooks/useControllableState";import{toast as m}from"sonner";function h(e){let{value:t,onValueChange:n,onUpload:h,progresses:v,accept:y={"image/*":[]},maxSize:b=1024*1024*2,maxFileCount:x=1,multiple:S=!1,disabled:C=!1,showText:w=!0,iconSize:T,className:E,...D}=e,[O,k]=p({prop:t,onChange:n}),A=o((e,t)=>{if(!S&&x===1&&e.length>1){m.error(`Cannot upload more than 1 file at a time`);return}if((O?.length??0)+e.length>x){m.error(`Cannot upload more than ${x} files`);return}let n=e.map(e=>Object.assign(e,{preview:URL.createObjectURL(e)})),r=O?[...O,...n]:n;if(k(r),t.length>0&&t.forEach(({file:e})=>{m.error(`File ${e.name} was rejected`)}),h&&r.length>0&&r.length<=x){let e=r.length>0?`${r.length} files`:`file`;h(r).then(()=>{k([]),m(`${e} uploaded`)})}},[O,x,S,h,k]);function j(e){if(!O)return;_(O[e])&&URL.revokeObjectURL(O[e].preview);let t=O.filter((t,n)=>n!==e);k(t),n?.(t)}s(()=>()=>{O&&O.forEach(e=>{_(e)&&URL.revokeObjectURL(e.preview)})},[]);let M=C||(O?.length??0)>=x;return l(`div`,{className:`relative flex w-full flex-col gap-6`,children:[c(f,{onDrop:A,accept:y,maxSize:b,maxFiles:x,multiple:x>1||S,disabled:M,children:({getRootProps:e,getInputProps:t,isDragActive:n})=>l(`div`,{...e(),className:u(`group`,`border-border-weak`,`hover:bg-border-weak/20`,`relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition`,`ring-offset-background`,`focus-visible:ring-primary-weak`,`focus-visible:ring-2`,`focus-visible:ring-offset-2`,`focus-visible:outline-hidden`,n&&`border-border-primary-strong bg-border-weak/40`,M&&`pointer-events-none opacity-60`,E),...D,children:[c(`input`,{...t()}),n?l(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[c(`div`,{className:`rounded-full border border-dashed p-3`,children:c(a,{className:`text-text-positive-muted size-7`,"aria-hidden":`true`})}),c(`p`,{className:`text-text-positive-muted font-medium`,children:`Drop the files here`})]}):l(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[c(`div`,{className:`rounded-full border border-dashed p-3`,children:c(a,{size:T||24,className:`text-muted-foreground`,"aria-hidden":`true`})}),w&&l(`div`,{className:`flex flex-col gap-px`,children:[l(`p`,{className:`text-text-positive-weak text-xs font-medium`,children:[`Drag `,`'n'`,` drop files here, or click to select files`]}),l(`p`,{className:`text-text-positive-muted text-xs`,children:[`You can upload`,x>1?` ${x===1/0?`multiple`:x}
1
+ "use client";import"../button.variants-DeCyas1F.mjs";import{t as e}from"../button-C6ybzxxj.mjs";import{t}from"../progress-0cpDwgAJ.mjs";import{FileText as n,Image as r,Trash2 as i,Upload as a}from"lucide-react";import{useCallback as o,useEffect as s}from"react";import{jsx as c,jsxs as l}from"react/jsx-runtime";import{cn as u,formatBytes as d}from"@customafk/react-toolkit/utils";import f from"react-dropzone";import{useControllableState as p}from"@customafk/react-toolkit/hooks/useControllableState";import{toast as m}from"sonner";function h(e){let{value:t,onValueChange:n,onUpload:h,progresses:v,accept:y={"image/*":[]},maxSize:b=1024*1024*2,maxFileCount:x=1,multiple:S=!1,disabled:C=!1,showText:w=!0,iconSize:T,className:E,...D}=e,[O,k]=p({prop:t,onChange:n}),A=o((e,t)=>{if(!S&&x===1&&e.length>1){m.error(`Cannot upload more than 1 file at a time`);return}if((O?.length??0)+e.length>x){m.error(`Cannot upload more than ${x} files`);return}let n=e.map(e=>Object.assign(e,{preview:URL.createObjectURL(e)})),r=O?[...O,...n]:n;if(k(r),t.length>0&&t.forEach(({file:e})=>{m.error(`File ${e.name} was rejected`)}),h&&r.length>0&&r.length<=x){let e=r.length>0?`${r.length} files`:`file`;h(r).then(()=>{k([]),m(`${e} uploaded`)})}},[O,x,S,h,k]);function j(e){if(!O)return;_(O[e])&&URL.revokeObjectURL(O[e].preview);let t=O.filter((t,n)=>n!==e);k(t),n?.(t)}s(()=>()=>{O&&O.forEach(e=>{_(e)&&URL.revokeObjectURL(e.preview)})},[]);let M=C||(O?.length??0)>=x;return l(`div`,{className:`relative flex w-full flex-col gap-6`,children:[c(f,{onDrop:A,accept:y,maxSize:b,maxFiles:x,multiple:x>1||S,disabled:M,children:({getRootProps:e,getInputProps:t,isDragActive:n})=>l(`div`,{...e(),className:u(`group`,`border-border-weak`,`hover:bg-border-weak/20`,`relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition`,`ring-offset-background`,`focus-visible:ring-primary-weak`,`focus-visible:ring-2`,`focus-visible:ring-offset-2`,`focus-visible:outline-hidden`,n&&`border-border-primary-strong bg-border-weak/40`,M&&`pointer-events-none opacity-60`,E),...D,children:[c(`input`,{...t()}),n?l(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[c(`div`,{className:`rounded-full border border-dashed p-3`,children:c(a,{className:`text-text-positive-muted size-7`,"aria-hidden":`true`})}),c(`p`,{className:`text-text-positive-muted font-medium`,children:`Drop the files here`})]}):l(`div`,{className:`flex flex-col items-center justify-center gap-4 sm:px-5`,children:[c(`div`,{className:`rounded-full border border-dashed p-3`,children:c(a,{size:T||24,className:`text-muted-foreground`,"aria-hidden":`true`})}),w&&l(`div`,{className:`flex flex-col gap-px`,children:[l(`p`,{className:`text-text-positive-weak text-xs font-medium`,children:[`Drag `,`'n'`,` drop files here, or click to select files`]}),l(`p`,{className:`text-text-positive-muted text-xs`,children:[`You can upload`,x>1?` ${x===1/0?`multiple`:x}
2
2
  files (up to ${d(b)} each)`:` a file with ${d(b)}`]})]})]})]})}),O?.length?l(`div`,{className:`h-fit w-full overflow-y-auto`,children:[l(`div`,{className:`flex items-center justify-between px-3 py-2.5`,children:[l(`div`,{className:`text-text-positive-weak flex items-center gap-1`,children:[c(r,{size:16,"aria-hidden":`true`}),l(`p`,{className:`text-sm`,children:[`Ảnh đã tải lên (`,O.length,`)`]})]}),l(`button`,{className:`hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200`,onClick:()=>{O&&(O.forEach(e=>{_(e)&&URL.revokeObjectURL(e.preview)}),k([]),n?.([]))},children:[c(i,{size:16,"aria-hidden":`true`}),c(`p`,{className:`text-sm`,children:`Xóa tất cả`})]})]}),c(`div`,{className:`flex flex-col gap-2.5`,children:O?.map((e,t)=>c(g,{file:e,onRemove:()=>j(t),progress:v?.[e.name]},t))})]}):null]})}function g({file:n,progress:r,onRemove:a}){return l(`div`,{className:`border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors`,children:[l(`div`,{className:`flex flex-1 gap-2.5`,children:[_(n)?c(v,{file:n}):null,l(`div`,{className:`flex w-full flex-col gap-2`,children:[l(`div`,{className:`flex flex-col gap-y-0.5`,children:[c(`p`,{className:`text-text-positive line-clamp-1 text-sm`,children:n.name}),c(`p`,{className:`text-text-positive-muted text-xs`,children:d(n.size)})]}),r?c(t,{value:r}):null]})]}),c(`div`,{className:`flex items-center gap-2`,children:l(e,{type:`button`,variant:`ghost`,color:`secondary`,size:`icon`,className:`size-7`,onClick:a,children:[c(i,{size:16,className:`text-text-positive-muted`,"aria-hidden":`true`}),c(`span`,{className:`sr-only`,children:`Remove file`})]})})]})}function _(e){return`preview`in e&&typeof e.preview==`string`}function v({file:e}){return e.type.startsWith(`image/`)?c(`img`,{src:e.preview,className:`border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm`}):c(n,{className:`text-text-positive-muted size-10 border`,"aria-hidden":`true`})}export{h as FileUploader};
3
3
  //# sourceMappingURL=file-uploader.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-uploader.mjs","names":[],"sources":["../../packages/components/ui/file-uploader.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useEffect } from 'react';\nimport Dropzone, { type DropzoneProps, type FileRejection } from 'react-dropzone';\nimport { useControllableState } from '@customafk/react-toolkit/hooks/useControllableState';\nimport { cn, formatBytes } from '@customafk/react-toolkit/utils';\n\nimport { FileText, Image, Trash2, Upload } from 'lucide-react';\nimport { toast } from 'sonner';\n\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\n/**\n * Props for the FileUploader component.\n *\n * @example\n * ```tsx\n * import { FileUploader } from '@customafk/lunas-ui/ui/file-uploader';\n *\n * <FileUploader\n * accept={{ 'image/*': [] }}\n * maxSize={1024 * 1024 * 5}\n * maxFileCount={3}\n * multiple\n * onUpload={async (files) => { await uploadFiles(files); }}\n * />\n * ```\n */\ninterface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Value of the uploader.\n * @type File[]\n * @default undefined\n * @example value={files}\n */\n value?: File[];\n\n /**\n * Function to be called when the value changes.\n * @type (files: File[]) => void\n * @default undefined\n * @example onValueChange={(files) => setFiles(files)}\n */\n onValueChange?: (files: File[]) => void;\n\n /**\n * Function to be called when files are uploaded.\n * @type (files: File[]) => Promise<void>\n * @default undefined\n * @example onUpload={(files) => uploadFiles(files)}\n */\n onUpload?: (files: File[]) => Promise<void>;\n\n /**\n * Progress of the uploaded files.\n * @type Record<string, number> | undefined\n * @default undefined\n * @example progresses={{ \"file1.png\": 50 }}\n */\n progresses?: Record<string, number>;\n\n /**\n * Accepted file types for the uploader.\n * @type { [key: string]: string[]}\n * @default\n * ```ts\n * { \"image/*\": [] }\n * ```\n * @example accept={[\"image/png\", \"image/jpeg\"]}\n */\n accept?: DropzoneProps['accept'];\n\n /**\n * Maximum file size for the uploader.\n * @type number | undefined\n * @default 1024 * 1024 * 2 // 2MB\n * @example maxSize={1024 * 1024 * 2} // 2MB\n */\n maxSize?: DropzoneProps['maxSize'];\n\n /**\n * Maximum number of files for the uploader.\n * @type number | undefined\n * @default 1\n * @example maxFileCount={4}\n */\n maxFileCount?: DropzoneProps['maxFiles'];\n\n /**\n * Whether the uploader should accept multiple files.\n * @type boolean\n * @default false\n * @example multiple\n */\n multiple?: boolean;\n\n /**\n * Whether the uploader is disabled.\n * @type boolean\n * @default false\n * @example disabled\n */\n disabled?: boolean;\n\n /**\n * Whether to show the instructional drag-and-drop text inside the drop zone.\n * @default true\n */\n showText?: boolean;\n /** Size in pixels for the upload icon. */\n iconSize?: number;\n}\n\n/**\n * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.\n */\nexport function FileUploader(props: FileUploaderProps) {\n const {\n value: valueProp,\n onValueChange,\n onUpload,\n progresses,\n accept = {\n 'image/*': [],\n },\n maxSize = 1024 * 1024 * 2,\n maxFileCount = 1,\n multiple = false,\n disabled = false,\n showText = true,\n iconSize,\n className,\n ...dropzoneProps\n } = props;\n\n const [files, setFiles] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n });\n\n const onDrop = useCallback(\n (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {\n if (!multiple && maxFileCount === 1 && acceptedFiles.length > 1) {\n toast.error('Cannot upload more than 1 file at a time');\n\n return;\n }\n\n if ((files?.length ?? 0) + acceptedFiles.length > maxFileCount) {\n toast.error(`Cannot upload more than ${maxFileCount} files`);\n return;\n }\n\n const newFiles = acceptedFiles.map(file =>\n Object.assign(file, {\n preview: URL.createObjectURL(file),\n })\n );\n\n const updatedFiles = files ? [...files, ...newFiles] : newFiles;\n\n setFiles(updatedFiles);\n\n if (rejectedFiles.length > 0) {\n rejectedFiles.forEach(({ file }) => {\n toast.error(`File ${file.name} was rejected`);\n });\n }\n\n if (onUpload && updatedFiles.length > 0 && updatedFiles.length <= maxFileCount) {\n const target = updatedFiles.length > 0 ? `${updatedFiles.length} files` : `file`;\n\n onUpload(updatedFiles).then(() => {\n setFiles([]);\n toast(`${target} uploaded`);\n });\n }\n },\n\n [files, maxFileCount, multiple, onUpload, setFiles]\n );\n\n function onRemove(index: number) {\n if (!files) return;\n\n if (isFileWithPreview(files[index])) {\n URL.revokeObjectURL(files[index].preview);\n }\n\n const newFiles = files.filter((_, i) => i !== index);\n setFiles(newFiles);\n onValueChange?.(newFiles);\n }\n\n // Revoke preview url when component unmounts\n useEffect(() => {\n return () => {\n if (!files) return;\n files.forEach(file => {\n if (isFileWithPreview(file)) {\n URL.revokeObjectURL(file.preview);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;\n\n return (\n <div className=\"relative flex w-full flex-col gap-6\">\n <Dropzone onDrop={onDrop} accept={accept} maxSize={maxSize} maxFiles={maxFileCount} multiple={maxFileCount > 1 || multiple} disabled={isDisabled}>\n {({ getRootProps, getInputProps, isDragActive }) => (\n <div\n {...getRootProps()}\n className={cn(\n 'group',\n 'border-border-weak',\n 'hover:bg-border-weak/20',\n 'relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition',\n 'ring-offset-background',\n 'focus-visible:ring-primary-weak',\n 'focus-visible:ring-2',\n 'focus-visible:ring-offset-2',\n 'focus-visible:outline-hidden',\n isDragActive && 'border-border-primary-strong bg-border-weak/40',\n isDisabled && 'pointer-events-none opacity-60',\n className\n )}\n {...dropzoneProps}\n >\n <input {...getInputProps()} />\n {isDragActive ? (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload className=\"text-text-positive-muted size-7\" aria-hidden=\"true\" />\n </div>\n <p className=\"text-text-positive-muted font-medium\">Drop the files here</p>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload size={iconSize || 24} className=\"text-muted-foreground\" aria-hidden=\"true\" />\n </div>\n {showText && (\n <div className=\"flex flex-col gap-px\">\n <p className=\"text-text-positive-weak text-xs font-medium\">Drag {`'n'`} drop files here, or click to select files</p>\n <p className=\"text-text-positive-muted text-xs\">\n You can upload\n {maxFileCount > 1\n ? ` ${maxFileCount === Infinity ? 'multiple' : maxFileCount}\n files (up to ${formatBytes(maxSize)} each)`\n : ` a file with ${formatBytes(maxSize)}`}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </Dropzone>\n {files?.length ? (\n <div className=\"h-fit w-full overflow-y-auto\">\n <div className=\"flex items-center justify-between px-3 py-2.5\">\n <div className=\"text-text-positive-weak flex items-center gap-1\">\n <Image size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Ảnh đã tải lên ({files.length})</p>\n </div>\n <button\n className=\"hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200\"\n onClick={() => {\n if (!files) return;\n files.forEach(file => {\n if (!isFileWithPreview(file)) return;\n URL.revokeObjectURL(file.preview);\n });\n setFiles([]);\n onValueChange?.([]);\n }}\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Xóa tất cả</p>\n </button>\n </div>\n <div className=\"flex flex-col gap-2.5\">\n {files?.map((file, index) => (\n <FileCard key={index} file={file} onRemove={() => onRemove(index)} progress={progresses?.[file.name]} />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface FileCardProps {\n file: File;\n onRemove: () => void;\n progress?: number;\n}\n\nfunction FileCard({ file, progress, onRemove }: FileCardProps) {\n return (\n <div className=\"border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors\">\n <div className=\"flex flex-1 gap-2.5\">\n {isFileWithPreview(file) ? <FilePreview file={file} /> : null}\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex flex-col gap-y-0.5\">\n <p className=\"text-text-positive line-clamp-1 text-sm\">{file.name}</p>\n <p className=\"text-text-positive-muted text-xs\">{formatBytes(file.size)}</p>\n </div>\n {progress ? <Progress value={progress} /> : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"ghost\" color=\"secondary\" size=\"icon\" className=\"size-7\" onClick={onRemove}>\n <Trash2 size={16} className=\"text-text-positive-muted\" aria-hidden=\"true\" />\n <span className=\"sr-only\">Remove file</span>\n </Button>\n </div>\n </div>\n );\n}\n\nfunction isFileWithPreview(file: File): file is File & { preview: string } {\n return 'preview' in file && typeof file.preview === 'string';\n}\n\ninterface FilePreviewProps {\n file: File & { preview: string };\n}\n\nfunction FilePreview({ file }: FilePreviewProps) {\n if (file.type.startsWith('image/')) {\n return <img src={file.preview} className=\"border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm\" />;\n }\n\n return <FileText className=\"text-text-positive-muted size-10 border\" aria-hidden=\"true\" />;\n}\n"],"mappings":"uhBAoHA,SAAgB,EAAa,EAA0B,CACrD,GAAM,CACJ,MAAO,EACP,gBACA,WACA,aACA,SAAS,CACP,UAAW,EAAE,CACd,CACD,UAAU,KAAO,KAAO,EACxB,eAAe,EACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,WACA,YACA,GAAG,GACD,EAEE,CAAC,EAAO,GAAY,EAAqB,CAC7C,KAAM,EACN,SAAU,EACX,CAAC,CAEI,EAAS,GACZ,EAAuB,IAAmC,CACzD,GAAI,CAAC,GAAY,IAAiB,GAAK,EAAc,OAAS,EAAG,CAC/D,EAAM,MAAM,2CAA2C,CAEvD,OAGF,IAAK,GAAO,QAAU,GAAK,EAAc,OAAS,EAAc,CAC9D,EAAM,MAAM,2BAA2B,EAAa,QAAQ,CAC5D,OAGF,IAAM,EAAW,EAAc,IAAI,GACjC,OAAO,OAAO,EAAM,CAClB,QAAS,IAAI,gBAAgB,EAAK,CACnC,CAAC,CACH,CAEK,EAAe,EAAQ,CAAC,GAAG,EAAO,GAAG,EAAS,CAAG,EAUvD,GARA,EAAS,EAAa,CAElB,EAAc,OAAS,GACzB,EAAc,SAAS,CAAE,UAAW,CAClC,EAAM,MAAM,QAAQ,EAAK,KAAK,eAAe,EAC7C,CAGA,GAAY,EAAa,OAAS,GAAK,EAAa,QAAU,EAAc,CAC9E,IAAM,EAAS,EAAa,OAAS,EAAI,GAAG,EAAa,OAAO,QAAU,OAE1E,EAAS,EAAa,CAAC,SAAW,CAChC,EAAS,EAAE,CAAC,CACZ,EAAM,GAAG,EAAO,WAAW,EAC3B,GAIN,CAAC,EAAO,EAAc,EAAU,EAAU,EAAS,CACpD,CAED,SAAS,EAAS,EAAe,CAC/B,GAAI,CAAC,EAAO,OAER,EAAkB,EAAM,GAAO,EACjC,IAAI,gBAAgB,EAAM,GAAO,QAAQ,CAG3C,IAAM,EAAW,EAAM,QAAQ,EAAG,IAAM,IAAM,EAAM,CACpD,EAAS,EAAS,CAClB,IAAgB,EAAS,CAI3B,UACe,CACN,GACL,EAAM,QAAQ,GAAQ,CAChB,EAAkB,EAAK,EACzB,IAAI,gBAAgB,EAAK,QAAQ,EAEnC,EAGH,EAAE,CAAC,CAEN,IAAM,EAAa,IAAa,GAAO,QAAU,IAAM,EAEvD,OACE,EAAC,MAAA,CAAI,UAAU,gDACb,EAAC,EAAA,CAAiB,SAAgB,SAAiB,UAAS,SAAU,EAAc,SAAU,EAAe,GAAK,EAAU,SAAU,YAClI,CAAE,eAAc,gBAAe,kBAC/B,EAAC,MAAA,CACC,GAAI,GAAc,CAClB,UAAW,EACT,QACA,qBACA,0BACA,mIACA,yBACA,kCACA,uBACA,8BACA,+BACA,GAAgB,iDAChB,GAAc,iCACd,EACD,CACD,GAAI,YAEJ,EAAC,QAAA,CAAM,GAAI,GAAe,CAAA,CAAI,CAC7B,EACC,EAAC,MAAA,CAAI,UAAU,oEACb,EAAC,MAAA,CAAI,UAAU,iDACb,EAAC,EAAA,CAAO,UAAU,kCAAkC,cAAY,QAAS,EACrE,CACN,EAAC,IAAA,CAAE,UAAU,gDAAuC,uBAAuB,CAAA,EACvE,CAEN,EAAC,MAAA,CAAI,UAAU,oEACb,EAAC,MAAA,CAAI,UAAU,iDACb,EAAC,EAAA,CAAO,KAAM,GAAY,GAAI,UAAU,wBAAwB,cAAY,QAAS,EACjF,CACL,GACC,EAAC,MAAA,CAAI,UAAU,iCACb,EAAC,IAAA,CAAE,UAAU,wDAA8C,QAAM,MAAM,+CAA8C,CACrH,EAAC,IAAA,CAAE,UAAU,6CAAmC,iBAE7C,EAAe,EACZ,IAAI,IAAiB,IAAW,WAAa,EAAa;qCAC/C,EAAY,EAAQ,CAAC,QAChC,gBAAgB,EAAY,EAAQ,GAAA,EACtC,CAAA,EACA,CAAA,EAEJ,CAAA,EAEJ,EAEC,CACV,GAAO,OACN,EAAC,MAAA,CAAI,UAAU,yCACb,EAAC,MAAA,CAAI,UAAU,0DACb,EAAC,MAAA,CAAI,UAAU,4DACb,EAAC,EAAA,CAAM,KAAM,GAAI,cAAY,QAAS,CACtC,EAAC,IAAA,CAAE,UAAU,oBAAU,mBAAiB,EAAM,OAAO,MAAK,CAAA,EACtD,CACN,EAAC,SAAA,CACC,UAAU,0HACV,YAAe,CACR,IACL,EAAM,QAAQ,GAAQ,CACf,EAAkB,EAAK,EAC5B,IAAI,gBAAgB,EAAK,QAAQ,EACjC,CACF,EAAS,EAAE,CAAC,CACZ,IAAgB,EAAE,CAAC,aAGrB,EAAC,EAAA,CAAO,KAAM,GAAI,cAAY,QAAS,CACvC,EAAC,IAAA,CAAE,UAAU,mBAAU,cAAc,CAAA,EAC9B,CAAA,EACL,CACN,EAAC,MAAA,CAAI,UAAU,iCACZ,GAAO,KAAK,EAAM,IACjB,EAAC,EAAA,CAA2B,OAAM,aAAgB,EAAS,EAAM,CAAE,SAAU,IAAa,EAAK,OAAhF,EAAyF,CACxG,EACE,CAAA,EACF,CACJ,KAAA,EACA,CAUV,SAAS,EAAS,CAAE,OAAM,WAAU,YAA2B,CAC7D,OACE,EAAC,MAAA,CAAI,UAAU,iJACb,EAAC,MAAA,CAAI,UAAU,gCACZ,EAAkB,EAAK,CAAG,EAAC,EAAA,CAAkB,OAAA,CAAQ,CAAG,KACzD,EAAC,MAAA,CAAI,UAAU,uCACb,EAAC,MAAA,CAAI,UAAU,oCACb,EAAC,IAAA,CAAE,UAAU,mDAA2C,EAAK,MAAS,CACtE,EAAC,IAAA,CAAE,UAAU,4CAAoC,EAAY,EAAK,KAAK,EAAK,CAAA,EACxE,CACL,EAAW,EAAC,EAAA,CAAS,MAAO,EAAA,CAAY,CAAG,KAAA,EACxC,CAAA,EACF,CACN,EAAC,MAAA,CAAI,UAAU,mCACb,EAAC,EAAA,CAAO,KAAK,SAAS,QAAQ,QAAQ,MAAM,YAAY,KAAK,OAAO,UAAU,SAAS,QAAS,YAC9F,EAAC,EAAA,CAAO,KAAM,GAAI,UAAU,2BAA2B,cAAY,QAAS,CAC5E,EAAC,OAAA,CAAK,UAAU,mBAAU,eAAkB,CAAA,EACrC,EACL,CAAA,EACF,CAIV,SAAS,EAAkB,EAAgD,CACzE,MAAO,YAAa,GAAQ,OAAO,EAAK,SAAY,SAOtD,SAAS,EAAY,CAAE,QAA0B,CAK/C,OAJI,EAAK,KAAK,WAAW,SAAS,CACzB,EAAC,MAAA,CAAI,IAAK,EAAK,QAAS,UAAU,iGAAkG,CAGtI,EAAC,EAAA,CAAS,UAAU,0CAA0C,cAAY,QAAS"}
1
+ {"version":3,"file":"file-uploader.mjs","names":[],"sources":["../../packages/components/ui/file-uploader.tsx"],"sourcesContent":["'use client';\nimport { useCallback, useEffect } from 'react';\nimport Dropzone, { type DropzoneProps, type FileRejection } from 'react-dropzone';\nimport { useControllableState } from '@customafk/react-toolkit/hooks/useControllableState';\nimport { cn, formatBytes } from '@customafk/react-toolkit/utils';\n\nimport { FileText, Image, Trash2, Upload } from 'lucide-react';\nimport { toast } from 'sonner';\n\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\n/**\n * Props for the FileUploader component.\n *\n * @example\n * ```tsx\n * import { FileUploader } from '@customafk/lunas-ui/ui/file-uploader';\n *\n * <FileUploader\n * accept={{ 'image/*': [] }}\n * maxSize={1024 * 1024 * 5}\n * maxFileCount={3}\n * multiple\n * onUpload={async (files) => { await uploadFiles(files); }}\n * />\n * ```\n */\ninterface FileUploaderProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Value of the uploader.\n * @type File[]\n * @default undefined\n * @example value={files}\n */\n value?: File[];\n\n /**\n * Function to be called when the value changes.\n * @type (files: File[]) => void\n * @default undefined\n * @example onValueChange={(files) => setFiles(files)}\n */\n onValueChange?: (files: File[]) => void;\n\n /**\n * Function to be called when files are uploaded.\n * @type (files: File[]) => Promise<void>\n * @default undefined\n * @example onUpload={(files) => uploadFiles(files)}\n */\n onUpload?: (files: File[]) => Promise<void>;\n\n /**\n * Progress of the uploaded files.\n * @type Record<string, number> | undefined\n * @default undefined\n * @example progresses={{ \"file1.png\": 50 }}\n */\n progresses?: Record<string, number>;\n\n /**\n * Accepted file types for the uploader.\n * @type { [key: string]: string[]}\n * @default\n * ```ts\n * { \"image/*\": [] }\n * ```\n * @example accept={[\"image/png\", \"image/jpeg\"]}\n */\n accept?: DropzoneProps['accept'];\n\n /**\n * Maximum file size for the uploader.\n * @type number | undefined\n * @default 1024 * 1024 * 2 // 2MB\n * @example maxSize={1024 * 1024 * 2} // 2MB\n */\n maxSize?: DropzoneProps['maxSize'];\n\n /**\n * Maximum number of files for the uploader.\n * @type number | undefined\n * @default 1\n * @example maxFileCount={4}\n */\n maxFileCount?: DropzoneProps['maxFiles'];\n\n /**\n * Whether the uploader should accept multiple files.\n * @type boolean\n * @default false\n * @example multiple\n */\n multiple?: boolean;\n\n /**\n * Whether the uploader is disabled.\n * @type boolean\n * @default false\n * @example disabled\n */\n disabled?: boolean;\n\n /**\n * Whether to show the instructional drag-and-drop text inside the drop zone.\n * @default true\n */\n showText?: boolean;\n /** Size in pixels for the upload icon. */\n iconSize?: number;\n}\n\n/**\n * A drag-and-drop file upload zone that manages file selection, validation, preview generation, and optional async upload with progress tracking.\n */\nexport function FileUploader(props: FileUploaderProps) {\n const {\n value: valueProp,\n onValueChange,\n onUpload,\n progresses,\n accept = {\n 'image/*': [],\n },\n maxSize = 1024 * 1024 * 2,\n maxFileCount = 1,\n multiple = false,\n disabled = false,\n showText = true,\n iconSize,\n className,\n ...dropzoneProps\n } = props;\n\n const [files, setFiles] = useControllableState({\n prop: valueProp,\n onChange: onValueChange,\n });\n\n const onDrop = useCallback(\n (acceptedFiles: File[], rejectedFiles: FileRejection[]) => {\n if (!multiple && maxFileCount === 1 && acceptedFiles.length > 1) {\n toast.error('Cannot upload more than 1 file at a time');\n\n return;\n }\n\n if ((files?.length ?? 0) + acceptedFiles.length > maxFileCount) {\n toast.error(`Cannot upload more than ${maxFileCount} files`);\n return;\n }\n\n const newFiles = acceptedFiles.map(file =>\n Object.assign(file, {\n preview: URL.createObjectURL(file),\n })\n );\n\n const updatedFiles = files ? [...files, ...newFiles] : newFiles;\n\n setFiles(updatedFiles);\n\n if (rejectedFiles.length > 0) {\n rejectedFiles.forEach(({ file }) => {\n toast.error(`File ${file.name} was rejected`);\n });\n }\n\n if (onUpload && updatedFiles.length > 0 && updatedFiles.length <= maxFileCount) {\n const target = updatedFiles.length > 0 ? `${updatedFiles.length} files` : `file`;\n\n onUpload(updatedFiles).then(() => {\n setFiles([]);\n toast(`${target} uploaded`);\n });\n }\n },\n\n [files, maxFileCount, multiple, onUpload, setFiles]\n );\n\n function onRemove(index: number) {\n if (!files) return;\n\n if (isFileWithPreview(files[index])) {\n URL.revokeObjectURL(files[index].preview);\n }\n\n const newFiles = files.filter((_, i) => i !== index);\n setFiles(newFiles);\n onValueChange?.(newFiles);\n }\n\n // Revoke preview url when component unmounts\n useEffect(() => {\n return () => {\n if (!files) return;\n files.forEach(file => {\n if (isFileWithPreview(file)) {\n URL.revokeObjectURL(file.preview);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const isDisabled = disabled || (files?.length ?? 0) >= maxFileCount;\n\n return (\n <div className=\"relative flex w-full flex-col gap-6\">\n <Dropzone onDrop={onDrop} accept={accept} maxSize={maxSize} maxFiles={maxFileCount} multiple={maxFileCount > 1 || multiple} disabled={isDisabled}>\n {({ getRootProps, getInputProps, isDragActive }) => (\n <div\n {...getRootProps()}\n className={cn(\n 'group',\n 'border-border-weak',\n 'hover:bg-border-weak/20',\n 'relative grid h-52 w-full cursor-pointer place-items-center rounded-lg border-2 border-dashed px-5 py-2.5 text-center transition',\n 'ring-offset-background',\n 'focus-visible:ring-primary-weak',\n 'focus-visible:ring-2',\n 'focus-visible:ring-offset-2',\n 'focus-visible:outline-hidden',\n isDragActive && 'border-border-primary-strong bg-border-weak/40',\n isDisabled && 'pointer-events-none opacity-60',\n className\n )}\n {...dropzoneProps}\n >\n <input {...getInputProps()} />\n {isDragActive ? (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload className=\"text-text-positive-muted size-7\" aria-hidden=\"true\" />\n </div>\n <p className=\"text-text-positive-muted font-medium\">Drop the files here</p>\n </div>\n ) : (\n <div className=\"flex flex-col items-center justify-center gap-4 sm:px-5\">\n <div className=\"rounded-full border border-dashed p-3\">\n <Upload size={iconSize || 24} className=\"text-muted-foreground\" aria-hidden=\"true\" />\n </div>\n {showText && (\n <div className=\"flex flex-col gap-px\">\n <p className=\"text-text-positive-weak text-xs font-medium\">Drag {`'n'`} drop files here, or click to select files</p>\n <p className=\"text-text-positive-muted text-xs\">\n You can upload\n {maxFileCount > 1\n ? ` ${maxFileCount === Infinity ? 'multiple' : maxFileCount}\n files (up to ${formatBytes(maxSize)} each)`\n : ` a file with ${formatBytes(maxSize)}`}\n </p>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </Dropzone>\n {files?.length ? (\n <div className=\"h-fit w-full overflow-y-auto\">\n <div className=\"flex items-center justify-between px-3 py-2.5\">\n <div className=\"text-text-positive-weak flex items-center gap-1\">\n <Image size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Ảnh đã tải lên ({files.length})</p>\n </div>\n <button\n className=\"hover:text-text-positive text-text-positive-muted flex cursor-pointer items-center gap-1 transition-colors duration-200\"\n onClick={() => {\n if (!files) return;\n files.forEach(file => {\n if (!isFileWithPreview(file)) return;\n URL.revokeObjectURL(file.preview);\n });\n setFiles([]);\n onValueChange?.([]);\n }}\n >\n <Trash2 size={16} aria-hidden=\"true\" />\n <p className=\"text-sm\">Xóa tất cả</p>\n </button>\n </div>\n <div className=\"flex flex-col gap-2.5\">\n {files?.map((file, index) => (\n <FileCard key={index} file={file} onRemove={() => onRemove(index)} progress={progresses?.[file.name]} />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\ninterface FileCardProps {\n file: File;\n onRemove: () => void;\n progress?: number;\n}\n\nfunction FileCard({ file, progress, onRemove }: FileCardProps) {\n return (\n <div className=\"border-border-weak hover:border-border relative flex items-center gap-4 rounded-md border py-2 pr-3 pl-2 shadow-xs transition-colors\">\n <div className=\"flex flex-1 gap-2.5\">\n {isFileWithPreview(file) ? <FilePreview file={file} /> : null}\n <div className=\"flex w-full flex-col gap-2\">\n <div className=\"flex flex-col gap-y-0.5\">\n <p className=\"text-text-positive line-clamp-1 text-sm\">{file.name}</p>\n <p className=\"text-text-positive-muted text-xs\">{formatBytes(file.size)}</p>\n </div>\n {progress ? <Progress value={progress} /> : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"ghost\" color=\"secondary\" size=\"icon\" className=\"size-7\" onClick={onRemove}>\n <Trash2 size={16} className=\"text-text-positive-muted\" aria-hidden=\"true\" />\n <span className=\"sr-only\">Remove file</span>\n </Button>\n </div>\n </div>\n );\n}\n\nfunction isFileWithPreview(file: File): file is File & { preview: string } {\n return 'preview' in file && typeof file.preview === 'string';\n}\n\ninterface FilePreviewProps {\n file: File & { preview: string };\n}\n\nfunction FilePreview({ file }: FilePreviewProps) {\n if (file.type.startsWith('image/')) {\n return <img src={file.preview} className=\"border-border aspect-square size-10 shrink-0 rounded border object-cover object-top shadow-sm\" />;\n }\n\n return <FileText className=\"text-text-positive-muted size-10 border\" aria-hidden=\"true\" />;\n}\n"],"mappings":"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"}
package/dist/ui/form.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use client";const e=require(`../chunk-Bmb41Sf3.cjs`);require(`../separator-BwZb12bh.cjs`),require(`../label-DkMTQ3Ch.cjs`);const t=require(`../field-CppNvoxV.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`),i=require(`@customafk/react-toolkit/utils`),a=require(`radix-ui`),o=require(`react-hook-form`);const s=o.FormProvider,c=(0,n.createContext)({}),l=({...e})=>(0,r.jsx)(c.Provider,{value:{name:e.name},children:(0,r.jsx)(o.Controller,{...e})}),u=()=>{let e=(0,n.use)(c),t=(0,n.use)(d),{getFieldState:r,control:i,resetField:a}=(0,o.useFormContext)(),s=(0,o.useFormState)({name:e.name}),l=r(e.name,s);if(!e)throw Error(`useFormField should be used within <FormField>`);let{id:u}=t;return{id:u,control:i,resetField:a,name:e.name,formItemId:`${u}-form-item`,formDescriptionId:`${u}-form-item-description`,formMessageId:`${u}-form-item-message`,...l}},d=(0,n.createContext)({}),f=(0,n.memo)(({className:e,orientation:i=`responsive`,...a})=>{let o=(0,n.useId)();return(0,r.jsx)(d.Provider,{value:{id:o},children:(0,r.jsx)(t.t,{orientation:i,...a,className:e})})});f.displayName=`FormItem`;const p=(0,n.memo)(({...e})=>{let{formItemId:n}=u();return(0,r.jsx)(t.o,{htmlFor:n,...e})});p.displayName=`FormLabel`;const m=(0,n.memo)(({...e})=>{let{error:t,formItemId:n,formDescriptionId:i,formMessageId:o}=u();return(0,r.jsx)(a.Slot.Slot,{"data-slot":`form-control`,id:n,"aria-describedby":t?`${i} ${o}`:`${i}`,"aria-invalid":!!t,...e})});m.displayName=`FormControl`;function h({className:e,...n}){let{formDescriptionId:a}=u();return(0,r.jsx)(t.r,{id:a,className:(0,i.cn)(`text-text-positive-weak text-sm/6 leading-normal font-normal`,`group-has-data-[orientation=horizontal]/field:text-balance`,`last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5`,`[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4`,e),...n})}function g({className:e,children:t,...n}){let{error:a,formMessageId:o}=u();return(0,r.jsx)(`span`,{"data-slot":`form-message`,id:o,className:(0,i.cn)(`text-danger text-xs`,e),...n,children:a?String(a?.message??``):t})}exports.Form=s,exports.FormControl=m,exports.FormDescription=h,exports.FormField=l,exports.FormItem=f,exports.FormLabel=p,exports.FormMessage=g,exports.useFormField=u;
1
+ "use client";const e=require(`../chunk-Bmb41Sf3.cjs`);require(`../separator-BwZb12bh.cjs`),require(`../label-zyBJYydC.cjs`);const t=require(`../field-C51eJ6QN.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`),i=require(`@customafk/react-toolkit/utils`),a=require(`radix-ui`),o=require(`react-hook-form`);const s=o.FormProvider,c=(0,n.createContext)({}),l=({...e})=>(0,r.jsx)(c.Provider,{value:{name:e.name},children:(0,r.jsx)(o.Controller,{...e})}),u=()=>{let e=(0,n.use)(c),t=(0,n.use)(d),{getFieldState:r,control:i,resetField:a}=(0,o.useFormContext)(),s=(0,o.useFormState)({name:e.name}),l=r(e.name,s);if(!e)throw Error(`useFormField should be used within <FormField>`);let{id:u}=t;return{id:u,control:i,resetField:a,name:e.name,formItemId:`${u}-form-item`,formDescriptionId:`${u}-form-item-description`,formMessageId:`${u}-form-item-message`,...l}},d=(0,n.createContext)({}),f=(0,n.memo)(({className:e,orientation:i=`responsive`,...a})=>{let o=(0,n.useId)();return(0,r.jsx)(d.Provider,{value:{id:o},children:(0,r.jsx)(t.t,{orientation:i,...a,className:e})})});f.displayName=`FormItem`;const p=(0,n.memo)(({...e})=>{let{formItemId:n}=u();return(0,r.jsx)(t.o,{htmlFor:n,...e})});p.displayName=`FormLabel`;const m=(0,n.memo)(({...e})=>{let{error:t,formItemId:n,formDescriptionId:i,formMessageId:o}=u();return(0,r.jsx)(a.Slot.Slot,{"data-slot":`form-control`,id:n,"aria-describedby":t?`${i} ${o}`:`${i}`,"aria-invalid":!!t,...e})});m.displayName=`FormControl`;function h({className:e,...n}){let{formDescriptionId:a}=u();return(0,r.jsx)(t.r,{id:a,className:(0,i.cn)(`text-text-positive-weak text-sm/6 leading-normal font-normal`,`group-has-data-[orientation=horizontal]/field:text-balance`,`last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5`,`[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4`,e),...n})}function g({className:e,children:t,...n}){let{error:a,formMessageId:o}=u();return(0,r.jsx)(`span`,{"data-slot":`form-message`,id:o,className:(0,i.cn)(`text-danger text-xs`,e),...n,children:a?String(a?.message??``):t})}exports.Form=s,exports.FormControl=m,exports.FormDescription=h,exports.FormField=l,exports.FormItem=f,exports.FormLabel=p,exports.FormMessage=g,exports.useFormField=u;
2
2
  //# sourceMappingURL=form.cjs.map
@@ -1,5 +1,5 @@
1
- import * as react_jsx_runtime280 from "react/jsx-runtime";
2
- import * as react31 from "react";
1
+ import * as react_jsx_runtime191 from "react/jsx-runtime";
2
+ import * as react15 from "react";
3
3
  import { Label, Slot } from "radix-ui";
4
4
  import * as react_hook_form0 from "react-hook-form";
5
5
  import { ControllerProps, FieldPath, FieldValues } from "react-hook-form";
@@ -39,7 +39,7 @@ declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransfor
39
39
  */
40
40
  declare const FormField: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({
41
41
  ...props
42
- }: ControllerProps<TFieldValues, TName>) => react_jsx_runtime280.JSX.Element;
42
+ }: ControllerProps<TFieldValues, TName>) => react_jsx_runtime191.JSX.Element;
43
43
  /**
44
44
  * Hook that returns the field state and IDs for the enclosing FormField.
45
45
  * Must be called inside a component rendered within a `<FormField>`.
@@ -63,32 +63,32 @@ declare const useFormField: () => {
63
63
  *
64
64
  * @param orientation - Layout direction: `'vertical'`, `'horizontal'`, or `'responsive'` (default).
65
65
  */
66
- declare const FormItem: react31.MemoExoticComponent<({
66
+ declare const FormItem: react15.MemoExoticComponent<({
67
67
  className,
68
68
  orientation,
69
69
  ...props
70
70
  }: React.ComponentProps<"div"> & {
71
71
  orientation?: "vertical" | "horizontal" | "responsive";
72
- }) => react_jsx_runtime280.JSX.Element>;
72
+ }) => react_jsx_runtime191.JSX.Element>;
73
73
  /** Styled label automatically associated with the FormItem's control via `htmlFor`. */
74
- declare const FormLabel: react31.MemoExoticComponent<({
74
+ declare const FormLabel: react15.MemoExoticComponent<({
75
75
  ...props
76
- }: React.ComponentProps<typeof Label.Root>) => react_jsx_runtime280.JSX.Element>;
76
+ }: React.ComponentProps<typeof Label.Root>) => react_jsx_runtime191.JSX.Element>;
77
77
  /** Radix Slot wrapper that wires the correct `id`, `aria-describedby`, and `aria-invalid` attributes onto the underlying control element. */
78
- declare const FormControl: react31.MemoExoticComponent<({
78
+ declare const FormControl: react15.MemoExoticComponent<({
79
79
  ...props
80
- }: React.ComponentProps<typeof Slot.Slot>) => react_jsx_runtime280.JSX.Element>;
80
+ }: React.ComponentProps<typeof Slot.Slot>) => react_jsx_runtime191.JSX.Element>;
81
81
  /** Helper text displayed below the control that provides additional context about the field. */
82
82
  declare function FormDescription({
83
83
  className,
84
84
  ...props
85
- }: React.ComponentProps<'p'>): react_jsx_runtime280.JSX.Element;
85
+ }: React.ComponentProps<'p'>): react_jsx_runtime191.JSX.Element;
86
86
  /** Displays the validation error message for the field, or falls back to `children` when there is no error. */
87
87
  declare function FormMessage({
88
88
  className,
89
89
  children,
90
90
  ...props
91
- }: React.ComponentProps<'p'>): react_jsx_runtime280.JSX.Element;
91
+ }: React.ComponentProps<'p'>): react_jsx_runtime191.JSX.Element;
92
92
  //#endregion
93
93
  export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
94
94
  //# sourceMappingURL=form.d.cts.map
@@ -1,5 +1,5 @@
1
- import * as react11 from "react";
2
- import * as react_jsx_runtime159 from "react/jsx-runtime";
1
+ import * as react1 from "react";
2
+ import * as react_jsx_runtime119 from "react/jsx-runtime";
3
3
  import { Label, Slot } from "radix-ui";
4
4
  import * as react_hook_form0 from "react-hook-form";
5
5
  import { ControllerProps, FieldPath, FieldValues } from "react-hook-form";
@@ -39,7 +39,7 @@ declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransfor
39
39
  */
40
40
  declare const FormField: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({
41
41
  ...props
42
- }: ControllerProps<TFieldValues, TName>) => react_jsx_runtime159.JSX.Element;
42
+ }: ControllerProps<TFieldValues, TName>) => react_jsx_runtime119.JSX.Element;
43
43
  /**
44
44
  * Hook that returns the field state and IDs for the enclosing FormField.
45
45
  * Must be called inside a component rendered within a `<FormField>`.
@@ -63,32 +63,32 @@ declare const useFormField: () => {
63
63
  *
64
64
  * @param orientation - Layout direction: `'vertical'`, `'horizontal'`, or `'responsive'` (default).
65
65
  */
66
- declare const FormItem: react11.MemoExoticComponent<({
66
+ declare const FormItem: react1.MemoExoticComponent<({
67
67
  className,
68
68
  orientation,
69
69
  ...props
70
70
  }: React.ComponentProps<"div"> & {
71
71
  orientation?: "vertical" | "horizontal" | "responsive";
72
- }) => react_jsx_runtime159.JSX.Element>;
72
+ }) => react_jsx_runtime119.JSX.Element>;
73
73
  /** Styled label automatically associated with the FormItem's control via `htmlFor`. */
74
- declare const FormLabel: react11.MemoExoticComponent<({
74
+ declare const FormLabel: react1.MemoExoticComponent<({
75
75
  ...props
76
- }: React.ComponentProps<typeof Label.Root>) => react_jsx_runtime159.JSX.Element>;
76
+ }: React.ComponentProps<typeof Label.Root>) => react_jsx_runtime119.JSX.Element>;
77
77
  /** Radix Slot wrapper that wires the correct `id`, `aria-describedby`, and `aria-invalid` attributes onto the underlying control element. */
78
- declare const FormControl: react11.MemoExoticComponent<({
78
+ declare const FormControl: react1.MemoExoticComponent<({
79
79
  ...props
80
- }: React.ComponentProps<typeof Slot.Slot>) => react_jsx_runtime159.JSX.Element>;
80
+ }: React.ComponentProps<typeof Slot.Slot>) => react_jsx_runtime119.JSX.Element>;
81
81
  /** Helper text displayed below the control that provides additional context about the field. */
82
82
  declare function FormDescription({
83
83
  className,
84
84
  ...props
85
- }: React.ComponentProps<'p'>): react_jsx_runtime159.JSX.Element;
85
+ }: React.ComponentProps<'p'>): react_jsx_runtime119.JSX.Element;
86
86
  /** Displays the validation error message for the field, or falls back to `children` when there is no error. */
87
87
  declare function FormMessage({
88
88
  className,
89
89
  children,
90
90
  ...props
91
- }: React.ComponentProps<'p'>): react_jsx_runtime159.JSX.Element;
91
+ }: React.ComponentProps<'p'>): react_jsx_runtime119.JSX.Element;
92
92
  //#endregion
93
93
  export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
94
94
  //# sourceMappingURL=form.d.mts.map
package/dist/ui/form.mjs CHANGED
@@ -1,2 +1,2 @@
1
- "use client";import"../separator-BMsbHAVt.mjs";import"../label-OmlGaZ5h.mjs";import{o as e,r as t,t as n}from"../field-CXVnw75a.mjs";import{createContext as r,memo as i,use as a,useId as o}from"react";import{jsx as s}from"react/jsx-runtime";import{cn as c}from"@customafk/react-toolkit/utils";import{Slot as l}from"radix-ui";import{Controller as u,FormProvider as d,useFormContext as f,useFormState as p}from"react-hook-form";const m=d,h=r({}),g=({...e})=>s(h.Provider,{value:{name:e.name},children:s(u,{...e})}),_=()=>{let e=a(h),t=a(v),{getFieldState:n,control:r,resetField:i}=f(),o=p({name:e.name}),s=n(e.name,o);if(!e)throw Error(`useFormField should be used within <FormField>`);let{id:c}=t;return{id:c,control:r,resetField:i,name:e.name,formItemId:`${c}-form-item`,formDescriptionId:`${c}-form-item-description`,formMessageId:`${c}-form-item-message`,...s}},v=r({}),y=i(({className:e,orientation:t=`responsive`,...r})=>{let i=o();return s(v.Provider,{value:{id:i},children:s(n,{orientation:t,...r,className:e})})});y.displayName=`FormItem`;const b=i(({...t})=>{let{formItemId:n}=_();return s(e,{htmlFor:n,...t})});b.displayName=`FormLabel`;const x=i(({...e})=>{let{error:t,formItemId:n,formDescriptionId:r,formMessageId:i}=_();return s(l.Slot,{"data-slot":`form-control`,id:n,"aria-describedby":t?`${r} ${i}`:`${r}`,"aria-invalid":!!t,...e})});x.displayName=`FormControl`;function S({className:e,...n}){let{formDescriptionId:r}=_();return s(t,{id:r,className:c(`text-text-positive-weak text-sm/6 leading-normal font-normal`,`group-has-data-[orientation=horizontal]/field:text-balance`,`last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5`,`[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4`,e),...n})}function C({className:e,children:t,...n}){let{error:r,formMessageId:i}=_();return s(`span`,{"data-slot":`form-message`,id:i,className:c(`text-danger text-xs`,e),...n,children:r?String(r?.message??``):t})}export{m as Form,x as FormControl,S as FormDescription,g as FormField,y as FormItem,b as FormLabel,C as FormMessage,_ as useFormField};
1
+ "use client";import"../separator-BMsbHAVt.mjs";import"../label-3vAlNtF9.mjs";import{o as e,r as t,t as n}from"../field-DfsTE4Ie.mjs";import{createContext as r,memo as i,use as a,useId as o}from"react";import{jsx as s}from"react/jsx-runtime";import{cn as c}from"@customafk/react-toolkit/utils";import{Slot as l}from"radix-ui";import{Controller as u,FormProvider as d,useFormContext as f,useFormState as p}from"react-hook-form";const m=d,h=r({}),g=({...e})=>s(h.Provider,{value:{name:e.name},children:s(u,{...e})}),_=()=>{let e=a(h),t=a(v),{getFieldState:n,control:r,resetField:i}=f(),o=p({name:e.name}),s=n(e.name,o);if(!e)throw Error(`useFormField should be used within <FormField>`);let{id:c}=t;return{id:c,control:r,resetField:i,name:e.name,formItemId:`${c}-form-item`,formDescriptionId:`${c}-form-item-description`,formMessageId:`${c}-form-item-message`,...s}},v=r({}),y=i(({className:e,orientation:t=`responsive`,...r})=>{let i=o();return s(v.Provider,{value:{id:i},children:s(n,{orientation:t,...r,className:e})})});y.displayName=`FormItem`;const b=i(({...t})=>{let{formItemId:n}=_();return s(e,{htmlFor:n,...t})});b.displayName=`FormLabel`;const x=i(({...e})=>{let{error:t,formItemId:n,formDescriptionId:r,formMessageId:i}=_();return s(l.Slot,{"data-slot":`form-control`,id:n,"aria-describedby":t?`${r} ${i}`:`${r}`,"aria-invalid":!!t,...e})});x.displayName=`FormControl`;function S({className:e,...n}){let{formDescriptionId:r}=_();return s(t,{id:r,className:c(`text-text-positive-weak text-sm/6 leading-normal font-normal`,`group-has-data-[orientation=horizontal]/field:text-balance`,`last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5`,`[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4`,e),...n})}function C({className:e,children:t,...n}){let{error:r,formMessageId:i}=_();return s(`span`,{"data-slot":`form-message`,id:i,className:c(`text-danger text-xs`,e),...n,children:r?String(r?.message??``):t})}export{m as Form,x as FormControl,S as FormDescription,g as FormField,y as FormItem,b as FormLabel,C as FormMessage,_ as useFormField};
2
2
  //# sourceMappingURL=form.mjs.map
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime134 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime121 from "react/jsx-runtime";
2
2
  import { HoverCard as HoverCard$1 } from "radix-ui";
3
3
 
4
4
  //#region packages/components/ui/hover-card.d.ts
@@ -20,18 +20,18 @@ import { HoverCard as HoverCard$1 } from "radix-ui";
20
20
  */
21
21
  declare function HoverCard({
22
22
  ...props
23
- }: React.ComponentProps<typeof HoverCard$1.Root>): react_jsx_runtime134.JSX.Element;
23
+ }: React.ComponentProps<typeof HoverCard$1.Root>): react_jsx_runtime121.JSX.Element;
24
24
  /** The element that triggers the HoverCard on pointer enter. */
25
25
  declare function HoverCardTrigger({
26
26
  ...props
27
- }: React.ComponentProps<typeof HoverCard$1.Trigger>): react_jsx_runtime134.JSX.Element;
27
+ }: React.ComponentProps<typeof HoverCard$1.Trigger>): react_jsx_runtime121.JSX.Element;
28
28
  /** The floating card panel displayed when the trigger is hovered. */
29
29
  declare function HoverCardContent({
30
30
  className,
31
31
  align,
32
32
  sideOffset,
33
33
  ...props
34
- }: React.ComponentProps<typeof HoverCard$1.Content>): react_jsx_runtime134.JSX.Element;
34
+ }: React.ComponentProps<typeof HoverCard$1.Content>): react_jsx_runtime121.JSX.Element;
35
35
  //#endregion
36
36
  export { HoverCard, HoverCardContent, HoverCardTrigger };
37
37
  //# sourceMappingURL=hover-card.d.cts.map