@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,368 @@
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
2
+ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
3
+ import { AlertTriangle, Loader2 } from 'lucide-react';
4
+ import { useResourceModal } from '../contexts/ResourceModalContext';
5
+ import { PanelMetadataProvider } from '../contexts/PanelMetadataContext';
6
+ import { PanelProviders } from '../contexts/PanelProviders';
7
+ import { Header } from './layout/Header';
8
+ import { Sidebar, ResourceMetadata } from './layout/Sidebar';
9
+ import { ResourceListPage } from '../pages/ResourceListPage';
10
+ import { PageRenderer } from './pages/PageRenderer';
11
+ import { ResourceModalRenderer } from './ResourceModalRenderer';
12
+ import { ErrorBoundary } from './errors/ErrorBoundary';
13
+ import { Slot } from '../slots/Slot';
14
+ import { PillButton } from './ui/PillButton';
15
+ import { AdminPanelProps } from '../types';
16
+ import { authenticatedFetch } from '../api/authenticatedFetch';
17
+ import { useTranslation } from '../i18n/useTranslation';
18
+ import { useLocale } from '../i18n/useLocale';
19
+
20
+ export interface PageMetadata {
21
+ slug: string;
22
+ label: string;
23
+ icon?: string;
24
+ navigationGroup?: string;
25
+ navigationSort?: number;
26
+ hidden?: boolean;
27
+ }
28
+
29
+ interface PanelMetadata {
30
+ id: string;
31
+ title?: string;
32
+ icon?: string;
33
+ favicon?: string;
34
+ basePath: string;
35
+ resources: ResourceMetadata[];
36
+ pages: PageMetadata[];
37
+ globalSearchAvailable: boolean;
38
+ /** Names of custom components registered server-side (informational) */
39
+ customFields?: string[];
40
+ customColumns?: string[];
41
+ customWidgets?: string[];
42
+ customBlocks?: string[];
43
+ }
44
+
45
+ function AdminPanelContent({ apiBaseUrl, panelId }: { apiBaseUrl: string; panelId?: string }) {
46
+ const { t } = useTranslation();
47
+ const { locale } = useLocale();
48
+ const [darkMode, setDarkMode] = useState(() => {
49
+ const stored = localStorage.getItem('darkMode');
50
+ if (stored !== null) {
51
+ return stored === 'true';
52
+ }
53
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
54
+ });
55
+
56
+ const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
57
+
58
+ const [panelMetadata, setPanelMetadata] = useState<PanelMetadata | null>(null);
59
+ const [loading, setLoading] = useState(true);
60
+ const [error, setError] = useState<string | null>(null);
61
+
62
+ // Apply dark mode to document
63
+ useEffect(() => {
64
+ if (darkMode) {
65
+ document.documentElement.classList.add('dark');
66
+ localStorage.setItem('darkMode', 'true');
67
+ } else {
68
+ document.documentElement.classList.remove('dark');
69
+ localStorage.setItem('darkMode', 'false');
70
+ }
71
+ }, [darkMode]);
72
+
73
+ // Merge badge maps into panel metadata (resources and pages)
74
+ const mergeBadgesIntoMeta = (
75
+ meta: PanelMetadata,
76
+ badges: {
77
+ resources?: Record<string, { value: string | number | null; color?: string } | null>;
78
+ pages?: Record<string, { value: string | number | null; color?: string } | null>;
79
+ },
80
+ ): PanelMetadata => ({
81
+ ...meta,
82
+ resources: (meta.resources || []).map(r => {
83
+ const b = badges.resources?.[r.slug];
84
+ return { ...r, badge: b?.value ?? null, badgeColor: b?.color };
85
+ }),
86
+ pages: (meta.pages || []).map(p => {
87
+ const b = badges.pages?.[p.slug];
88
+ return { ...p, badge: b?.value ?? null, badgeColor: b?.color };
89
+ }),
90
+ });
91
+
92
+ // Fetch panel metadata and badges in parallel, then merge
93
+ useEffect(() => {
94
+ const metaUrl = panelId ? `${apiBaseUrl}/meta?panelId=${panelId}` : `${apiBaseUrl}/meta`;
95
+ const badgesUrl = panelId ? `${apiBaseUrl}/meta/badges?panelId=${panelId}` : `${apiBaseUrl}/meta/badges`;
96
+
97
+ const fetchMetadata = async () => {
98
+ try {
99
+ const [metaRes, badgesRes] = await Promise.all([
100
+ authenticatedFetch(metaUrl, { headers: { 'Content-Type': 'application/json' } }, apiBaseUrl),
101
+ authenticatedFetch(badgesUrl, { headers: { 'Content-Type': 'application/json' } }, apiBaseUrl),
102
+ ]);
103
+ if (!metaRes.ok) {
104
+ if (metaRes.status === 401) throw new Error('Unauthorized - Please login again');
105
+ throw new Error(t('core:error.connect'));
106
+ }
107
+ const meta: PanelMetadata = await metaRes.json();
108
+ const badges = badgesRes.ok ? await badgesRes.json() : { resources: {}, pages: {} };
109
+ setPanelMetadata(mergeBadgesIntoMeta(meta, badges));
110
+ } catch (err) {
111
+ setError(err instanceof Error ? err.message : t('core:error.connect'));
112
+ } finally {
113
+ setLoading(false);
114
+ }
115
+ };
116
+
117
+ fetchMetadata();
118
+ // `locale` is a dependency so switching language re-fetches /meta (labels,
119
+ // nav groups) in the new locale; the locale header is sent automatically.
120
+ }, [apiBaseUrl, panelId, locale]);
121
+
122
+ // Subscribe to badge refresh events and refetch badges
123
+ useEffect(() => {
124
+ const refreshBadges = async () => {
125
+ const badgesUrl = panelId ? `${apiBaseUrl}/meta/badges?panelId=${panelId}` : `${apiBaseUrl}/meta/badges`;
126
+ try {
127
+ const res = await authenticatedFetch(
128
+ badgesUrl,
129
+ { headers: { 'Content-Type': 'application/json' } },
130
+ apiBaseUrl,
131
+ );
132
+ if (!res.ok) return;
133
+ const badges = await res.json();
134
+ setPanelMetadata(prev => (prev ? mergeBadgesIntoMeta(prev, badges) : prev));
135
+ } catch {
136
+ // ignore
137
+ }
138
+ };
139
+ const handler = () => refreshBadges();
140
+ window.addEventListener('kratosjs-refresh-badges', handler);
141
+ return () => window.removeEventListener('kratosjs-refresh-badges', handler);
142
+ }, [apiBaseUrl, panelId]);
143
+
144
+ if (loading) {
145
+ return (
146
+ <div className="min-h-screen bg-base flex items-center justify-center">
147
+ <div className="text-center">
148
+ <Loader2 className="w-12 h-12 text-accent animate-spin mx-auto" />
149
+ <p className="mt-4 text-fg-secondary">{t('core:panel.loading')}</p>
150
+ </div>
151
+ </div>
152
+ );
153
+ }
154
+
155
+ if (error) {
156
+ return (
157
+ <div className="min-h-screen bg-base flex items-center justify-center">
158
+ <div className="text-center p-8 bg-surface border border-border rounded-xl max-w-md">
159
+ <AlertTriangle className="w-16 h-16 text-red-500 mx-auto mb-4" />
160
+ <h2 className="text-xl font-semibold text-fg mb-2">{t('core:panel.connection_error')}</h2>
161
+ <p className="text-fg-secondary mb-4">{error}</p>
162
+ <PillButton variant="primary" onClick={() => window.location.reload()}>
163
+ {t('core:common.retry')}
164
+ </PillButton>
165
+ </div>
166
+ </div>
167
+ );
168
+ }
169
+
170
+ if (!panelMetadata) {
171
+ return (
172
+ <div className="min-h-screen bg-base flex items-center justify-center">
173
+ <div className="text-center p-8 bg-surface border border-border rounded-lg max-w-md">
174
+ <p className="text-fg-secondary">{t('core:panel.empty')}</p>
175
+ </div>
176
+ </div>
177
+ );
178
+ }
179
+
180
+ // Determine default route: first page if available, otherwise first resource
181
+ const defaultRoute =
182
+ panelMetadata.pages.length > 0
183
+ ? `/page/${panelMetadata.pages[0].slug}`
184
+ : panelMetadata.resources.length > 0
185
+ ? `/${panelMetadata.resources[0].slug}`
186
+ : '/';
187
+
188
+ return (
189
+ <PanelMetadataProvider resources={panelMetadata.resources} pages={panelMetadata.pages}>
190
+ <div className="flex min-h-screen bg-base transition-colors">
191
+ <Sidebar
192
+ panelTitle={panelMetadata.title}
193
+ panelIcon={panelMetadata.icon}
194
+ panelFavicon={panelMetadata.favicon}
195
+ resources={panelMetadata.resources}
196
+ pages={panelMetadata.pages}
197
+ mobileOpen={mobileSidebarOpen}
198
+ onMobileClose={() => setMobileSidebarOpen(false)}
199
+ />
200
+
201
+ <div className="flex min-w-0 flex-1 flex-col">
202
+ <Header
203
+ panelId={panelMetadata.id}
204
+ darkMode={darkMode}
205
+ onDarkModeToggle={() => setDarkMode(!darkMode)}
206
+ onMobileMenuToggle={() => setMobileSidebarOpen(!mobileSidebarOpen)}
207
+ apiBaseUrl={apiBaseUrl}
208
+ globalSearchAvailable={panelMetadata.globalSearchAvailable}
209
+ />
210
+
211
+ <main className="flex-1 overflow-hidden">
212
+ <div className="h-full w-full overflow-auto p-4 sm:p-6">
213
+ <ErrorBoundary label="this page">
214
+ <Routes>
215
+ <Route path="/" element={<Navigate to={defaultRoute} replace />} />
216
+ {panelMetadata.pages.map(page => (
217
+ <Route
218
+ key={page.slug}
219
+ path={`/page/${page.slug}`}
220
+ element={<PageRenderer pageSlug={page.slug} apiBaseUrl={apiBaseUrl} />}
221
+ />
222
+ ))}
223
+ {panelMetadata.resources.map(resource => (
224
+ <Route
225
+ key={resource.slug}
226
+ path={`/${resource.slug}/*`}
227
+ element={
228
+ <ResourceListPage
229
+ apiBaseUrl={apiBaseUrl}
230
+ resourceSlug={resource.slug}
231
+ resourceName={resource.label}
232
+ pluralLabel={resource.pluralLabel}
233
+ />
234
+ }
235
+ />
236
+ ))}
237
+ <Route path="*" element={<Navigate to={defaultRoute} replace />} />
238
+ </Routes>
239
+ </ErrorBoundary>
240
+ </div>
241
+ </main>
242
+
243
+ <Slot
244
+ name="panel.footer"
245
+ as="footer"
246
+ className="shrink-0 border-t border-border px-4 py-3 sm:px-6"
247
+ />
248
+ </div>
249
+
250
+ <ModalStackRenderer apiBaseUrl={apiBaseUrl} />
251
+ </div>
252
+ </PanelMetadataProvider>
253
+ );
254
+ }
255
+
256
+ /**
257
+ * Renders all modals in the modal stack
258
+ */
259
+ function ModalStackRenderer({ apiBaseUrl }: { apiBaseUrl: string }) {
260
+ const { modalStack, closeModal, closeAllModals } = useResourceModal();
261
+
262
+ // Refs so handlers always read the latest values without being recreated.
263
+ // ResourceModalRenderer is memoized and ignores onClose/onCloseAll prop updates.
264
+ const modalStackRef = useRef(modalStack);
265
+ modalStackRef.current = modalStack;
266
+
267
+ // When back is pressed on modal M, replaceState to the now-visible state:
268
+ // - Parent exists → /${parent.resource}/${parent.recordId}
269
+ // - M was the last modal → /${M.resource} (the list)
270
+ // We use replaceState (not navigate) so React Router's internal location is never
271
+ // mutated — no modal refresh/flash. Re-opening still works because navigate() from
272
+ // a row-click always produces a new location.key, which ResourceListPage watches.
273
+ //
274
+ // IMPORTANT: only update the URL if it currently belongs to one of the open modal
275
+ // resources. If the user opened a modal via a cross-resource deeplink the URL bar
276
+ // still shows the origin page (e.g. /withdrawals) — we must not overwrite that.
277
+ const handleCloseModal = useCallback(() => {
278
+ const stack = modalStackRef.current;
279
+ if (stack.length === 0) return;
280
+
281
+ const closing = stack[stack.length - 1];
282
+ closeModal();
283
+
284
+ if (stack.length === 1) {
285
+ // Last modal closing — restore to where the user came from.
286
+ // originUrl is set when the modal was opened via a cross-resource deeplink
287
+ // (pushState updated the address bar; originUrl holds the prior URL).
288
+ // Without originUrl, only update if the address bar is on this resource.
289
+ if (closing.originUrl) {
290
+ window.history.replaceState(null, '', closing.originUrl);
291
+ } else {
292
+ const firstSegment = window.location.pathname.split('/').filter(Boolean)[0] ?? '';
293
+ if (firstSegment === closing.resource) {
294
+ window.history.replaceState(null, '', `/${closing.resource}`);
295
+ }
296
+ }
297
+ } else {
298
+ // Parent modal is still visible — show the parent's own URL.
299
+ // NOTE: we use the parent's resource/id, NOT parent.originUrl.
300
+ // originUrl means "where to go when *the parent itself* closes",
301
+ // not the URL to display while the parent is still open.
302
+ const parent = stack[stack.length - 2];
303
+ window.history.replaceState(null, '', `/${parent.resource}/${parent.recordId || ''}`);
304
+ }
305
+ }, [closeModal]);
306
+
307
+ // Close All: jump straight to the origin (before any modal was opened).
308
+ const handleCloseAll = useCallback(() => {
309
+ const stack = modalStackRef.current;
310
+ if (stack.length === 0) return;
311
+
312
+ const root = stack[0];
313
+ closeAllModals();
314
+
315
+ if (root.originUrl) {
316
+ // Root was opened via deeplink — restore the page the user came from.
317
+ window.history.replaceState(null, '', root.originUrl);
318
+ } else {
319
+ // URL-based root — only reset to the list if the address bar is on it.
320
+ const firstSegment = window.location.pathname.split('/').filter(Boolean)[0] ?? '';
321
+ if (firstSegment === root.resource) {
322
+ window.history.replaceState(null, '', `/${root.resource}`);
323
+ }
324
+ }
325
+ }, [closeAllModals]);
326
+
327
+ return (
328
+ <>
329
+ {modalStack.map(modal => (
330
+ <ResourceModalRenderer
331
+ key={`${modal.resource}-${modal.recordId || 'create'}-${modal.mode}-${modal.depth}`}
332
+ modal={modal}
333
+ apiBaseUrl={apiBaseUrl}
334
+ onClose={handleCloseModal}
335
+ onCloseAll={handleCloseAll}
336
+ />
337
+ ))}
338
+ </>
339
+ );
340
+ }
341
+
342
+ export function AdminPanel({
343
+ apiBaseUrl,
344
+ panelId,
345
+ customFields,
346
+ customColumns,
347
+ customWidgets,
348
+ customBlocks,
349
+ customAuthChallenges,
350
+ customSlots,
351
+ i18nConfig,
352
+ }: AdminPanelProps) {
353
+ return (
354
+ <BrowserRouter>
355
+ <PanelProviders
356
+ apiBaseUrl={apiBaseUrl}
357
+ customFields={customFields}
358
+ customColumns={customColumns}
359
+ customWidgets={customWidgets}
360
+ customBlocks={customBlocks}
361
+ customAuthChallenges={customAuthChallenges}
362
+ customSlots={customSlots}
363
+ i18nConfig={i18nConfig}>
364
+ <AdminPanelContent apiBaseUrl={apiBaseUrl} panelId={panelId} />
365
+ </PanelProviders>
366
+ </BrowserRouter>
367
+ );
368
+ }
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { cn } from '../utils/classNames';
3
+
4
+ interface CheckboxProps {
5
+ checked: boolean;
6
+ onChange: (checked: boolean) => void;
7
+ id?: string;
8
+ className?: string;
9
+ disabled?: boolean;
10
+ }
11
+
12
+ export function Checkbox({ checked, onChange, id, className, disabled }: CheckboxProps) {
13
+ const checkboxId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
14
+
15
+ return (
16
+ <label
17
+ htmlFor={checkboxId}
18
+ className={cn(
19
+ 'flex items-center cursor-pointer select-none',
20
+ disabled && 'cursor-not-allowed opacity-50',
21
+ className,
22
+ )}>
23
+ <input
24
+ id={checkboxId}
25
+ type="checkbox"
26
+ checked={checked}
27
+ onChange={e => onChange(e.target.checked)}
28
+ disabled={disabled}
29
+ className="sr-only"
30
+ />
31
+ <div
32
+ className={cn(
33
+ 'w-4 h-4 rounded border transition-colors flex items-center justify-center',
34
+ checked
35
+ ? 'bg-accent border-accent'
36
+ : cn(
37
+ 'border-gray-300 dark:border-gray-600',
38
+ 'bg-gray-200 dark:bg-gray-700',
39
+ 'hover:bg-gray-300 dark:hover:bg-gray-600',
40
+ ),
41
+ 'focus-within:ring-2 focus-within:ring-ring/50 focus-within:border-accent ',
42
+ disabled && 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-not-allowed',
43
+ )}>
44
+ {checked && (
45
+ <svg
46
+ className="w-3 h-3 text-white"
47
+ fill="none"
48
+ strokeLinecap="round"
49
+ strokeLinejoin="round"
50
+ strokeWidth="2.5"
51
+ viewBox="0 0 24 24"
52
+ stroke="currentColor">
53
+ <path d="M5 13l4 4L19 7" />
54
+ </svg>
55
+ )}
56
+ </div>
57
+ </label>
58
+ );
59
+ }
@@ -0,0 +1,88 @@
1
+ import React from 'react';
2
+ import { useFormContext } from 'react-hook-form';
3
+ import { getFieldError } from '../utils/fieldErrors';
4
+ import { FieldProps } from '../types';
5
+ import { useValidation } from '../hooks/useValidation';
6
+ import { cn } from '../utils/classNames';
7
+ import { HintDisplay } from './utils/HintDisplay';
8
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
9
+ import { formatBoolean } from '../utils/formatValue';
10
+ import { Icon } from './utils/Icon';
11
+
12
+ /**
13
+ * Checkbox field component
14
+ * Renders a single checkbox input
15
+ */
16
+ export function CheckboxField(props: FieldProps) {
17
+ // View mode: render formatted display
18
+ if (props.mode === 'view') {
19
+ const value = props.value;
20
+ const displayValue = formatBoolean(value);
21
+ return (
22
+ <ViewFieldWrapper label={props.label}>
23
+ <div className="flex items-center gap-2">
24
+ {value ? (
25
+ <Icon name="Check" size={16} className="text-green-600" />
26
+ ) : (
27
+ <Icon name="X" size={16} className="text-gray-400" />
28
+ )}
29
+ <span>{displayValue}</span>
30
+ </div>
31
+ </ViewFieldWrapper>
32
+ );
33
+ }
34
+
35
+ const {
36
+ register,
37
+ formState: { errors },
38
+ } = useFormContext();
39
+
40
+ const validation = useValidation(props.validation?.rules || [], props.operation, props.name);
41
+ const error = getFieldError(errors, props.name);
42
+ const hasError = !!error;
43
+
44
+ return (
45
+ <div className="mb-4">
46
+ <div className="flex items-start">
47
+ <div className="flex items-center h-5">
48
+ <input
49
+ id={props.name}
50
+ type="checkbox"
51
+ {...register(props.name, validation)}
52
+ disabled={props.disabled}
53
+ className={cn(
54
+ 'w-4 h-4 border rounded',
55
+ 'text-accent dark:text-accent',
56
+ 'k-input',
57
+ 'focus:ring-2 focus:ring-ring',
58
+ 'transition duration-150 ease-in-out',
59
+ hasError && 'border-red-500 dark:border-red-400',
60
+ props.disabled && 'opacity-60 cursor-not-allowed',
61
+ )}
62
+ />
63
+ </div>
64
+
65
+ {props.label && (
66
+ <div className="ml-3">
67
+ <label htmlFor={props.name} className="text-sm font-medium text-gray-700 dark:text-gray-300">
68
+ {props.label}
69
+ {validation.required && <span className="text-red-500 dark:text-red-400 ml-1">*</span>}
70
+ </label>
71
+
72
+ {props.helperText && (
73
+ <p className="text-sm text-gray-500 dark:text-gray-400 mt-0.5">{props.helperText}</p>
74
+ )}
75
+ </div>
76
+ )}
77
+ </div>
78
+
79
+ {hasError && <p className="mt-1 ml-7 text-sm text-red-600 dark:text-red-400">{error?.message as string}</p>}
80
+
81
+ {!hasError && (
82
+ <div className="ml-7">
83
+ <HintDisplay hint={props.hint} hintIcon={props.hintIcon} hintColor={props.hintColor} />
84
+ </div>
85
+ )}
86
+ </div>
87
+ );
88
+ }
@@ -0,0 +1,93 @@
1
+ import React from 'react';
2
+ import { useFormContext, useWatch } from 'react-hook-form';
3
+ import { getFieldError } from '../utils/fieldErrors';
4
+ import { FieldProps } from '../types';
5
+ import { useValidation } from '../hooks/useValidation';
6
+ import { cn } from '../utils/classNames';
7
+ import { HintDisplay } from './utils/HintDisplay';
8
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
9
+ import { translate } from '../i18n/activeLocale';
10
+
11
+ /**
12
+ * ColorPicker field component
13
+ * Renders a color input with preview
14
+ */
15
+ export function ColorPickerField(props: FieldProps) {
16
+ // View mode: render formatted display
17
+ if (props.mode === 'view') {
18
+ const value = props.value || '#000000';
19
+ return (
20
+ <ViewFieldWrapper label={props.label}>
21
+ <div className="flex items-center gap-3">
22
+ <div className="w-8 h-8 rounded border border-border" style={{ backgroundColor: value }} />
23
+ <span className="text-fg font-mono">{value}</span>
24
+ </div>
25
+ </ViewFieldWrapper>
26
+ );
27
+ }
28
+
29
+ const {
30
+ register,
31
+ control,
32
+ formState: { errors },
33
+ } = useFormContext();
34
+
35
+ const validation = useValidation(props.validation?.rules || [], props.operation, props.name);
36
+ const error = getFieldError(errors, props.name);
37
+ const hasError = !!error;
38
+
39
+ // Watch the color value for preview
40
+ const colorValue = useWatch({ control, name: props.name, defaultValue: props.default || '#000000' });
41
+
42
+ return (
43
+ <div className="mb-4">
44
+ {props.label && (
45
+ <label htmlFor={props.name} className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
46
+ {props.label}
47
+ {validation.required && <span className="text-red-500 dark:text-red-400 ml-1">*</span>}
48
+ </label>
49
+ )}
50
+
51
+ <div className="flex items-center gap-3">
52
+ <input
53
+ id={props.name}
54
+ type="color"
55
+ {...register(props.name, validation)}
56
+ disabled={props.disabled}
57
+ className={cn(
58
+ 'h-10 w-20 border rounded-lg cursor-pointer',
59
+ 'k-input',
60
+ 'focus:outline-none focus:ring-2 focus:ring-ring',
61
+ 'transition duration-150 ease-in-out',
62
+ hasError && 'border-red-500 dark:border-red-400',
63
+ props.disabled && 'opacity-60 cursor-not-allowed',
64
+ )}
65
+ />
66
+
67
+ <div className="flex-1">
68
+ <input
69
+ type="text"
70
+ value={colorValue}
71
+ readOnly
72
+ className={cn(
73
+ 'w-full px-3 py-2 border rounded-lg shadow-sm',
74
+ 'bg-muted text-fg border-border text-sm font-mono',
75
+ )}
76
+ />
77
+ </div>
78
+
79
+ <div
80
+ className="h-10 w-10 rounded-lg border-2 border-border shadow-sm"
81
+ style={{ backgroundColor: colorValue }}
82
+ title={translate('core:a11y.color_preview')}
83
+ />
84
+ </div>
85
+
86
+ {hasError && <p className="mt-1 text-sm text-red-600 dark:text-red-400">{error?.message as string}</p>}
87
+
88
+ {props.helperText && <p className="mt-1 text-sm text-gray-500 dark:text-gray-400">{props.helperText}</p>}
89
+
90
+ {!hasError && <HintDisplay hint={props.hint} hintIcon={props.hintIcon} hintColor={props.hintColor} />}
91
+ </div>
92
+ );
93
+ }