@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,111 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { FieldRenderer } from '../FieldRenderer';
4
+ import { Icon } from './utils/Icon';
5
+ import { ChevronRight, ChevronDown } from 'lucide-react';
6
+ import { getFieldLayoutClasses } from './utils/layoutHelpers';
7
+ // Section background by depth; no bg-muted — direct opacity scale for light and dark.
8
+ const SECTION_BG_LIGHT = [
9
+ 'bg-black/[0.04]',
10
+ 'bg-black/[0.08]',
11
+ 'bg-black/[0.12]',
12
+ 'bg-black/[0.16]',
13
+ 'bg-black/[0.20]',
14
+ 'bg-black/[0.25]',
15
+ 'bg-black/[0.30]',
16
+ 'bg-black/[0.35]',
17
+ ];
18
+ const SECTION_BG_DARK = [
19
+ 'dark:bg-black/35',
20
+ 'dark:bg-black/50',
21
+ 'dark:bg-black/62',
22
+ 'dark:bg-black/72',
23
+ 'dark:bg-black/80',
24
+ 'dark:bg-black/87',
25
+ 'dark:bg-black/93',
26
+ 'dark:bg-black',
27
+ ];
28
+ export function SectionField({ heading, description, icon, collapsible, collapsed: initialCollapsed, compact, aside, mode, schema, columns, disabled, value, _recordData, operation, apiBaseUrl, resource, isLastSectionInParent, sectionDepth = 0, }) {
29
+ // Default to collapsed if not specified
30
+ const [isCollapsed, setIsCollapsed] = React.useState(initialCollapsed !== undefined ? initialCollapsed : true);
31
+ // In view mode, sections are always expanded and not collapsible
32
+ const isViewMode = mode === 'view';
33
+ const viewCollapsed = false;
34
+ if (!heading && !description) {
35
+ // Section without header - just a visual separator
36
+ return _jsx("div", { className: "my-6 border-t border-gray-200 dark:border-gray-700" });
37
+ }
38
+ const toggleCollapse = () => {
39
+ if (collapsible && !isViewMode) {
40
+ setIsCollapsed(!isCollapsed);
41
+ }
42
+ };
43
+ // In view mode, use viewCollapsed (always false)
44
+ const displayCollapsed = isViewMode ? viewCollapsed : isCollapsed;
45
+ // In view mode, use _recordData if provided, otherwise use value
46
+ const recordData = mode === 'view' && _recordData ? _recordData : value || {};
47
+ // Get layout classes for nested fields
48
+ const fieldLayoutClasses = getFieldLayoutClasses(columns);
49
+ // At each level, the last section gets smaller padding and no border; others get full padding and border.
50
+ // Background gets darker for each nesting level; supports arbitrary depth (capped at array length).
51
+ const hasNestedSections = schema && Array.isArray(schema) && schema.some((f) => f.type === 'section');
52
+ const isLast = Boolean(isLastSectionInParent);
53
+ const depthIndex = Math.min(sectionDepth, SECTION_BG_LIGHT.length - 1);
54
+ const bgByDepth = `${SECTION_BG_LIGHT[depthIndex]} ${SECTION_BG_DARK[depthIndex]}`;
55
+ // Dark mode uses solid colors from styles.css (.dark .section-depth-bg[data-section-depth="1"] etc.)
56
+ const bodyWrapperClass = `${bgByDepth} section-depth-bg`;
57
+ const bodyWrapperData = { 'data-section-depth': depthIndex + 1 }; // CSS uses "1"–"8"
58
+ // Last section: same padding as others, only border-bottom removed.
59
+ const bodyClasses = isLast
60
+ ? `rounded-lg ${bodyWrapperClass} p-4 border border-gray-100 dark:border-gray-700/50 border-b-0 mb-2`
61
+ : `rounded-lg ${bodyWrapperClass} p-4 border border-gray-100 dark:border-gray-700/50 mb-2`;
62
+ const outerClasses = hasNestedSections && !isLast ? (compact ? 'my-4' : 'my-6') : '';
63
+ return (_jsx("div", { className: outerClasses, children: _jsxs("div", { className: `${aside ? 'flex gap-6' : ''}`, children: [_jsxs("div", { className: `${aside ? 'w-1/3' : 'mb-4'}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [icon && _jsx(Icon, { name: icon, size: 20, className: "text-gray-500 dark:text-gray-400" }), heading && (_jsxs("h3", { className: `font-semibold ${aside ? 'text-lg' : 'text-xl'} text-gray-900 dark:text-gray-100 ${collapsible && !isViewMode
64
+ ? 'cursor-pointer hover:text-gray-700 dark:hover:text-gray-300 flex items-center gap-2'
65
+ : ''}`, onClick: toggleCollapse, children: [heading, collapsible &&
66
+ !isViewMode &&
67
+ (displayCollapsed ? (_jsx(ChevronRight, { size: 16, className: "text-gray-500 dark:text-gray-400" })) : (_jsx(ChevronDown, { size: 16, className: "text-gray-500 dark:text-gray-400" })))] }))] }), description && _jsx("p", { className: "mt-1 text-sm text-gray-600 dark:text-gray-400", children: description })] }), aside ? (_jsx("div", { className: "flex-1", children: schema &&
68
+ Array.isArray(schema) &&
69
+ !displayCollapsed &&
70
+ (() => {
71
+ const lastSectionIndex = schema.reduce((last, f, i) => (f.type === 'section' ? i : last), -1);
72
+ return (_jsx("div", { className: bodyClasses, ...bodyWrapperData, children: _jsx("div", { className: fieldLayoutClasses, children: schema.map((field, index) => {
73
+ const isSection = field.type === 'section';
74
+ const nestedField = {
75
+ ...field,
76
+ disabled: disabled || field.disabled,
77
+ mode: mode || field.mode,
78
+ // Only the single section at lastSectionIndex is "last"; others get false so border shows.
79
+ isLastSectionInParent: isSection
80
+ ? lastSectionIndex >= 0 && index === lastSectionIndex
81
+ : undefined,
82
+ sectionDepth: isSection ? sectionDepth + 1 : undefined,
83
+ };
84
+ const nestedValue = mode === 'view' && field.name
85
+ ? recordData[field.name]
86
+ : undefined;
87
+ return (_jsx(FieldRenderer, { field: nestedField, mode: mode, value: nestedValue, operation: operation, apiBaseUrl: apiBaseUrl, resource: resource }, index));
88
+ }) }) }));
89
+ })() })) : (_jsxs(_Fragment, { children: [schema &&
90
+ Array.isArray(schema) &&
91
+ !displayCollapsed &&
92
+ (() => {
93
+ const lastSectionIndex = schema.reduce((last, f, i) => (f.type === 'section' ? i : last), -1);
94
+ return (_jsx("div", { className: !isLast && hasNestedSections ? `mt-4 ${bodyClasses}` : bodyClasses, ...bodyWrapperData, children: _jsx("div", { className: fieldLayoutClasses, children: schema.map((field, index) => {
95
+ const isSection = field.type === 'section';
96
+ const nestedField = {
97
+ ...field,
98
+ disabled: disabled || field.disabled,
99
+ mode: mode || field.mode,
100
+ isLastSectionInParent: isSection
101
+ ? lastSectionIndex >= 0 && index === lastSectionIndex
102
+ : undefined,
103
+ sectionDepth: isSection ? sectionDepth + 1 : undefined,
104
+ };
105
+ const nestedValue = mode === 'view' && field.name
106
+ ? recordData[field.name]
107
+ : undefined;
108
+ return (_jsx(FieldRenderer, { field: nestedField, mode: mode, value: nestedValue, operation: operation, apiBaseUrl: apiBaseUrl, resource: resource }, index));
109
+ }) }) }));
110
+ })(), hasNestedSections && !isLast && (_jsx("div", { className: "mt-4 border-t border-gray-200 dark:border-gray-700" }))] }))] }) }));
111
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { FieldProps } from '../types';
3
+ /**
4
+ * Select field component
5
+ * Renders single or multi-select dropdowns with optional creatable functionality
6
+ * Supports relationship-based data fetching from API
7
+ */
8
+ export declare function SelectField(props: FieldProps): React.JSX.Element;
@@ -0,0 +1,523 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { useFormContext, useWatch } from 'react-hook-form';
4
+ import { getFieldError } from '../utils/fieldErrors';
5
+ import { useValidation } from '../hooks/useValidation';
6
+ import { cn } from '../utils/classNames';
7
+ import { HintDisplay } from './utils/HintDisplay';
8
+ import { Icon } from './utils/Icon';
9
+ import { ResourceFormModal } from './modals/ResourceFormModal';
10
+ import { executeSerializedFunction } from '../runtime/serializedFunctions';
11
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
12
+ import { formatSelectLabel } from '../utils/formatValue';
13
+ import { authenticatedFetch } from '../api/authenticatedFetch';
14
+ import { translate } from '../i18n/activeLocale';
15
+ /**
16
+ * Component for rendering SelectField in view mode with relationship data fetching
17
+ */
18
+ function SelectFieldViewMode({ value, isMultiple, relationship, label, optionLabelFormatter, apiBaseUrl, }) {
19
+ const [displayValue, setDisplayValue] = useState('-');
20
+ const [isLoading, setIsLoading] = useState(false);
21
+ useEffect(() => {
22
+ const fetchRelationshipData = async () => {
23
+ if (!value || (isMultiple && (!Array.isArray(value) || value.length === 0))) {
24
+ setDisplayValue('-');
25
+ return;
26
+ }
27
+ // Extract IDs from value
28
+ const valueIds = isMultiple
29
+ ? (Array.isArray(value) ? value : []).map((v) => {
30
+ if (typeof v === 'object' && v !== null) {
31
+ return v._id || v.id || String(v);
32
+ }
33
+ return String(v);
34
+ })
35
+ : typeof value === 'object' && value !== null
36
+ ? [value._id || value.id || String(value)]
37
+ : [String(value)];
38
+ if (valueIds.length === 0) {
39
+ setDisplayValue('-');
40
+ return;
41
+ }
42
+ // If all values are already objects with titleAttribute, use them directly
43
+ if (isMultiple && Array.isArray(value)) {
44
+ const allHaveTitle = value.every((v) => typeof v === 'object' && v !== null && v[relationship.titleAttribute]);
45
+ if (allHaveTitle) {
46
+ const formatted = value
47
+ .map((v) => {
48
+ const title = v[relationship.titleAttribute] || String(v);
49
+ if (optionLabelFormatter) {
50
+ const formattedTitle = executeSerializedFunction(optionLabelFormatter, v._id || v.id || String(v), v);
51
+ return formattedTitle !== null && formattedTitle !== undefined
52
+ ? String(formattedTitle)
53
+ : title;
54
+ }
55
+ return title;
56
+ })
57
+ .join(', ');
58
+ setDisplayValue(formatted);
59
+ return;
60
+ }
61
+ }
62
+ else if (!isMultiple &&
63
+ typeof value === 'object' &&
64
+ value !== null &&
65
+ value[relationship.titleAttribute]) {
66
+ const title = value[relationship.titleAttribute];
67
+ if (optionLabelFormatter) {
68
+ const formattedTitle = executeSerializedFunction(optionLabelFormatter, value._id || value.id || String(value), value);
69
+ setDisplayValue(formattedTitle !== null && formattedTitle !== undefined ? String(formattedTitle) : title);
70
+ }
71
+ else {
72
+ setDisplayValue(title);
73
+ }
74
+ return;
75
+ }
76
+ // Need to fetch records
77
+ setIsLoading(true);
78
+ try {
79
+ const resourceSlug = relationship.resource || relationship.name;
80
+ const apiUrl = apiBaseUrl;
81
+ const fetchPromises = valueIds.map(async (id) => {
82
+ try {
83
+ const response = await authenticatedFetch(`${apiUrl}/${resourceSlug}/${id}`, {
84
+ headers: {},
85
+ }, apiUrl.substring(0, apiUrl.lastIndexOf('/')));
86
+ if (response.ok) {
87
+ const result = await response.json();
88
+ const record = result.data || result;
89
+ return { id, record };
90
+ }
91
+ }
92
+ catch (error) {
93
+ console.error(`Error fetching record ${id}:`, error);
94
+ }
95
+ return null;
96
+ });
97
+ const results = await Promise.all(fetchPromises);
98
+ const validResults = results.filter((r) => r !== null);
99
+ if (validResults.length === 0) {
100
+ setDisplayValue(valueIds.join(', '));
101
+ return;
102
+ }
103
+ // Format the display value
104
+ const formatted = validResults
105
+ .map(({ id, record }) => {
106
+ const title = record[relationship.titleAttribute] || id;
107
+ if (optionLabelFormatter) {
108
+ const formattedTitle = executeSerializedFunction(optionLabelFormatter, id, record);
109
+ return formattedTitle !== null && formattedTitle !== undefined
110
+ ? String(formattedTitle)
111
+ : title;
112
+ }
113
+ return title;
114
+ })
115
+ .join(', ');
116
+ setDisplayValue(formatted);
117
+ }
118
+ catch (error) {
119
+ console.error('Error fetching relationship data:', error);
120
+ // Fallback to showing IDs
121
+ setDisplayValue(valueIds.join(', '));
122
+ }
123
+ finally {
124
+ setIsLoading(false);
125
+ }
126
+ };
127
+ fetchRelationshipData();
128
+ }, [value, isMultiple, relationship, optionLabelFormatter, apiBaseUrl]);
129
+ if (isLoading) {
130
+ return (_jsx(ViewFieldWrapper, { label: label, children: _jsx("span", { className: "text-fg-secondary", children: translate('core:select.loading') }) }));
131
+ }
132
+ return (_jsx(ViewFieldWrapper, { label: label, children: _jsx("span", { dangerouslySetInnerHTML: { __html: displayValue || '-' } }) }));
133
+ }
134
+ /**
135
+ * Select field component
136
+ * Renders single or multi-select dropdowns with optional creatable functionality
137
+ * Supports relationship-based data fetching from API
138
+ */
139
+ export function SelectField(props) {
140
+ // View mode: render formatted display
141
+ if (props.mode === 'view') {
142
+ const value = props.value;
143
+ const isMultiple = props.isMultiple || props.multiple;
144
+ const hasRelationship = !!props.relationship;
145
+ // For relationship-based selects, we need to fetch the related records if value is just an ID
146
+ if (hasRelationship && props.relationship) {
147
+ // Use a component that fetches relationship data
148
+ return (_jsx(SelectFieldViewMode, { value: value, isMultiple: isMultiple, relationship: props.relationship, label: props.label, optionLabelFormatter: props.optionLabelFormatter, apiBaseUrl: props.apiBaseUrl }));
149
+ }
150
+ // For non-relationship selects, use static options
151
+ const displayValue = formatSelectLabel(value, props.options, isMultiple);
152
+ return _jsx(ViewFieldWrapper, { label: props.label, children: displayValue });
153
+ }
154
+ const { register, setValue, control, formState: { errors }, } = useFormContext();
155
+ const validation = useValidation(props.validation?.rules || [], props.operation, props.name);
156
+ const error = getFieldError(errors, props.name);
157
+ const hasError = !!error;
158
+ const isMultiple = props.isMultiple || props.multiple;
159
+ const isCreatable = props.creatable;
160
+ const isNative = props.native;
161
+ const hasRelationship = !!props.relationship;
162
+ // Watch current value for multi-select - let the form handle defaults
163
+ const rawValue = useWatch({ control, name: props.name });
164
+ // Normalize value: if it's an object (from edit mode), extract the ID
165
+ const normalizeValue = (value) => {
166
+ if (!value)
167
+ return isMultiple ? [] : '';
168
+ if (isMultiple) {
169
+ if (!Array.isArray(value))
170
+ return [];
171
+ return value.map((v) => {
172
+ if (typeof v === 'object' && v !== null) {
173
+ return v._id || v.id || String(v);
174
+ }
175
+ return String(v);
176
+ });
177
+ }
178
+ else {
179
+ if (typeof value === 'object' && value !== null) {
180
+ return value._id || value.id || String(value);
181
+ }
182
+ return String(value);
183
+ }
184
+ };
185
+ const currentValue = normalizeValue(rawValue) || (isMultiple ? [] : '');
186
+ // Update form value if it was an object (normalize it to ID)
187
+ useEffect(() => {
188
+ if (rawValue && typeof rawValue === 'object' && !Array.isArray(rawValue)) {
189
+ const normalized = normalizeValue(rawValue);
190
+ if (normalized !== rawValue) {
191
+ setValue(props.name, normalized, { shouldValidate: false });
192
+ }
193
+ }
194
+ else if (rawValue && Array.isArray(rawValue) && rawValue.some((v) => typeof v === 'object')) {
195
+ const normalized = normalizeValue(rawValue);
196
+ setValue(props.name, normalized, { shouldValidate: false });
197
+ }
198
+ }, [rawValue, props.name, setValue]);
199
+ const [isOpen, setIsOpen] = useState(false);
200
+ const [searchTerm, setSearchTerm] = useState('');
201
+ const [inputValue, setInputValue] = useState('');
202
+ const [relationshipOptions, setRelationshipOptions] = useState({});
203
+ const [relationshipRecords, setRelationshipRecords] = useState({});
204
+ // Track which records were individually fetched (for edit mode) - these should be formatted
205
+ const [individuallyFetchedIds, setIndividuallyFetchedIds] = useState(new Set());
206
+ // Cache formatted labels for individually fetched records to prevent re-rendering
207
+ const [formattedLabels, setFormattedLabels] = useState({});
208
+ const [isLoadingRelationship, setIsLoadingRelationship] = useState(false);
209
+ const [showCreateModal, setShowCreateModal] = useState(false);
210
+ const dropdownRef = useRef(null);
211
+ // Format option label using custom formatter if provided
212
+ const formatOptionLabel = (value, label, record) => {
213
+ if (props.optionLabelFormatter && record) {
214
+ const result = executeSerializedFunction(props.optionLabelFormatter, value, record);
215
+ return result !== null && result !== undefined ? String(result) : label;
216
+ }
217
+ return label;
218
+ };
219
+ // Fetch relationship data when component mounts or search term changes
220
+ useEffect(() => {
221
+ if (!hasRelationship || !props.relationship)
222
+ return;
223
+ const fetchRelationshipData = async () => {
224
+ setIsLoadingRelationship(true);
225
+ try {
226
+ const { resource, titleAttribute } = props.relationship;
227
+ const resourceSlug = resource || props.relationship.name;
228
+ if (!resourceSlug) {
229
+ throw new Error('Resource slug is required for relationship data fetching');
230
+ }
231
+ const apiBaseUrl = props.apiBaseUrl;
232
+ const url = `${apiBaseUrl}/${resourceSlug}/list`;
233
+ const body = { perPage: 50 };
234
+ if (searchTerm) {
235
+ body.search = searchTerm;
236
+ }
237
+ const response = await authenticatedFetch(url, {
238
+ method: 'POST',
239
+ headers: { 'Content-Type': 'application/json' },
240
+ body: JSON.stringify(body),
241
+ }, apiBaseUrl);
242
+ if (!response.ok) {
243
+ throw new Error(`Failed to fetch relationship data: ${response.status}`);
244
+ }
245
+ const result = await response.json();
246
+ const data = result.data || [];
247
+ const options = {};
248
+ const records = {};
249
+ data.forEach((item) => {
250
+ const id = item._id || item.id;
251
+ const title = item[titleAttribute] || id;
252
+ options[id] = title;
253
+ records[id] = item;
254
+ });
255
+ // Replace with API results so the list reflects current search; preserve labels for selected value(s) so chips still display
256
+ const valueIds = isMultiple
257
+ ? Array.isArray(currentValue)
258
+ ? currentValue
259
+ : []
260
+ : currentValue
261
+ ? [currentValue]
262
+ : [];
263
+ setRelationshipOptions(prev => {
264
+ const next = { ...options };
265
+ valueIds.forEach((id) => {
266
+ if (prev[id])
267
+ next[id] = prev[id];
268
+ });
269
+ return next;
270
+ });
271
+ // Replace records with API results; preserve individually fetched ones so formatted labels are kept
272
+ setRelationshipRecords(prev => {
273
+ const next = { ...records };
274
+ valueIds.forEach((id) => {
275
+ if (individuallyFetchedIds.has(id) && prev[id])
276
+ next[id] = prev[id];
277
+ });
278
+ return next;
279
+ });
280
+ }
281
+ catch (error) {
282
+ console.error('Error fetching relationship data:', error);
283
+ setRelationshipOptions({});
284
+ }
285
+ finally {
286
+ setIsLoadingRelationship(false);
287
+ }
288
+ };
289
+ const timeoutId = setTimeout(fetchRelationshipData, searchTerm ? 300 : 0);
290
+ return () => clearTimeout(timeoutId);
291
+ }, [hasRelationship, searchTerm, props.relationship, individuallyFetchedIds, currentValue, isMultiple]);
292
+ // Fetch related record(s) when editing (if we have a current value but no record data)
293
+ useEffect(() => {
294
+ if (!hasRelationship || !props.relationship || !currentValue)
295
+ return;
296
+ const valueIds = isMultiple ? (Array.isArray(currentValue) ? currentValue : []) : [currentValue];
297
+ const missingIds = valueIds.filter((id) => !relationshipRecords[id]);
298
+ if (missingIds.length > 0) {
299
+ const fetchRelatedRecords = async () => {
300
+ try {
301
+ const { resource, titleAttribute } = props.relationship;
302
+ const resourceSlug = resource || props.relationship.name;
303
+ const apiBaseUrl = props.apiBaseUrl;
304
+ const fetchPromises = missingIds.map(async (id) => {
305
+ try {
306
+ const response = await authenticatedFetch(`${apiBaseUrl}/${resourceSlug}/${id}`, {
307
+ headers: {},
308
+ }, apiBaseUrl);
309
+ if (response.ok) {
310
+ const result = await response.json();
311
+ // Handle new response structure: { data, metadata }
312
+ const record = result.data || result;
313
+ return { id, record };
314
+ }
315
+ }
316
+ catch (error) {
317
+ console.error(`Error fetching record ${id}:`, error);
318
+ }
319
+ return null;
320
+ });
321
+ const results = await Promise.all(fetchPromises);
322
+ const newOptions = { ...relationshipOptions };
323
+ const newRecords = { ...relationshipRecords };
324
+ const newFormattedLabels = {};
325
+ results.forEach(result => {
326
+ if (result) {
327
+ const { id, record } = result;
328
+ const title = record[titleAttribute] || id;
329
+ newOptions[id] = title;
330
+ newRecords[id] = record;
331
+ // Pre-format and cache the label for this individually fetched record
332
+ const formatted = formatOptionLabel(id, title, record);
333
+ newFormattedLabels[id] = formatted;
334
+ }
335
+ });
336
+ setRelationshipOptions(newOptions);
337
+ setRelationshipRecords(newRecords);
338
+ // Mark these records as individually fetched and cache their formatted labels
339
+ setIndividuallyFetchedIds(prev => {
340
+ const newSet = new Set(prev);
341
+ results.forEach(result => {
342
+ if (result)
343
+ newSet.add(result.id);
344
+ });
345
+ return newSet;
346
+ });
347
+ setFormattedLabels(prev => ({ ...prev, ...newFormattedLabels }));
348
+ }
349
+ catch (error) {
350
+ console.error('Error fetching related records:', error);
351
+ }
352
+ };
353
+ fetchRelatedRecords();
354
+ }
355
+ }, [hasRelationship, currentValue, relationshipRecords, props.relationship, isMultiple]);
356
+ // Close dropdown when clicking outside
357
+ useEffect(() => {
358
+ const handleClickOutside = (event) => {
359
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
360
+ setIsOpen(false);
361
+ setSearchTerm('');
362
+ setInputValue('');
363
+ }
364
+ };
365
+ document.addEventListener('mousedown', handleClickOutside);
366
+ return () => document.removeEventListener('mousedown', handleClickOutside);
367
+ }, []);
368
+ // Use relationship options if available, otherwise use static options
369
+ const effectiveOptions = hasRelationship ? relationshipOptions : props.options || {};
370
+ // If native or not multiple and not creatable and not relationship, use native select
371
+ if (isNative || (!isMultiple && !isCreatable && !hasRelationship)) {
372
+ return (_jsxs("div", { className: "mb-4", children: [props.label && (_jsxs("label", { htmlFor: props.name, className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: [props.label, validation.required && _jsx("span", { className: "text-red-500 dark:text-red-400 ml-1", children: "*" })] })), _jsxs("select", { id: props.name, ...register(props.name, validation), disabled: props.disabled, multiple: isMultiple, className: cn('w-full px-3 py-2 border rounded-lg shadow-sm', 'k-input', 'focus:outline-none focus:ring-2 focus:ring-ring', 'transition duration-150 ease-in-out', hasError && 'border-red-500 dark:border-red-400 focus:ring-red-500 dark:focus:ring-red-400', props.disabled && 'opacity-60 cursor-not-allowed', isMultiple && 'min-h-[120px]'), children: [props.placeholder && !isMultiple && props.selectablePlaceholder !== false && (_jsx("option", { value: "", children: props.placeholder })), effectiveOptions &&
373
+ Object.entries(effectiveOptions).map(([value, label]) => (_jsx("option", { value: value, children: label }, value)))] }), hasError && _jsx("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error?.message }), props.helperText && (_jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: props.helperText })), !hasError && _jsx(HintDisplay, { hint: props.hint, hintIcon: props.hintIcon, hintColor: props.hintColor }), isMultiple && !hasError && (_jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: "Hold Ctrl/Cmd to select multiple options" }))] }));
374
+ }
375
+ // Enhanced multi-select with chips
376
+ const selectedValues = isMultiple
377
+ ? Array.isArray(currentValue)
378
+ ? currentValue.filter((v) => typeof v === 'string')
379
+ : []
380
+ : currentValue && typeof currentValue === 'string'
381
+ ? [currentValue]
382
+ : [];
383
+ const optionEntries = Object.entries(effectiveOptions);
384
+ // Filter options based on search term
385
+ // For relationship-based selects, the API already filters the results, so skip client-side filtering
386
+ const filteredOptions = hasRelationship
387
+ ? optionEntries
388
+ : optionEntries.filter(([value, label]) => {
389
+ const matchesSearch = !searchTerm || label.toLowerCase().includes(searchTerm.toLowerCase());
390
+ return matchesSearch;
391
+ });
392
+ // Check if we can create a new option
393
+ const canCreateNew = isCreatable &&
394
+ searchTerm &&
395
+ !optionEntries.some(([value, label]) => label.toLowerCase() === searchTerm.toLowerCase()) &&
396
+ !selectedValues.includes(searchTerm);
397
+ // Check if we can create a new relationship record
398
+ const canCreateRelationship = hasRelationship && props.createOptionForm;
399
+ const toggleOption = (value) => {
400
+ // When selecting a new option, format and cache its label if we have the record
401
+ const record = relationshipRecords[value];
402
+ if (record && !formattedLabels[value]) {
403
+ const label = relationshipOptions[value] || value;
404
+ const formatted = formatOptionLabel(value, label, record);
405
+ setFormattedLabels(prev => ({ ...prev, [value]: formatted }));
406
+ // Mark as individually fetched so it stays formatted
407
+ setIndividuallyFetchedIds(prev => new Set(prev).add(value));
408
+ }
409
+ if (isMultiple) {
410
+ const newValues = selectedValues.includes(value)
411
+ ? selectedValues.filter((v) => v !== value)
412
+ : [...selectedValues, value];
413
+ setValue(props.name, newValues, { shouldValidate: true });
414
+ }
415
+ else {
416
+ setValue(props.name, value, { shouldValidate: true });
417
+ setIsOpen(false);
418
+ setSearchTerm('');
419
+ }
420
+ };
421
+ const removeValue = (value) => {
422
+ if (isMultiple) {
423
+ const newValues = selectedValues.filter((v) => v !== value);
424
+ setValue(props.name, newValues, { shouldValidate: true });
425
+ }
426
+ else {
427
+ setValue(props.name, '', { shouldValidate: true });
428
+ }
429
+ };
430
+ const createNewOption = () => {
431
+ if (!canCreateNew || !searchTerm)
432
+ return;
433
+ const trimmedValue = searchTerm.trim();
434
+ if (isMultiple) {
435
+ const newValues = [...selectedValues, trimmedValue];
436
+ setValue(props.name, newValues, { shouldValidate: true });
437
+ }
438
+ else {
439
+ setValue(props.name, trimmedValue, { shouldValidate: true });
440
+ setIsOpen(false);
441
+ }
442
+ setSearchTerm('');
443
+ setInputValue('');
444
+ };
445
+ const handleCreateRelationshipSuccess = (newRecord) => {
446
+ const id = newRecord._id || newRecord.id;
447
+ const title = newRecord[props.relationship.titleAttribute] || id;
448
+ setRelationshipOptions(prev => ({ ...prev, [id]: title }));
449
+ setRelationshipRecords(prev => ({ ...prev, [id]: newRecord }));
450
+ // Format and cache the label for the newly created record
451
+ const formatted = formatOptionLabel(id, title, newRecord);
452
+ setFormattedLabels(prev => ({ ...prev, [id]: formatted }));
453
+ setIndividuallyFetchedIds(prev => new Set(prev).add(id));
454
+ if (isMultiple) {
455
+ const newValues = [...selectedValues, id];
456
+ setValue(props.name, newValues, { shouldValidate: true });
457
+ }
458
+ else {
459
+ setValue(props.name, id, { shouldValidate: true });
460
+ }
461
+ setShowCreateModal(false);
462
+ setIsOpen(false);
463
+ setSearchTerm('');
464
+ };
465
+ const handleKeyDown = (e) => {
466
+ if (e.key === 'Enter') {
467
+ e.preventDefault();
468
+ if (canCreateNew) {
469
+ createNewOption();
470
+ }
471
+ else if (filteredOptions.length === 1) {
472
+ toggleOption(filteredOptions[0][0]);
473
+ setSearchTerm('');
474
+ }
475
+ }
476
+ else if (e.key === 'Backspace' && !searchTerm && selectedValues.length > 0 && isMultiple) {
477
+ removeValue(selectedValues[selectedValues.length - 1]);
478
+ }
479
+ };
480
+ const getDisplayLabel = (value) => {
481
+ // If we have a cached formatted label for this individually fetched record, use it
482
+ if (formattedLabels[value]) {
483
+ return formattedLabels[value];
484
+ }
485
+ // Otherwise, return the plain label
486
+ return effectiveOptions[value] || value;
487
+ };
488
+ return (_jsxs("div", { className: "mb-4", children: [props.label && (_jsxs("label", { htmlFor: props.name, className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: [props.label, validation.required && _jsx("span", { className: "text-red-500 dark:text-red-400 ml-1", children: "*" })] })), _jsx("input", { type: "hidden", ...register(props.name, validation) }), _jsxs("div", { ref: dropdownRef, className: "relative", children: [_jsx("div", { onClick: () => !props.disabled && setIsOpen(!isOpen), className: cn('w-full min-h-[42px] px-3 py-2 border rounded-lg shadow-sm cursor-pointer', 'k-input', 'focus-within:outline-none focus-within:ring-2 focus-within:ring-ring ', 'transition duration-150 ease-in-out', hasError &&
489
+ 'border-red-500 dark:border-red-400 focus-within:ring-red-500 dark:focus-within:ring-red-400', props.disabled && 'opacity-60 cursor-not-allowed bg-muted'), children: _jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [selectedValues.map((value) => {
490
+ const displayLabel = getDisplayLabel(value);
491
+ const hasHTML = /<[^>]+>/.test(displayLabel);
492
+ return (_jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 rounded text-sm font-medium bg-accent-soft dark:bg-accent-soft text-accent", children: [hasHTML ? (_jsx("span", { dangerouslySetInnerHTML: { __html: displayLabel } })) : (_jsx("span", { children: displayLabel })), !props.disabled && (_jsx("button", { type: "button", onClick: e => {
493
+ e.stopPropagation();
494
+ removeValue(value);
495
+ }, className: "hover:text-accent-hover transition-colors", children: _jsx(Icon, { name: "X", size: 14 }) }))] }, value));
496
+ }), !props.disabled && (_jsx("input", { type: "text", value: searchTerm, onChange: e => {
497
+ setSearchTerm(e.target.value);
498
+ if (!isOpen)
499
+ setIsOpen(true);
500
+ }, onKeyDown: handleKeyDown, onClick: e => {
501
+ e.stopPropagation();
502
+ setIsOpen(true);
503
+ }, onFocus: () => setIsOpen(true), placeholder: selectedValues.length === 0
504
+ ? props.placeholder || translate('core:select.placeholder')
505
+ : '', className: "flex-1 min-w-[120px] outline-none bg-transparent text-fg", disabled: props.disabled })), _jsx(Icon, { name: isOpen ? 'ChevronUp' : 'ChevronDown', size: 16, className: "text-gray-400 shrink-0" })] }) }), isOpen && !props.disabled && (_jsxs("div", { className: "absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-border rounded-lg shadow-lg max-h-60 overflow-auto", children: [isLoadingRelationship && (_jsxs("div", { className: "px-3 py-2 text-sm text-fg-secondary flex items-center gap-2", children: [_jsx(Icon, { name: "Loader2", size: 16, className: "animate-spin" }), _jsx("span", { children: translate('core:select.loading') })] })), !isLoadingRelationship &&
506
+ filteredOptions.length === 0 &&
507
+ !canCreateNew &&
508
+ !canCreateRelationship && (_jsx("div", { className: "px-3 py-2 text-sm text-fg-secondary", children: searchTerm
509
+ ? translate('core:select.no_matching')
510
+ : translate('core:filters.no_options') })), !isLoadingRelationship &&
511
+ filteredOptions.map(([value, label]) => {
512
+ const record = relationshipRecords[value];
513
+ const displayLabel = formatOptionLabel(value, label, record);
514
+ const hasHTML = /<[^>]+>/.test(displayLabel);
515
+ return (_jsx("div", { onClick: () => {
516
+ toggleOption(value);
517
+ setSearchTerm('');
518
+ }, className: cn('px-3 py-2 cursor-pointer text-sm transition-colors text-fg', 'hover:bg-gray-100 dark:hover:bg-gray-700', selectedValues.includes(value) && 'bg-accent-soft text-accent'), children: _jsxs("div", { className: "flex items-center justify-between", children: [hasHTML ? (_jsx("span", { dangerouslySetInnerHTML: { __html: displayLabel } })) : (_jsx("span", { children: displayLabel })), selectedValues.includes(value) && _jsx(Icon, { name: "Check", size: 16 })] }) }, value));
519
+ }), canCreateNew && !canCreateRelationship && (_jsx("div", { onClick: createNewOption, className: cn('px-3 py-2 cursor-pointer text-sm transition-colors hover:bg-gray-100 dark:hover:bg-gray-700 text-accent font-medium', filteredOptions.length > 0 && 'border-t border-border'), children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { name: "Plus", size: 16 }), _jsx("span", { children: translate('core:select.create', { term: searchTerm }) })] }) })), canCreateRelationship && (_jsx("div", { onClick: () => {
520
+ setShowCreateModal(true);
521
+ setIsOpen(false);
522
+ }, className: cn('px-3 py-2 cursor-pointer text-sm transition-colors hover:bg-gray-100 dark:hover:bg-gray-700 text-accent font-medium', filteredOptions.length > 0 && 'border-t border-border'), children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { name: "Plus", size: 16 }), _jsx("span", { children: props.createOptionModalHeading || translate('core:select.create_new') })] }) }))] }))] }), hasError && _jsx("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error?.message }), props.helperText && _jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: props.helperText }), !hasError && _jsx(HintDisplay, { hint: props.hint, hintIcon: props.hintIcon, hintColor: props.hintColor }), canCreateRelationship && showCreateModal && (_jsx(ResourceFormModal, { isOpen: showCreateModal, onClose: () => setShowCreateModal(false), mode: "create", resourceName: props.createOptionModalHeading || translate('core:common.record'), resourceSlug: props.relationship.resource || props.relationship.name, apiBaseUrl: props.apiBaseUrl, formSchema: { type: 'form', components: props.createOptionForm || [] }, onSuccess: handleCreateRelationshipSuccess, depth: 1 }))] }));
523
+ }