@maxal_studio/kratosjs-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. package/README.md +44 -0
  2. package/dist/FieldRenderer.d.ts +13 -0
  3. package/dist/FieldRenderer.js +62 -0
  4. package/dist/FormRenderer.d.ts +7 -0
  5. package/dist/FormRenderer.js +78 -0
  6. package/dist/TableRenderer.d.ts +2 -0
  7. package/dist/TableRenderer.js +1 -0
  8. package/dist/api/actionsApi.d.ts +23 -0
  9. package/dist/api/actionsApi.js +46 -0
  10. package/dist/api/authenticatedFetch.d.ts +8 -0
  11. package/dist/api/authenticatedFetch.js +31 -0
  12. package/dist/api/exportApi.d.ts +18 -0
  13. package/dist/api/exportApi.js +50 -0
  14. package/dist/api/http.d.ts +24 -0
  15. package/dist/api/http.js +52 -0
  16. package/dist/api/resourceApi.d.ts +37 -0
  17. package/dist/api/resourceApi.js +52 -0
  18. package/dist/api/tableApi.d.ts +83 -0
  19. package/dist/api/tableApi.js +51 -0
  20. package/dist/api/urls.d.ts +19 -0
  21. package/dist/api/urls.js +46 -0
  22. package/dist/app.d.ts +101 -0
  23. package/dist/app.js +89 -0
  24. package/dist/auth/AuthContext.d.ts +22 -0
  25. package/dist/auth/AuthContext.js +147 -0
  26. package/dist/auth/LoginPage.d.ts +10 -0
  27. package/dist/auth/LoginPage.js +179 -0
  28. package/dist/auth/ProtectedRoute.d.ts +12 -0
  29. package/dist/auth/ProtectedRoute.js +22 -0
  30. package/dist/auth/authApiClient.d.ts +24 -0
  31. package/dist/auth/authApiClient.js +95 -0
  32. package/dist/auth/types.d.ts +103 -0
  33. package/dist/auth/types.js +1 -0
  34. package/dist/components/ActionFormModal.d.ts +22 -0
  35. package/dist/components/ActionFormModal.js +8 -0
  36. package/dist/components/AdminPanel.d.ts +11 -0
  37. package/dist/components/AdminPanel.js +194 -0
  38. package/dist/components/Checkbox.d.ts +10 -0
  39. package/dist/components/Checkbox.js +8 -0
  40. package/dist/components/CheckboxField.d.ts +7 -0
  41. package/dist/components/CheckboxField.js +26 -0
  42. package/dist/components/ColorPickerField.d.ts +7 -0
  43. package/dist/components/ColorPickerField.js +26 -0
  44. package/dist/components/DateTimePickerField.d.ts +7 -0
  45. package/dist/components/DateTimePickerField.js +64 -0
  46. package/dist/components/FileUploadField.d.ts +9 -0
  47. package/dist/components/FileUploadField.js +478 -0
  48. package/dist/components/GlobalSearch.d.ts +22 -0
  49. package/dist/components/GlobalSearch.js +181 -0
  50. package/dist/components/GroupField.d.ts +7 -0
  51. package/dist/components/GroupField.js +23 -0
  52. package/dist/components/HiddenField.d.ts +3 -0
  53. package/dist/components/HiddenField.js +10 -0
  54. package/dist/components/ModalBreadcrumb.d.ts +5 -0
  55. package/dist/components/ModalBreadcrumb.js +33 -0
  56. package/dist/components/ModalDrawer.d.ts +15 -0
  57. package/dist/components/ModalDrawer.js +40 -0
  58. package/dist/components/RadioField.d.ts +7 -0
  59. package/dist/components/RadioField.js +26 -0
  60. package/dist/components/RepeaterField.d.ts +3 -0
  61. package/dist/components/RepeaterField.js +191 -0
  62. package/dist/components/ResourceModalRenderer.d.ts +10 -0
  63. package/dist/components/ResourceModalRenderer.js +80 -0
  64. package/dist/components/RichEditorField.d.ts +3 -0
  65. package/dist/components/RichEditorField.js +655 -0
  66. package/dist/components/SectionField.d.ts +9 -0
  67. package/dist/components/SectionField.js +111 -0
  68. package/dist/components/SelectField.d.ts +8 -0
  69. package/dist/components/SelectField.js +523 -0
  70. package/dist/components/TabsField.d.ts +10 -0
  71. package/dist/components/TabsField.js +214 -0
  72. package/dist/components/TagsInputField.d.ts +7 -0
  73. package/dist/components/TagsInputField.js +172 -0
  74. package/dist/components/TextInputField.d.ts +7 -0
  75. package/dist/components/TextInputField.js +44 -0
  76. package/dist/components/TextareaField.d.ts +7 -0
  77. package/dist/components/TextareaField.js +31 -0
  78. package/dist/components/ToggleField.d.ts +7 -0
  79. package/dist/components/ToggleField.js +57 -0
  80. package/dist/components/ViewModal.d.ts +25 -0
  81. package/dist/components/ViewModal.js +159 -0
  82. package/dist/components/blocks/BlockRenderer.d.ts +7 -0
  83. package/dist/components/blocks/BlockRenderer.js +36 -0
  84. package/dist/components/blocks/FormBlockRenderer.d.ts +6 -0
  85. package/dist/components/blocks/FormBlockRenderer.js +110 -0
  86. package/dist/components/blocks/TableBlockRenderer.d.ts +6 -0
  87. package/dist/components/blocks/TableBlockRenderer.js +12 -0
  88. package/dist/components/blocks/TabsBlockRenderer.d.ts +7 -0
  89. package/dist/components/blocks/TabsBlockRenderer.js +11 -0
  90. package/dist/components/blocks/WidgetBlockRenderer.d.ts +6 -0
  91. package/dist/components/blocks/WidgetBlockRenderer.js +11 -0
  92. package/dist/components/columns/CheckboxColumnComponent.d.ts +6 -0
  93. package/dist/components/columns/CheckboxColumnComponent.js +21 -0
  94. package/dist/components/columns/ColorColumnComponent.d.ts +3 -0
  95. package/dist/components/columns/ColorColumnComponent.js +11 -0
  96. package/dist/components/columns/DeeplinkWrapper.d.ts +15 -0
  97. package/dist/components/columns/DeeplinkWrapper.js +85 -0
  98. package/dist/components/columns/IconColumnComponent.d.ts +3 -0
  99. package/dist/components/columns/IconColumnComponent.js +52 -0
  100. package/dist/components/columns/ImageColumnComponent.d.ts +3 -0
  101. package/dist/components/columns/ImageColumnComponent.js +98 -0
  102. package/dist/components/columns/MediaColumnComponent.d.ts +3 -0
  103. package/dist/components/columns/MediaColumnComponent.js +160 -0
  104. package/dist/components/columns/SelectColumnComponent.d.ts +6 -0
  105. package/dist/components/columns/SelectColumnComponent.js +26 -0
  106. package/dist/components/columns/TagsColumnComponent.d.ts +3 -0
  107. package/dist/components/columns/TagsColumnComponent.js +18 -0
  108. package/dist/components/columns/TextColumnComponent.d.ts +11 -0
  109. package/dist/components/columns/TextColumnComponent.js +107 -0
  110. package/dist/components/columns/TextInputColumnComponent.d.ts +6 -0
  111. package/dist/components/columns/TextInputColumnComponent.js +18 -0
  112. package/dist/components/columns/ToggleColumnComponent.d.ts +6 -0
  113. package/dist/components/columns/ToggleColumnComponent.js +25 -0
  114. package/dist/components/columns/VideoColumnComponent.d.ts +3 -0
  115. package/dist/components/columns/VideoColumnComponent.js +125 -0
  116. package/dist/components/columns/ViewColumnComponent.d.ts +3 -0
  117. package/dist/components/columns/ViewColumnComponent.js +7 -0
  118. package/dist/components/errors/ErrorBoundary.d.ts +23 -0
  119. package/dist/components/errors/ErrorBoundary.js +33 -0
  120. package/dist/components/filters/CustomFilterComponent.d.ts +10 -0
  121. package/dist/components/filters/CustomFilterComponent.js +33 -0
  122. package/dist/components/filters/DateFilterComponent.d.ts +15 -0
  123. package/dist/components/filters/DateFilterComponent.js +132 -0
  124. package/dist/components/filters/QueryBuilderFilterComponent.d.ts +11 -0
  125. package/dist/components/filters/QueryBuilderFilterComponent.js +200 -0
  126. package/dist/components/layout/Header.d.ts +10 -0
  127. package/dist/components/layout/Header.js +70 -0
  128. package/dist/components/layout/PanelBrandMark.d.ts +8 -0
  129. package/dist/components/layout/PanelBrandMark.js +28 -0
  130. package/dist/components/layout/Sidebar.d.ts +35 -0
  131. package/dist/components/layout/Sidebar.js +125 -0
  132. package/dist/components/modals/RelationCreateModal.d.ts +19 -0
  133. package/dist/components/modals/RelationCreateModal.js +57 -0
  134. package/dist/components/modals/ResourceFormModal.d.ts +37 -0
  135. package/dist/components/modals/ResourceFormModal.js +44 -0
  136. package/dist/components/modals/useResourceForm.d.ts +40 -0
  137. package/dist/components/modals/useResourceForm.js +138 -0
  138. package/dist/components/modals/view/RecordActions.d.ts +17 -0
  139. package/dist/components/modals/view/RecordActions.js +16 -0
  140. package/dist/components/modals/view/RecordDetails.d.ts +13 -0
  141. package/dist/components/modals/view/RecordDetails.js +29 -0
  142. package/dist/components/modals/view/RelationPanel.d.ts +18 -0
  143. package/dist/components/modals/view/RelationPanel.js +16 -0
  144. package/dist/components/modals/view/RelationTabs.d.ts +32 -0
  145. package/dist/components/modals/view/RelationTabs.js +42 -0
  146. package/dist/components/modals/view/useRecordView.d.ts +18 -0
  147. package/dist/components/modals/view/useRecordView.js +114 -0
  148. package/dist/components/pages/PageRenderer.d.ts +6 -0
  149. package/dist/components/pages/PageRenderer.js +107 -0
  150. package/dist/components/table/ColumnTogglePopup.d.ts +11 -0
  151. package/dist/components/table/ColumnTogglePopup.js +16 -0
  152. package/dist/components/table/GridCard.d.ts +21 -0
  153. package/dist/components/table/GridCard.js +30 -0
  154. package/dist/components/table/GridView.d.ts +23 -0
  155. package/dist/components/table/GridView.js +49 -0
  156. package/dist/components/table/LayoutToggle.d.ts +7 -0
  157. package/dist/components/table/LayoutToggle.js +9 -0
  158. package/dist/components/table/TableActionsDropdown.d.ts +13 -0
  159. package/dist/components/table/TableActionsDropdown.js +46 -0
  160. package/dist/components/table/TableBulkActions.d.ts +11 -0
  161. package/dist/components/table/TableBulkActions.js +21 -0
  162. package/dist/components/table/TableHeader.d.ts +14 -0
  163. package/dist/components/table/TableHeader.js +23 -0
  164. package/dist/components/table/TablePagination.d.ts +13 -0
  165. package/dist/components/table/TablePagination.js +55 -0
  166. package/dist/components/table/TableRow.d.ts +21 -0
  167. package/dist/components/table/TableRow.js +32 -0
  168. package/dist/components/table/TableSearchBar.d.ts +11 -0
  169. package/dist/components/table/TableSearchBar.js +12 -0
  170. package/dist/components/table/TableTabs.d.ts +14 -0
  171. package/dist/components/table/TableTabs.js +8 -0
  172. package/dist/components/ui/Badge.d.ts +6 -0
  173. package/dist/components/ui/Badge.js +12 -0
  174. package/dist/components/ui/Button.d.ts +22 -0
  175. package/dist/components/ui/Button.js +22 -0
  176. package/dist/components/ui/Card.d.ts +7 -0
  177. package/dist/components/ui/Card.js +5 -0
  178. package/dist/components/ui/ConfirmDialog.d.ts +19 -0
  179. package/dist/components/ui/ConfirmDialog.js +45 -0
  180. package/dist/components/ui/EmptyState.d.ts +9 -0
  181. package/dist/components/ui/EmptyState.js +6 -0
  182. package/dist/components/ui/ErrorAlert.d.ts +7 -0
  183. package/dist/components/ui/ErrorAlert.js +9 -0
  184. package/dist/components/ui/Input.d.ts +11 -0
  185. package/dist/components/ui/Input.js +10 -0
  186. package/dist/components/ui/Label.d.ts +5 -0
  187. package/dist/components/ui/Label.js +5 -0
  188. package/dist/components/ui/PillButton.d.ts +14 -0
  189. package/dist/components/ui/PillButton.js +19 -0
  190. package/dist/components/ui/Select.d.ts +7 -0
  191. package/dist/components/ui/Select.js +7 -0
  192. package/dist/components/ui/Spinner.d.ts +8 -0
  193. package/dist/components/ui/Spinner.js +14 -0
  194. package/dist/components/ui/Toast.d.ts +21 -0
  195. package/dist/components/ui/Toast.js +47 -0
  196. package/dist/components/ui/index.d.ts +24 -0
  197. package/dist/components/ui/index.js +12 -0
  198. package/dist/components/utils/HintDisplay.d.ts +11 -0
  199. package/dist/components/utils/HintDisplay.js +12 -0
  200. package/dist/components/utils/Icon.d.ts +22 -0
  201. package/dist/components/utils/Icon.js +22 -0
  202. package/dist/components/utils/MediaPreviewModal.d.ts +14 -0
  203. package/dist/components/utils/MediaPreviewModal.js +32 -0
  204. package/dist/components/utils/ViewFieldWrapper.d.ts +11 -0
  205. package/dist/components/utils/ViewFieldWrapper.js +9 -0
  206. package/dist/components/utils/layoutHelpers.d.ts +19 -0
  207. package/dist/components/utils/layoutHelpers.js +257 -0
  208. package/dist/components/widgets/ChartWidget.d.ts +16 -0
  209. package/dist/components/widgets/ChartWidget.js +192 -0
  210. package/dist/components/widgets/StatsWidget.d.ts +16 -0
  211. package/dist/components/widgets/StatsWidget.js +39 -0
  212. package/dist/components/widgets/WidgetRenderer.d.ts +10 -0
  213. package/dist/components/widgets/WidgetRenderer.js +50 -0
  214. package/dist/components/widgets/WidgetShell.d.ts +9 -0
  215. package/dist/components/widgets/WidgetShell.js +7 -0
  216. package/dist/contexts/AuthChallengeRegistryContext.d.ts +15 -0
  217. package/dist/contexts/AuthChallengeRegistryContext.js +15 -0
  218. package/dist/contexts/BlockRegistryContext.d.ts +18 -0
  219. package/dist/contexts/BlockRegistryContext.js +8 -0
  220. package/dist/contexts/ColumnRegistryContext.d.ts +8 -0
  221. package/dist/contexts/ColumnRegistryContext.js +30 -0
  222. package/dist/contexts/FieldRegistryContext.d.ts +13 -0
  223. package/dist/contexts/FieldRegistryContext.js +46 -0
  224. package/dist/contexts/PanelMetadataContext.d.ts +26 -0
  225. package/dist/contexts/PanelMetadataContext.js +26 -0
  226. package/dist/contexts/PanelProviders.d.ts +27 -0
  227. package/dist/contexts/PanelProviders.js +24 -0
  228. package/dist/contexts/ResourceModalContext.d.ts +26 -0
  229. package/dist/contexts/ResourceModalContext.js +76 -0
  230. package/dist/contexts/SlotRegistryContext.d.ts +19 -0
  231. package/dist/contexts/SlotRegistryContext.js +24 -0
  232. package/dist/contexts/TableRefreshContext.d.ts +10 -0
  233. package/dist/contexts/TableRefreshContext.js +30 -0
  234. package/dist/contexts/WidgetRegistryContext.d.ts +17 -0
  235. package/dist/contexts/WidgetRegistryContext.js +14 -0
  236. package/dist/contexts/createRegistryContext.d.ts +19 -0
  237. package/dist/contexts/createRegistryContext.js +20 -0
  238. package/dist/hooks/useAfterStateUpdated.d.ts +6 -0
  239. package/dist/hooks/useAfterStateUpdated.js +62 -0
  240. package/dist/hooks/useValidation.d.ts +26 -0
  241. package/dist/hooks/useValidation.js +76 -0
  242. package/dist/i18n/I18nProvider.d.ts +27 -0
  243. package/dist/i18n/I18nProvider.js +101 -0
  244. package/dist/i18n/LocaleSwitcher.d.ts +10 -0
  245. package/dist/i18n/LocaleSwitcher.js +30 -0
  246. package/dist/i18n/activeLocale.d.ts +11 -0
  247. package/dist/i18n/activeLocale.js +34 -0
  248. package/dist/i18n/buildClientI18n.d.ts +28 -0
  249. package/dist/i18n/buildClientI18n.js +67 -0
  250. package/dist/i18n/index.d.ts +11 -0
  251. package/dist/i18n/index.js +9 -0
  252. package/dist/i18n/locales/core/en.d.ts +225 -0
  253. package/dist/i18n/locales/core/en.js +252 -0
  254. package/dist/i18n/locales/core/index.d.ts +2 -0
  255. package/dist/i18n/locales/core/index.js +4 -0
  256. package/dist/i18n/locales/core/sq.d.ts +253 -0
  257. package/dist/i18n/locales/core/sq.js +255 -0
  258. package/dist/i18n/useFormatter.d.ts +18 -0
  259. package/dist/i18n/useFormatter.js +37 -0
  260. package/dist/i18n/useLocale.d.ts +11 -0
  261. package/dist/i18n/useLocale.js +11 -0
  262. package/dist/i18n/useTranslation.d.ts +12 -0
  263. package/dist/i18n/useTranslation.js +12 -0
  264. package/dist/index.d.ts +106 -0
  265. package/dist/index.js +101 -0
  266. package/dist/pages/ResourceListPage.d.ts +8 -0
  267. package/dist/pages/ResourceListPage.js +139 -0
  268. package/dist/plugin.d.ts +79 -0
  269. package/dist/plugin.js +34 -0
  270. package/dist/runtime/conditions.d.ts +35 -0
  271. package/dist/runtime/conditions.js +97 -0
  272. package/dist/runtime/formTraversal.d.ts +25 -0
  273. package/dist/runtime/formTraversal.js +37 -0
  274. package/dist/runtime/serializedFunctions.d.ts +41 -0
  275. package/dist/runtime/serializedFunctions.js +264 -0
  276. package/dist/slots/Slot.d.ts +24 -0
  277. package/dist/slots/Slot.js +29 -0
  278. package/dist/slots/SlotCluster.d.ts +22 -0
  279. package/dist/slots/SlotCluster.js +49 -0
  280. package/dist/slots/index.d.ts +7 -0
  281. package/dist/slots/index.js +4 -0
  282. package/dist/slots/mergeSlots.d.ts +18 -0
  283. package/dist/slots/mergeSlots.js +35 -0
  284. package/dist/slots/types.d.ts +87 -0
  285. package/dist/slots/types.js +30 -0
  286. package/dist/styles.css +1 -0
  287. package/dist/table/TableContext.d.ts +36 -0
  288. package/dist/table/TableContext.js +13 -0
  289. package/dist/table/TableRenderer.d.ts +29 -0
  290. package/dist/table/TableRenderer.js +159 -0
  291. package/dist/table/components/FiltersPanel.d.ts +11 -0
  292. package/dist/table/components/FiltersPanel.js +52 -0
  293. package/dist/table/components/TableToolbar.d.ts +28 -0
  294. package/dist/table/components/TableToolbar.js +27 -0
  295. package/dist/table/components/TableToolbarButton.d.ts +6 -0
  296. package/dist/table/components/TableToolbarButton.js +9 -0
  297. package/dist/table/components/TableView.d.ts +12 -0
  298. package/dist/table/components/TableView.js +21 -0
  299. package/dist/table/defaultRowActions.d.ts +21 -0
  300. package/dist/table/defaultRowActions.js +37 -0
  301. package/dist/table/hooks/useColumnVisibility.d.ts +13 -0
  302. package/dist/table/hooks/useColumnVisibility.js +59 -0
  303. package/dist/table/hooks/useEditableRows.d.ts +22 -0
  304. package/dist/table/hooks/useEditableRows.js +63 -0
  305. package/dist/table/hooks/useTableActions.d.ts +54 -0
  306. package/dist/table/hooks/useTableActions.js +313 -0
  307. package/dist/table/hooks/useTableData.d.ts +28 -0
  308. package/dist/table/hooks/useTableData.js +63 -0
  309. package/dist/table/hooks/useTableLayout.d.ts +12 -0
  310. package/dist/table/hooks/useTableLayout.js +31 -0
  311. package/dist/table/hooks/useTableQuery.d.ts +29 -0
  312. package/dist/table/hooks/useTableQuery.js +135 -0
  313. package/dist/types/index.d.ts +224 -0
  314. package/dist/types/index.js +6 -0
  315. package/dist/utils/classNames.d.ts +7 -0
  316. package/dist/utils/classNames.js +9 -0
  317. package/dist/utils/columnMediaDimensions.d.ts +13 -0
  318. package/dist/utils/columnMediaDimensions.js +29 -0
  319. package/dist/utils/columnVisibilityStorage.d.ts +22 -0
  320. package/dist/utils/columnVisibilityStorage.js +56 -0
  321. package/dist/utils/fieldErrors.d.ts +13 -0
  322. package/dist/utils/fieldErrors.js +25 -0
  323. package/dist/utils/formatValue.d.ts +28 -0
  324. package/dist/utils/formatValue.js +109 -0
  325. package/dist/utils/layoutStorage.d.ts +23 -0
  326. package/dist/utils/layoutStorage.js +53 -0
  327. package/dist/utils/redirectHandler.d.ts +7 -0
  328. package/dist/utils/redirectHandler.js +25 -0
  329. package/dist/utils/tableFormatters.d.ts +14 -0
  330. package/dist/utils/tableFormatters.js +93 -0
  331. package/dist/utils/widgetVisibilityStorage.d.ts +11 -0
  332. package/dist/utils/widgetVisibilityStorage.js +39 -0
  333. package/package.json +101 -0
  334. package/src/FieldRenderer.test.tsx +44 -0
  335. package/src/FieldRenderer.tsx +104 -0
  336. package/src/FormRenderer.containers.test.tsx +121 -0
  337. package/src/FormRenderer.test.tsx +174 -0
  338. package/src/FormRenderer.tsx +140 -0
  339. package/src/TableRenderer.tsx +2 -0
  340. package/src/api/actionsApi.ts +76 -0
  341. package/src/api/authenticatedFetch.ts +40 -0
  342. package/src/api/exportApi.ts +66 -0
  343. package/src/api/http.test.ts +58 -0
  344. package/src/api/http.ts +68 -0
  345. package/src/api/resourceApi.ts +88 -0
  346. package/src/api/tableApi.test.ts +108 -0
  347. package/src/api/tableApi.ts +107 -0
  348. package/src/api/urls.ts +50 -0
  349. package/src/app.test.tsx +67 -0
  350. package/src/app.tsx +181 -0
  351. package/src/auth/AuthContext.tsx +188 -0
  352. package/src/auth/LoginPage.tsx +380 -0
  353. package/src/auth/ProtectedRoute.tsx +39 -0
  354. package/src/auth/authApiClient.ts +109 -0
  355. package/src/auth/authFlow.test.tsx +168 -0
  356. package/src/auth/types.ts +104 -0
  357. package/src/components/ActionFormModal.tsx +45 -0
  358. package/src/components/AdminPanel.tsx +368 -0
  359. package/src/components/Checkbox.tsx +59 -0
  360. package/src/components/CheckboxField.tsx +88 -0
  361. package/src/components/ColorPickerField.tsx +93 -0
  362. package/src/components/DateTimePickerField.tsx +112 -0
  363. package/src/components/FileUploadField.tsx +841 -0
  364. package/src/components/GlobalSearch.tsx +436 -0
  365. package/src/components/GroupField.tsx +85 -0
  366. package/src/components/HiddenField.tsx +14 -0
  367. package/src/components/ModalBreadcrumb.tsx +74 -0
  368. package/src/components/ModalDrawer.tsx +137 -0
  369. package/src/components/RadioField.tsx +80 -0
  370. package/src/components/RepeaterField.tsx +546 -0
  371. package/src/components/ResourceModalRenderer.tsx +144 -0
  372. package/src/components/RichEditorField.tsx +942 -0
  373. package/src/components/SectionField.tsx +242 -0
  374. package/src/components/SelectField.tsx +843 -0
  375. package/src/components/TabsField.test.tsx +151 -0
  376. package/src/components/TabsField.tsx +386 -0
  377. package/src/components/TagsInputField.tsx +411 -0
  378. package/src/components/TextInputField.tsx +91 -0
  379. package/src/components/TextareaField.tsx +110 -0
  380. package/src/components/ToggleField.tsx +126 -0
  381. package/src/components/ViewModal.tsx +353 -0
  382. package/src/components/blocks/BlockRenderer.tsx +56 -0
  383. package/src/components/blocks/FormBlockRenderer.tsx +160 -0
  384. package/src/components/blocks/TableBlockRenderer.tsx +33 -0
  385. package/src/components/blocks/TabsBlockRenderer.tsx +49 -0
  386. package/src/components/blocks/WidgetBlockRenderer.tsx +19 -0
  387. package/src/components/columns/CheckboxColumnComponent.tsx +38 -0
  388. package/src/components/columns/ColorColumnComponent.tsx +23 -0
  389. package/src/components/columns/CustomColumn.test.tsx +55 -0
  390. package/src/components/columns/DeeplinkWrapper.tsx +103 -0
  391. package/src/components/columns/IconColumnComponent.tsx +55 -0
  392. package/src/components/columns/ImageColumnComponent.tsx +220 -0
  393. package/src/components/columns/MediaColumnComponent.tsx +294 -0
  394. package/src/components/columns/SelectColumnComponent.tsx +49 -0
  395. package/src/components/columns/TagsColumnComponent.tsx +46 -0
  396. package/src/components/columns/TextColumnComponent.tsx +191 -0
  397. package/src/components/columns/TextInputColumnComponent.tsx +35 -0
  398. package/src/components/columns/ToggleColumnComponent.tsx +56 -0
  399. package/src/components/columns/VideoColumnComponent.tsx +236 -0
  400. package/src/components/columns/ViewColumnComponent.tsx +9 -0
  401. package/src/components/errors/ErrorBoundary.tsx +58 -0
  402. package/src/components/filters/CustomFilterComponent.tsx +130 -0
  403. package/src/components/filters/DateFilterComponent.tsx +272 -0
  404. package/src/components/filters/QueryBuilderFilterComponent.tsx +502 -0
  405. package/src/components/layout/Header.tsx +212 -0
  406. package/src/components/layout/PanelBrandMark.tsx +61 -0
  407. package/src/components/layout/Sidebar.tsx +283 -0
  408. package/src/components/modals/RelationCreateModal.tsx +107 -0
  409. package/src/components/modals/ResourceFormModal.test.tsx +119 -0
  410. package/src/components/modals/ResourceFormModal.tsx +128 -0
  411. package/src/components/modals/useResourceForm.ts +207 -0
  412. package/src/components/modals/view/RecordActions.tsx +69 -0
  413. package/src/components/modals/view/RecordDetails.tsx +60 -0
  414. package/src/components/modals/view/RelationPanel.tsx +76 -0
  415. package/src/components/modals/view/RelationTabs.tsx +145 -0
  416. package/src/components/modals/view/useRecordView.ts +134 -0
  417. package/src/components/pages/PageRenderer.tsx +173 -0
  418. package/src/components/table/ColumnTogglePopup.tsx +85 -0
  419. package/src/components/table/GridCard.tsx +155 -0
  420. package/src/components/table/GridView.tsx +138 -0
  421. package/src/components/table/LayoutToggle.tsx +24 -0
  422. package/src/components/table/TableActionsDropdown.tsx +114 -0
  423. package/src/components/table/TableBulkActions.tsx +65 -0
  424. package/src/components/table/TableHeader.tsx +96 -0
  425. package/src/components/table/TablePagination.tsx +169 -0
  426. package/src/components/table/TableRow.tsx +155 -0
  427. package/src/components/table/TableSearchBar.tsx +66 -0
  428. package/src/components/table/TableTabs.tsx +49 -0
  429. package/src/components/ui/Badge.tsx +30 -0
  430. package/src/components/ui/Button.test.tsx +78 -0
  431. package/src/components/ui/Button.tsx +102 -0
  432. package/src/components/ui/Card.tsx +23 -0
  433. package/src/components/ui/ConfirmDialog.tsx +112 -0
  434. package/src/components/ui/EmptyState.tsx +24 -0
  435. package/src/components/ui/ErrorAlert.tsx +37 -0
  436. package/src/components/ui/Input.tsx +48 -0
  437. package/src/components/ui/Label.tsx +15 -0
  438. package/src/components/ui/PillButton.tsx +72 -0
  439. package/src/components/ui/Select.tsx +33 -0
  440. package/src/components/ui/Spinner.tsx +39 -0
  441. package/src/components/ui/Toast.tsx +105 -0
  442. package/src/components/ui/index.ts +24 -0
  443. package/src/components/utils/HintDisplay.tsx +26 -0
  444. package/src/components/utils/Icon.tsx +36 -0
  445. package/src/components/utils/MediaPreviewModal.tsx +114 -0
  446. package/src/components/utils/ViewFieldWrapper.tsx +23 -0
  447. package/src/components/utils/layoutHelpers.ts +267 -0
  448. package/src/components/widgets/ChartWidget.tsx +247 -0
  449. package/src/components/widgets/StatsWidget.tsx +72 -0
  450. package/src/components/widgets/WidgetRenderer.tsx +108 -0
  451. package/src/components/widgets/WidgetShell.tsx +37 -0
  452. package/src/contexts/AuthChallengeRegistryContext.tsx +29 -0
  453. package/src/contexts/BlockRegistryContext.tsx +28 -0
  454. package/src/contexts/ColumnRegistryContext.tsx +38 -0
  455. package/src/contexts/FieldRegistryContext.tsx +56 -0
  456. package/src/contexts/PanelMetadataContext.tsx +60 -0
  457. package/src/contexts/PanelProviders.tsx +85 -0
  458. package/src/contexts/ResourceModalContext.tsx +137 -0
  459. package/src/contexts/SlotRegistryContext.tsx +35 -0
  460. package/src/contexts/TableRefreshContext.tsx +44 -0
  461. package/src/contexts/WidgetRegistryContext.tsx +34 -0
  462. package/src/contexts/createRegistryContext.tsx +29 -0
  463. package/src/hooks/useAfterStateUpdated.ts +70 -0
  464. package/src/hooks/useValidation.test.ts +59 -0
  465. package/src/hooks/useValidation.ts +95 -0
  466. package/src/i18n/I18nProvider.tsx +128 -0
  467. package/src/i18n/LocaleSwitcher.tsx +50 -0
  468. package/src/i18n/activeLocale.ts +39 -0
  469. package/src/i18n/buildClientI18n.ts +101 -0
  470. package/src/i18n/i18n.test.tsx +140 -0
  471. package/src/i18n/index.ts +12 -0
  472. package/src/i18n/locales/core/en.ts +274 -0
  473. package/src/i18n/locales/core/index.ts +5 -0
  474. package/src/i18n/locales/core/sq.ts +275 -0
  475. package/src/i18n/useFormatter.ts +42 -0
  476. package/src/i18n/useLocale.ts +16 -0
  477. package/src/i18n/useTranslation.ts +17 -0
  478. package/src/index.ts +244 -0
  479. package/src/pages/ResourceListPage.tsx +205 -0
  480. package/src/plugin.ts +110 -0
  481. package/src/runtime/conditions.test.ts +99 -0
  482. package/src/runtime/conditions.ts +148 -0
  483. package/src/runtime/formTraversal.ts +41 -0
  484. package/src/runtime/serializedFunctions.test.ts +59 -0
  485. package/src/runtime/serializedFunctions.ts +284 -0
  486. package/src/slots/Slot.test.tsx +89 -0
  487. package/src/slots/Slot.tsx +47 -0
  488. package/src/slots/SlotCluster.test.tsx +95 -0
  489. package/src/slots/SlotCluster.tsx +107 -0
  490. package/src/slots/index.ts +15 -0
  491. package/src/slots/mergeSlots.test.ts +71 -0
  492. package/src/slots/mergeSlots.ts +40 -0
  493. package/src/slots/slotNames.test.ts +21 -0
  494. package/src/slots/types.ts +119 -0
  495. package/src/styles.css +437 -0
  496. package/src/table/TableContext.tsx +41 -0
  497. package/src/table/TableRenderer.test.tsx +197 -0
  498. package/src/table/TableRenderer.tsx +390 -0
  499. package/src/table/components/FiltersPanel.tsx +193 -0
  500. package/src/table/components/TableToolbar.tsx +153 -0
  501. package/src/table/components/TableToolbarButton.tsx +14 -0
  502. package/src/table/components/TableView.tsx +106 -0
  503. package/src/table/defaultRowActions.ts +43 -0
  504. package/src/table/hooks/useColumnVisibility.test.ts +51 -0
  505. package/src/table/hooks/useColumnVisibility.ts +71 -0
  506. package/src/table/hooks/useEditableRows.test.ts +69 -0
  507. package/src/table/hooks/useEditableRows.ts +89 -0
  508. package/src/table/hooks/useTableActions.ts +393 -0
  509. package/src/table/hooks/useTableData.ts +89 -0
  510. package/src/table/hooks/useTableLayout.ts +45 -0
  511. package/src/table/hooks/useTableQuery.test.ts +116 -0
  512. package/src/table/hooks/useTableQuery.ts +172 -0
  513. package/src/test/mockFetch.ts +67 -0
  514. package/src/test/setup.ts +25 -0
  515. package/src/types/index.ts +228 -0
  516. package/src/utils/classNames.ts +10 -0
  517. package/src/utils/columnMediaDimensions.ts +45 -0
  518. package/src/utils/columnVisibilityStorage.ts +55 -0
  519. package/src/utils/fieldErrors.test.ts +35 -0
  520. package/src/utils/fieldErrors.ts +27 -0
  521. package/src/utils/formatValue.test.tsx +65 -0
  522. package/src/utils/formatValue.tsx +117 -0
  523. package/src/utils/layoutStorage.ts +52 -0
  524. package/src/utils/redirectHandler.ts +29 -0
  525. package/src/utils/tableFormatters.test.ts +54 -0
  526. package/src/utils/tableFormatters.ts +104 -0
  527. package/src/utils/widgetVisibilityStorage.ts +38 -0
  528. package/tailwind.config.js +9 -0
  529. package/vite.config.ts +17 -0
@@ -0,0 +1,478 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useCallback, useState, useEffect, useRef, useMemo } from 'react';
3
+ import { useFormContext } from 'react-hook-form';
4
+ import { getFieldError } from '../utils/fieldErrors';
5
+ import { useDropzone } from 'react-dropzone';
6
+ import { Check, Upload, File, Trash2, Loader2 } from 'lucide-react';
7
+ import { HintDisplay } from './utils/HintDisplay';
8
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
9
+ import { MediaPreviewModal } from './utils/MediaPreviewModal';
10
+ import { authenticatedFetch } from '../api/authenticatedFetch';
11
+ import { useValidation } from '../hooks/useValidation';
12
+ import { translate } from '../i18n/activeLocale';
13
+ /**
14
+ * Generate a unique ID for file tracking
15
+ */
16
+ const generateId = () => `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
17
+ /**
18
+ * Convert File to base64 string
19
+ */
20
+ const fileToBase64 = (file) => {
21
+ return new Promise((resolve, reject) => {
22
+ const reader = new FileReader();
23
+ reader.onload = () => {
24
+ const result = reader.result;
25
+ resolve(result.split(',')[1]);
26
+ };
27
+ reader.onerror = reject;
28
+ reader.readAsDataURL(file);
29
+ });
30
+ };
31
+ /**
32
+ * Format bytes to human readable size
33
+ */
34
+ const formatFileSize = (bytes) => {
35
+ if (bytes === 0)
36
+ return '0 Bytes';
37
+ const k = 1024;
38
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
39
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
40
+ return `${Math.round((bytes / Math.pow(k, i)) * 100) / 100} ${sizes[i]}`;
41
+ };
42
+ /**
43
+ * Check if a URL points to an image
44
+ */
45
+ const isImageUrl = (url) => {
46
+ if (!url)
47
+ return false;
48
+ if (url.startsWith('blob:'))
49
+ return true;
50
+ return /\.(jpg|jpeg|png|gif|webp|svg|bmp)$/i.test(url);
51
+ };
52
+ /**
53
+ * Check if a URL points to a video
54
+ */
55
+ const isVideoUrl = (url) => {
56
+ if (!url)
57
+ return false;
58
+ return /\.(mp4|webm|ogg|mov|m4v)$/i.test(url);
59
+ };
60
+ /**
61
+ * Check if a URL points to an audio file
62
+ */
63
+ const isAudioUrl = (url) => {
64
+ if (!url)
65
+ return false;
66
+ return /\.(mp3|wav|ogg|m4a)$/i.test(url);
67
+ };
68
+ function FileUploadViewField({ label, value }) {
69
+ const [previewOpen, setPreviewOpen] = useState(false);
70
+ const [previewUrl, setPreviewUrl] = useState(null);
71
+ const [previewType, setPreviewType] = useState('image');
72
+ const displayValue = value || null;
73
+ const filesArray = Array.isArray(displayValue) ? displayValue : displayValue ? [displayValue] : [];
74
+ if (filesArray.length === 0) {
75
+ return _jsx(ViewFieldWrapper, { label: label, children: "-" });
76
+ }
77
+ const openPreview = (url, type) => {
78
+ setPreviewUrl(url);
79
+ setPreviewType(type);
80
+ setPreviewOpen(true);
81
+ };
82
+ return (_jsxs(ViewFieldWrapper, { label: label, children: [_jsx("div", { className: "flex flex-wrap gap-4", children: filesArray.map((file, index) => {
83
+ const fileUrl = typeof file === 'object' && file !== null ? file.url || file.key : file;
84
+ if (!fileUrl) {
85
+ return null;
86
+ }
87
+ const image = isImageUrl(fileUrl);
88
+ const video = isVideoUrl(fileUrl);
89
+ if (video) {
90
+ return (_jsx("div", { className: "relative", children: _jsx("video", { src: fileUrl, controls: true, className: "w-72 h-44 rounded-lg border border-border object-cover bg-black", onClick: e => {
91
+ e.stopPropagation();
92
+ openPreview(fileUrl, 'video');
93
+ } }) }, index));
94
+ }
95
+ if (image) {
96
+ return (_jsx("div", { className: "relative", children: _jsx("img", { src: fileUrl, alt: `${label || translate('core:common.image')} ${index + 1}`, className: "w-40 h-40 object-cover rounded-lg border border-border cursor-pointer hover:opacity-80 transition-opacity", onClick: () => openPreview(fileUrl, 'image') }) }, index));
97
+ }
98
+ return (_jsxs("div", { className: "flex items-center gap-2 p-2 border border-border rounded-lg bg-surface", children: [_jsx(File, { size: 20, className: "text-fg-secondary" }), _jsx("span", { className: "text-sm text-fg", children: typeof file === 'object' && file !== null
99
+ ? file.key || translate('core:common.file')
100
+ : translate('core:common.file') })] }, index));
101
+ }) }), previewUrl && (_jsx(MediaPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), mediaUrl: previewUrl, mediaType: previewType, title: label, autoplay: previewType === 'video', controls: true }))] }));
102
+ }
103
+ export function FileUploadField({ name, label, helperText, hint, hintIcon, hintColor, acceptedFileTypes = [], maxSize, minSize, multiple = false, maxFiles, disabled, required, visibility, directory, bucket, apiBaseUrl, resource, mode, value, validation, operation, }) {
104
+ // View mode: render formatted display (with image/video preview)
105
+ if (mode === 'view') {
106
+ return _jsx(FileUploadViewField, { label: label, value: value });
107
+ }
108
+ const { setValue, watch, register, formState: { errors: formErrors }, } = useFormContext();
109
+ const [files, setFiles] = useState([]);
110
+ const [errors, setErrors] = useState([]);
111
+ const initializedRef = useRef(false);
112
+ // Preview state for edit mode
113
+ const [editPreviewOpen, setEditPreviewOpen] = useState(false);
114
+ const [editPreviewUrl, setEditPreviewUrl] = useState(null);
115
+ const [editPreviewType, setEditPreviewType] = useState('image');
116
+ const currentValue = watch(name);
117
+ // Evaluate validation conditions with form context
118
+ const validationResult = useValidation(validation?.rules || [], operation, name);
119
+ const isRequired = validationResult.required !== undefined;
120
+ const fieldError = getFieldError(formErrors, name);
121
+ // Register field with React Hook Form for validation
122
+ React.useEffect(() => {
123
+ register(name, validationResult);
124
+ }, [register, name, validationResult]);
125
+ // Compute endpoints
126
+ // Use generic media endpoint if no resource is provided, otherwise use resource-specific endpoint
127
+ const uploadEndpoint = useMemo(() => {
128
+ if (!apiBaseUrl)
129
+ return null;
130
+ if (resource) {
131
+ return `${apiBaseUrl}/${resource}/media/upload`;
132
+ }
133
+ return `${apiBaseUrl}/media/upload`;
134
+ }, [apiBaseUrl, resource]);
135
+ const deleteEndpoint = useMemo(() => {
136
+ if (!apiBaseUrl)
137
+ return null;
138
+ if (resource) {
139
+ return `${apiBaseUrl}/${resource}/media/delete`;
140
+ }
141
+ return `${apiBaseUrl}/media/delete`;
142
+ }, [apiBaseUrl, resource]);
143
+ /**
144
+ * Initialize from existing value (server sends { url, key } objects)
145
+ * Only runs once on mount if there's an initial value
146
+ */
147
+ useEffect(() => {
148
+ if (initializedRef.current)
149
+ return;
150
+ if (!currentValue)
151
+ return;
152
+ initializedRef.current = true;
153
+ const existingFiles = [];
154
+ const keys = [];
155
+ const processItem = (item) => {
156
+ if (!item)
157
+ return null;
158
+ // New format: { key, bucket, url }
159
+ if (typeof item === 'object' && item.key) {
160
+ keys.push(item.key);
161
+ return {
162
+ id: generateId(),
163
+ key: item.key,
164
+ bucket: item.bucket,
165
+ url: item.url || item.key, // Use url if available, fallback to key
166
+ status: 'existing',
167
+ };
168
+ }
169
+ // String form: treat the value as a storage key
170
+ if (typeof item === 'string') {
171
+ keys.push(item);
172
+ return {
173
+ id: generateId(),
174
+ key: item,
175
+ url: item,
176
+ status: 'existing',
177
+ };
178
+ }
179
+ return null;
180
+ };
181
+ if (Array.isArray(currentValue)) {
182
+ currentValue.forEach(item => {
183
+ const fileItem = processItem(item);
184
+ if (fileItem)
185
+ existingFiles.push(fileItem);
186
+ });
187
+ }
188
+ else {
189
+ const fileItem = processItem(currentValue);
190
+ if (fileItem)
191
+ existingFiles.push(fileItem);
192
+ }
193
+ setFiles(existingFiles);
194
+ // Set form value to just keys (don't validate on initial load)
195
+ setValue(name, multiple ? keys : keys[0] || null, { shouldValidate: false });
196
+ // eslint-disable-next-line react-hooks/exhaustive-deps
197
+ }, []); // Only run once on mount
198
+ /**
199
+ * Upload a single file to the server
200
+ */
201
+ const uploadFile = useCallback(async (file) => {
202
+ if (!uploadEndpoint) {
203
+ console.warn('No upload endpoint configured');
204
+ return null;
205
+ }
206
+ try {
207
+ const base64 = await fileToBase64(file);
208
+ const response = await authenticatedFetch(uploadEndpoint, {
209
+ method: 'POST',
210
+ headers: { 'Content-Type': 'application/json' },
211
+ body: JSON.stringify({
212
+ file: base64,
213
+ filename: file.name,
214
+ contentType: file.type,
215
+ fieldName: name,
216
+ isArray: multiple,
217
+ path: directory,
218
+ visibility,
219
+ bucket, // Pass bucket adapter name
220
+ }),
221
+ }, apiBaseUrl);
222
+ if (!response.ok) {
223
+ const error = await response.json();
224
+ throw new Error(`Upload failed: ${error.message || response.statusText}`);
225
+ }
226
+ return await response.json();
227
+ }
228
+ catch (error) {
229
+ console.error('Upload error:', error);
230
+ return null;
231
+ }
232
+ }, [uploadEndpoint, name, multiple, directory, visibility]);
233
+ /**
234
+ * Delete a file from bucket
235
+ */
236
+ const deleteFromStorage = useCallback(async (payload) => {
237
+ if (!deleteEndpoint)
238
+ return true;
239
+ try {
240
+ const body = typeof payload === 'string' ? { key: payload } : payload;
241
+ const response = await authenticatedFetch(deleteEndpoint, {
242
+ method: 'POST',
243
+ headers: { 'Content-Type': 'application/json' },
244
+ body: JSON.stringify(body),
245
+ }, apiBaseUrl);
246
+ return response.ok;
247
+ }
248
+ catch (error) {
249
+ console.error('Delete error:', error);
250
+ return false;
251
+ }
252
+ }, [deleteEndpoint]);
253
+ /**
254
+ * Update form value with current keys
255
+ * Backend will automatically detect deletions by comparing with existing record
256
+ */
257
+ const updateFormValue = useCallback((fileList) => {
258
+ // Get keys from uploaded/existing files
259
+ const keys = fileList
260
+ .filter(f => f.key && (f.status === 'uploaded' || f.status === 'existing'))
261
+ .map(f => f.key);
262
+ // Set main field value - backend will detect deletions automatically
263
+ // Trigger validation when value changes
264
+ if (multiple) {
265
+ setValue(name, keys.length > 0 ? keys : [], { shouldValidate: true });
266
+ }
267
+ else {
268
+ setValue(name, keys[0] || null, { shouldValidate: true });
269
+ }
270
+ }, [multiple, name, setValue]);
271
+ /**
272
+ * Handle file drop/selection
273
+ */
274
+ const onDrop = useCallback(async (acceptedFiles, rejectedFiles) => {
275
+ setErrors([]);
276
+ // Handle rejected files
277
+ const newErrors = [];
278
+ rejectedFiles.forEach(({ file, errors: fileErrors }) => {
279
+ fileErrors.forEach((error) => {
280
+ switch (error.code) {
281
+ case 'file-too-large':
282
+ newErrors.push(`${file.name}: File is too large`);
283
+ break;
284
+ case 'file-too-small':
285
+ newErrors.push(`${file.name}: File is too small`);
286
+ break;
287
+ case 'file-invalid-type':
288
+ newErrors.push(`${file.name}: Invalid file type`);
289
+ break;
290
+ case 'too-many-files':
291
+ newErrors.push(`Too many files. Maximum is ${maxFiles}`);
292
+ break;
293
+ default:
294
+ newErrors.push(`${file.name}: ${error.message}`);
295
+ }
296
+ });
297
+ });
298
+ if (newErrors.length > 0) {
299
+ setErrors(newErrors);
300
+ return;
301
+ }
302
+ if (acceptedFiles.length === 0)
303
+ return;
304
+ // Create file items with pending status
305
+ const newFileItems = acceptedFiles.map(file => ({
306
+ id: generateId(),
307
+ file,
308
+ blobUrl: file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined,
309
+ status: 'pending',
310
+ }));
311
+ // Handle single file replacement
312
+ let updatedFiles;
313
+ if (!multiple) {
314
+ // Clean up existing file
315
+ const existingFile = files[0];
316
+ if (existingFile) {
317
+ // Revoke blob URL
318
+ if (existingFile.blobUrl) {
319
+ URL.revokeObjectURL(existingFile.blobUrl);
320
+ }
321
+ if (existingFile.key && existingFile.status === 'uploaded') {
322
+ // Delete immediately (not saved yet) - backend will handle existing files
323
+ const deletePayload = existingFile.bucket
324
+ ? { key: existingFile.key, bucket: existingFile.bucket }
325
+ : { key: existingFile.key };
326
+ deleteFromStorage(deletePayload);
327
+ }
328
+ // Note: For existing files, backend will detect deletion automatically
329
+ }
330
+ updatedFiles = newFileItems;
331
+ }
332
+ else {
333
+ updatedFiles = [...files, ...newFileItems];
334
+ }
335
+ // Update state with pending files
336
+ setFiles(updatedFiles);
337
+ // Upload files
338
+ if (uploadEndpoint) {
339
+ // Mark files as uploading
340
+ setFiles(prev => prev.map(f => newFileItems.find(nf => nf.id === f.id) ? { ...f, status: 'uploading' } : f));
341
+ // Upload all new files and collect results
342
+ const uploadResults = [];
343
+ for (const fileItem of newFileItems) {
344
+ const result = await uploadFile(fileItem.file);
345
+ uploadResults.push({ id: fileItem.id, result });
346
+ }
347
+ // Build the final file list
348
+ const finalFiles = [];
349
+ // Start with existing/previously uploaded files (for multiple mode)
350
+ if (multiple) {
351
+ for (const f of updatedFiles) {
352
+ // Keep files that aren't part of this upload batch
353
+ if (!newFileItems.find(nf => nf.id === f.id)) {
354
+ finalFiles.push(f);
355
+ }
356
+ }
357
+ }
358
+ // Add newly uploaded files with their results
359
+ for (const fileItem of newFileItems) {
360
+ const uploadResult = uploadResults.find(r => r.id === fileItem.id);
361
+ if (uploadResult?.result?.data?.url && uploadResult?.result?.data?.key) {
362
+ // Revoke blob URL since we have server URL now
363
+ if (fileItem.blobUrl) {
364
+ URL.revokeObjectURL(fileItem.blobUrl);
365
+ }
366
+ // Create new object explicitly to avoid any issues with spread
367
+ // Extract bucket from formatted data if available
368
+ const bucketName = bucket;
369
+ finalFiles.push({
370
+ id: fileItem.id,
371
+ file: fileItem.file,
372
+ key: uploadResult.result.data.key,
373
+ bucket: bucketName,
374
+ url: uploadResult.result.data.url,
375
+ status: 'uploaded',
376
+ });
377
+ }
378
+ else {
379
+ finalFiles.push({
380
+ id: fileItem.id,
381
+ file: fileItem.file,
382
+ blobUrl: fileItem.blobUrl,
383
+ status: 'error',
384
+ error: 'Upload failed',
385
+ });
386
+ }
387
+ }
388
+ // Update state and form value separately (not inside setFiles callback)
389
+ setFiles(finalFiles);
390
+ updateFormValue(finalFiles);
391
+ }
392
+ else {
393
+ // No upload endpoint - just update state
394
+ setFiles(updatedFiles);
395
+ }
396
+ }, [files, multiple, maxFiles, uploadEndpoint, uploadFile, deleteFromStorage, updateFormValue]);
397
+ /**
398
+ * Remove a file
399
+ * Backend will automatically detect deletions by comparing with existing record
400
+ */
401
+ const removeFile = useCallback(async (fileId) => {
402
+ const fileToRemove = files.find(f => f.id === fileId);
403
+ if (!fileToRemove)
404
+ return;
405
+ // Revoke blob URL
406
+ if (fileToRemove.blobUrl) {
407
+ URL.revokeObjectURL(fileToRemove.blobUrl);
408
+ }
409
+ if (fileToRemove.key && fileToRemove.status === 'uploaded') {
410
+ // Delete immediately (not saved to DB yet) - backend will handle existing files
411
+ const deletePayload = fileToRemove.bucket
412
+ ? { key: fileToRemove.key, bucket: fileToRemove.bucket }
413
+ : { key: fileToRemove.key };
414
+ const deleted = await deleteFromStorage(deletePayload);
415
+ if (!deleted) {
416
+ setErrors(['Failed to delete file from bucket']);
417
+ return;
418
+ }
419
+ }
420
+ // Note: For existing files, backend will detect deletion automatically
421
+ // Update files state
422
+ const updatedFiles = files.filter(f => f.id !== fileId);
423
+ setFiles(updatedFiles);
424
+ // Update form value - backend will detect deletions
425
+ updateFormValue(updatedFiles);
426
+ }, [files, deleteFromStorage, updateFormValue]);
427
+ // Calculate upload limits
428
+ const validFileCount = files.filter(f => f.status !== 'error').length;
429
+ const maxAllowed = multiple ? maxFiles || Infinity : 1;
430
+ const remainingSlots = Math.max(0, maxAllowed - validFileCount);
431
+ const isAtLimit = remainingSlots <= 0;
432
+ // Dropzone config
433
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({
434
+ onDrop,
435
+ accept: acceptedFileTypes.length > 0
436
+ ? acceptedFileTypes.reduce((acc, type) => ({ ...acc, [type]: [] }), {})
437
+ : undefined,
438
+ maxSize: maxSize ? maxSize * 1024 : undefined,
439
+ minSize: minSize ? minSize * 1024 : undefined,
440
+ multiple,
441
+ maxFiles: remainingSlots,
442
+ disabled: disabled || isAtLimit,
443
+ });
444
+ // Get display URL for a file
445
+ const getDisplayUrl = (file) => file.url || file.blobUrl;
446
+ // Get display name for a file
447
+ const getDisplayName = (file) => {
448
+ if (file.file?.name)
449
+ return file.file.name;
450
+ if (file.url)
451
+ return file.url.split('/').pop() || 'File';
452
+ if (file.key)
453
+ return file.key.split('/').pop() || 'File';
454
+ return 'File';
455
+ };
456
+ const openEditPreview = (url, type) => {
457
+ setEditPreviewUrl(url);
458
+ setEditPreviewType(type);
459
+ setEditPreviewOpen(true);
460
+ };
461
+ return (_jsxs("div", { className: "space-y-2", children: [label && (_jsxs("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300", children: [label, isRequired && _jsx("span", { className: "text-red-500 dark:text-red-400 ml-1", children: "*" })] })), helperText && _jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: helperText }), _jsx(HintDisplay, { hint: hint, hintIcon: hintIcon, hintColor: hintColor }), isAtLimit ? (_jsxs("div", { className: "border-2 border-dashed rounded-lg p-6 text-center border-border bg-gray-50 dark:bg-gray-800/50", children: [_jsx(Check, { className: "mx-auto h-12 w-12 text-green-500 dark:text-green-400", strokeWidth: 1.5 }), _jsx("p", { className: "mt-2 text-sm text-gray-600 dark:text-gray-400", children: multiple ? (_jsxs(_Fragment, { children: ["Maximum of ", _jsx("span", { className: "font-semibold", children: maxFiles }), " files reached"] })) : (_jsx(_Fragment, { children: translate('core:file.uploaded') })) }), _jsxs("p", { className: "mt-1 text-xs text-gray-500", children: ["Remove ", multiple ? 'a file' : 'the file', " to upload a new one"] })] })) : (_jsxs("div", { ...getRootProps(), className: `
462
+ border-2 border-dashed rounded-lg p-6 text-center cursor-pointer transition-colors
463
+ ${isDragActive ? 'border-accent bg-accent-soft dark:bg-accent-soft' : 'border-border hover:border-gray-400'}
464
+ ${disabled ? 'opacity-50 cursor-not-allowed' : ''}
465
+ `, children: [_jsx("input", { ...getInputProps() }), _jsx(Upload, { className: "mx-auto h-12 w-12 text-gray-400 dark:text-gray-500", strokeWidth: 1.5 }), _jsx("p", { className: "mt-2 text-sm text-gray-600 dark:text-gray-400", children: isDragActive ? (_jsx("span", { className: "font-semibold text-accent", children: translate('core:file.drop_here') })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-semibold text-accent", children: translate('core:file.click_to_upload') }), ' ', "or drag and drop"] })) }), _jsxs("p", { className: "mt-1 text-xs text-gray-500", children: [acceptedFileTypes.length > 0 ? acceptedFileTypes.join(', ') : 'Any file type', maxSize && ` • Max ${maxSize}KB`, multiple && maxFiles && ` • ${validFileCount}/${maxFiles} files`] })] })), (errors.length > 0 || fieldError) && (_jsxs("div", { className: "space-y-1", children: [errors.map((error, index) => (_jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: error }, index))), fieldError && (_jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: fieldError.message }))] })), files.length > 0 && (_jsx("div", { className: "space-y-2 mt-4", children: files.map(file => {
466
+ const displayUrl = getDisplayUrl(file);
467
+ const displayName = getDisplayName(file);
468
+ const isImage = (displayUrl && isImageUrl(displayUrl)) || file.file?.type?.startsWith('image/');
469
+ const isVideo = (displayUrl && isVideoUrl(displayUrl)) || file.file?.type?.startsWith('video/');
470
+ const isAudio = (displayUrl && isAudioUrl(displayUrl)) || file.file?.type?.startsWith('audio/');
471
+ const isLoading = file.status === 'pending' || file.status === 'uploading';
472
+ const hasError = file.status === 'error';
473
+ return (_jsxs("div", { className: `flex items-center justify-between p-3 bg-muted rounded-lg border border-border
474
+ ${isLoading ? 'opacity-60' : ''}
475
+ ${hasError ? 'border-red-500 dark:border-red-400' : ''}
476
+ `, children: [_jsxs("div", { className: "flex items-center space-x-3 flex-1 min-w-0", children: [displayUrl && (isImage || isVideo || isAudio) ? (_jsx("button", { type: "button", onClick: () => openEditPreview(displayUrl, isVideo ? 'video' : isAudio ? 'audio' : 'image'), className: "h-14 w-14 rounded overflow-hidden flex items-center justify-center bg-muted hover:opacity-80 transition-opacity", children: isImage ? (_jsx("img", { src: displayUrl, alt: displayName, className: "h-full w-full object-cover" })) : isVideo ? (_jsx("div", { className: "h-full w-full flex items-center justify-center bg-black text-white text-xs", children: _jsx("span", { className: "px-1", children: translate('core:file.video') }) })) : (_jsx("div", { className: "h-full w-full flex items-center justify-center bg-linear-to-r from-blue-600 to-purple-600 text-white text-xs", children: _jsx("span", { className: "px-1", children: translate('core:file.audio') }) })) })) : (_jsx("div", { className: "h-10 w-10 bg-muted rounded flex items-center justify-center", children: _jsx(File, { className: "h-6 w-6 text-gray-400 dark:text-gray-500" }) })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate", children: displayName }), file.status === 'pending' && (_jsxs("p", { className: "text-xs text-gray-500 flex items-center gap-1", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Waiting..."] })), file.status === 'uploading' && (_jsxs("p", { className: "text-xs text-accent flex items-center gap-1", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin" }), "Uploading..."] })), file.status === 'error' && (_jsx("p", { className: "text-xs text-red-500 dark:text-red-400", children: file.error || translate('core:common.error') })), file.status === 'uploaded' && (_jsx("p", { className: "text-xs text-green-500 dark:text-green-400", children: translate('core:file.saved') })), file.status === 'existing' && (_jsx("p", { className: "text-xs text-green-500 dark:text-green-400", children: translate('core:file.saved') })), file.file && file.status !== 'error' && (_jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: formatFileSize(file.file.size) }))] })] }), _jsx("button", { type: "button", onClick: () => removeFile(file.id), className: "ml-3 text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 focus:outline-none", disabled: disabled || isLoading, children: _jsx(Trash2, { className: "h-5 w-5" }) })] }, file.id));
477
+ }) })), editPreviewUrl && (_jsx(MediaPreviewModal, { isOpen: editPreviewOpen, onClose: () => setEditPreviewOpen(false), mediaUrl: editPreviewUrl, mediaType: editPreviewType, title: typeof label === 'string' ? label : undefined, autoplay: editPreviewType === 'video' || editPreviewType === 'audio', controls: true }))] }));
478
+ }
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ export interface GlobalSearchResult {
3
+ _id: string;
4
+ title: string;
5
+ featuredImage?: {
6
+ url: string;
7
+ key: string;
8
+ bucket: string;
9
+ };
10
+ record: Record<string, unknown>;
11
+ }
12
+ export interface GlobalSearchResourceResults {
13
+ label: string;
14
+ pluralLabel: string;
15
+ icon?: string;
16
+ results: GlobalSearchResult[];
17
+ }
18
+ export interface GlobalSearchProps {
19
+ apiBaseUrl: string;
20
+ onResultClick?: (resourceSlug: string, recordId: string) => void;
21
+ }
22
+ export declare function GlobalSearch({ apiBaseUrl, onResultClick }: GlobalSearchProps): React.JSX.Element;