@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,267 @@
1
+ /**
2
+ * Layout helper utilities for column span, column start, and grid classes.
3
+ *
4
+ * IMPORTANT: every Tailwind class must appear as a full literal string here.
5
+ * Tailwind v4 only generates utilities it can see while scanning the source —
6
+ * template-built class names (`grid-cols-${n}`) silently produce no CSS.
7
+ */
8
+
9
+ const GRID_COLS: Record<string, Record<number, string>> = {
10
+ base: {
11
+ 1: 'grid-cols-1',
12
+ 2: 'grid-cols-2',
13
+ 3: 'grid-cols-3',
14
+ 4: 'grid-cols-4',
15
+ 5: 'grid-cols-5',
16
+ 6: 'grid-cols-6',
17
+ },
18
+ sm: {
19
+ 1: 'sm:grid-cols-1',
20
+ 2: 'sm:grid-cols-2',
21
+ 3: 'sm:grid-cols-3',
22
+ 4: 'sm:grid-cols-4',
23
+ 5: 'sm:grid-cols-5',
24
+ 6: 'sm:grid-cols-6',
25
+ },
26
+ md: {
27
+ 1: 'md:grid-cols-1',
28
+ 2: 'md:grid-cols-2',
29
+ 3: 'md:grid-cols-3',
30
+ 4: 'md:grid-cols-4',
31
+ 5: 'md:grid-cols-5',
32
+ 6: 'md:grid-cols-6',
33
+ },
34
+ lg: {
35
+ 1: 'lg:grid-cols-1',
36
+ 2: 'lg:grid-cols-2',
37
+ 3: 'lg:grid-cols-3',
38
+ 4: 'lg:grid-cols-4',
39
+ 5: 'lg:grid-cols-5',
40
+ 6: 'lg:grid-cols-6',
41
+ },
42
+ xl: {
43
+ 1: 'xl:grid-cols-1',
44
+ 2: 'xl:grid-cols-2',
45
+ 3: 'xl:grid-cols-3',
46
+ 4: 'xl:grid-cols-4',
47
+ 5: 'xl:grid-cols-5',
48
+ 6: 'xl:grid-cols-6',
49
+ },
50
+ '2xl': {
51
+ 1: '2xl:grid-cols-1',
52
+ 2: '2xl:grid-cols-2',
53
+ 3: '2xl:grid-cols-3',
54
+ 4: '2xl:grid-cols-4',
55
+ 5: '2xl:grid-cols-5',
56
+ 6: '2xl:grid-cols-6',
57
+ },
58
+ };
59
+
60
+ const COL_SPAN: Record<string, Record<number | 'full', string>> = {
61
+ base: {
62
+ 1: 'col-span-1',
63
+ 2: 'col-span-2',
64
+ 3: 'col-span-3',
65
+ 4: 'col-span-4',
66
+ 5: 'col-span-5',
67
+ 6: 'col-span-6',
68
+ full: 'col-span-full',
69
+ },
70
+ sm: {
71
+ 1: 'sm:col-span-1',
72
+ 2: 'sm:col-span-2',
73
+ 3: 'sm:col-span-3',
74
+ 4: 'sm:col-span-4',
75
+ 5: 'sm:col-span-5',
76
+ 6: 'sm:col-span-6',
77
+ full: 'sm:col-span-full',
78
+ },
79
+ md: {
80
+ 1: 'md:col-span-1',
81
+ 2: 'md:col-span-2',
82
+ 3: 'md:col-span-3',
83
+ 4: 'md:col-span-4',
84
+ 5: 'md:col-span-5',
85
+ 6: 'md:col-span-6',
86
+ full: 'md:col-span-full',
87
+ },
88
+ lg: {
89
+ 1: 'lg:col-span-1',
90
+ 2: 'lg:col-span-2',
91
+ 3: 'lg:col-span-3',
92
+ 4: 'lg:col-span-4',
93
+ 5: 'lg:col-span-5',
94
+ 6: 'lg:col-span-6',
95
+ full: 'lg:col-span-full',
96
+ },
97
+ xl: {
98
+ 1: 'xl:col-span-1',
99
+ 2: 'xl:col-span-2',
100
+ 3: 'xl:col-span-3',
101
+ 4: 'xl:col-span-4',
102
+ 5: 'xl:col-span-5',
103
+ 6: 'xl:col-span-6',
104
+ full: 'xl:col-span-full',
105
+ },
106
+ '2xl': {
107
+ 1: '2xl:col-span-1',
108
+ 2: '2xl:col-span-2',
109
+ 3: '2xl:col-span-3',
110
+ 4: '2xl:col-span-4',
111
+ 5: '2xl:col-span-5',
112
+ 6: '2xl:col-span-6',
113
+ full: '2xl:col-span-full',
114
+ },
115
+ };
116
+
117
+ const COL_START: Record<string, Record<number, string>> = {
118
+ base: {
119
+ 1: 'col-start-1',
120
+ 2: 'col-start-2',
121
+ 3: 'col-start-3',
122
+ 4: 'col-start-4',
123
+ 5: 'col-start-5',
124
+ 6: 'col-start-6',
125
+ 7: 'col-start-7',
126
+ },
127
+ sm: {
128
+ 1: 'sm:col-start-1',
129
+ 2: 'sm:col-start-2',
130
+ 3: 'sm:col-start-3',
131
+ 4: 'sm:col-start-4',
132
+ 5: 'sm:col-start-5',
133
+ 6: 'sm:col-start-6',
134
+ 7: 'sm:col-start-7',
135
+ },
136
+ md: {
137
+ 1: 'md:col-start-1',
138
+ 2: 'md:col-start-2',
139
+ 3: 'md:col-start-3',
140
+ 4: 'md:col-start-4',
141
+ 5: 'md:col-start-5',
142
+ 6: 'md:col-start-6',
143
+ 7: 'md:col-start-7',
144
+ },
145
+ lg: {
146
+ 1: 'lg:col-start-1',
147
+ 2: 'lg:col-start-2',
148
+ 3: 'lg:col-start-3',
149
+ 4: 'lg:col-start-4',
150
+ 5: 'lg:col-start-5',
151
+ 6: 'lg:col-start-6',
152
+ 7: 'lg:col-start-7',
153
+ },
154
+ xl: {
155
+ 1: 'xl:col-start-1',
156
+ 2: 'xl:col-start-2',
157
+ 3: 'xl:col-start-3',
158
+ 4: 'xl:col-start-4',
159
+ 5: 'xl:col-start-5',
160
+ 6: 'xl:col-start-6',
161
+ 7: 'xl:col-start-7',
162
+ },
163
+ '2xl': {
164
+ 1: '2xl:col-start-1',
165
+ 2: '2xl:col-start-2',
166
+ 3: '2xl:col-start-3',
167
+ 4: '2xl:col-start-4',
168
+ 5: '2xl:col-start-5',
169
+ 6: '2xl:col-start-6',
170
+ 7: '2xl:col-start-7',
171
+ },
172
+ };
173
+
174
+ const BREAKPOINTS = ['sm', 'md', 'lg', 'xl', '2xl'] as const;
175
+
176
+ function spanClass(breakpoint: string, value: number | string): string | undefined {
177
+ const key = value === 'full' ? 'full' : Number(value);
178
+ return COL_SPAN[breakpoint]?.[key as number | 'full'];
179
+ }
180
+
181
+ /**
182
+ * Get Tailwind CSS classes for column span and column start.
183
+ * Supports both simple values and responsive objects.
184
+ */
185
+ export function getColumnClasses(
186
+ columnSpan?: number | string | Record<string, number | string>,
187
+ columnStart?: number | Record<string, number>,
188
+ ): string {
189
+ const classes: string[] = [];
190
+
191
+ if (columnSpan) {
192
+ if (typeof columnSpan === 'number' || typeof columnSpan === 'string') {
193
+ const cls = spanClass('base', columnSpan);
194
+ if (cls) classes.push(cls);
195
+ } else if (typeof columnSpan === 'object') {
196
+ const span = columnSpan as Record<string, number | string>;
197
+ if (span.default) {
198
+ const cls = spanClass('base', span.default);
199
+ if (cls) classes.push(cls);
200
+ }
201
+ for (const bp of BREAKPOINTS) {
202
+ if (span[bp]) {
203
+ const cls = spanClass(bp, span[bp]);
204
+ if (cls) classes.push(cls);
205
+ }
206
+ }
207
+ }
208
+ }
209
+
210
+ if (columnStart) {
211
+ if (typeof columnStart === 'number') {
212
+ const cls = COL_START.base[columnStart];
213
+ if (cls) classes.push(cls);
214
+ } else if (typeof columnStart === 'object') {
215
+ const start = columnStart as Record<string, number>;
216
+ if (start.default) {
217
+ const cls = COL_START.base[start.default];
218
+ if (cls) classes.push(cls);
219
+ }
220
+ for (const bp of BREAKPOINTS) {
221
+ if (start[bp]) {
222
+ const cls = COL_START[bp]?.[start[bp]];
223
+ if (cls) classes.push(cls);
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ return classes.join(' ');
230
+ }
231
+
232
+ /**
233
+ * Get Tailwind CSS grid classes based on columns configuration.
234
+ * Supports both simple numbers (applied from lg up) and responsive objects.
235
+ */
236
+ export function getGridClasses(columns?: number | Record<string, number>, gapX: string = 'gap-x-4'): string {
237
+ if (!columns || columns === 1) {
238
+ return `grid grid-cols-1 ${gapX}`;
239
+ }
240
+
241
+ if (typeof columns === 'number') {
242
+ const cls = GRID_COLS.lg[columns];
243
+ return cls ? `grid grid-cols-1 ${cls} ${gapX}` : `grid grid-cols-1 ${gapX}`;
244
+ }
245
+
246
+ const classes = ['grid', gapX];
247
+ const cols = columns as Record<string, number>;
248
+
249
+ classes.push(cols.default ? GRID_COLS.base[cols.default] || 'grid-cols-1' : 'grid-cols-1');
250
+
251
+ for (const bp of BREAKPOINTS) {
252
+ if (cols[bp]) {
253
+ const cls = GRID_COLS[bp]?.[cols[bp]];
254
+ if (cls) classes.push(cls);
255
+ }
256
+ }
257
+
258
+ return classes.join(' ');
259
+ }
260
+
261
+ /** Vertical rhythm for stacked form fields (single column) or grid rows (multi-column). */
262
+ export function getFieldLayoutClasses(columns?: number | Record<string, number>): string {
263
+ if (!columns || columns === 1) {
264
+ return 'flex flex-col gap-4';
265
+ }
266
+ return `${getGridClasses(columns)} gap-y-4`;
267
+ }
@@ -0,0 +1,247 @@
1
+ import React, { useMemo } from 'react';
2
+ import {
3
+ Chart as ChartJS,
4
+ CategoryScale,
5
+ LinearScale,
6
+ PointElement,
7
+ LineElement,
8
+ BarElement,
9
+ ArcElement,
10
+ Title,
11
+ Tooltip,
12
+ Legend,
13
+ ChartOptions,
14
+ } from 'chart.js';
15
+ import { Line, Bar, Pie } from 'react-chartjs-2';
16
+ import { cn } from '../../utils/classNames';
17
+ import { WidgetShell } from './WidgetShell';
18
+ import { translate } from '../../i18n/activeLocale';
19
+
20
+ ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, Title, Tooltip, Legend);
21
+
22
+ export interface ChartWidgetProps {
23
+ widget: {
24
+ name: string;
25
+ label?: string;
26
+ icon?: string;
27
+ color?: string;
28
+ chartType: 'line' | 'bar' | 'pie';
29
+ showLegend?: boolean;
30
+ };
31
+ data: Array<{ label: string; value: number }> | null;
32
+ }
33
+
34
+ function readThemeColor(cssVar: string, fallback: string): string {
35
+ if (typeof document === 'undefined') return fallback;
36
+ const value = getComputedStyle(document.documentElement).getPropertyValue(cssVar).trim();
37
+ return value || fallback;
38
+ }
39
+
40
+ function getThemeColors() {
41
+ const fallbackAccent = '59, 130, 246';
42
+ const defaultPalette = ['#2563eb', '#059669', '#d97706', '#dc2626', '#52525b'];
43
+ const defaultPaletteSoft = ['#dbeafe', '#d1fae5', '#fef3c7', '#fee2e2', '#f3f4f6'];
44
+
45
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
46
+ return {
47
+ accent: `rgb(${fallbackAccent})`,
48
+ accentSoft: `rgba(${fallbackAccent}, 0.35)`,
49
+ accentFaint: `rgba(${fallbackAccent}, 0.12)`,
50
+ grid: 'rgba(148, 163, 184, 0.2)',
51
+ tick: 'rgba(148, 163, 184, 0.85)',
52
+ tooltipBg: 'rgba(15, 23, 42, 0.92)',
53
+ palette: defaultPalette,
54
+ paletteSoft: defaultPaletteSoft,
55
+ };
56
+ }
57
+
58
+ const accent = readThemeColor('--kratos-accent', '#2563eb');
59
+ const fgMuted = readThemeColor('--kratos-fg-muted', '#9ca3af');
60
+ const surface = readThemeColor('--kratos-surface', '#151517');
61
+
62
+ const palette = [
63
+ readThemeColor('--kratos-accent', '#2563eb'),
64
+ readThemeColor('--kratos-success', '#059669'),
65
+ readThemeColor('--kratos-warning', '#d97706'),
66
+ readThemeColor('--kratos-danger', '#dc2626'),
67
+ readThemeColor('--kratos-fg-secondary', '#52525b'),
68
+ ];
69
+
70
+ const paletteSoft = [
71
+ readThemeColor('--kratos-accent-soft', '#dbeafe'),
72
+ readThemeColor('--kratos-success-soft', '#d1fae5'),
73
+ readThemeColor('--kratos-warning-soft', '#fef3c7'),
74
+ readThemeColor('--kratos-danger-soft', '#fee2e2'),
75
+ readThemeColor('--kratos-muted', '#f3f4f6'),
76
+ ];
77
+
78
+ return {
79
+ accent,
80
+ accentSoft: readThemeColor('--kratos-accent-soft', '#dbeafe'),
81
+ accentFaint: readThemeColor('--kratos-accent-soft', '#dbeafe'),
82
+ grid: fgMuted,
83
+ tick: fgMuted,
84
+ tooltipBg: surface,
85
+ palette,
86
+ paletteSoft,
87
+ };
88
+ }
89
+
90
+ function colorForIndex(theme: ReturnType<typeof getThemeColors>, index: number, soft = false): string {
91
+ const colors = soft ? theme.paletteSoft : theme.palette;
92
+ return colors[index % colors.length] ?? colors[0];
93
+ }
94
+
95
+ /** Prefer stable semantic colors for common labels (e.g. admin/editor roles). */
96
+ function colorForLabel(theme: ReturnType<typeof getThemeColors>, label: string, index: number, soft = false): string {
97
+ const semanticIndex: Record<string, number> = {
98
+ admin: 3,
99
+ editor: 0,
100
+ active: 1,
101
+ inactive: 4,
102
+ published: 1,
103
+ draft: 4,
104
+ };
105
+ const mapped = semanticIndex[label.toLowerCase()];
106
+ return colorForIndex(theme, mapped ?? index, soft);
107
+ }
108
+
109
+ export function ChartWidget({ widget, data }: ChartWidgetProps) {
110
+ const theme = useMemo(() => getThemeColors(), []);
111
+
112
+ const chartData = useMemo(() => {
113
+ if (!data || data.length === 0) {
114
+ return { labels: [], datasets: [] };
115
+ }
116
+
117
+ if (widget.chartType === 'pie') {
118
+ return {
119
+ labels: data.map(item => item.label),
120
+ datasets: [
121
+ {
122
+ data: data.map(item => item.value),
123
+ backgroundColor: data.map((item, index) => colorForLabel(theme, item.label, index)),
124
+ borderColor: 'transparent',
125
+ borderWidth: 0,
126
+ },
127
+ ],
128
+ };
129
+ }
130
+
131
+ if (widget.chartType === 'bar') {
132
+ return {
133
+ labels: data.map(item => item.label),
134
+ datasets: [
135
+ {
136
+ label: widget.label || translate('core:widget.data_label'),
137
+ data: data.map(item => item.value),
138
+ backgroundColor: data.map((item, index) => colorForLabel(theme, item.label, index, true)),
139
+ borderColor: data.map((item, index) => colorForLabel(theme, item.label, index)),
140
+ borderWidth: 2,
141
+ borderRadius: 6,
142
+ },
143
+ ],
144
+ };
145
+ }
146
+
147
+ return {
148
+ labels: data.map(item => item.label),
149
+ datasets: [
150
+ {
151
+ label: widget.label || translate('core:widget.data_label'),
152
+ data: data.map(item => item.value),
153
+ backgroundColor: theme.accentFaint,
154
+ borderColor: theme.accent,
155
+ borderWidth: 2,
156
+ fill: true,
157
+ tension: 0.35,
158
+ pointRadius: 3,
159
+ pointHoverRadius: 4,
160
+ pointBackgroundColor: theme.accent,
161
+ },
162
+ ],
163
+ };
164
+ }, [data, widget.label, widget.chartType, theme]);
165
+
166
+ const options: ChartOptions<'line' | 'bar' | 'pie'> = useMemo(() => {
167
+ const showLegend = widget.showLegend ?? false;
168
+
169
+ if (widget.chartType === 'pie') {
170
+ return {
171
+ responsive: true,
172
+ maintainAspectRatio: false,
173
+ plugins: {
174
+ legend: {
175
+ display: showLegend,
176
+ position: 'bottom',
177
+ labels: {
178
+ padding: 12,
179
+ usePointStyle: true,
180
+ boxWidth: 8,
181
+ color: theme.tick,
182
+ font: { size: 11 },
183
+ },
184
+ },
185
+ tooltip: {
186
+ backgroundColor: theme.tooltipBg,
187
+ titleColor: theme.tick,
188
+ bodyColor: theme.tick,
189
+ borderColor: theme.grid,
190
+ borderWidth: 1,
191
+ padding: 10,
192
+ },
193
+ },
194
+ };
195
+ }
196
+
197
+ return {
198
+ responsive: true,
199
+ maintainAspectRatio: false,
200
+ plugins: {
201
+ legend: { display: showLegend, labels: { color: theme.tick, boxWidth: 8 } },
202
+ tooltip: {
203
+ backgroundColor: theme.tooltipBg,
204
+ titleColor: theme.tick,
205
+ bodyColor: theme.tick,
206
+ borderColor: theme.grid,
207
+ borderWidth: 1,
208
+ padding: 10,
209
+ displayColors: false,
210
+ },
211
+ },
212
+ scales: {
213
+ x: {
214
+ display: false,
215
+ grid: { display: false },
216
+ ticks: { display: false },
217
+ },
218
+ y: {
219
+ beginAtZero: true,
220
+ grid: { color: `${theme.grid}33` },
221
+ ticks: { color: theme.tick, maxTicksLimit: 4, font: { size: 10 } },
222
+ border: { display: false },
223
+ },
224
+ },
225
+ };
226
+ }, [widget.chartType, widget.showLegend, theme]);
227
+
228
+ const ChartComponent = widget.chartType === 'line' ? Line : widget.chartType === 'bar' ? Bar : Pie;
229
+
230
+ if (!data || data.length === 0) {
231
+ return (
232
+ <WidgetShell label={widget.label} icon={widget.icon} className={widget.color}>
233
+ <div className="flex flex-1 items-center justify-center rounded-lg border border-dashed border-border/70 bg-base/40 px-3 py-6">
234
+ <p className="text-sm text-fg-muted">{translate('core:state.no_data')}</p>
235
+ </div>
236
+ </WidgetShell>
237
+ );
238
+ }
239
+
240
+ return (
241
+ <WidgetShell label={widget.label} icon={widget.icon} className={cn('min-h-[11rem]', widget.color)}>
242
+ <div className="min-h-[7.5rem] flex-1">
243
+ <ChartComponent data={chartData} options={options as any} />
244
+ </div>
245
+ </WidgetShell>
246
+ );
247
+ }
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { WidgetShell } from './WidgetShell';
3
+
4
+ export interface StatsWidgetProps {
5
+ widget: {
6
+ name: string;
7
+ label?: string;
8
+ icon?: string;
9
+ color?: string;
10
+ format?: 'number' | 'currency' | 'percentage';
11
+ currency?: string;
12
+ precision?: number;
13
+ suffix?: string;
14
+ prefix?: string;
15
+ };
16
+ data: number | null;
17
+ }
18
+
19
+ export function StatsWidget({ widget, data }: StatsWidgetProps) {
20
+ const formatValue = (value: number | null): string => {
21
+ if (value === null || value === undefined) {
22
+ return '—';
23
+ }
24
+
25
+ const { format, currency, precision = 0, prefix, suffix } = widget;
26
+
27
+ let formatted: string;
28
+
29
+ switch (format) {
30
+ case 'currency':
31
+ formatted = new Intl.NumberFormat(undefined, {
32
+ style: 'currency',
33
+ currency: currency || 'USD',
34
+ minimumFractionDigits: precision,
35
+ maximumFractionDigits: precision,
36
+ }).format(value);
37
+ break;
38
+
39
+ case 'percentage':
40
+ formatted = `${value.toFixed(precision)}%`;
41
+ break;
42
+
43
+ case 'number':
44
+ default:
45
+ formatted = new Intl.NumberFormat(undefined, {
46
+ minimumFractionDigits: precision,
47
+ maximumFractionDigits: precision,
48
+ }).format(value);
49
+ break;
50
+ }
51
+
52
+ if (prefix && format !== 'currency') {
53
+ formatted = `${prefix}${formatted}`;
54
+ }
55
+
56
+ if (suffix) {
57
+ formatted = `${formatted} ${suffix}`;
58
+ }
59
+
60
+ return formatted;
61
+ };
62
+
63
+ return (
64
+ <WidgetShell label={widget.label} icon={widget.icon} className={widget.color}>
65
+ <div className="mt-auto">
66
+ <p className="text-2xl font-semibold leading-tight tracking-tight text-fg sm:text-3xl">
67
+ {formatValue(data)}
68
+ </p>
69
+ </div>
70
+ </WidgetShell>
71
+ );
72
+ }
@@ -0,0 +1,108 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { ChevronDown, ChevronUp } from 'lucide-react';
3
+ import { useWidgetRegistry } from '../../contexts/WidgetRegistryContext';
4
+ import { ErrorBoundary } from '../errors/ErrorBoundary';
5
+ import { Slot } from '../../slots/Slot';
6
+ import { cn } from '../../utils/classNames';
7
+ import { widgetVisibilityStorage, getDefaultWidgetsExpanded } from '../../utils/widgetVisibilityStorage';
8
+ import { PillButton } from '../ui/PillButton';
9
+ import { translate } from '../../i18n/activeLocale';
10
+
11
+ export interface WidgetRendererProps {
12
+ widgets?: any[];
13
+ widgetData?: Record<string, any>;
14
+ className?: string;
15
+ /** When set, controlled mode: no internal toggle, use this value and callback */
16
+ expanded?: boolean;
17
+ onExpandedChange?: (expanded: boolean) => void;
18
+ }
19
+
20
+ export function WidgetRenderer({
21
+ widgets,
22
+ widgetData,
23
+ className,
24
+ expanded: controlledExpanded,
25
+ onExpandedChange,
26
+ }: WidgetRendererProps) {
27
+ const widgetRegistry = useWidgetRegistry();
28
+ const [internalExpanded, setInternalExpanded] = useState(false);
29
+
30
+ const isControlled = controlledExpanded !== undefined && onExpandedChange !== undefined;
31
+ const expanded = isControlled ? controlledExpanded : internalExpanded;
32
+
33
+ useEffect(() => {
34
+ if (isControlled) return;
35
+ const stored = widgetVisibilityStorage.get();
36
+ if (stored !== null) {
37
+ setInternalExpanded(stored);
38
+ } else {
39
+ setInternalExpanded(getDefaultWidgetsExpanded());
40
+ }
41
+ }, [isControlled]);
42
+
43
+ const toggleExpanded = () => {
44
+ const next = !expanded;
45
+ if (isControlled) {
46
+ widgetVisibilityStorage.set(next);
47
+ onExpandedChange(next);
48
+ } else {
49
+ setInternalExpanded(next);
50
+ widgetVisibilityStorage.set(next);
51
+ }
52
+ };
53
+
54
+ if (!widgets || widgets.length === 0) {
55
+ return null;
56
+ }
57
+
58
+ return (
59
+ <div className={cn('mb-4', className)}>
60
+ {!isControlled && (
61
+ <div className="mb-2 flex justify-end">
62
+ <PillButton
63
+ variant="default"
64
+ onClick={toggleExpanded}
65
+ aria-expanded={expanded}
66
+ aria-controls="widgets-content"
67
+ id="widgets-toggle"
68
+ icon={expanded ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}>
69
+ {translate('core:common.widgets')}
70
+ </PillButton>
71
+ </div>
72
+ )}
73
+
74
+ <div
75
+ id="widgets-content"
76
+ role="region"
77
+ aria-labelledby="widgets-toggle"
78
+ className={cn(
79
+ 'overflow-hidden transition-[grid-template-rows] duration-200 ease-out',
80
+ expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',
81
+ )}
82
+ style={{ display: 'grid' }}>
83
+ <div className="min-h-0">
84
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4">
85
+ {widgets.map(widget => {
86
+ const WidgetComponent = widgetRegistry[widget.type];
87
+ if (!WidgetComponent) {
88
+ console.warn(`Widget type "${widget.type}" not registered`);
89
+ return null;
90
+ }
91
+
92
+ const data = widgetData?.[widget.name] ?? null;
93
+
94
+ return (
95
+ <div key={widget.name} className="min-w-0">
96
+ <ErrorBoundary label={`widget "${widget.name}"`}>
97
+ <WidgetComponent widget={widget} data={data} />
98
+ </ErrorBoundary>
99
+ </div>
100
+ );
101
+ })}
102
+ <Slot name="widgets.append" />
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ );
108
+ }