@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,98 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useState } from 'react';
3
+ import { formatValue } from '../../utils/tableFormatters';
4
+ import { getColumnMediaDimensions } from '../../utils/columnMediaDimensions';
5
+ import { Icon } from '../utils/Icon';
6
+ import { DeeplinkWrapper } from './DeeplinkWrapper';
7
+ import { translate } from '../../i18n/activeLocale';
8
+ function ImagePreviewModal({ isOpen, onClose, imageUrl, title }) {
9
+ if (!isOpen)
10
+ return null;
11
+ return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm", onClick: onClose, children: _jsxs("div", { className: "relative max-w-4xl max-h-[90vh] p-2 bg-surface rounded-lg shadow-2xl", onClick: e => e.stopPropagation(), children: [title && (_jsx("div", { className: "px-4 py-2 border-b border-border", children: _jsx("h3", { className: "text-lg font-semibold text-fg", children: title }) })), _jsx("button", { onClick: onClose, className: "absolute top-2 right-2 p-2 rounded-full bg-hover hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors z-10", title: translate('core:modal.close'), children: _jsx(Icon, { name: "X", size: 20, className: "text-fg" }) }), _jsx("div", { className: "p-4", children: _jsx("img", { src: imageUrl, alt: title || translate('core:common.preview'), className: "max-w-full max-h-[80vh] object-contain rounded" }) })] }) }));
12
+ }
13
+ export function ImageColumnComponent({ column, record }) {
14
+ const [previewOpen, setPreviewOpen] = useState(false);
15
+ const [previewUrl, setPreviewUrl] = useState('');
16
+ const rawValue = record[column.name];
17
+ const value = rawValue;
18
+ const hasDeeplink = !!column.deeplink;
19
+ // Apply formatter if present (e.g., to extract nested property or prepend URL)
20
+ const formattedValue = formatValue(rawValue, column, record);
21
+ // Extract URL from new format: { key, storage, url } or use formatted value
22
+ let imageUrl = null;
23
+ if (formattedValue) {
24
+ if (typeof formattedValue === 'object' && formattedValue !== null) {
25
+ // New format: { key, storage, url } or array of such objects
26
+ if (Array.isArray(formattedValue)) {
27
+ imageUrl = formattedValue.map((item) => (typeof item === 'object' && item?.url ? item.url : item));
28
+ }
29
+ else if (formattedValue.url) {
30
+ imageUrl = formattedValue.url;
31
+ }
32
+ else {
33
+ imageUrl = formattedValue;
34
+ }
35
+ }
36
+ else {
37
+ imageUrl = formattedValue;
38
+ }
39
+ }
40
+ imageUrl = imageUrl || column.defaultImageUrl;
41
+ if (!imageUrl) {
42
+ return _jsx("span", { className: "text-fg-secondary", children: translate('core:file.no_image') });
43
+ }
44
+ const getImageClasses = (circular) => {
45
+ if (circular) {
46
+ return 'h-full w-full object-cover';
47
+ }
48
+ const classes = ['object-cover'];
49
+ if (column.square) {
50
+ classes.push('rounded-none');
51
+ }
52
+ else {
53
+ classes.push('rounded');
54
+ }
55
+ if (column.clickable || hasDeeplink) {
56
+ classes.push('cursor-pointer hover:opacity-80 transition-opacity');
57
+ }
58
+ return classes.join(' ');
59
+ };
60
+ const handleImageClick = (url) => {
61
+ // If there's a deeplink, don't handle the click here - DeeplinkWrapper will handle it
62
+ if (hasDeeplink) {
63
+ return;
64
+ }
65
+ // Fall back to existing clickable behavior
66
+ if (!column.clickable)
67
+ return;
68
+ if (column.clickAction === 'link') {
69
+ window.open(url, '_blank');
70
+ }
71
+ else {
72
+ // Default to preview
73
+ setPreviewUrl(url);
74
+ setPreviewOpen(true);
75
+ }
76
+ };
77
+ const dimensions = getColumnMediaDimensions(column, 40);
78
+ const isCircular = !!column.circular;
79
+ // Render single image helper
80
+ const renderImage = (url, extraClasses = '') => {
81
+ const interactive = column.clickable || hasDeeplink;
82
+ const imgElement = isCircular ? (_jsx("span", { className: `inline-flex shrink-0 overflow-hidden rounded-full ${interactive ? 'cursor-pointer hover:opacity-80 transition-opacity' : ''} ${extraClasses}`.trim(), style: dimensions, onClick: () => handleImageClick(url), children: _jsx("img", { src: url, alt: "", className: getImageClasses(true) }) })) : (_jsx("img", { src: url, alt: "", className: `${getImageClasses(false)} ${extraClasses}`.trim(), style: dimensions, onClick: () => handleImageClick(url) }));
83
+ // Wrap in deeplink if exists
84
+ if (hasDeeplink) {
85
+ return (_jsx(DeeplinkWrapper, { column: column, record: record, value: value, className: "inline-block", children: imgElement }));
86
+ }
87
+ return imgElement;
88
+ };
89
+ // Handle arrays (stacked images)
90
+ if (Array.isArray(imageUrl)) {
91
+ const images = column.limit ? imageUrl.slice(0, column.limit) : imageUrl;
92
+ if (column.stacked) {
93
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex -space-x-2", children: [images.map((url, idx) => (_jsx(React.Fragment, { children: renderImage(url, 'ring-2 ring-white dark:ring-gray-800') }, idx))), column.limit && imageUrl.length > column.limit && (_jsxs("div", { className: `flex items-center justify-center bg-muted text-fg-secondary text-xs font-medium ring-2 ring-surface ${isCircular ? 'rounded-full' : 'rounded'}`.trim(), style: dimensions, children: ["+", imageUrl.length - column.limit] }))] }), _jsx(ImagePreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), imageUrl: previewUrl, title: column.previewTitle })] }));
94
+ }
95
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "flex gap-2", children: images.map((url, idx) => (_jsx(React.Fragment, { children: renderImage(url) }, idx))) }), _jsx(ImagePreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), imageUrl: previewUrl, title: column.previewTitle })] }));
96
+ }
97
+ return (_jsxs(_Fragment, { children: [renderImage(imageUrl), _jsx(ImagePreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), imageUrl: previewUrl, title: column.previewTitle })] }));
98
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export declare function MediaColumnComponent({ column, record }: ColumnProps): React.JSX.Element;
@@ -0,0 +1,160 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { formatValue } from '../../utils/tableFormatters';
4
+ import { getColumnMediaDimensions } from '../../utils/columnMediaDimensions';
5
+ import { Icon } from '../utils/Icon';
6
+ import { MediaPreviewModal } from '../utils/MediaPreviewModal';
7
+ import { translate } from '../../i18n/activeLocale';
8
+ /**
9
+ * Resolve media type from column config
10
+ */
11
+ function resolveMediaType(column, record) {
12
+ const rawValue = record[column.name];
13
+ // Check for media type function (serialized as string)
14
+ if (column.mediaTypeFn) {
15
+ try {
16
+ // eslint-disable-next-line no-new-func
17
+ const mediaTypeFn = new Function('return ' + column.mediaTypeFn)();
18
+ const result = mediaTypeFn(rawValue, record);
19
+ if (result === 'image' || result === 'video' || result === 'audio')
20
+ return result;
21
+ return 'image';
22
+ }
23
+ catch {
24
+ console.warn('Failed to execute mediaType function');
25
+ return 'image';
26
+ }
27
+ }
28
+ // Static media type
29
+ if (column.mediaType === 'image' || column.mediaType === 'video' || column.mediaType === 'audio') {
30
+ return column.mediaType;
31
+ }
32
+ // Default to image
33
+ return 'image';
34
+ }
35
+ /**
36
+ * Resolve thumbnail URL from column config
37
+ * Supports: field name string, function string (serialized), variants, or default thumbnail
38
+ */
39
+ function resolveThumbnail(column, record) {
40
+ const rawValue = record[column.name];
41
+ // Check for variants.thumbnail.url in new format
42
+ if (rawValue && typeof rawValue === 'object' && rawValue.variants?.thumbnail?.url) {
43
+ return rawValue.variants.thumbnail.url;
44
+ }
45
+ // Check for thumbnail function (serialized as string)
46
+ if (column.thumbnailFn) {
47
+ try {
48
+ // eslint-disable-next-line no-new-func
49
+ const thumbnailFn = new Function('return ' + column.thumbnailFn)();
50
+ const result = thumbnailFn(rawValue, record);
51
+ if (result)
52
+ return result;
53
+ }
54
+ catch {
55
+ console.warn('Failed to execute thumbnail function');
56
+ }
57
+ }
58
+ // Check for thumbnail field name
59
+ if (column.thumbnailField) {
60
+ const fieldName = column.thumbnailField;
61
+ // Support nested field access (e.g., 'mediaFile.thumbnailUrl')
62
+ const fieldValue = fieldName.split('.').reduce((obj, key) => obj?.[key], record);
63
+ if (fieldValue) {
64
+ // If it's a string, use it directly; otherwise check for new format
65
+ if (typeof fieldValue === 'string') {
66
+ return fieldValue;
67
+ }
68
+ if (typeof fieldValue === 'object' && fieldValue?.url) {
69
+ return fieldValue.url;
70
+ }
71
+ }
72
+ }
73
+ // Fallback to default thumbnail
74
+ if (column.defaultThumbnail) {
75
+ return column.defaultThumbnail;
76
+ }
77
+ return null;
78
+ }
79
+ export function MediaColumnComponent({ column, record }) {
80
+ const [previewOpen, setPreviewOpen] = useState(false);
81
+ const rawValue = record[column.name];
82
+ // Apply formatter if present
83
+ const formattedValue = formatValue(rawValue, column, record);
84
+ // Extract URL from new format: { key, storage, url }
85
+ let mediaUrl = null;
86
+ if (formattedValue) {
87
+ if (typeof formattedValue === 'object' && formattedValue !== null && formattedValue.url) {
88
+ mediaUrl = formattedValue.url;
89
+ }
90
+ else if (typeof formattedValue === 'string') {
91
+ mediaUrl = formattedValue;
92
+ }
93
+ }
94
+ // Resolve media type
95
+ const mediaType = resolveMediaType(column, record);
96
+ // Get thumbnail URL (for videos)
97
+ const thumbnailUrl = resolveThumbnail(column, record);
98
+ // Get default image URL (for images)
99
+ const defaultImageUrl = column.defaultImageUrl;
100
+ // Aspect ratio (default 16/9; circular columns force 1:1 via getColumnMediaDimensions)
101
+ const dimensions = getColumnMediaDimensions(column, 40);
102
+ const placeholderIcon = column.placeholderIcon ||
103
+ (mediaType === 'video' ? 'Video' : mediaType === 'audio' ? 'Music' : 'Image');
104
+ const isClickable = column.clickable !== false;
105
+ const getContainerClasses = () => {
106
+ const classes = ['relative', 'flex', 'items-center', 'justify-center', 'overflow-hidden'];
107
+ if (column.circular) {
108
+ classes.push('rounded-full');
109
+ }
110
+ else if (column.square) {
111
+ classes.push('rounded-none');
112
+ }
113
+ else {
114
+ classes.push('rounded');
115
+ }
116
+ if (isClickable && mediaUrl) {
117
+ classes.push('cursor-pointer', 'hover:opacity-80', 'transition-opacity');
118
+ }
119
+ if (mediaType === 'video') {
120
+ classes.push('bg-gray-100', 'dark:bg-gray-800', 'group');
121
+ }
122
+ return classes.join(' ');
123
+ };
124
+ const handleClick = () => {
125
+ if (!isClickable || !mediaUrl)
126
+ return;
127
+ if (column.clickAction === 'link') {
128
+ window.open(mediaUrl, '_blank');
129
+ }
130
+ else {
131
+ setPreviewOpen(true);
132
+ }
133
+ };
134
+ // If media type is null (hidden), show nothing
135
+ if (mediaType === null) {
136
+ return _jsx("span", { className: "text-fg-secondary", children: "-" });
137
+ }
138
+ // If no media URL
139
+ if (!mediaUrl) {
140
+ // For images, check default image URL
141
+ if (mediaType === 'image' && defaultImageUrl) {
142
+ return (_jsxs(_Fragment, { children: [_jsx("img", { src: defaultImageUrl, alt: "", className: `object-cover ${getContainerClasses()}`, style: dimensions, onClick: handleClick }), isClickable && (_jsx(MediaPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), mediaUrl: defaultImageUrl, mediaType: "image", title: column.previewTitle }))] }));
143
+ }
144
+ // Show placeholder for video/audio
145
+ if (mediaType === 'video' || mediaType === 'audio') {
146
+ return (_jsx("div", { className: `${getContainerClasses()} opacity-50 cursor-not-allowed bg-gray-100 dark:bg-gray-800`, style: dimensions, children: _jsx(Icon, { name: placeholderIcon, size: 20, className: "text-gray-400" }) }));
147
+ }
148
+ return _jsx("span", { className: "text-fg-secondary", children: translate('core:file.no_image') });
149
+ }
150
+ // Render video
151
+ if (mediaType === 'video') {
152
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: `${getContainerClasses()} bg-gray-100 dark:bg-gray-800`, style: dimensions, onClick: handleClick, children: thumbnailUrl ? (_jsxs(_Fragment, { children: [_jsx("img", { src: thumbnailUrl, alt: translate('core:common.video_thumbnail'), className: "w-full h-full object-cover" }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/30 group-hover:bg-black/40 transition-colors", children: _jsx("div", { className: "w-8 h-8 flex items-center justify-center bg-white/90 rounded-full", children: _jsx(Icon, { name: "Play", size: 16, className: "text-gray-800 ml-0.5" }) }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { name: placeholderIcon, size: 24, className: "text-gray-500 dark:text-gray-400" }), _jsx("div", { className: "absolute bottom-1 right-1 w-4 h-4 flex items-center justify-center bg-accent rounded-full", children: _jsx(Icon, { name: "Play", size: 10, className: "text-white ml-0.5" }) })] })) }), _jsx(MediaPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), mediaUrl: mediaUrl, mediaType: "video", title: column.previewTitle, autoplay: column.autoplay, controls: column.controls !== false, loop: column.loop, muted: column.muted })] }));
153
+ }
154
+ // Render audio
155
+ if (mediaType === 'audio') {
156
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `${getContainerClasses()} bg-linear-to-br from-blue-600 to-purple-600`, style: dimensions, onClick: handleClick, children: [_jsx(Icon, { name: placeholderIcon, size: 24, className: "text-white" }), _jsx("div", { className: "absolute bottom-1 right-1 w-4 h-4 flex items-center justify-center bg-white/90 rounded-full", children: _jsx(Icon, { name: "Play", size: 10, className: "text-gray-800 ml-0.5" }) })] }), _jsx(MediaPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), mediaUrl: mediaUrl, mediaType: "audio", title: column.previewTitle, autoplay: column.autoplay, controls: column.controls !== false, loop: column.loop })] }));
157
+ }
158
+ // Render single image
159
+ return (_jsxs(_Fragment, { children: [_jsx("img", { src: mediaUrl, alt: "", className: `object-cover ${getContainerClasses()}`, style: dimensions, onClick: handleClick }), _jsx(MediaPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), mediaUrl: mediaUrl, mediaType: "image", title: column.previewTitle })] }));
160
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export interface EditableColumnProps extends ColumnProps {
4
+ onCellChange?: (value: any) => void;
5
+ }
6
+ export declare function SelectColumnComponent({ column, record, onCellChange }: EditableColumnProps): React.JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ export function SelectColumnComponent({ column, record, onCellChange }) {
4
+ const [value, setValue] = useState(record[column.name] || '');
5
+ const isDisabled = column.disabled;
6
+ // Update local value when record changes (e.g., after reset)
7
+ useEffect(() => {
8
+ setValue(record[column.name] || '');
9
+ }, [record[column.name]]);
10
+ const handleChange = (e) => {
11
+ if (isDisabled)
12
+ return;
13
+ const newValue = e.target.value;
14
+ setValue(newValue);
15
+ // Notify parent of change
16
+ if (onCellChange) {
17
+ onCellChange(newValue);
18
+ }
19
+ };
20
+ return (_jsxs("select", { value: value, onChange: handleChange, disabled: isDisabled, className: "k-input text-sm py-1.5 px-3 pr-8 rounded-md border border-border focus:outline-none focus:ring-2 focus:ring-ring focus:border-accent disabled:opacity-50 disabled:cursor-not-allowed transition-colors appearance-none bg-no-repeat bg-right", style: {
21
+ backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E")`,
22
+ backgroundPosition: 'right 0.5rem center',
23
+ backgroundSize: '1.5em 1.5em',
24
+ }, children: [column.placeholder && column.selectablePlaceholder && _jsx("option", { value: "", children: column.placeholder }), column.options &&
25
+ Object.entries(column.options).map(([key, label]) => (_jsx("option", { value: key, children: label }, key)))] }));
26
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export declare function TagsColumnComponent({ column, record }: ColumnProps): React.JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/classNames';
3
+ import { formatValue } from '../../utils/tableFormatters';
4
+ export function TagsColumnComponent({ column, record }) {
5
+ const rawValue = record[column.name];
6
+ // Apply formatter if present
7
+ const value = formatValue(rawValue, column, record);
8
+ if (!value || (Array.isArray(value) && value.length === 0)) {
9
+ return _jsx("span", { className: "text-fg-secondary", children: "-" });
10
+ }
11
+ const tags = Array.isArray(value) ? value : [value];
12
+ const displayTags = column.limit ? tags.slice(0, column.limit) : tags;
13
+ // If no tags to display, return empty
14
+ if (!displayTags || displayTags.length === 0) {
15
+ return _jsx(_Fragment, {});
16
+ }
17
+ return (_jsxs("div", { className: "flex flex-wrap gap-1", children: [displayTags.map((tag, idx) => (_jsx("span", { className: cn('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', 'bg-accent-soft dark:bg-accent-soft text-accent'), children: String(tag) }, idx))), column.limit && tags.length > column.limit && (_jsxs("span", { className: cn('inline-flex items-center px-2 py-0.5 rounded text-xs font-medium', 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300'), children: ["+", tags.length - column.limit] }))] }));
18
+ }
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import { SerializedColumn } from '@maxal_studio/kratosjs';
3
+ export interface ColumnProps {
4
+ column: SerializedColumn;
5
+ record: any;
6
+ rowIndex: number;
7
+ }
8
+ /**
9
+ * TextColumn component for displaying text values
10
+ */
11
+ export declare function TextColumnComponent({ column, record, rowIndex }: ColumnProps): React.JSX.Element;
@@ -0,0 +1,107 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from '../../utils/classNames';
3
+ import { formatValue } from '../../utils/tableFormatters';
4
+ import { DeeplinkWrapper } from './DeeplinkWrapper';
5
+ /**
6
+ * TextColumn component for displaying text values
7
+ */
8
+ export function TextColumnComponent({ column, record, rowIndex }) {
9
+ const value = record[column.name];
10
+ // Handle row index
11
+ if (column.rowIndex) {
12
+ const displayIndex = column.rowIndexFromZero ? rowIndex : rowIndex + 1;
13
+ return _jsx("span", { className: "text-fg", children: displayIndex });
14
+ }
15
+ // Format value (pass entire record for formatStateUsing function)
16
+ const formattedValue = formatValue(value, column, record);
17
+ if (!formattedValue) {
18
+ return _jsx(_Fragment, {});
19
+ }
20
+ const hasDeeplink = !!column.deeplink;
21
+ // Handle arrays
22
+ if (Array.isArray(formattedValue)) {
23
+ const items = column.limit ? formattedValue.slice(0, column.limit) : formattedValue;
24
+ const shouldRenderHtml = column.stripHtml === false;
25
+ if (column.bulleted) {
26
+ return (_jsxs("ul", { className: "list-disc list-inside space-y-1", children: [items.map((item, idx) => {
27
+ const itemText = String(item);
28
+ return (_jsx("li", { className: "text-fg text-sm", children: shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: itemText } }) : itemText }, idx));
29
+ }), column.limit && formattedValue.length > column.limit && (_jsxs("li", { className: "text-fg-secondary text-sm italic", children: ["+", formattedValue.length - column.limit, " more"] }))] }));
30
+ }
31
+ if (column.listWithLineBreaks) {
32
+ return (_jsxs("div", { className: "space-y-1", children: [items.map((item, idx) => {
33
+ const itemText = String(item);
34
+ return (_jsx("div", { className: "text-fg text-sm", children: shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: itemText } }) : itemText }, idx));
35
+ }), column.limit && formattedValue.length > column.limit && (_jsxs("div", { className: "text-fg-secondary text-sm italic", children: ["+", formattedValue.length - column.limit, " more"] }))] }));
36
+ }
37
+ // Default: comma-separated
38
+ const joinedText = items.join(', ');
39
+ return (_jsx("span", { className: "text-fg", children: shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: joinedText } }) : joinedText }));
40
+ }
41
+ // Get styling classes
42
+ const getTextClasses = () => {
43
+ const classes = ['text-fg'];
44
+ if (column.weight) {
45
+ classes.push(`font-${column.weight}`);
46
+ }
47
+ if (column.fontFamily) {
48
+ classes.push(`font-${column.fontFamily}`);
49
+ }
50
+ if (column.size) {
51
+ if (typeof column.size === 'string') {
52
+ classes.push(`text-${column.size}`);
53
+ }
54
+ }
55
+ if (column.lineClamp) {
56
+ classes.push(`line-clamp-${column.lineClamp}`);
57
+ }
58
+ if (!column.wrap) {
59
+ classes.push('truncate');
60
+ }
61
+ return cn(classes);
62
+ };
63
+ // Check if HTML should be rendered (stripHtml defaults to true in backend)
64
+ const shouldRenderHtml = column.stripHtml === false;
65
+ const textContent = String(formattedValue);
66
+ // Render badge
67
+ if (column.badge) {
68
+ let badgeColor = 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200';
69
+ if (column.color) {
70
+ if (typeof column.color === 'object') {
71
+ // Color mapping based on value
72
+ const colorKey = column.color[value];
73
+ if (colorKey) {
74
+ badgeColor = getBadgeColorClasses(colorKey);
75
+ }
76
+ }
77
+ else {
78
+ badgeColor = getBadgeColorClasses(column.color);
79
+ }
80
+ }
81
+ const badgeElement = (_jsx("span", { className: cn('inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium', badgeColor, hasDeeplink && 'hover:opacity-80'), children: shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: textContent } }) : textContent }));
82
+ // Wrap badge in deeplink if exists
83
+ if (hasDeeplink) {
84
+ return (_jsx(DeeplinkWrapper, { column: column, record: record, value: value, className: "inline-block", children: badgeElement }));
85
+ }
86
+ return badgeElement;
87
+ }
88
+ // Regular text - render as HTML if stripHtml is false
89
+ const textElement = shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: textContent } }) : textContent;
90
+ // Wrap in deeplink if exists
91
+ if (hasDeeplink) {
92
+ return (_jsx(DeeplinkWrapper, { column: column, record: record, value: value, className: getTextClasses(), children: textElement }));
93
+ }
94
+ return (_jsx("span", { className: getTextClasses(), children: shouldRenderHtml ? _jsx("span", { dangerouslySetInnerHTML: { __html: textContent } }) : textContent }));
95
+ }
96
+ function getBadgeColorClasses(color) {
97
+ const colorMap = {
98
+ primary: 'bg-accent-soft dark:bg-accent-soft text-accent',
99
+ secondary: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200',
100
+ success: 'bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300',
101
+ danger: 'bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-300',
102
+ warning: 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-300',
103
+ info: 'bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-300',
104
+ gray: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-200',
105
+ };
106
+ return colorMap[color] || colorMap.gray;
107
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export interface EditableColumnProps extends ColumnProps {
4
+ onCellChange?: (value: any) => void;
5
+ }
6
+ export declare function TextInputColumnComponent({ column, record, onCellChange }: EditableColumnProps): React.JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ export function TextInputColumnComponent({ column, record, onCellChange }) {
4
+ const [value, setValue] = useState(record[column.name] || '');
5
+ const isDisabled = column.disabled;
6
+ // Update local value when record changes (e.g., after reset)
7
+ useEffect(() => {
8
+ setValue(record[column.name] || '');
9
+ }, [record[column.name]]);
10
+ const handleChange = (newValue) => {
11
+ setValue(newValue);
12
+ // Notify parent of change
13
+ if (onCellChange) {
14
+ onCellChange(newValue);
15
+ }
16
+ };
17
+ return (_jsx("input", { type: column.inputType || 'text', value: value, onChange: e => handleChange(e.target.value), disabled: isDisabled, placeholder: column.placeholder, className: "k-input text-sm py-1.5 px-3 w-full rounded-md border border-border focus:outline-none focus:ring-2 focus:ring-ring focus:border-accent disabled:opacity-50 disabled:cursor-not-allowed transition-colors" }));
18
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export interface EditableColumnProps extends ColumnProps {
4
+ onCellChange?: (value: any) => void;
5
+ }
6
+ export declare function ToggleColumnComponent({ column, record, onCellChange }: EditableColumnProps): React.JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { Icon } from '../utils/Icon';
4
+ import { cn } from '../../utils/classNames';
5
+ export function ToggleColumnComponent({ column, record, onCellChange }) {
6
+ const [value, setValue] = useState(Boolean(record[column.name]));
7
+ const isDisabled = column.disabled;
8
+ // Update local value when record changes (e.g., after reset)
9
+ useEffect(() => {
10
+ setValue(Boolean(record[column.name]));
11
+ }, [record[column.name]]);
12
+ const handleToggle = () => {
13
+ if (isDisabled)
14
+ return;
15
+ const newValue = !value;
16
+ setValue(newValue);
17
+ // Notify parent of change
18
+ if (onCellChange) {
19
+ onCellChange(newValue);
20
+ }
21
+ };
22
+ // Get colors
23
+ const trackClasses = (value ? column.onColor : column.offColor) ?? (value ? 'bg-accent' : 'bg-gray-200 dark:bg-gray-700');
24
+ return (_jsx("button", { type: "button", onClick: handleToggle, disabled: isDisabled, className: cn('relative inline-flex h-6 w-11 items-center rounded-full transition-colors', 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed', ...trackClasses.split(/\s+/)), children: _jsxs("span", { className: cn('inline-flex items-center justify-center h-4 w-4 transform rounded-full bg-white transition-transform', value ? 'translate-x-6' : 'translate-x-1'), children: [column.onIcon && value && _jsx(Icon, { name: column.onIcon, size: 10, className: "text-green-600" }), column.offIcon && !value && _jsx(Icon, { name: column.offIcon, size: 10, className: "text-gray-400" })] }) }));
25
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export declare function VideoColumnComponent({ column, record }: ColumnProps): React.JSX.Element;
@@ -0,0 +1,125 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { formatValue } from '../../utils/tableFormatters';
4
+ import { getColumnMediaDimensions } from '../../utils/columnMediaDimensions';
5
+ import { Icon } from '../utils/Icon';
6
+ import { translate } from '../../i18n/activeLocale';
7
+ function VideoPreviewModal({ isOpen, onClose, videoUrl, title, autoplay = false, controls = true, loop = false, muted = false, }) {
8
+ const videoRef = useRef(null);
9
+ useEffect(() => {
10
+ if (isOpen && videoRef.current && autoplay) {
11
+ videoRef.current.play().catch(() => {
12
+ // Autoplay may be blocked by browser
13
+ });
14
+ }
15
+ }, [isOpen, autoplay]);
16
+ useEffect(() => {
17
+ // Pause video when modal closes
18
+ if (!isOpen && videoRef.current) {
19
+ videoRef.current.pause();
20
+ }
21
+ }, [isOpen]);
22
+ if (!isOpen)
23
+ return null;
24
+ return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm", onClick: onClose, children: _jsxs("div", { className: "relative max-w-4xl w-full mx-4 bg-surface rounded-lg shadow-2xl overflow-hidden", onClick: e => e.stopPropagation(), children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [_jsx("h3", { className: "text-lg font-semibold text-fg", children: title || translate('core:file.video_preview') }), _jsx("button", { onClick: onClose, className: "p-2 rounded-full bg-hover hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors", title: translate('core:modal.close'), children: _jsx(Icon, { name: "X", size: 20, className: "text-fg" }) })] }), _jsx("div", { className: "p-4 bg-black", children: _jsx("video", { ref: videoRef, src: videoUrl, className: "w-full max-h-[70vh] object-contain", controls: controls, loop: loop, muted: muted, playsInline: true }) })] }) }));
25
+ }
26
+ /**
27
+ * Resolve thumbnail URL from column config
28
+ * Supports: field name string, function string (serialized), variants, or default thumbnail
29
+ */
30
+ function resolveThumbnail(column, record) {
31
+ const rawValue = record[column.name];
32
+ // Check for variants.thumbnail.url in new format
33
+ if (rawValue && typeof rawValue === 'object' && rawValue.variants?.thumbnail?.url) {
34
+ return rawValue.variants.thumbnail.url;
35
+ }
36
+ // Check for thumbnail function (serialized as string)
37
+ if (column.thumbnailFn) {
38
+ try {
39
+ // eslint-disable-next-line no-new-func
40
+ const thumbnailFn = new Function('return ' + column.thumbnailFn)();
41
+ const result = thumbnailFn(rawValue, record);
42
+ if (result)
43
+ return result;
44
+ }
45
+ catch {
46
+ console.warn('Failed to execute thumbnail function');
47
+ }
48
+ }
49
+ // Check for thumbnail field name
50
+ if (column.thumbnailField) {
51
+ const fieldName = column.thumbnailField;
52
+ // Support nested field access (e.g., 'mediaFile.thumbnailUrl')
53
+ const fieldValue = fieldName.split('.').reduce((obj, key) => obj?.[key], record);
54
+ if (fieldValue) {
55
+ // If it's a string, use it directly; otherwise try to format it
56
+ // Also check if it's the new format { url, key, storage }
57
+ if (typeof fieldValue === 'string') {
58
+ return fieldValue;
59
+ }
60
+ if (typeof fieldValue === 'object' && fieldValue?.url) {
61
+ return fieldValue.url;
62
+ }
63
+ }
64
+ }
65
+ // Fallback to default thumbnail
66
+ if (column.defaultThumbnail) {
67
+ return column.defaultThumbnail;
68
+ }
69
+ return null;
70
+ }
71
+ export function VideoColumnComponent({ column, record }) {
72
+ const [previewOpen, setPreviewOpen] = useState(false);
73
+ const rawValue = record[column.name];
74
+ // Apply formatter if present (e.g., to extract nested property or prepend URL)
75
+ const formattedValue = formatValue(rawValue, column, record);
76
+ // Extract URL from new format: { key, storage, url }
77
+ let videoUrl = null;
78
+ if (formattedValue) {
79
+ if (typeof formattedValue === 'object' && formattedValue !== null && formattedValue.url) {
80
+ videoUrl = formattedValue.url;
81
+ }
82
+ else if (typeof formattedValue === 'string') {
83
+ videoUrl = formattedValue;
84
+ }
85
+ }
86
+ // Get thumbnail URL using the resolver
87
+ const thumbnailUrl = resolveThumbnail(column, record);
88
+ const dimensions = getColumnMediaDimensions(column, 40);
89
+ const placeholderIcon = column.placeholderIcon || 'Video';
90
+ const getContainerClasses = () => {
91
+ const classes = [
92
+ 'relative',
93
+ 'flex',
94
+ 'items-center',
95
+ 'justify-center',
96
+ 'cursor-pointer',
97
+ 'overflow-hidden',
98
+ 'bg-gray-100',
99
+ 'dark:bg-gray-800',
100
+ 'hover:opacity-80',
101
+ 'transition-opacity',
102
+ 'group',
103
+ ];
104
+ if (column.circular) {
105
+ classes.push('rounded-full');
106
+ }
107
+ else if (column.square) {
108
+ classes.push('rounded-none');
109
+ }
110
+ else {
111
+ classes.push('rounded');
112
+ }
113
+ return classes.join(' ');
114
+ };
115
+ const handleClick = () => {
116
+ if (videoUrl) {
117
+ setPreviewOpen(true);
118
+ }
119
+ };
120
+ // If no video URL, show disabled state
121
+ if (!videoUrl) {
122
+ return (_jsx("div", { className: `${getContainerClasses()} opacity-50 cursor-not-allowed`, style: dimensions, children: _jsx(Icon, { name: placeholderIcon, size: 20, className: "text-gray-400" }) }));
123
+ }
124
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: getContainerClasses(), style: dimensions, onClick: handleClick, children: thumbnailUrl ? (_jsxs(_Fragment, { children: [_jsx("img", { src: thumbnailUrl, alt: translate('core:common.video_thumbnail'), className: "w-full h-full object-cover" }), _jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/30 group-hover:bg-black/40 transition-colors", children: _jsx("div", { className: "w-8 h-8 flex items-center justify-center bg-white/90 rounded-full", children: _jsx(Icon, { name: "Play", size: 16, className: "text-gray-800 ml-0.5" }) }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Icon, { name: placeholderIcon, size: 24, className: "text-gray-500 dark:text-gray-400" }), _jsx("div", { className: "absolute bottom-1 right-1 w-4 h-4 flex items-center justify-center bg-accent rounded-full", children: _jsx(Icon, { name: "Play", size: 10, className: "text-white ml-0.5" }) })] })) }), _jsx(VideoPreviewModal, { isOpen: previewOpen, onClose: () => setPreviewOpen(false), videoUrl: videoUrl, title: column.previewTitle, autoplay: column.autoplay, controls: column.controls !== false, loop: column.loop, muted: column.muted })] }));
125
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import { ColumnProps } from './TextColumnComponent';
3
+ export declare function ViewColumnComponent({ column, record }: ColumnProps): React.JSX.Element;