@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,181 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { Search, X, CornerDownLeft } from 'lucide-react';
5
+ import { Icon } from './utils/Icon';
6
+ import { cn } from '../utils/classNames';
7
+ import { authenticatedFetch } from '../api/authenticatedFetch';
8
+ import { useResourceModal } from '../contexts/ResourceModalContext';
9
+ import { Spinner } from './ui';
10
+ import { translate } from '../i18n/activeLocale';
11
+ function KeyboardHint({ children }) {
12
+ return (_jsx("kbd", { className: "inline-flex min-w-[20px] items-center justify-center rounded border border-border bg-muted px-1.5 py-0.5 font-sans text-[10px] font-medium text-fg-muted", children: children }));
13
+ }
14
+ export function GlobalSearch({ apiBaseUrl, onResultClick }) {
15
+ const { openModal } = useResourceModal();
16
+ const [paletteOpen, setPaletteOpen] = useState(false);
17
+ const [query, setQuery] = useState('');
18
+ const [debouncedQuery, setDebouncedQuery] = useState('');
19
+ const [results, setResults] = useState({});
20
+ const [loading, setLoading] = useState(false);
21
+ const [selectedIndex, setSelectedIndex] = useState(-1);
22
+ const inputRef = useRef(null);
23
+ const closePalette = useCallback(() => {
24
+ setPaletteOpen(false);
25
+ setQuery('');
26
+ setDebouncedQuery('');
27
+ setResults({});
28
+ setSelectedIndex(-1);
29
+ setLoading(false);
30
+ }, []);
31
+ const openPalette = useCallback(() => {
32
+ setPaletteOpen(true);
33
+ }, []);
34
+ useEffect(() => {
35
+ const timer = setTimeout(() => {
36
+ setDebouncedQuery(query);
37
+ }, 300);
38
+ return () => clearTimeout(timer);
39
+ }, [query]);
40
+ useEffect(() => {
41
+ if (!paletteOpen)
42
+ return;
43
+ const frame = requestAnimationFrame(() => {
44
+ inputRef.current?.focus();
45
+ });
46
+ return () => cancelAnimationFrame(frame);
47
+ }, [paletteOpen]);
48
+ useEffect(() => {
49
+ if (!debouncedQuery.trim()) {
50
+ setResults({});
51
+ setLoading(false);
52
+ setSelectedIndex(-1);
53
+ return;
54
+ }
55
+ const fetchResults = async () => {
56
+ setLoading(true);
57
+ try {
58
+ const response = await authenticatedFetch(`${apiBaseUrl}/global-search`, {
59
+ method: 'POST',
60
+ headers: { 'Content-Type': 'application/json' },
61
+ body: JSON.stringify({ query: debouncedQuery }),
62
+ }, apiBaseUrl);
63
+ if (!response.ok) {
64
+ throw new Error('Failed to fetch search results');
65
+ }
66
+ const data = await response.json();
67
+ setResults(data);
68
+ setSelectedIndex(-1);
69
+ }
70
+ catch (error) {
71
+ console.error('Error fetching search results:', error);
72
+ setResults({});
73
+ }
74
+ finally {
75
+ setLoading(false);
76
+ }
77
+ };
78
+ fetchResults();
79
+ }, [debouncedQuery, apiBaseUrl]);
80
+ useEffect(() => {
81
+ const handleShortcut = (event) => {
82
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
83
+ event.preventDefault();
84
+ if (paletteOpen) {
85
+ closePalette();
86
+ }
87
+ else {
88
+ openPalette();
89
+ }
90
+ }
91
+ };
92
+ document.addEventListener('keydown', handleShortcut);
93
+ return () => document.removeEventListener('keydown', handleShortcut);
94
+ }, [paletteOpen, closePalette, openPalette]);
95
+ useEffect(() => {
96
+ if (!paletteOpen)
97
+ return;
98
+ const handleEscape = (event) => {
99
+ if (event.key === 'Escape') {
100
+ closePalette();
101
+ }
102
+ };
103
+ document.addEventListener('keydown', handleEscape);
104
+ return () => document.removeEventListener('keydown', handleEscape);
105
+ }, [paletteOpen, closePalette]);
106
+ const flattenedResults = useMemo(() => {
107
+ const items = [];
108
+ for (const [resourceSlug, resourceData] of Object.entries(results)) {
109
+ for (const result of resourceData.results) {
110
+ items.push({ resourceSlug, result, resourceData });
111
+ }
112
+ }
113
+ return items;
114
+ }, [results]);
115
+ const handleResultClick = useCallback((resourceSlug, recordId) => {
116
+ openModal(resourceSlug, 'view', recordId);
117
+ closePalette();
118
+ onResultClick?.(resourceSlug, recordId);
119
+ }, [openModal, closePalette, onResultClick]);
120
+ const handleKeyDown = (event) => {
121
+ if (event.key === 'ArrowDown') {
122
+ event.preventDefault();
123
+ if (flattenedResults.length === 0)
124
+ return;
125
+ setSelectedIndex(prev => (prev < flattenedResults.length - 1 ? prev + 1 : 0));
126
+ return;
127
+ }
128
+ if (event.key === 'ArrowUp') {
129
+ event.preventDefault();
130
+ if (flattenedResults.length === 0)
131
+ return;
132
+ setSelectedIndex(prev => (prev > 0 ? prev - 1 : flattenedResults.length - 1));
133
+ return;
134
+ }
135
+ if (event.key === 'Enter') {
136
+ event.preventDefault();
137
+ if (selectedIndex >= 0 && flattenedResults[selectedIndex]) {
138
+ const { resourceSlug, result } = flattenedResults[selectedIndex];
139
+ handleResultClick(resourceSlug, result._id);
140
+ }
141
+ }
142
+ };
143
+ const hasQuery = debouncedQuery.trim().length > 0;
144
+ const hasResults = flattenedResults.length > 0;
145
+ const palette = paletteOpen
146
+ ? createPortal(_jsxs("div", { className: "fixed inset-0 z-[100] flex items-start justify-center px-4 pt-[12vh] sm:pt-[15vh]", children: [_jsx("button", { type: "button", className: "absolute inset-0 bg-black/45 backdrop-blur-md", onClick: closePalette, "aria-label": translate('core:search.close') }), _jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": translate('core:search.records'), className: "relative w-full max-w-2xl overflow-hidden rounded-2xl border border-border/80 bg-surface/95 shadow-soft-lg backdrop-blur-xl", children: [_jsxs("div", { className: "flex items-center gap-3 border-b border-border px-4", children: [_jsx(Search, { className: "h-5 w-5 shrink-0 text-fg-muted" }), _jsx("input", { ref: inputRef, type: "text", value: query, onChange: event => setQuery(event.target.value), onKeyDown: handleKeyDown, placeholder: translate('core:common.search'), autoComplete: "off", spellCheck: false, className: "h-14 min-w-0 flex-1 bg-transparent text-base text-fg placeholder:text-fg-muted focus:outline-none" }), loading && _jsx(Spinner, { size: "sm", className: "shrink-0 text-accent" }), query && !loading && (_jsx("button", { type: "button", onClick: () => {
147
+ setQuery('');
148
+ setDebouncedQuery('');
149
+ setResults({});
150
+ setSelectedIndex(-1);
151
+ inputRef.current?.focus();
152
+ }, className: "rounded-md p-1 text-fg-muted transition-colors hover:bg-hover hover:text-fg", "aria-label": translate('core:search.clear'), children: _jsx(X, { className: "h-4 w-4" }) }))] }), _jsxs("div", { className: "max-h-[min(420px,52vh)] overflow-y-auto", children: [!hasQuery && (_jsxs("div", { className: "px-4 py-8 text-center", children: [_jsx("p", { className: "text-sm text-fg-secondary", children: translate('core:search.subtitle') }), _jsx("p", { className: "mt-1 text-xs text-fg-muted", children: translate('core:search.start_typing') })] })), hasQuery && loading && (_jsxs("div", { className: "flex items-center justify-center gap-2 px-4 py-10 text-sm text-fg-secondary", children: [_jsx(Spinner, { size: "sm", className: "text-accent" }), "Searching\u2026"] })), hasQuery && !loading && !hasResults && (_jsxs("div", { className: "px-4 py-10 text-center text-sm text-fg-secondary", children: ["No results for \u201C", debouncedQuery, "\u201D"] })), hasQuery && !loading && hasResults && (_jsx("div", { className: "py-2", children: Object.entries(results).map(([resourceSlug, resourceData]) => {
153
+ let itemIndex = 0;
154
+ for (const [slug, data] of Object.entries(results)) {
155
+ if (slug === resourceSlug)
156
+ break;
157
+ itemIndex += data.results.length;
158
+ }
159
+ return (_jsxs("div", { className: "mb-1 last:mb-0", children: [_jsxs("div", { className: "flex items-center gap-2 px-4 py-1.5", children: [resourceData.icon && (_jsx(Icon, { name: resourceData.icon, className: "h-3.5 w-3.5 text-fg-muted" })), _jsx("span", { className: "text-[11px] font-medium uppercase tracking-wide text-fg-muted", children: resourceData.pluralLabel })] }), _jsx("ul", { className: "px-2", children: resourceData.results.map((result, resultIndex) => {
160
+ const globalIndex = itemIndex + resultIndex;
161
+ const isSelected = selectedIndex === globalIndex;
162
+ return (_jsx("li", { children: _jsxs("button", { type: "button", onMouseEnter: () => setSelectedIndex(globalIndex), onClick: () => handleResultClick(resourceSlug, result._id), className: cn('flex w-full items-center gap-3 rounded-xl px-3 py-2.5 text-left transition-colors', isSelected
163
+ ? 'bg-accent text-accent-fg'
164
+ : 'text-fg hover:bg-hover'), children: [result.featuredImage ? (_jsx("div", { className: cn('h-9 w-9 shrink-0 overflow-hidden rounded-lg', isSelected
165
+ ? 'ring-1 ring-white/20'
166
+ : 'bg-muted'), children: _jsx("img", { src: result.featuredImage.url, alt: "", className: "h-full w-full object-cover", onError: event => {
167
+ event.target.style.display = 'none';
168
+ } }) })) : (_jsx("div", { className: cn('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', isSelected
169
+ ? 'bg-white/15 text-accent-fg'
170
+ : 'bg-muted text-fg-muted'), children: resourceData.icon ? (_jsx(Icon, { name: resourceData.icon, className: "h-4 w-4" })) : (_jsx(Search, { className: "h-4 w-4" })) })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: cn('truncate text-sm font-medium', isSelected
171
+ ? 'text-accent-fg'
172
+ : 'text-fg'), dangerouslySetInnerHTML: {
173
+ __html: result.title,
174
+ } }), _jsx("p", { className: cn('truncate text-xs', isSelected
175
+ ? 'text-accent-fg/80'
176
+ : 'text-fg-muted'), children: resourceData.label })] }), isSelected && (_jsx(CornerDownLeft, { className: "h-4 w-4 shrink-0 opacity-80" }))] }) }, result._id));
177
+ }) })] }, resourceSlug));
178
+ }) }))] }), _jsxs("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-border px-4 py-2.5 text-[11px] text-fg-muted", children: [_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(KeyboardHint, { children: "\u2191\u2193" }), translate('core:search.nav_navigate')] }), _jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(KeyboardHint, { children: "\u21B5" }), translate('core:search.nav_open')] }), _jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(KeyboardHint, { children: "esc" }), translate('core:search.nav_close')] })] })] })] }), document.body)
179
+ : null;
180
+ return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: openPalette, "aria-label": translate('core:search.records'), className: cn('inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-border bg-input/60 transition-colors sm:hidden', 'hover:border-border-strong hover:bg-hover', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'), children: _jsx(Search, { className: "h-4 w-4 text-fg-muted" }) }), _jsxs("button", { type: "button", onClick: openPalette, className: cn('hidden h-9 w-full min-w-0 items-center gap-2 rounded-lg border border-border bg-input/60 px-3 text-left text-sm transition-colors sm:flex', 'hover:border-border-strong hover:bg-hover', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'), children: [_jsx(Search, { className: "h-4 w-4 shrink-0 text-fg-muted" }), _jsx("span", { className: "min-w-0 flex-1 truncate text-fg-muted", children: translate('core:common.search') }), _jsx("kbd", { className: "ml-auto shrink-0 rounded border border-border bg-muted px-1.5 py-0.5 text-[10px] font-medium text-fg-muted", children: "\u2318K" })] }), palette] }));
181
+ }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { FieldProps } from '../types';
3
+ export declare function GroupField({ label, description, hint, hintIcon, hintColor, icon, schema, columns, disabled, mode, value, _recordData, operation, apiBaseUrl, resource, }: FieldProps & {
4
+ _recordData?: any;
5
+ apiBaseUrl?: string;
6
+ resource?: string;
7
+ }): React.JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId } from 'react';
3
+ import { FieldRenderer } from '../FieldRenderer';
4
+ import { HintDisplay } from './utils/HintDisplay';
5
+ import { Icon } from './utils/Icon';
6
+ import { getGridClasses } from './utils/layoutHelpers';
7
+ import { cn } from '../utils/classNames';
8
+ export function GroupField({ label, description, hint, hintIcon, hintColor, icon, schema, columns, disabled, mode, value, _recordData, operation, apiBaseUrl, resource, }) {
9
+ const groupId = useId();
10
+ const recordData = mode === 'view' && _recordData ? _recordData : value || {};
11
+ const gridClasses = getGridClasses(columns);
12
+ const hasHeader = Boolean(label || description || hint || icon);
13
+ return (_jsxs("div", { role: "group", "aria-labelledby": label ? groupId : undefined, className: "w-full rounded-xl border border-border bg-surface", children: [hasHeader && (_jsx("div", { className: "rounded-t-xl border-b border-border/60 bg-muted/25 px-4 py-3", children: _jsxs("div", { className: "flex items-start gap-3", children: [icon && (_jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-raised text-fg-secondary shadow-soft-sm", children: _jsx(Icon, { name: icon, className: "h-4 w-4" }) })), _jsxs("div", { className: "min-w-0 flex-1", children: [label && (_jsx("p", { id: groupId, className: "text-sm font-semibold leading-snug text-fg", children: label })), description && (_jsx("p", { className: cn('text-sm leading-relaxed text-fg-secondary', label && 'mt-1'), children: description })), _jsx(HintDisplay, { hint: hint, hintIcon: hintIcon, hintColor: hintColor })] })] }) })), _jsx("div", { className: cn('p-4', gridClasses, 'gap-y-4'), children: schema &&
14
+ schema.map((field, index) => {
15
+ const nestedField = {
16
+ ...field,
17
+ disabled: disabled || field.disabled,
18
+ mode: mode || field.mode,
19
+ };
20
+ const nestedValue = mode === 'view' && field.name ? recordData[field.name] : undefined;
21
+ return (_jsx(FieldRenderer, { field: nestedField, mode: mode, value: nestedValue, operation: operation, apiBaseUrl: apiBaseUrl, resource: resource }, index));
22
+ }) })] }));
23
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { FieldProps } from '../types';
3
+ export declare function HiddenField({ name, default: defaultValue, mode }: FieldProps): React.JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useFormContext } from 'react-hook-form';
3
+ export function HiddenField({ name, default: defaultValue, mode }) {
4
+ // Hidden fields should not be displayed in view mode
5
+ if (mode === 'view') {
6
+ return null;
7
+ }
8
+ const { register } = useFormContext();
9
+ return _jsx("input", { type: "hidden", ...register(name), defaultValue: defaultValue });
10
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ /**
3
+ * Stack breadcrumb for nested modals — pill items matching sidebar/table tabs.
4
+ */
5
+ export declare function ModalBreadcrumb(): React.JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { ChevronRight, Loader2 } from 'lucide-react';
4
+ import { useResourceModal } from '../contexts/ResourceModalContext';
5
+ import { cn } from '../utils/classNames';
6
+ import { pillTabClass } from './ui/PillButton';
7
+ import { translate } from '../i18n/activeLocale';
8
+ function getModalKey(modal) {
9
+ return `${modal.resource}-${modal.mode}-${modal.recordId || 'new'}`;
10
+ }
11
+ /**
12
+ * Stack breadcrumb for nested modals — pill items matching sidebar/table tabs.
13
+ */
14
+ export function ModalBreadcrumb() {
15
+ const { modalStack, modalTitles, closeModal } = useResourceModal();
16
+ if (modalStack.length <= 1) {
17
+ return null;
18
+ }
19
+ const handleBreadcrumbClick = (targetIndex) => {
20
+ const modalsToClose = modalStack.length - 1 - targetIndex;
21
+ for (let i = 0; i < modalsToClose; i++) {
22
+ closeModal();
23
+ }
24
+ const target = modalStack[targetIndex];
25
+ window.history.replaceState(null, '', `/${target.resource}/${target.recordId || ''}`);
26
+ };
27
+ return (_jsx("div", { className: "shrink-0 border-b border-border/60 bg-base/30 px-4 py-2.5", children: _jsx("nav", { className: "flex items-center gap-1 overflow-x-auto overscroll-x-contain", style: { WebkitOverflowScrolling: 'touch' }, "aria-label": translate('core:modal.stack'), children: modalStack.map((modal, index) => {
28
+ const modalKey = getModalKey(modal);
29
+ const title = modal.mode === 'action' && modal.actionLabel ? modal.actionLabel : modalTitles[modalKey];
30
+ const isLast = index === modalStack.length - 1;
31
+ return (_jsxs(React.Fragment, { children: [_jsx("button", { type: "button", onClick: () => !isLast && handleBreadcrumbClick(index), disabled: isLast, className: cn(pillTabClass(isLast), isLast ? 'cursor-default' : 'cursor-pointer', !title && 'italic'), title: title || modal.resource, "aria-current": isLast ? 'page' : undefined, children: !title ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }), _jsx("span", { children: translate('core:common.loading_ellipsis') })] })) : (_jsx("span", { className: "max-w-[180px] truncate", children: title })) }), !isLast && _jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-fg-muted", "aria-hidden": true })] }, modalKey));
32
+ }) }) }));
33
+ }
@@ -0,0 +1,15 @@
1
+ import React, { ReactNode } from 'react';
2
+ export interface ModalDrawerProps {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ title: string | ReactNode;
6
+ children: ReactNode;
7
+ depth?: number;
8
+ onCloseAll?: () => void;
9
+ width?: string;
10
+ onCopyUrl?: () => void;
11
+ urlCopied?: boolean;
12
+ /** Optional pinned footer (e.g. form buttons) */
13
+ footer?: ReactNode;
14
+ }
15
+ export declare function ModalDrawer({ isOpen, onClose, title, children, depth, onCloseAll, onCopyUrl, urlCopied, footer, }: ModalDrawerProps): React.JSX.Element;
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
3
+ import { X, ArrowLeft, Copy, Check } from 'lucide-react';
4
+ import { cn } from '../utils/classNames';
5
+ import { ModalBreadcrumb } from './ModalBreadcrumb';
6
+ import { PillIconButton } from './ui/PillButton';
7
+ import { translate } from '../i18n/activeLocale';
8
+ import { Slot } from '../slots/Slot';
9
+ export function ModalDrawer({ isOpen, onClose, title, children, depth = 0, onCloseAll, onCopyUrl, urlCopied, footer, }) {
10
+ useEffect(() => {
11
+ const handleEscape = (e) => {
12
+ if (e.key === 'Escape') {
13
+ onClose();
14
+ }
15
+ };
16
+ if (isOpen) {
17
+ document.addEventListener('keydown', handleEscape);
18
+ document.body.style.overflow = 'hidden';
19
+ }
20
+ return () => {
21
+ document.removeEventListener('keydown', handleEscape);
22
+ document.body.style.overflow = 'unset';
23
+ };
24
+ }, [isOpen, onClose]);
25
+ if (!isOpen)
26
+ return null;
27
+ const zIndex = 50 + depth;
28
+ const renderTitle = () => {
29
+ if (typeof title === 'string') {
30
+ if (/<[^>]+>/.test(title)) {
31
+ return _jsx("span", { dangerouslySetInnerHTML: { __html: title } });
32
+ }
33
+ return title;
34
+ }
35
+ return title;
36
+ };
37
+ return (_jsxs("div", { className: "fixed inset-0", style: { zIndex }, children: [_jsx("div", { className: cn('absolute inset-0 transition-opacity', depth === 0 && 'bg-black/40 backdrop-blur-[2px]'), onClick: onCloseAll ?? onClose, "aria-hidden": true }), _jsxs("div", { className: cn('fixed top-0 flex h-full w-full flex-col border-border bg-surface transition-transform duration-300 ease-out md:w-1/2 md:max-w-2xl md:border-l', 'shadow-soft-lg'), style: {
38
+ right: depth === 0 ? '0px' : `${depth * 16}px`,
39
+ }, onClick: e => e.stopPropagation(), role: "dialog", "aria-modal": "true", children: [_jsxs("div", { className: "flex h-14 shrink-0 items-center justify-between gap-3 border-b border-border/60 bg-base/80 px-4 backdrop-blur-sm", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [_jsx(PillIconButton, { variant: "ghost", onClick: onClose, "aria-label": translate('core:modal.close'), title: translate('core:modal.close'), children: _jsx(ArrowLeft, { className: "h-4 w-4" }) }), _jsx("h2", { className: "truncate text-base font-semibold text-fg", children: renderTitle() })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [_jsx(Slot, { name: "modal.headerActions", as: "div", className: "flex items-center gap-1 empty:hidden" }), onCopyUrl && (_jsx(PillIconButton, { variant: "ghost", active: urlCopied, onClick: onCopyUrl, "aria-label": translate('core:common.copy_url'), title: translate('core:common.copy_url'), className: urlCopied ? 'text-success' : undefined, children: urlCopied ? _jsx(Check, { className: "h-4 w-4" }) : _jsx(Copy, { className: "h-4 w-4" }) })), depth > 0 && onCloseAll && (_jsx(PillIconButton, { variant: "danger", onClick: onCloseAll, "aria-label": translate('core:modal.close_all'), title: translate('core:modal.close_all'), children: _jsx(X, { className: "h-4 w-4" }) }))] })] }), _jsx(ModalBreadcrumb, {}), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto overflow-x-hidden bg-surface p-4 sm:p-6", children: children }), _jsxs("div", { className: "shrink-0 border-t border-border/60 bg-base/50 px-4 py-3 empty:hidden sm:px-6 sm:py-4", children: [footer, _jsx(Slot, { name: "modal.footer", as: "div", className: "mt-2 first:mt-0 empty:hidden" })] })] })] }));
40
+ }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { FieldProps } from '../types';
3
+ /**
4
+ * Radio field component
5
+ * Renders a radio button group
6
+ */
7
+ export declare function RadioField(props: FieldProps): React.JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useFormContext } from 'react-hook-form';
3
+ import { getFieldError } from '../utils/fieldErrors';
4
+ import { useValidation } from '../hooks/useValidation';
5
+ import { cn } from '../utils/classNames';
6
+ import { HintDisplay } from './utils/HintDisplay';
7
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
8
+ import { formatSelectLabel } from '../utils/formatValue';
9
+ /**
10
+ * Radio field component
11
+ * Renders a radio button group
12
+ */
13
+ export function RadioField(props) {
14
+ // View mode: render formatted display
15
+ if (props.mode === 'view') {
16
+ const value = props.value;
17
+ const displayValue = formatSelectLabel(value, props.options);
18
+ return _jsx(ViewFieldWrapper, { label: props.label, children: displayValue });
19
+ }
20
+ const { register, formState: { errors }, } = useFormContext();
21
+ const validation = useValidation(props.validation?.rules || [], props.operation, props.name);
22
+ const error = getFieldError(errors, props.name);
23
+ const hasError = !!error;
24
+ return (_jsxs("div", { className: "mb-4", children: [props.label && (_jsxs("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: [props.label, validation.required && _jsx("span", { className: "text-red-500 dark:text-red-400 ml-1", children: "*" })] })), _jsx("div", { className: "space-y-2", children: props.options &&
25
+ Object.entries(props.options).map(([value, label]) => (_jsxs("div", { className: "flex items-center", children: [_jsx("input", { id: `${props.name}-${value}`, type: "radio", ...register(props.name, validation), value: value, disabled: props.disabled, className: cn('w-4 h-4 border', 'text-accent dark:text-accent', 'k-input', 'focus:ring-2 focus:ring-ring', 'transition duration-150 ease-in-out', hasError && 'border-red-500 dark:border-red-400', props.disabled && 'opacity-60 cursor-not-allowed') }), _jsx("label", { htmlFor: `${props.name}-${value}`, className: cn('ml-3 text-sm text-gray-700 dark:text-gray-300', props.disabled && 'opacity-60 cursor-not-allowed'), children: label })] }, value))) }), hasError && _jsx("p", { className: "mt-1 text-sm text-red-600 dark:text-red-400", children: error?.message }), props.helperText && _jsx("p", { className: "mt-1 text-sm text-gray-500 dark:text-gray-400", children: props.helperText }), !hasError && _jsx(HintDisplay, { hint: props.hint, hintIcon: props.hintIcon, hintColor: props.hintColor })] }));
26
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { FieldProps } from '../types';
3
+ export declare function RepeaterField(props: FieldProps): React.JSX.Element;
@@ -0,0 +1,191 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState } from 'react';
3
+ import { useFormContext, useFieldArray, useWatch } from 'react-hook-form';
4
+ import { getFieldError } from '../utils/fieldErrors';
5
+ import { FieldRenderer } from '../FieldRenderer';
6
+ import { HintDisplay } from './utils/HintDisplay';
7
+ import { ViewFieldWrapper } from './utils/ViewFieldWrapper';
8
+ import { PillButton } from './ui/PillButton';
9
+ import { translate } from '../i18n/activeLocale';
10
+ export function RepeaterField(props) {
11
+ const { name, label, helperText, hint, hintIcon, hintColor, schema = [], defaultItems = 0, minItems, maxItems, addable = true, deletable = true, reorderable = true, itemLabel, disabled = false, collapsible = false, mode, value, operation, } = props;
12
+ // Threaded down so nested fields (e.g. relation selects, file uploads) can reach the API.
13
+ const apiBaseUrl = props.apiBaseUrl;
14
+ const resource = props.resource;
15
+ // Determine if repeater should be treated as required (for minItems fallback)
16
+ let isRequired = props.required === true;
17
+ const validationRules = props.validation?.rules;
18
+ if (validationRules && Array.isArray(validationRules)) {
19
+ if (validationRules.some(rule => rule === 'required' || (typeof rule === 'object' && rule.rule === 'required'))) {
20
+ isRequired = true;
21
+ }
22
+ }
23
+ // Effective minItems: honor explicit minItems, otherwise infer from required
24
+ const effectiveMinItems = minItems !== undefined ? minItems : isRequired ? 1 : undefined;
25
+ // View mode: render formatted display
26
+ if (mode === 'view') {
27
+ const items = Array.isArray(value) ? value : [];
28
+ if (items.length === 0) {
29
+ return _jsx(ViewFieldWrapper, { label: label, children: "-" });
30
+ }
31
+ return (_jsx(ViewFieldWrapper, { label: label, children: _jsx("div", { className: "space-y-4", children: items.map((item, index) => (_jsxs("div", { className: "border border-border rounded-lg p-4 bg-surface", children: [itemLabel && (_jsxs("div", { className: "font-medium text-fg-secondary mb-3", children: [itemLabel, " ", index + 1] })), _jsx("div", { className: "space-y-3", children: schema.map((field, fieldIndex) => {
32
+ const fieldValue = field.name ? item[field.name] : undefined;
33
+ return (_jsx(FieldRenderer, { field: { ...field, mode: 'view' }, mode: "view", value: fieldValue, operation: operation ?? 'view', apiBaseUrl: apiBaseUrl, resource: resource }, fieldIndex));
34
+ }) })] }, index))) }) }));
35
+ }
36
+ const formContext = useFormContext();
37
+ const { control, register } = formContext;
38
+ const errors = formContext.formState?.errors || {};
39
+ const { fields, append, remove, move } = useFieldArray({
40
+ control,
41
+ name,
42
+ });
43
+ // Track active tab (for non-collapsible mode)
44
+ const [activeTab, setActiveTab] = useState(0);
45
+ // Track collapsed state for each item (for collapsible mode)
46
+ const [collapsedItems, setCollapsedItems] = useState(new Set());
47
+ // Default items are handled by FormRenderer's extractDefaultValues.
48
+ // We do not auto-add placeholders for minItems here, to avoid off-by-one
49
+ // issues and keep the UI strictly in sync with the actual form state.
50
+ // Ensure active tab is valid
51
+ React.useEffect(() => {
52
+ if (activeTab >= fields.length && fields.length > 0) {
53
+ setActiveTab(fields.length - 1);
54
+ }
55
+ }, [fields.length, activeTab]);
56
+ const canAdd = addable && !disabled && (maxItems === undefined || fields.length < maxItems);
57
+ const canDelete = (index) => deletable && !disabled && (effectiveMinItems === undefined || fields.length > effectiveMinItems);
58
+ const canMoveUp = (index) => reorderable && !disabled && index > 0;
59
+ const canMoveDown = (index) => reorderable && !disabled && index < fields.length - 1;
60
+ const handleDelete = (index) => {
61
+ if (canDelete(index)) {
62
+ remove(index);
63
+ // Switch to previous tab if deleting active tab
64
+ if (activeTab >= index && activeTab > 0) {
65
+ setActiveTab(activeTab - 1);
66
+ }
67
+ }
68
+ };
69
+ const handleMoveUp = (index) => {
70
+ if (canMoveUp(index)) {
71
+ move(index, index - 1);
72
+ // Update active tab if moving the active item
73
+ if (activeTab === index) {
74
+ setActiveTab(index - 1);
75
+ }
76
+ else if (activeTab === index - 1) {
77
+ setActiveTab(index);
78
+ }
79
+ }
80
+ };
81
+ const handleMoveDown = (index) => {
82
+ if (canMoveDown(index)) {
83
+ move(index, index + 1);
84
+ // Update active tab if moving the active item
85
+ if (activeTab === index) {
86
+ setActiveTab(index + 1);
87
+ }
88
+ else if (activeTab === index + 1) {
89
+ setActiveTab(index);
90
+ }
91
+ }
92
+ };
93
+ const handleAdd = () => {
94
+ if (canAdd) {
95
+ append({});
96
+ if (!collapsible) {
97
+ setActiveTab(fields.length); // Switch to the newly added tab
98
+ }
99
+ }
100
+ };
101
+ const toggleCollapse = (index) => {
102
+ setCollapsedItems(prev => {
103
+ const newSet = new Set(prev);
104
+ if (newSet.has(index)) {
105
+ newSet.delete(index);
106
+ }
107
+ else {
108
+ newSet.add(index);
109
+ }
110
+ return newSet;
111
+ });
112
+ };
113
+ // Watch all repeater items for dynamic labels
114
+ const watchedItems = useWatch({
115
+ control,
116
+ name: name,
117
+ defaultValue: [],
118
+ });
119
+ // Helper function to get dynamic label for an item
120
+ const getItemLabel = (index) => {
121
+ // Default label format
122
+ const baseLabel = itemLabel || translate('core:common.item');
123
+ // Check if itemLabel has a field name specified (e.g., "Product: {name}")
124
+ if (typeof itemLabel === 'string' && itemLabel.includes('{') && itemLabel.includes('}')) {
125
+ const match = itemLabel.match(/\{([^}]+)\}/);
126
+ if (match) {
127
+ const fieldName = match[1];
128
+ const template = itemLabel;
129
+ // Get the field value from watched items
130
+ const item = watchedItems?.[index];
131
+ const fieldValue = item?.[fieldName];
132
+ // Replace {fieldName} with actual value
133
+ if (fieldValue) {
134
+ return template.replace(/\{[^}]+\}/, fieldValue);
135
+ }
136
+ // If no value, show placeholder
137
+ return template.replace(/\{[^}]+\}/, `#${index + 1}`);
138
+ }
139
+ }
140
+ // Fallback to numbered format
141
+ return `${baseLabel} ${index + 1}`;
142
+ };
143
+ // Validation for repeater as a whole (min items / required)
144
+ const repeaterValidation = React.useMemo(() => {
145
+ const rules = {};
146
+ if (effectiveMinItems && effectiveMinItems > 0) {
147
+ rules.validate = {
148
+ minItems: (value) => {
149
+ const length = Array.isArray(value) ? value.length : 0;
150
+ return length >= effectiveMinItems || `At least ${effectiveMinItems} item(s) are required`;
151
+ },
152
+ };
153
+ }
154
+ return rules;
155
+ }, [effectiveMinItems]);
156
+ const repeaterError = getFieldError(errors, name);
157
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("input", { type: "hidden", ...register(name, repeaterValidation) }), label && (_jsxs("div", { className: "mb-4", children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: label }), helperText && _jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: helperText }), _jsx(HintDisplay, { hint: hint, hintIcon: hintIcon, hintColor: hintColor })] })), fields.length === 0 ? (
158
+ /* Empty State */
159
+ _jsxs("div", { className: "text-center py-12 text-fg-secondary text-sm border-2 border-dashed border-border rounded-lg bg-muted", children: [_jsx("svg", { className: "w-12 h-12 mx-auto mb-3 text-gray-400 dark:text-gray-500", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }), _jsx("p", { className: "mb-4", children: translate('core:repeater.empty') })] })) : collapsible ? (
160
+ /* Collapsible/Accordion Mode */
161
+ _jsx("div", { className: "space-y-3", children: fields.map((field, index) => {
162
+ const displayLabel = getItemLabel(index);
163
+ const isCollapsed = collapsedItems.has(index);
164
+ return (_jsxs("div", { className: "border border-border rounded-lg bg-surface shadow-sm overflow-hidden", children: [_jsxs("div", { className: "flex items-center bg-muted border-b border-border", children: [_jsxs("button", { type: "button", onClick: () => toggleCollapse(index), className: "flex items-center flex-1 px-4 py-3 text-sm font-medium text-fg hover:bg-hover transition-colors text-left", children: [_jsx("svg", { className: `w-5 h-5 mr-2 transition-transform ${isCollapsed ? '' : 'rotate-90'}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }), _jsx("span", { children: displayLabel })] }), _jsxs("div", { className: "flex items-center gap-1 px-2 py-2 border-l border-border", children: [reorderable && (_jsx("button", { type: "button", onClick: () => handleMoveUp(index), disabled: !canMoveUp(index), className: "p-2 text-fg-secondary hover:text-fg hover:bg-hover rounded disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": translate('core:common.move_up'), title: translate('core:common.move_up'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) }) })), reorderable && (_jsx("button", { type: "button", onClick: () => handleMoveDown(index), disabled: !canMoveDown(index), className: "p-2 text-fg-secondary hover:text-fg hover:bg-hover rounded disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": translate('core:common.move_down'), title: translate('core:common.move_down'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) }) })), _jsx("button", { type: "button", onClick: () => handleDelete(index), disabled: !canDelete(index), className: "p-2 text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/30 rounded disabled:opacity-30 disabled:cursor-not-allowed transition-colors", "aria-label": translate('core:common.delete'), title: translate('core:common.delete'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }) })] })] }), !isCollapsed && (_jsx("div", { className: "p-6", children: _jsx("div", { className: "space-y-4", children: schema.map((fieldSchema) => {
165
+ const nestedField = {
166
+ ...fieldSchema,
167
+ name: `${name}.${index}.${fieldSchema.name}`,
168
+ };
169
+ return (_jsx(FieldRenderer, { field: nestedField, operation: operation, apiBaseUrl: apiBaseUrl, resource: resource }, fieldSchema.name));
170
+ }) }) }))] }, field.id));
171
+ }) })) : (
172
+ /* Tab Mode (Original) */
173
+ _jsxs("div", { className: "border border-border rounded-lg bg-surface shadow-sm overflow-hidden", children: [_jsxs("div", { className: "flex items-center bg-muted border-b border-border overflow-x-auto", children: [_jsx("div", { className: "flex flex-1 min-w-0", children: fields.map((field, index) => {
174
+ const displayLabel = getItemLabel(index);
175
+ const isActive = activeTab === index;
176
+ return (_jsxs("button", { type: "button", onClick: () => setActiveTab(index), className: `
177
+ flex items-center px-4 py-3 text-sm font-medium border-r border-border whitespace-nowrap transition-colors
178
+ ${isActive
179
+ ? 'bg-surface text-accent border-b-2 border-b-accent -mb-px'
180
+ : 'text-fg-secondary hover:text-fg hover:bg-hover'}
181
+ `, children: [_jsx("span", { className: "mr-2", children: displayLabel }), isActive && (_jsx("span", { className: "w-2 h-2 bg-accent rounded-full", "aria-label": translate('core:repeater.active_tab') }))] }, field.id));
182
+ }) }), _jsxs("div", { className: "flex items-center gap-1 px-2 py-2 border-l border-border bg-muted", children: [reorderable && (_jsx("button", { type: "button", onClick: () => handleMoveUp(activeTab), disabled: !canMoveUp(activeTab), className: "p-2 text-fg-secondary hover:text-fg hover:bg-hover rounded disabled:opacity-30 disabled:cursor-not-allowed focus:outline-none transition-colors", "aria-label": translate('core:common.move_left'), title: translate('core:common.move_left'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) })), reorderable && (_jsx("button", { type: "button", onClick: () => handleMoveDown(activeTab), disabled: !canMoveDown(activeTab), className: "p-2 text-fg-secondary hover:text-fg hover:bg-hover rounded disabled:opacity-30 disabled:cursor-not-allowed focus:outline-none transition-colors", "aria-label": translate('core:common.move_right'), title: translate('core:common.move_right'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }) })), _jsx("button", { type: "button", onClick: () => handleDelete(activeTab), disabled: !canDelete(activeTab), className: "p-2 text-red-500 dark:text-red-400 hover:text-red-700 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/30 rounded disabled:opacity-30 disabled:cursor-not-allowed focus:outline-none transition-colors", "aria-label": translate('core:common.delete'), title: translate('core:common.delete'), children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }) })] })] }), _jsx("div", { className: "p-6", children: fields.map((field, index) => (_jsx("div", { className: activeTab === index ? 'block' : 'hidden', children: _jsx("div", { className: "space-y-4", children: schema.map((fieldSchema) => {
183
+ // Create a namespaced field for the nested schema
184
+ const nestedField = {
185
+ ...fieldSchema,
186
+ name: `${name}.${index}.${fieldSchema.name}`,
187
+ disabled: disabled || fieldSchema.disabled, // Propagate disabled state
188
+ };
189
+ return (_jsx(FieldRenderer, { field: nestedField, operation: operation, apiBaseUrl: apiBaseUrl, resource: resource }, fieldSchema.name));
190
+ }) }) }, field.id))) })] })), _jsx(PillButton, { type: "button", onClick: handleAdd, disabled: !canAdd, className: "w-full border-accent/30 bg-accent-soft text-accent hover:bg-accent-soft", children: _jsxs("span", { className: "flex items-center justify-center", children: [_jsx("svg", { className: "w-5 h-5 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" }) }), translate('core:common.add'), maxItems !== undefined && ` (${fields.length}/${maxItems})`] }) }), (minItems !== undefined || maxItems !== undefined) && (_jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 text-center", children: [minItems !== undefined && `Minimum: ${minItems}`, minItems !== undefined && maxItems !== undefined && ' • ', maxItems !== undefined && `Maximum: ${maxItems}`] }))] }));
191
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { ModalState } from '../contexts/ResourceModalContext';
3
+ interface ResourceModalRendererProps {
4
+ modal: ModalState;
5
+ apiBaseUrl: string;
6
+ onClose: () => void;
7
+ onCloseAll: () => void;
8
+ }
9
+ export declare const ResourceModalRenderer: React.MemoExoticComponent<({ modal, apiBaseUrl, onClose, onCloseAll }: ResourceModalRendererProps) => React.JSX.Element>;
10
+ export {};