@k3-universe/react-kit 0.0.27 → 0.0.29

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 (422) hide show
  1. package/.storybook/main.ts +1 -1
  2. package/.storybook/preview.ts +18 -10
  3. package/biome.json +10 -0
  4. package/dist/index.js +2319 -1227
  5. package/dist/kit/builder/auth/AuthProvider.d.ts +36 -0
  6. package/dist/kit/builder/auth/AuthProvider.d.ts.map +1 -0
  7. package/dist/kit/builder/auth/adapter.d.ts +14 -0
  8. package/dist/kit/builder/auth/adapter.d.ts.map +1 -0
  9. package/dist/kit/builder/auth/client-adapters.d.ts +149 -0
  10. package/dist/kit/builder/auth/client-adapters.d.ts.map +1 -0
  11. package/dist/kit/builder/auth/components.d.ts +119 -0
  12. package/dist/kit/builder/auth/components.d.ts.map +1 -0
  13. package/dist/kit/builder/auth/hooks.d.ts +158 -0
  14. package/dist/kit/builder/auth/hooks.d.ts.map +1 -0
  15. package/dist/kit/builder/auth/index.d.ts +11 -0
  16. package/dist/kit/builder/auth/index.d.ts.map +1 -0
  17. package/dist/kit/builder/auth/permission-checker.d.ts +31 -0
  18. package/dist/kit/builder/auth/permission-checker.d.ts.map +1 -0
  19. package/dist/kit/builder/auth/storage.d.ts +17 -0
  20. package/dist/kit/builder/auth/storage.d.ts.map +1 -0
  21. package/dist/kit/builder/auth/token-manager.d.ts +9 -0
  22. package/dist/kit/builder/auth/token-manager.d.ts.map +1 -0
  23. package/dist/kit/builder/auth/types.d.ts +183 -0
  24. package/dist/kit/builder/auth/types.d.ts.map +1 -0
  25. package/dist/kit/builder/data-table/components/DataTable.d.ts +2 -1
  26. package/dist/kit/builder/data-table/components/DataTable.d.ts.map +1 -1
  27. package/dist/kit/builder/data-table/components/DataTableColumnHeader.d.ts +2 -2
  28. package/dist/kit/builder/data-table/components/DataTableColumnHeader.d.ts.map +1 -1
  29. package/dist/kit/builder/data-table/components/DataTablePagination.d.ts +2 -1
  30. package/dist/kit/builder/data-table/components/DataTablePagination.d.ts.map +1 -1
  31. package/dist/kit/builder/data-table/components/DataTableViewOptions.d.ts +1 -1
  32. package/dist/kit/builder/data-table/components/DataTableViewOptions.d.ts.map +1 -1
  33. package/dist/kit/builder/data-table/types.d.ts.map +1 -1
  34. package/dist/kit/builder/dialog/index.d.ts +1 -1
  35. package/dist/kit/builder/dialog/index.d.ts.map +1 -1
  36. package/dist/kit/builder/dialog/provider.d.ts +0 -1
  37. package/dist/kit/builder/dialog/provider.d.ts.map +1 -1
  38. package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
  39. package/dist/kit/builder/form/components/FormBuilderActions.d.ts.map +1 -1
  40. package/dist/kit/builder/form/components/FormBuilderContext.d.ts.map +1 -1
  41. package/dist/kit/builder/form/components/FormBuilderField.d.ts +1 -1
  42. package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -1
  43. package/dist/kit/builder/form/components/fields/ArrayField.d.ts +1 -1
  44. package/dist/kit/builder/form/components/fields/ArrayField.d.ts.map +1 -1
  45. package/dist/kit/builder/form/components/fields/AutocompleteField.d.ts +1 -1
  46. package/dist/kit/builder/form/components/fields/AutocompleteField.d.ts.map +1 -1
  47. package/dist/kit/builder/form/components/fields/CheckboxField.d.ts +1 -1
  48. package/dist/kit/builder/form/components/fields/CheckboxField.d.ts.map +1 -1
  49. package/dist/kit/builder/form/components/fields/DateField.d.ts +1 -1
  50. package/dist/kit/builder/form/components/fields/DateField.d.ts.map +1 -1
  51. package/dist/kit/builder/form/components/fields/DatePickerField.d.ts +1 -1
  52. package/dist/kit/builder/form/components/fields/DatePickerField.d.ts.map +1 -1
  53. package/dist/kit/builder/form/components/fields/DateRangePickerField.d.ts +1 -1
  54. package/dist/kit/builder/form/components/fields/DateRangePickerField.d.ts.map +1 -1
  55. package/dist/kit/builder/form/components/fields/DateTimePickerField.d.ts +1 -1
  56. package/dist/kit/builder/form/components/fields/DateTimePickerField.d.ts.map +1 -1
  57. package/dist/kit/builder/form/components/fields/DateTimeRangePickerField.d.ts +1 -1
  58. package/dist/kit/builder/form/components/fields/DateTimeRangePickerField.d.ts.map +1 -1
  59. package/dist/kit/builder/form/components/fields/FileField.d.ts +1 -1
  60. package/dist/kit/builder/form/components/fields/FileField.d.ts.map +1 -1
  61. package/dist/kit/builder/form/components/fields/MonthPickerField.d.ts +1 -1
  62. package/dist/kit/builder/form/components/fields/MonthPickerField.d.ts.map +1 -1
  63. package/dist/kit/builder/form/components/fields/MonthRangePickerField.d.ts +1 -1
  64. package/dist/kit/builder/form/components/fields/MonthRangePickerField.d.ts.map +1 -1
  65. package/dist/kit/builder/form/components/fields/NumberField.d.ts +1 -1
  66. package/dist/kit/builder/form/components/fields/NumberField.d.ts.map +1 -1
  67. package/dist/kit/builder/form/components/fields/ObjectField.d.ts.map +1 -1
  68. package/dist/kit/builder/form/components/fields/RadioField.d.ts +1 -1
  69. package/dist/kit/builder/form/components/fields/RadioField.d.ts.map +1 -1
  70. package/dist/kit/builder/form/components/fields/SelectField.d.ts +1 -1
  71. package/dist/kit/builder/form/components/fields/SelectField.d.ts.map +1 -1
  72. package/dist/kit/builder/form/components/fields/SwitchField.d.ts +1 -1
  73. package/dist/kit/builder/form/components/fields/SwitchField.d.ts.map +1 -1
  74. package/dist/kit/builder/form/components/fields/TextField.d.ts +1 -1
  75. package/dist/kit/builder/form/components/fields/TextField.d.ts.map +1 -1
  76. package/dist/kit/builder/form/components/fields/TextareaField.d.ts +1 -1
  77. package/dist/kit/builder/form/components/fields/TextareaField.d.ts.map +1 -1
  78. package/dist/kit/builder/form/components/fields/TimePickerField.d.ts +1 -1
  79. package/dist/kit/builder/form/components/fields/TimePickerField.d.ts.map +1 -1
  80. package/dist/kit/builder/form/components/fields/TimeRangePickerField.d.ts +1 -1
  81. package/dist/kit/builder/form/components/fields/TimeRangePickerField.d.ts.map +1 -1
  82. package/dist/kit/builder/form/components/fields/index.d.ts.map +1 -1
  83. package/dist/kit/builder/form/components/fields/types.d.ts.map +1 -1
  84. package/dist/kit/builder/form/components/sectionNodes.d.ts.map +1 -1
  85. package/dist/kit/builder/form/hooks/useFormBuilder.d.ts.map +1 -1
  86. package/dist/kit/builder/form/types.d.ts.map +1 -1
  87. package/dist/kit/builder/form/utils/section-factories.d.ts.map +1 -1
  88. package/dist/kit/builder/page/Page.d.ts.map +1 -1
  89. package/dist/kit/builder/page/index.d.ts.map +1 -1
  90. package/dist/kit/builder/section/SectionBuilder.d.ts +1 -1
  91. package/dist/kit/builder/section/SectionBuilder.d.ts.map +1 -1
  92. package/dist/kit/builder/section/SectionContainer.d.ts +14 -0
  93. package/dist/kit/builder/section/SectionContainer.d.ts.map +1 -0
  94. package/dist/kit/builder/stack-dialog/context.d.ts.map +1 -1
  95. package/dist/kit/builder/stack-dialog/hooks.d.ts.map +1 -1
  96. package/dist/kit/builder/stack-dialog/index.d.ts +3 -3
  97. package/dist/kit/builder/stack-dialog/index.d.ts.map +1 -1
  98. package/dist/kit/builder/stack-dialog/provider.d.ts.map +1 -1
  99. package/dist/kit/builder/stack-dialog/renderer.d.ts.map +1 -1
  100. package/dist/kit/builder/stack-dialog/types.d.ts +1 -1
  101. package/dist/kit/builder/stack-dialog/types.d.ts.map +1 -1
  102. package/dist/kit/components/autocomplete/Autocomplete.d.ts +1 -1
  103. package/dist/kit/components/autocomplete/Autocomplete.d.ts.map +1 -1
  104. package/dist/kit/components/autocomplete/types.d.ts.map +1 -1
  105. package/dist/kit/components/datepicker/DatePicker.d.ts.map +1 -1
  106. package/dist/kit/components/datepicker/DateRangePicker.d.ts.map +1 -1
  107. package/dist/kit/components/datetimepicker/DateTimePicker.d.ts.map +1 -1
  108. package/dist/kit/components/datetimepicker/DateTimeRangePicker.d.ts.map +1 -1
  109. package/dist/kit/components/datetimepicker/index.d.ts.map +1 -1
  110. package/dist/kit/components/fileuploader/FileUploader.d.ts.map +1 -1
  111. package/dist/kit/components/fileuploader/types.d.ts +2 -2
  112. package/dist/kit/components/forminfo/FormInfoError.d.ts.map +1 -1
  113. package/dist/kit/components/login/Login.d.ts +1 -1
  114. package/dist/kit/components/login/Login.d.ts.map +1 -1
  115. package/dist/kit/components/monthpicker/MonthInput.d.ts.map +1 -1
  116. package/dist/kit/components/monthpicker/MonthPicker.d.ts.map +1 -1
  117. package/dist/kit/components/monthpicker/MonthRangeInput.d.ts.map +1 -1
  118. package/dist/kit/components/monthpicker/MonthRangePicker.d.ts.map +1 -1
  119. package/dist/kit/components/timepicker/TimePicker.d.ts.map +1 -1
  120. package/dist/kit/components/timepicker/TimeRangePicker.d.ts.map +1 -1
  121. package/dist/kit/components/timepicker/index.d.ts.map +1 -1
  122. package/dist/kit/layouts/admin/components/AdminLayout.d.ts.map +1 -1
  123. package/dist/kit/layouts/admin/components/ThemeToggle.d.ts.map +1 -1
  124. package/dist/kit/layouts/admin/hooks/menu.d.ts.map +1 -1
  125. package/dist/kit/layouts/admin/providers/AdminMenuProvider.d.ts +1 -1
  126. package/dist/kit/layouts/admin/providers/AdminMenuProvider.d.ts.map +1 -1
  127. package/dist/shadcn/hooks/use-mobile.d.ts.map +1 -1
  128. package/dist/shadcn/ui/accordion.d.ts +2 -2
  129. package/dist/shadcn/ui/accordion.d.ts.map +1 -1
  130. package/dist/shadcn/ui/alert-dialog.d.ts +4 -4
  131. package/dist/shadcn/ui/alert-dialog.d.ts.map +1 -1
  132. package/dist/shadcn/ui/alert.d.ts +4 -4
  133. package/dist/shadcn/ui/alert.d.ts.map +1 -1
  134. package/dist/shadcn/ui/aspect-ratio.d.ts +1 -1
  135. package/dist/shadcn/ui/aspect-ratio.d.ts.map +1 -1
  136. package/dist/shadcn/ui/avatar.d.ts +2 -2
  137. package/dist/shadcn/ui/avatar.d.ts.map +1 -1
  138. package/dist/shadcn/ui/badge.d.ts +2 -2
  139. package/dist/shadcn/ui/badge.d.ts.map +1 -1
  140. package/dist/shadcn/ui/breadcrumb.d.ts +8 -8
  141. package/dist/shadcn/ui/breadcrumb.d.ts.map +1 -1
  142. package/dist/shadcn/ui/button.d.ts +2 -2
  143. package/dist/shadcn/ui/button.d.ts.map +1 -1
  144. package/dist/shadcn/ui/calendar.d.ts +2 -2
  145. package/dist/shadcn/ui/calendar.d.ts.map +1 -1
  146. package/dist/shadcn/ui/card.d.ts +8 -8
  147. package/dist/shadcn/ui/card.d.ts.map +1 -1
  148. package/dist/shadcn/ui/carousel.d.ts +5 -5
  149. package/dist/shadcn/ui/carousel.d.ts.map +1 -1
  150. package/dist/shadcn/ui/chart.d.ts +7 -7
  151. package/dist/shadcn/ui/chart.d.ts.map +1 -1
  152. package/dist/shadcn/ui/checkbox.d.ts +2 -2
  153. package/dist/shadcn/ui/checkbox.d.ts.map +1 -1
  154. package/dist/shadcn/ui/collapsible.d.ts +1 -1
  155. package/dist/shadcn/ui/collapsible.d.ts.map +1 -1
  156. package/dist/shadcn/ui/command.d.ts +2 -2
  157. package/dist/shadcn/ui/command.d.ts.map +1 -1
  158. package/dist/shadcn/ui/context-menu.d.ts +4 -4
  159. package/dist/shadcn/ui/context-menu.d.ts.map +1 -1
  160. package/dist/shadcn/ui/dialog.d.ts +4 -4
  161. package/dist/shadcn/ui/dialog.d.ts.map +1 -1
  162. package/dist/shadcn/ui/drawer.d.ts +3 -3
  163. package/dist/shadcn/ui/drawer.d.ts.map +1 -1
  164. package/dist/shadcn/ui/dropdown-menu.d.ts +4 -4
  165. package/dist/shadcn/ui/dropdown-menu.d.ts.map +1 -1
  166. package/dist/shadcn/ui/form.d.ts +5 -5
  167. package/dist/shadcn/ui/form.d.ts.map +1 -1
  168. package/dist/shadcn/ui/hover-card.d.ts +2 -2
  169. package/dist/shadcn/ui/hover-card.d.ts.map +1 -1
  170. package/dist/shadcn/ui/input-otp.d.ts +4 -4
  171. package/dist/shadcn/ui/input-otp.d.ts.map +1 -1
  172. package/dist/shadcn/ui/input.d.ts +2 -2
  173. package/dist/shadcn/ui/input.d.ts.map +1 -1
  174. package/dist/shadcn/ui/label.d.ts +2 -2
  175. package/dist/shadcn/ui/label.d.ts.map +1 -1
  176. package/dist/shadcn/ui/menubar.d.ts +4 -4
  177. package/dist/shadcn/ui/menubar.d.ts.map +1 -1
  178. package/dist/shadcn/ui/navigation-menu.d.ts +2 -2
  179. package/dist/shadcn/ui/navigation-menu.d.ts.map +1 -1
  180. package/dist/shadcn/ui/pagination.d.ts +6 -6
  181. package/dist/shadcn/ui/pagination.d.ts.map +1 -1
  182. package/dist/shadcn/ui/popover.d.ts +2 -2
  183. package/dist/shadcn/ui/popover.d.ts.map +1 -1
  184. package/dist/shadcn/ui/progress.d.ts +2 -2
  185. package/dist/shadcn/ui/progress.d.ts.map +1 -1
  186. package/dist/shadcn/ui/radio-group.d.ts +2 -2
  187. package/dist/shadcn/ui/radio-group.d.ts.map +1 -1
  188. package/dist/shadcn/ui/resizable.d.ts +2 -2
  189. package/dist/shadcn/ui/resizable.d.ts.map +1 -1
  190. package/dist/shadcn/ui/scroll-area.d.ts +2 -2
  191. package/dist/shadcn/ui/scroll-area.d.ts.map +1 -1
  192. package/dist/shadcn/ui/select.d.ts +3 -3
  193. package/dist/shadcn/ui/select.d.ts.map +1 -1
  194. package/dist/shadcn/ui/separator.d.ts +2 -2
  195. package/dist/shadcn/ui/separator.d.ts.map +1 -1
  196. package/dist/shadcn/ui/sheet.d.ts +5 -5
  197. package/dist/shadcn/ui/sheet.d.ts.map +1 -1
  198. package/dist/shadcn/ui/sidebar.d.ts +26 -26
  199. package/dist/shadcn/ui/sidebar.d.ts.map +1 -1
  200. package/dist/shadcn/ui/skeleton.d.ts +1 -1
  201. package/dist/shadcn/ui/skeleton.d.ts.map +1 -1
  202. package/dist/shadcn/ui/slider.d.ts +2 -2
  203. package/dist/shadcn/ui/slider.d.ts.map +1 -1
  204. package/dist/shadcn/ui/sonner.d.ts.map +1 -1
  205. package/dist/shadcn/ui/switch.d.ts +2 -2
  206. package/dist/shadcn/ui/switch.d.ts.map +1 -1
  207. package/dist/shadcn/ui/table.d.ts +9 -9
  208. package/dist/shadcn/ui/table.d.ts.map +1 -1
  209. package/dist/shadcn/ui/tabs.d.ts +2 -2
  210. package/dist/shadcn/ui/tabs.d.ts.map +1 -1
  211. package/dist/shadcn/ui/textarea.d.ts +2 -2
  212. package/dist/shadcn/ui/textarea.d.ts.map +1 -1
  213. package/dist/shadcn/ui/toggle-group.d.ts +2 -2
  214. package/dist/shadcn/ui/toggle-group.d.ts.map +1 -1
  215. package/dist/shadcn/ui/toggle.d.ts +2 -2
  216. package/dist/shadcn/ui/toggle.d.ts.map +1 -1
  217. package/dist/shadcn/ui/tooltip.d.ts +2 -2
  218. package/dist/shadcn/ui/tooltip.d.ts.map +1 -1
  219. package/package.json +2 -2
  220. package/src/index.ts +1 -1
  221. package/src/kit/builder/auth/AuthProvider.tsx +131 -0
  222. package/src/kit/builder/auth/adapter.ts +436 -0
  223. package/src/kit/builder/auth/client-adapters.ts +398 -0
  224. package/src/kit/builder/auth/components.tsx +221 -0
  225. package/src/kit/builder/auth/hooks.ts +237 -0
  226. package/src/kit/builder/auth/index.ts +134 -0
  227. package/src/kit/builder/auth/permission-checker.ts +150 -0
  228. package/src/kit/builder/auth/storage.ts +366 -0
  229. package/src/kit/builder/auth/token-manager.ts +55 -0
  230. package/src/kit/builder/auth/types.ts +393 -0
  231. package/src/kit/builder/data-table/components/DataTable.tsx +216 -82
  232. package/src/kit/builder/data-table/components/DataTableColumnHeader.tsx +9 -5
  233. package/src/kit/builder/data-table/components/DataTablePagination.tsx +49 -27
  234. package/src/kit/builder/data-table/components/DataTableViewOptions.tsx +13 -4
  235. package/src/kit/builder/data-table/types.ts +18 -3
  236. package/src/kit/builder/dialog/index.ts +5 -1
  237. package/src/kit/builder/dialog/provider.tsx +56 -27
  238. package/src/kit/builder/form/components/FormBuilder.tsx +10 -14
  239. package/src/kit/builder/form/components/FormBuilderActions.tsx +1 -1
  240. package/src/kit/builder/form/components/FormBuilderContext.tsx +13 -6
  241. package/src/kit/builder/form/components/FormBuilderField.tsx +70 -20
  242. package/src/kit/builder/form/components/fields/ArrayField.tsx +148 -62
  243. package/src/kit/builder/form/components/fields/AutocompleteField.tsx +53 -18
  244. package/src/kit/builder/form/components/fields/CheckboxField.tsx +20 -11
  245. package/src/kit/builder/form/components/fields/DateField.tsx +17 -6
  246. package/src/kit/builder/form/components/fields/DatePickerField.tsx +15 -10
  247. package/src/kit/builder/form/components/fields/DateRangePickerField.tsx +20 -15
  248. package/src/kit/builder/form/components/fields/DateTimePickerField.tsx +16 -11
  249. package/src/kit/builder/form/components/fields/DateTimeRangePickerField.tsx +23 -17
  250. package/src/kit/builder/form/components/fields/FileField.tsx +10 -5
  251. package/src/kit/builder/form/components/fields/MonthPickerField.tsx +18 -11
  252. package/src/kit/builder/form/components/fields/MonthRangePickerField.tsx +23 -17
  253. package/src/kit/builder/form/components/fields/NumberField.tsx +9 -4
  254. package/src/kit/builder/form/components/fields/ObjectField.tsx +12 -7
  255. package/src/kit/builder/form/components/fields/RadioField.tsx +32 -14
  256. package/src/kit/builder/form/components/fields/SelectField.tsx +26 -11
  257. package/src/kit/builder/form/components/fields/SwitchField.tsx +20 -11
  258. package/src/kit/builder/form/components/fields/TextField.tsx +11 -5
  259. package/src/kit/builder/form/components/fields/TextareaField.tsx +9 -4
  260. package/src/kit/builder/form/components/fields/TimePickerField.tsx +16 -11
  261. package/src/kit/builder/form/components/fields/TimeRangePickerField.tsx +23 -17
  262. package/src/kit/builder/form/components/fields/index.ts +21 -21
  263. package/src/kit/builder/form/components/fields/types.ts +15 -11
  264. package/src/kit/builder/form/components/sectionNodes.tsx +63 -40
  265. package/src/kit/builder/form/hooks/useFormBuilder.ts +83 -34
  266. package/src/kit/builder/form/types.ts +173 -148
  267. package/src/kit/builder/form/utils/section-factories.ts +4 -1
  268. package/src/kit/builder/form/utils/transformers.ts +4 -4
  269. package/src/kit/builder/form/utils/validations.ts +1 -1
  270. package/src/kit/builder/page/Page.tsx +26 -6
  271. package/src/kit/builder/page/index.ts +1 -1
  272. package/src/kit/builder/section/SectionBuilder.tsx +252 -127
  273. package/src/kit/builder/section/SectionContainer.tsx +85 -0
  274. package/src/kit/builder/stack-dialog/context.ts +10 -4
  275. package/src/kit/builder/stack-dialog/hooks.ts +4 -3
  276. package/src/kit/builder/stack-dialog/index.ts +5 -11
  277. package/src/kit/builder/stack-dialog/provider.tsx +11 -11
  278. package/src/kit/builder/stack-dialog/renderer.tsx +23 -26
  279. package/src/kit/builder/stack-dialog/types.ts +18 -18
  280. package/src/kit/components/autocomplete/Autocomplete.tsx +631 -549
  281. package/src/kit/components/autocomplete/types.ts +17 -17
  282. package/src/kit/components/datepicker/DatePicker.tsx +33 -9
  283. package/src/kit/components/datepicker/DateRangePicker.tsx +159 -87
  284. package/src/kit/components/datetimepicker/DateTimePicker.tsx +136 -30
  285. package/src/kit/components/datetimepicker/DateTimeRangePicker.tsx +257 -67
  286. package/src/kit/components/datetimepicker/index.ts +3 -3
  287. package/src/kit/components/fileuploader/FileUploader.tsx +315 -180
  288. package/src/kit/components/fileuploader/index.ts +3 -3
  289. package/src/kit/components/fileuploader/types.ts +3 -3
  290. package/src/kit/components/forminfo/FormInfoError.tsx +26 -11
  291. package/src/kit/components/login/Login.tsx +13 -4
  292. package/src/kit/components/monthpicker/MonthInput.tsx +13 -4
  293. package/src/kit/components/monthpicker/MonthPicker.tsx +12 -11
  294. package/src/kit/components/monthpicker/MonthRangeInput.tsx +29 -8
  295. package/src/kit/components/monthpicker/MonthRangePicker.tsx +23 -21
  296. package/src/kit/components/timepicker/TimePicker.tsx +19 -11
  297. package/src/kit/components/timepicker/TimeRangePicker.tsx +106 -29
  298. package/src/kit/components/timepicker/index.ts +3 -3
  299. package/src/kit/layouts/admin/components/AdminLayout.tsx +53 -24
  300. package/src/kit/layouts/admin/components/ThemeToggle.tsx +3 -9
  301. package/src/kit/layouts/admin/hooks/menu.ts +11 -5
  302. package/src/kit/layouts/admin/providers/AdminMenuProvider.tsx +59 -39
  303. package/src/kit/layouts/admin/types/index.ts +1 -1
  304. package/src/kit/themes/base.css +1 -1
  305. package/src/kit/themes/clean-slate.css +40 -32
  306. package/src/kit/themes/default.css +34 -24
  307. package/src/kit/themes/minimal-modern.css +37 -29
  308. package/src/kit/themes/spotify.css +56 -39
  309. package/src/shadcn/hooks/use-mobile.ts +13 -11
  310. package/src/shadcn/lib/utils.ts +2 -2
  311. package/src/shadcn/ui/accordion.tsx +14 -14
  312. package/src/shadcn/ui/alert-dialog.tsx +29 -29
  313. package/src/shadcn/ui/alert.tsx +20 -20
  314. package/src/shadcn/ui/aspect-ratio.tsx +4 -4
  315. package/src/shadcn/ui/avatar.tsx +13 -13
  316. package/src/shadcn/ui/badge.tsx +16 -16
  317. package/src/shadcn/ui/breadcrumb.tsx +28 -28
  318. package/src/shadcn/ui/button.tsx +23 -23
  319. package/src/shadcn/ui/calendar.tsx +82 -78
  320. package/src/shadcn/ui/card.tsx +27 -27
  321. package/src/shadcn/ui/carousel.tsx +93 -93
  322. package/src/shadcn/ui/chart.tsx +103 -103
  323. package/src/shadcn/ui/checkbox.tsx +9 -9
  324. package/src/shadcn/ui/collapsible.tsx +6 -6
  325. package/src/shadcn/ui/command.tsx +36 -36
  326. package/src/shadcn/ui/context-menu.tsx +40 -40
  327. package/src/shadcn/ui/dialog.tsx +28 -28
  328. package/src/shadcn/ui/drawer.tsx +30 -30
  329. package/src/shadcn/ui/dropdown-menu.tsx +41 -41
  330. package/src/shadcn/ui/form.tsx +48 -47
  331. package/src/shadcn/ui/hover-card.tsx +11 -11
  332. package/src/shadcn/ui/input-otp.tsx +23 -23
  333. package/src/shadcn/ui/input.tsx +9 -9
  334. package/src/shadcn/ui/label.tsx +8 -8
  335. package/src/shadcn/ui/menubar.tsx +47 -47
  336. package/src/shadcn/ui/navigation-menu.tsx +33 -33
  337. package/src/shadcn/ui/pagination.tsx +28 -28
  338. package/src/shadcn/ui/popover.tsx +12 -12
  339. package/src/shadcn/ui/progress.tsx +8 -8
  340. package/src/shadcn/ui/radio-group.tsx +11 -11
  341. package/src/shadcn/ui/resizable.tsx +14 -14
  342. package/src/shadcn/ui/scroll-area.tsx +15 -15
  343. package/src/shadcn/ui/select.tsx +34 -34
  344. package/src/shadcn/ui/separator.tsx +9 -9
  345. package/src/shadcn/ui/sheet.tsx +36 -36
  346. package/src/shadcn/ui/sidebar.tsx +227 -227
  347. package/src/shadcn/ui/skeleton.tsx +5 -5
  348. package/src/shadcn/ui/slider.tsx +12 -12
  349. package/src/shadcn/ui/sonner.tsx +11 -11
  350. package/src/shadcn/ui/switch.tsx +9 -9
  351. package/src/shadcn/ui/table.tsx +32 -32
  352. package/src/shadcn/ui/tabs.tsx +14 -14
  353. package/src/shadcn/ui/textarea.tsx +7 -7
  354. package/src/shadcn/ui/toggle-group.tsx +17 -17
  355. package/src/shadcn/ui/toggle.tsx +16 -16
  356. package/src/shadcn/ui/tooltip.tsx +11 -11
  357. package/src/stories/FileUploader.stories.tsx +23 -4
  358. package/src/stories/kit/builder/DataTable.Basic.stories.tsx +14 -4
  359. package/src/stories/kit/builder/DataTable.Filters.stories.tsx +36 -14
  360. package/src/stories/kit/builder/DataTable.Pagination.stories.tsx +3 -2
  361. package/src/stories/kit/builder/DataTable.SelectionAndActions.stories.tsx +18 -4
  362. package/src/stories/kit/builder/DataTable.Sorting.stories.tsx +18 -7
  363. package/src/stories/kit/builder/Dialog.stories.tsx +19 -13
  364. package/src/stories/kit/builder/Form.ArrayLayouts.stories.tsx +40 -16
  365. package/src/stories/kit/builder/Form.Autocomplete.stories.tsx +34 -22
  366. package/src/stories/kit/builder/Form.Basic.stories.tsx +38 -6
  367. package/src/stories/kit/builder/Form.Complex.stories.tsx +356 -111
  368. package/src/stories/kit/builder/Form.DateTime.stories.tsx +12 -8
  369. package/src/stories/kit/builder/Form.Dynamic.stories.tsx +695 -132
  370. package/src/stories/kit/builder/Form.Files.stories.tsx +37 -26
  371. package/src/stories/kit/builder/Form.MultipleFormBuilder.stories.tsx +46 -42
  372. package/src/stories/kit/builder/Form.Pickers.stories.tsx +12 -8
  373. package/src/stories/kit/builder/Form.Simple.stories.tsx +15 -6
  374. package/src/stories/kit/builder/Form.Time.stories.tsx +12 -8
  375. package/src/stories/kit/builder/Page.stories.tsx +32 -6
  376. package/src/stories/kit/builder/Section.stories.tsx +58 -11
  377. package/src/stories/kit/components/Autocomplete.stories.tsx +55 -22
  378. package/src/stories/kit/components/DatePicker.stories.tsx +80 -13
  379. package/src/stories/kit/components/DateRangePicker.stories.tsx +52 -11
  380. package/src/stories/kit/components/Login.stories.tsx +8 -2
  381. package/src/stories/kit/components/MonthPicker.stories.tsx +26 -6
  382. package/src/stories/kit/components/MonthRangePicker.stories.tsx +24 -5
  383. package/src/stories/kit/components/TimePicker.stories.tsx +18 -16
  384. package/src/stories/kit/components/TimeRangePicker.stories.tsx +18 -12
  385. package/src/stories/kit/layouts/admin/AdminLayout.Basic.stories.tsx +29 -6
  386. package/src/stories/kit/layouts/admin/AdminLayout.Collapsible.stories.tsx +26 -5
  387. package/src/stories/kit/layouts/admin/AdminLayout.Complex.stories.tsx +101 -18
  388. package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarHeaderComponent.stories.tsx +18 -4
  389. package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarTitleAndIcon.stories.tsx +17 -4
  390. package/src/stories/kit/layouts/admin/AdminLayout.HeaderSlots.stories.tsx +28 -6
  391. package/src/stories/shadcn/ui/Accordion.stories.tsx +33 -10
  392. package/src/stories/shadcn/ui/AlertDialog.stories.tsx +3 -1
  393. package/src/stories/shadcn/ui/Button.stories.tsx +3 -1
  394. package/src/stories/shadcn/ui/Calendar.stories.tsx +6 -1
  395. package/src/stories/shadcn/ui/Card.stories.tsx +11 -2
  396. package/src/stories/shadcn/ui/Checkbox.stories.tsx +11 -3
  397. package/src/stories/shadcn/ui/Collapsible.stories.tsx +12 -5
  398. package/src/stories/shadcn/ui/ContextMenu.stories.tsx +12 -4
  399. package/src/stories/shadcn/ui/Dialog.stories.tsx +15 -3
  400. package/src/stories/shadcn/ui/Drawer.stories.tsx +5 -2
  401. package/src/stories/shadcn/ui/DropdownMenu.stories.tsx +15 -5
  402. package/src/stories/shadcn/ui/Form.stories.tsx +5 -2
  403. package/src/stories/shadcn/ui/HoverCard.stories.tsx +8 -2
  404. package/src/stories/shadcn/ui/Input.stories.tsx +3 -1
  405. package/src/stories/shadcn/ui/InputOtp.stories.tsx +9 -2
  406. package/src/stories/shadcn/ui/Menubar.stories.tsx +21 -7
  407. package/src/stories/shadcn/ui/NavigationMenu.stories.tsx +30 -5
  408. package/src/stories/shadcn/ui/Popover.stories.tsx +8 -2
  409. package/src/stories/shadcn/ui/Resizable.stories.tsx +17 -5
  410. package/src/stories/shadcn/ui/ScrollArea.stories.tsx +54 -2
  411. package/src/stories/shadcn/ui/Select.stories.tsx +7 -1
  412. package/src/stories/shadcn/ui/Sheet.stories.tsx +2 -1
  413. package/src/stories/shadcn/ui/Sidebar.stories.tsx +13 -2
  414. package/src/stories/shadcn/ui/Sonner.stories.tsx +12 -2
  415. package/src/stories/shadcn/ui/Table.stories.tsx +86 -27
  416. package/src/stories/shadcn/ui/Tabs.stories.tsx +9 -2
  417. package/src/stories/shadcn/ui/Textarea.stories.tsx +3 -1
  418. package/src/stories/shadcn/ui/Toggle.stories.tsx +10 -2
  419. package/src/stories/shadcn/ui/Tooltip.stories.tsx +6 -1
  420. package/tsconfig.json +1 -5
  421. package/tsconfig.tsbuildinfo +1 -0
  422. package/eslint.config.mjs +0 -19
@@ -1,9 +1,14 @@
1
- import { useCallback, useEffect, useRef, useState, memo } from "react";
2
- import { useDropzone, type Accept } from "react-dropzone";
3
- import { cn } from "../../../shadcn/lib/utils";
4
- import { Button } from "../../../shadcn/ui/button";
5
- import { Progress } from "../../../shadcn/ui/progress";
6
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../../shadcn/ui/tooltip";
1
+ import { useCallback, useEffect, useRef, useState, memo } from 'react';
2
+ import { useDropzone, type Accept } from 'react-dropzone';
3
+ import { cn } from '../../../shadcn/lib/utils';
4
+ import { Button } from '../../../shadcn/ui/button';
5
+ import { Progress } from '../../../shadcn/ui/progress';
6
+ import {
7
+ Tooltip,
8
+ TooltipContent,
9
+ TooltipProvider,
10
+ TooltipTrigger,
11
+ } from '../../../shadcn/ui/tooltip';
7
12
  import {
8
13
  Loader2,
9
14
  UploadCloud,
@@ -19,38 +24,71 @@ import {
19
24
  Download,
20
25
  Trash2,
21
26
  RotateCcw,
22
- } from "lucide-react";
23
- import type { FileRecord, FileUploaderProps } from "./types";
27
+ } from 'lucide-react';
28
+ import type { FileRecord, FileUploaderProps } from './types';
24
29
 
25
30
  // Cache preview URLs per File instance without mutating the File object
26
31
  const previewUrlMap: WeakMap<File, string> = new WeakMap();
27
32
 
28
33
  function formatBytes(bytes?: number) {
29
- if (!bytes && bytes !== 0) return "";
30
- const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
31
- if (bytes === 0) return "0 Byte";
34
+ if (!bytes && bytes !== 0) return '';
35
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
36
+ if (bytes === 0) return '0 Byte';
32
37
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
33
- return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`;
38
+ return `${(bytes / 1024 ** i).toFixed(2)} ${sizes[i]}`;
34
39
  }
35
40
 
36
41
  function isImageType(type?: string, name?: string) {
37
42
  if (!type && name) {
38
- const ext = name.toLowerCase().split(".").pop();
43
+ const ext = name.toLowerCase().split('.').pop();
39
44
  if (!ext) return false;
40
- return ["png", "jpg", "jpeg", "webp", "gif", "bmp", "svg", "heic", "heif"].includes(ext);
45
+ return [
46
+ 'png',
47
+ 'jpg',
48
+ 'jpeg',
49
+ 'webp',
50
+ 'gif',
51
+ 'bmp',
52
+ 'svg',
53
+ 'heic',
54
+ 'heif',
55
+ ].includes(ext);
41
56
  }
42
- return !!type?.startsWith("image/");
57
+ return !!type?.startsWith('image/');
43
58
  }
44
59
 
45
60
  function pickIconByType(type?: string, name?: string) {
46
- const t = (type || "").toLowerCase();
47
- const ext = (name?.split(".").pop() || "").toLowerCase();
48
- if (t.startsWith("image/") || ["png", "jpg", "jpeg", "webp", "gif", "bmp", "svg", "heic", "heif"].includes(ext)) return <ImageIcon className="h-8 w-8" />;
49
- if (t.startsWith("video/") || ["mp4", "mov", "webm", "mkv"].includes(ext)) return <Video className="h-8 w-8" />;
50
- if (t.startsWith("audio/") || ["mp3", "wav", "aac", "flac"].includes(ext)) return <Music className="h-8 w-8" />;
51
- if (["zip", "rar", "7z", "tar", "gz"].includes(ext)) return <Archive className="h-8 w-8" />;
52
- if (["txt", "md", "rtf"].includes(ext)) return <FileText className="h-8 w-8" />;
53
- if (["js", "ts", "tsx", "json", "yml", "yaml", "xml", "html", "css"].includes(ext)) return <FileCode className="h-8 w-8" />;
61
+ const t = (type || '').toLowerCase();
62
+ const ext = (name?.split('.').pop() || '').toLowerCase();
63
+ if (
64
+ t.startsWith('image/') ||
65
+ [
66
+ 'png',
67
+ 'jpg',
68
+ 'jpeg',
69
+ 'webp',
70
+ 'gif',
71
+ 'bmp',
72
+ 'svg',
73
+ 'heic',
74
+ 'heif',
75
+ ].includes(ext)
76
+ )
77
+ return <ImageIcon className="h-8 w-8" />;
78
+ if (t.startsWith('video/') || ['mp4', 'mov', 'webm', 'mkv'].includes(ext))
79
+ return <Video className="h-8 w-8" />;
80
+ if (t.startsWith('audio/') || ['mp3', 'wav', 'aac', 'flac'].includes(ext))
81
+ return <Music className="h-8 w-8" />;
82
+ if (['zip', 'rar', '7z', 'tar', 'gz'].includes(ext))
83
+ return <Archive className="h-8 w-8" />;
84
+ if (['txt', 'md', 'rtf'].includes(ext))
85
+ return <FileText className="h-8 w-8" />;
86
+ if (
87
+ ['js', 'ts', 'tsx', 'json', 'yml', 'yaml', 'xml', 'html', 'css'].includes(
88
+ ext,
89
+ )
90
+ )
91
+ return <FileCode className="h-8 w-8" />;
54
92
  return <FileIcon className="h-8 w-8" />;
55
93
  }
56
94
 
@@ -81,10 +119,10 @@ export function FileUploader({
81
119
  multiple = true,
82
120
  maxFiles,
83
121
  accept,
84
- layout = "grid",
122
+ layout = 'grid',
85
123
  disabled,
86
124
  withDownload = true,
87
- placeholder = "Drag and drop files here, or click to select",
125
+ placeholder = 'Drag and drop files here, or click to select',
88
126
  className,
89
127
  }: FileUploaderProps) {
90
128
  const isControlled = value !== undefined;
@@ -93,7 +131,9 @@ export function FileUploader({
93
131
  const prevUrlsRef = useRef<Set<string>>(new Set());
94
132
  useEffect(() => {
95
133
  return () => {
96
- prevUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));
134
+ prevUrlsRef.current.forEach((url) => {
135
+ URL.revokeObjectURL(url);
136
+ });
97
137
  prevUrlsRef.current.clear();
98
138
  };
99
139
  }, []);
@@ -102,7 +142,7 @@ export function FileUploader({
102
142
  (updater: FileRecord[] | ((prev: FileRecord[]) => FileRecord[])) => {
103
143
  setFiles((prev) => {
104
144
  let next: FileRecord[];
105
- if (typeof updater === "function") {
145
+ if (typeof updater === 'function') {
106
146
  const fn = updater as (p: FileRecord[]) => FileRecord[];
107
147
  next = fn(prev);
108
148
  } else {
@@ -115,8 +155,6 @@ export function FileUploader({
115
155
  [onChange],
116
156
  );
117
157
 
118
-
119
-
120
158
  useEffect(() => {
121
159
  if (isControlled && value) setFiles(value);
122
160
  if (isControlled && !value) setFiles([]);
@@ -129,13 +167,13 @@ export function FileUploader({
129
167
  const next = prev.map((f) => {
130
168
  if ((f.url || f.thumbnailUrl) && !f.status) {
131
169
  changed = true;
132
- return { ...f, status: "success" as const, progress: 100 };
170
+ return { ...f, status: 'success' as const, progress: 100 };
133
171
  }
134
172
  return f;
135
173
  });
136
174
  return changed ? next : prev;
137
175
  });
138
- }, [isControlled]);
176
+ }, []);
139
177
 
140
178
  const handleRemove = useCallback(
141
179
  async (idx: number) => {
@@ -156,14 +194,23 @@ export function FileUploader({
156
194
  try {
157
195
  setFilesAndEmit((prev) => {
158
196
  const n = [...prev];
159
- n[index] = { ...n[index], status: "uploading", progress: 0, errorMessage: undefined };
197
+ n[index] = {
198
+ ...n[index],
199
+ status: 'uploading',
200
+ progress: 0,
201
+ errorMessage: undefined,
202
+ };
160
203
  return n;
161
204
  });
162
205
  const result = await uploader(f, (pct) => {
163
206
  setFilesAndEmit((prev) => {
164
207
  const n = [...prev];
165
208
  if (!n[index]) return prev;
166
- n[index] = { ...n[index], progress: Math.min(100, Math.max(0, Math.round(pct))), status: "uploading" };
209
+ n[index] = {
210
+ ...n[index],
211
+ progress: Math.min(100, Math.max(0, Math.round(pct))),
212
+ status: 'uploading',
213
+ };
167
214
  return n;
168
215
  });
169
216
  });
@@ -173,7 +220,7 @@ export function FileUploader({
173
220
  n[index] = {
174
221
  ...n[index],
175
222
  ...result,
176
- status: "success",
223
+ status: 'success',
177
224
  progress: 100,
178
225
  };
179
226
  return n;
@@ -184,15 +231,28 @@ export function FileUploader({
184
231
  setFilesAndEmit((prev) => {
185
232
  const n = [...prev];
186
233
  if (!n[index]) return prev;
187
- const msg = err && typeof err === "object" && "message" in (err as Record<string, unknown>) ? String((err as { message?: unknown }).message) : "Upload failed";
188
- n[index] = { ...n[index], status: "error", errorMessage: msg };
234
+ const msg =
235
+ err &&
236
+ typeof err === 'object' &&
237
+ 'message' in (err as Record<string, unknown>)
238
+ ? String((err as { message?: unknown }).message)
239
+ : 'Upload failed';
240
+ n[index] = { ...n[index], status: 'error', errorMessage: msg };
189
241
  return n;
190
242
  });
191
243
  const failed = (isControlled ? value : files)[index] ?? undefined;
192
244
  if (failed) onUploadError?.(failed, err);
193
245
  }
194
246
  },
195
- [files, isControlled, onUploadError, onUploadSuccess, setFilesAndEmit, uploader, value],
247
+ [
248
+ files,
249
+ isControlled,
250
+ onUploadError,
251
+ onUploadSuccess,
252
+ setFilesAndEmit,
253
+ uploader,
254
+ value,
255
+ ],
196
256
  );
197
257
 
198
258
  const handleRetry = useCallback(
@@ -207,7 +267,7 @@ export function FileUploader({
207
267
 
208
268
  const handleRetryAll = useCallback(() => {
209
269
  if (!uploader) return;
210
- const failedFiles = files.filter((f) => f.status === "error" && !!f.file);
270
+ const failedFiles = files.filter((f) => f.status === 'error' && !!f.file);
211
271
  if (failedFiles.length === 0) return;
212
272
  onRetryAll?.(failedFiles);
213
273
  failedFiles.forEach((fr) => {
@@ -224,45 +284,68 @@ export function FileUploader({
224
284
  if (!acceptedFiles?.length) return;
225
285
  setFilesAndEmit((prev) => {
226
286
  const existing = [...prev];
227
- const capacity = typeof maxFiles === "number" ? Math.max(0, maxFiles - existing.length) : acceptedFiles.length;
228
- const incoming = acceptedFiles.slice(0, capacity).map<FileRecord>((f) => ({
229
- id: undefined,
230
- url: undefined,
231
- thumbnailUrl: undefined,
232
- file: f,
233
- name: f.name,
234
- size: f.size,
235
- type: f.type,
236
- status: uploader ? "uploading" : "idle",
237
- progress: uploader ? 0 : undefined,
238
- }));
239
- const next = multiple ? [...existing, ...incoming] : [incoming[0]].filter(Boolean) as FileRecord[];
287
+ const capacity =
288
+ typeof maxFiles === 'number'
289
+ ? Math.max(0, maxFiles - existing.length)
290
+ : acceptedFiles.length;
291
+ const incoming = acceptedFiles
292
+ .slice(0, capacity)
293
+ .map<FileRecord>((f) => ({
294
+ id: undefined,
295
+ url: undefined,
296
+ thumbnailUrl: undefined,
297
+ file: f,
298
+ name: f.name,
299
+ size: f.size,
300
+ type: f.type,
301
+ status: uploader ? 'uploading' : 'idle',
302
+ progress: uploader ? 0 : undefined,
303
+ }));
304
+ const next = multiple
305
+ ? [...existing, ...incoming]
306
+ : ([incoming[0]].filter(Boolean) as FileRecord[]);
240
307
  return next;
241
308
  });
242
309
 
243
310
  if (uploader) {
244
311
  const baseIndex = (isControlled ? value : files)?.length ?? 0;
245
- const capacity = typeof maxFiles === "number" ? Math.max(0, maxFiles - ((isControlled ? value : files)?.length ?? 0)) : acceptedFiles.length;
312
+ const capacity =
313
+ typeof maxFiles === 'number'
314
+ ? Math.max(
315
+ 0,
316
+ maxFiles - ((isControlled ? value : files)?.length ?? 0),
317
+ )
318
+ : acceptedFiles.length;
246
319
  acceptedFiles.slice(0, capacity).forEach((f, i) => {
247
320
  const index = multiple ? baseIndex + i : 0;
248
321
  void startUpload(index, f);
249
322
  });
250
323
  }
251
324
  },
252
- [files, isControlled, maxFiles, multiple, startUpload, uploader, value, setFilesAndEmit],
325
+ [
326
+ files,
327
+ isControlled,
328
+ maxFiles,
329
+ multiple,
330
+ startUpload,
331
+ uploader,
332
+ value,
333
+ setFilesAndEmit,
334
+ ],
253
335
  );
254
336
 
255
337
  const disabledBecauseFull = !!maxFiles && files.length >= maxFiles;
256
338
 
257
- const { getRootProps, getInputProps, isDragActive, isDragReject, open } = useDropzone({
258
- onDrop,
259
- multiple,
260
- maxFiles: multiple ? maxFiles : 1,
261
- accept: accept as Accept | undefined,
262
- noClick: true,
263
- noKeyboard: true,
264
- disabled: disabled || disabledBecauseFull,
265
- });
339
+ const { getRootProps, getInputProps, isDragActive, isDragReject, open } =
340
+ useDropzone({
341
+ onDrop,
342
+ multiple,
343
+ maxFiles: multiple ? maxFiles : 1,
344
+ accept: accept as Accept | undefined,
345
+ noClick: true,
346
+ noKeyboard: true,
347
+ disabled: disabled || disabledBecauseFull,
348
+ });
266
349
 
267
350
  useEffect(() => {
268
351
  const urls = new Set<string>();
@@ -277,167 +360,219 @@ export function FileUploader({
277
360
  }, [files]);
278
361
 
279
362
  const rootClasses = cn(
280
- "w-full border border-dashed rounded-md p-4 text-sm transition-colors bg-background",
281
- "hover:border-foreground/50",
282
- isDragActive && "border-primary",
283
- isDragReject && "border-destructive",
284
- (disabled || disabledBecauseFull) && "opacity-50 pointer-events-none",
363
+ 'w-full border border-dashed rounded-md p-4 text-sm transition-colors bg-background',
364
+ 'hover:border-foreground/50',
365
+ isDragActive && 'border-primary',
366
+ isDragReject && 'border-destructive',
367
+ (disabled || disabledBecauseFull) && 'opacity-50 pointer-events-none',
285
368
  );
286
369
 
287
370
  // (renderThumb removed; inlined into FileItem for better memoization)
288
371
 
289
372
  // Stable handler refs so children don't see new function identities each render
290
373
  const removeRef = useRef(handleRemove);
291
- useEffect(() => { removeRef.current = handleRemove; }, [handleRemove]);
374
+ useEffect(() => {
375
+ removeRef.current = handleRemove;
376
+ }, [handleRemove]);
292
377
  const retryRef = useRef(handleRetry);
293
- useEffect(() => { retryRef.current = handleRetry; }, [handleRetry]);
294
- const onRemoveAt = useCallback((i: number) => { removeRef.current(i); }, []);
295
- const onRetryAt = useCallback((i: number) => { retryRef.current(i); }, []);
378
+ useEffect(() => {
379
+ retryRef.current = handleRetry;
380
+ }, [handleRetry]);
381
+ const onRemoveAt = useCallback((i: number) => {
382
+ removeRef.current(i);
383
+ }, []);
384
+ const onRetryAt = useCallback((i: number) => {
385
+ retryRef.current(i);
386
+ }, []);
296
387
 
297
388
  type FileItemProps = {
298
389
  fr: FileRecord;
299
390
  idx: number;
300
- layout: "grid" | "list";
391
+ layout: 'grid' | 'list';
301
392
  withDownload: boolean;
302
393
  uploaderPresent: boolean;
303
394
  onRemove: (idx: number) => void;
304
395
  onRetry: (idx: number) => void;
305
396
  };
306
397
 
307
- const FileItem = memo(function FileItem({ fr, idx, layout, withDownload, uploaderPresent, onRemove, onRetry }: FileItemProps) {
308
- const name = fr.name;
309
- const size = formatBytes(fr.size);
310
- const error = fr.status === "error" ? fr.errorMessage : undefined;
311
- const preview = getPreviewUrl(fr);
312
- return (
313
- <div className={cn(
314
- "flex items-center gap-3 border rounded-md p-2 bg-card",
315
- layout === "grid" ? "flex-col items-stretch" : "flex-row",
316
- )}>
317
- <div className={cn(layout === "grid" ? "self-center" : "")}>{
318
- (
319
- <div className={cn(
320
- "relative overflow-hidden bg-muted/40 border rounded-md flex items-center justify-center",
321
- layout === "grid" ? "h-28 w-28" : "h-16 w-16",
322
- )}>
323
- {preview ? (
324
- <img src={preview} alt={fr.name} className="object-cover w-full h-full" />
325
- ) : (
326
- <div className="flex items-center justify-center text-muted-foreground">
327
- {pickIconByType(fr.type, fr.name)}
328
- </div>
329
- )}
330
- {fr.status === "uploading" ? (
331
- <div className="absolute inset-0 bg-black/40 flex items-center justify-center">
332
- <Loader2 className="h-6 w-6 text-white animate-spin" />
333
- </div>
334
- ) : null}
335
- {fr.status === "success" ? (
336
- <div className="absolute top-1 right-1 text-green-500">
337
- <CheckCircle2 className="h-5 w-5 drop-shadow" />
338
- </div>
339
- ) : null}
340
- {fr.status === "error" ? (
341
- <div className="absolute top-1 right-1 text-red-500">
342
- <XCircle className="h-5 w-5 drop-shadow" />
398
+ const FileItem = memo(
399
+ function FileItem({
400
+ fr,
401
+ idx,
402
+ layout,
403
+ withDownload,
404
+ uploaderPresent,
405
+ onRemove,
406
+ onRetry,
407
+ }: FileItemProps) {
408
+ const name = fr.name;
409
+ const size = formatBytes(fr.size);
410
+ const error = fr.status === 'error' ? fr.errorMessage : undefined;
411
+ const preview = getPreviewUrl(fr);
412
+ return (
413
+ <div
414
+ className={cn(
415
+ 'flex items-center gap-3 border rounded-md p-2 bg-card',
416
+ layout === 'grid' ? 'flex-col items-stretch' : 'flex-row',
417
+ )}
418
+ >
419
+ <div className={cn(layout === 'grid' ? 'self-center' : '')}>
420
+ {
421
+ <div
422
+ className={cn(
423
+ 'relative overflow-hidden bg-muted/40 border rounded-md flex items-center justify-center',
424
+ layout === 'grid' ? 'h-28 w-28' : 'h-16 w-16',
425
+ )}
426
+ >
427
+ {preview ? (
428
+ <img
429
+ src={preview}
430
+ alt={fr.name}
431
+ className="object-cover w-full h-full"
432
+ />
433
+ ) : (
434
+ <div className="flex items-center justify-center text-muted-foreground">
435
+ {pickIconByType(fr.type, fr.name)}
436
+ </div>
437
+ )}
438
+ {fr.status === 'uploading' ? (
439
+ <div className="absolute inset-0 bg-black/40 flex items-center justify-center">
440
+ <Loader2 className="h-6 w-6 text-white animate-spin" />
441
+ </div>
442
+ ) : null}
443
+ {fr.status === 'success' ? (
444
+ <div className="absolute top-1 right-1 text-green-500">
445
+ <CheckCircle2 className="h-5 w-5 drop-shadow" />
446
+ </div>
447
+ ) : null}
448
+ {fr.status === 'error' ? (
449
+ <div className="absolute top-1 right-1 text-red-500">
450
+ <XCircle className="h-5 w-5 drop-shadow" />
451
+ </div>
452
+ ) : null}
453
+ </div>
454
+ }
455
+ </div>
456
+ <div
457
+ className={cn('min-w-0 flex-1', layout === 'grid' ? 'mt-2' : '')}
458
+ >
459
+ <div className="flex items-center justify-between gap-2">
460
+ <div className="min-w-0">
461
+ <div className="truncate font-medium" title={name}>
462
+ {name}
343
463
  </div>
344
- ) : null}
345
- </div>
346
- )
347
- }</div>
348
- <div className={cn("min-w-0 flex-1", layout === "grid" ? "mt-2" : "")}>
349
- <div className="flex items-center justify-between gap-2">
350
- <div className="min-w-0">
351
- <div className="truncate font-medium" title={name}>{name}</div>
352
- <div className="text-xs text-muted-foreground">{size}</div>
353
- </div>
354
- <div className="flex items-center gap-1">
355
- {fr.status === "error" ? (
356
- <Tooltip>
357
- <TooltipTrigger asChild>
358
- <Button
359
- size="icon"
360
- variant="ghost"
361
- onClick={() => onRetry(idx)}
362
- aria-label="Retry upload"
363
- disabled={!uploaderPresent || !fr.file}
364
- >
365
- <RotateCcw className="h-4 w-4" />
366
- </Button>
367
- </TooltipTrigger>
368
- <TooltipContent>Retry</TooltipContent>
369
- </Tooltip>
370
- ) : null}
371
- {withDownload && (fr.url || fr.thumbnailUrl) ? (
464
+ <div className="text-xs text-muted-foreground">{size}</div>
465
+ </div>
466
+ <div className="flex items-center gap-1">
467
+ {fr.status === 'error' ? (
468
+ <Tooltip>
469
+ <TooltipTrigger asChild>
470
+ <Button
471
+ size="icon"
472
+ variant="ghost"
473
+ onClick={() => onRetry(idx)}
474
+ aria-label="Retry upload"
475
+ disabled={!uploaderPresent || !fr.file}
476
+ >
477
+ <RotateCcw className="h-4 w-4" />
478
+ </Button>
479
+ </TooltipTrigger>
480
+ <TooltipContent>Retry</TooltipContent>
481
+ </Tooltip>
482
+ ) : null}
483
+ {withDownload && (fr.url || fr.thumbnailUrl) ? (
484
+ <Tooltip>
485
+ <TooltipTrigger asChild>
486
+ <Button
487
+ size="icon"
488
+ variant="ghost"
489
+ onClick={() => {
490
+ const url = fr.url ?? fr.thumbnailUrl;
491
+ if (url) {
492
+ window.open(url, '_blank', 'noopener,noreferrer');
493
+ }
494
+ }}
495
+ aria-label="Download"
496
+ >
497
+ <Download className="h-4 w-4" />
498
+ </Button>
499
+ </TooltipTrigger>
500
+ <TooltipContent>Download</TooltipContent>
501
+ </Tooltip>
502
+ ) : null}
372
503
  <Tooltip>
373
504
  <TooltipTrigger asChild>
374
505
  <Button
375
506
  size="icon"
376
507
  variant="ghost"
377
- onClick={() => {
378
- const url = fr.url ?? fr.thumbnailUrl;
379
- if (url) {
380
- window.open(url, "_blank", "noopener,noreferrer");
381
- }
382
- }}
383
- aria-label="Download"
508
+ onClick={() => onRemove(idx)}
509
+ aria-label="Remove"
384
510
  >
385
- <Download className="h-4 w-4" />
511
+ <Trash2 className="h-4 w-4" />
386
512
  </Button>
387
513
  </TooltipTrigger>
388
- <TooltipContent>Download</TooltipContent>
514
+ <TooltipContent>Remove</TooltipContent>
389
515
  </Tooltip>
390
- ) : null}
391
- <Tooltip>
392
- <TooltipTrigger asChild>
393
- <Button
394
- size="icon"
395
- variant="ghost"
396
- onClick={() => onRemove(idx)}
397
- aria-label="Remove"
398
- >
399
- <Trash2 className="h-4 w-4" />
400
- </Button>
401
- </TooltipTrigger>
402
- <TooltipContent>Remove</TooltipContent>
403
- </Tooltip>
516
+ </div>
404
517
  </div>
518
+ {fr.status === 'uploading' ? (
519
+ <div className="mt-2">
520
+ <Progress value={fr.progress ?? 0} />
521
+ </div>
522
+ ) : null}
523
+ {error ? (
524
+ <div className="mt-2 text-xs text-destructive">{error}</div>
525
+ ) : null}
405
526
  </div>
406
- {fr.status === "uploading" ? (
407
- <div className="mt-2">
408
- <Progress value={fr.progress ?? 0} />
409
- </div>
410
- ) : null}
411
- {error ? (
412
- <div className="mt-2 text-xs text-destructive">{error}</div>
413
- ) : null}
414
527
  </div>
415
- </div>
416
- );
417
- }, (prev, next) => prev.fr === next.fr && prev.layout === next.layout && prev.withDownload === next.withDownload && prev.uploaderPresent === next.uploaderPresent && prev.idx === next.idx);
528
+ );
529
+ },
530
+ (prev, next) =>
531
+ prev.fr === next.fr &&
532
+ prev.layout === next.layout &&
533
+ prev.withDownload === next.withDownload &&
534
+ prev.uploaderPresent === next.uploaderPresent &&
535
+ prev.idx === next.idx,
536
+ );
418
537
 
419
538
  return (
420
- <div className={cn("space-y-3", className)}>
539
+ <div className={cn('space-y-3', className)}>
421
540
  <div {...getRootProps({ className: rootClasses })}>
422
- <input {...getInputProps({ onClick: (e) => { (e.target as HTMLInputElement).value = ""; } })} />
541
+ <input
542
+ {...getInputProps({
543
+ onClick: (e) => {
544
+ (e.target as HTMLInputElement).value = '';
545
+ },
546
+ })}
547
+ />
423
548
  <div className="flex items-center justify-between gap-3">
424
549
  <div className="flex items-center gap-2 text-muted-foreground">
425
550
  <Button
426
551
  size="sm"
427
552
  variant="secondary"
428
553
  disabled={disabled || disabledBecauseFull}
429
- onClick={(e) => { e.preventDefault(); e.stopPropagation(); open(); }}
554
+ onClick={(e) => {
555
+ e.preventDefault();
556
+ e.stopPropagation();
557
+ open();
558
+ }}
430
559
  >
431
560
  Select files
432
561
  </Button>
433
562
  <UploadCloud className="h-5 w-5" />
434
563
  <div>
435
564
  <div className="font-medium">
436
- {disabledBecauseFull ? "File limit reached" : isDragActive ? "Drop the files here" : placeholder}
565
+ {disabledBecauseFull
566
+ ? 'File limit reached'
567
+ : isDragActive
568
+ ? 'Drop the files here'
569
+ : placeholder}
437
570
  </div>
438
571
  <div className="text-xs">
439
- {accept ? "Specific file types only" : "Any file type"}
440
- {typeof maxFiles === "number" ? ` • Up to ${maxFiles} file${maxFiles > 1 ? "s" : ""}` : ""}
572
+ {accept ? 'Specific file types only' : 'Any file type'}
573
+ {typeof maxFiles === 'number'
574
+ ? ` • Up to ${maxFiles} file${maxFiles > 1 ? 's' : ''}`
575
+ : ''}
441
576
  </div>
442
577
  </div>
443
578
  </div>
@@ -448,7 +583,9 @@ export function FileUploader({
448
583
  variant="ghost"
449
584
  onClick={handleRetryAll}
450
585
  disabled={
451
- !!disabled || !uploader || files.every((f) => f.status !== "error" || !f.file)
586
+ !!disabled ||
587
+ !uploader ||
588
+ files.every((f) => f.status !== 'error' || !f.file)
452
589
  }
453
590
  >
454
591
  <RotateCcw className="mr-1 h-4 w-4" /> Retry failed
@@ -461,9 +598,7 @@ export function FileUploader({
461
598
  <TooltipProvider>
462
599
  <div
463
600
  className={cn(
464
- layout === "grid"
465
- ? "flex flex-wrap gap-3"
466
- : "flex flex-col gap-2",
601
+ layout === 'grid' ? 'flex flex-wrap gap-3' : 'flex flex-col gap-2',
467
602
  )}
468
603
  >
469
604
  {files.length === 0 ? (