@firecms/core 3.0.0-canary.27 → 3.0.0-canary.271

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 (408) hide show
  1. package/README.md +3 -3
  2. package/dist/app/AppBar.d.ts +12 -0
  3. package/dist/app/Drawer.d.ts +16 -0
  4. package/dist/app/Scaffold.d.ts +34 -0
  5. package/dist/app/index.d.ts +4 -0
  6. package/dist/app/useApp.d.ts +16 -0
  7. package/dist/components/ArrayContainer.d.ts +31 -12
  8. package/dist/components/CircularProgressCenter.d.ts +1 -1
  9. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  10. package/dist/components/{DeleteConfirmationDialog.d.ts → ConfirmationDialog.d.ts} +1 -1
  11. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +14 -13
  12. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  13. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +22 -6
  14. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  15. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  16. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +3 -1
  17. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  18. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  19. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  20. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +7 -4
  21. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +20 -2
  22. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  23. package/dist/components/EntityCollectionView/utils.d.ts +3 -0
  24. package/dist/components/EntityJsonPreview.d.ts +3 -0
  25. package/dist/components/EntityPreview.d.ts +10 -7
  26. package/dist/components/ErrorView.d.ts +1 -1
  27. package/dist/components/HomePage/DefaultHomePage.d.ts +2 -15
  28. package/dist/components/HomePage/HomePageDnD.d.ts +76 -0
  29. package/dist/components/HomePage/NavigationCard.d.ts +3 -1
  30. package/dist/components/HomePage/NavigationCardBinding.d.ts +4 -3
  31. package/dist/components/HomePage/NavigationGroup.d.ts +8 -1
  32. package/dist/components/HomePage/RenameGroupDialog.d.ts +9 -0
  33. package/dist/components/PropertyConfigBadge.d.ts +2 -1
  34. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  35. package/dist/components/ReferenceWidget.d.ts +3 -1
  36. package/dist/components/SelectableTable/SelectableTable.d.ts +14 -4
  37. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  38. package/dist/components/UnsavedChangesDialog.d.ts +8 -0
  39. package/dist/components/VirtualTable/VirtualTableProps.d.ts +24 -12
  40. package/dist/components/VirtualTable/types.d.ts +3 -3
  41. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -3
  42. package/dist/components/common/index.d.ts +2 -1
  43. package/dist/components/common/table_height.d.ts +5 -0
  44. package/dist/components/common/types.d.ts +4 -6
  45. package/dist/components/common/useColumnsIds.d.ts +3 -1
  46. package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +13 -2
  47. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  48. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  49. package/dist/components/index.d.ts +5 -2
  50. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  51. package/dist/core/DefaultAppBar.d.ts +29 -0
  52. package/dist/core/DefaultDrawer.d.ts +19 -0
  53. package/dist/core/DrawerNavigationItem.d.ts +10 -0
  54. package/dist/core/EntityEditView.d.ts +43 -11
  55. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  56. package/dist/core/FireCMS.d.ts +3 -3
  57. package/dist/core/FireCMSRouter.d.ts +4 -0
  58. package/dist/core/NavigationRoutes.d.ts +2 -3
  59. package/dist/core/SideDialogs.d.ts +4 -2
  60. package/dist/core/field_configs.d.ts +1 -1
  61. package/dist/core/index.d.ts +4 -4
  62. package/dist/form/EntityForm.d.ts +37 -64
  63. package/dist/form/EntityFormActions.d.ts +21 -0
  64. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  65. package/dist/form/components/ErrorFocus.d.ts +1 -1
  66. package/dist/form/components/FieldHelperText.d.ts +3 -3
  67. package/dist/form/components/FormEntry.d.ts +6 -0
  68. package/dist/form/components/FormLayout.d.ts +5 -0
  69. package/dist/form/components/LabelWithIcon.d.ts +1 -1
  70. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  71. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  72. package/dist/form/components/index.d.ts +3 -1
  73. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  74. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  75. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  76. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  77. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  78. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  79. package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
  80. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  81. package/dist/form/field_bindings/ReferenceAsStringFieldBinding.d.ts +9 -0
  82. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -2
  83. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  84. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  85. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +5 -13
  86. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -2
  87. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  88. package/dist/form/index.d.ts +17 -18
  89. package/dist/form/useClearRestoreValue.d.ts +2 -2
  90. package/dist/hooks/data/delete.d.ts +4 -4
  91. package/dist/hooks/data/save.d.ts +4 -5
  92. package/dist/hooks/data/useCollectionFetch.d.ts +1 -1
  93. package/dist/hooks/data/useEntityFetch.d.ts +4 -3
  94. package/dist/hooks/index.d.ts +2 -0
  95. package/dist/hooks/useAuthController.d.ts +1 -1
  96. package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
  97. package/dist/hooks/useBuildNavigationController.d.ts +57 -13
  98. package/dist/hooks/useCollapsedGroups.d.ts +9 -0
  99. package/dist/hooks/useFireCMSContext.d.ts +1 -1
  100. package/dist/hooks/useModeController.d.ts +1 -2
  101. package/dist/hooks/useProjectLog.d.ts +8 -2
  102. package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
  103. package/dist/hooks/useValidateAuthenticator.d.ts +4 -8
  104. package/dist/index.d.ts +1 -0
  105. package/dist/index.es.js +23154 -13912
  106. package/dist/index.es.js.map +1 -1
  107. package/dist/index.umd.js +25917 -588
  108. package/dist/index.umd.js.map +1 -1
  109. package/dist/internal/useBuildDataSource.d.ts +3 -17
  110. package/dist/internal/useBuildSideEntityController.d.ts +3 -3
  111. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  112. package/dist/preview/PropertyPreviewProps.d.ts +6 -1
  113. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  114. package/dist/preview/components/ReferencePreview.d.ts +4 -3
  115. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  116. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  117. package/dist/preview/util.d.ts +3 -3
  118. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  119. package/dist/routes/FireCMSRoute.d.ts +1 -0
  120. package/dist/routes/HomePageRoute.d.ts +3 -0
  121. package/dist/types/analytics.d.ts +1 -1
  122. package/dist/types/auth.d.ts +8 -10
  123. package/dist/types/collections.d.ts +112 -25
  124. package/dist/types/customization_controller.d.ts +8 -0
  125. package/dist/types/datasource.d.ts +52 -36
  126. package/dist/types/dialogs_controller.d.ts +7 -3
  127. package/dist/types/entities.d.ts +7 -2
  128. package/dist/types/entity_actions.d.ts +72 -8
  129. package/dist/types/entity_callbacks.d.ts +16 -16
  130. package/dist/types/entity_overrides.d.ts +2 -2
  131. package/dist/types/export_import.d.ts +4 -4
  132. package/dist/types/fields.d.ts +74 -42
  133. package/dist/types/firecms.d.ts +16 -3
  134. package/dist/types/firecms_context.d.ts +1 -1
  135. package/dist/types/index.d.ts +0 -1
  136. package/dist/types/navigation.d.ts +62 -19
  137. package/dist/types/permissions.d.ts +4 -4
  138. package/dist/types/plugins.d.ts +56 -13
  139. package/dist/types/properties.d.ts +81 -25
  140. package/dist/types/property_config.d.ts +1 -3
  141. package/dist/types/roles.d.ts +3 -0
  142. package/dist/types/side_dialogs_controller.d.ts +10 -0
  143. package/dist/types/side_entity_controller.d.ts +14 -1
  144. package/dist/types/storage.d.ts +75 -0
  145. package/dist/types/user.d.ts +1 -0
  146. package/dist/util/builders.d.ts +3 -3
  147. package/dist/util/callbacks.d.ts +2 -0
  148. package/dist/util/createFormexStub.d.ts +2 -0
  149. package/dist/util/entities.d.ts +3 -3
  150. package/dist/util/entity_actions.d.ts +2 -0
  151. package/dist/util/entity_cache.d.ts +23 -0
  152. package/dist/util/icon_list.d.ts +5 -1
  153. package/dist/util/icon_synonyms.d.ts +1 -98
  154. package/dist/util/icons.d.ts +7 -4
  155. package/dist/util/index.d.ts +3 -0
  156. package/dist/util/navigation_from_path.d.ts +10 -1
  157. package/dist/util/navigation_utils.d.ts +15 -3
  158. package/dist/util/objects.d.ts +2 -1
  159. package/dist/util/permissions.d.ts +4 -4
  160. package/dist/util/plurals.d.ts +0 -2
  161. package/dist/util/property_utils.d.ts +4 -4
  162. package/dist/util/references.d.ts +2 -2
  163. package/dist/util/resolutions.d.ts +42 -17
  164. package/dist/util/storage.d.ts +23 -2
  165. package/dist/util/useStorageUploadController.d.ts +3 -3
  166. package/package.json +69 -52
  167. package/src/app/AppBar.tsx +18 -0
  168. package/src/app/Drawer.tsx +24 -0
  169. package/src/app/Scaffold.tsx +253 -0
  170. package/src/app/index.ts +4 -0
  171. package/src/app/useApp.tsx +32 -0
  172. package/src/components/ArrayContainer.tsx +447 -229
  173. package/src/components/CircularProgressCenter.tsx +2 -2
  174. package/src/components/ClearFilterSortButton.tsx +41 -0
  175. package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +12 -11
  176. package/src/components/DeleteEntityDialog.tsx +13 -20
  177. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +65 -40
  178. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +38 -31
  179. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +30 -9
  180. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +72 -42
  181. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  182. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +30 -16
  183. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +19 -17
  184. package/src/components/EntityCollectionTable/index.tsx +1 -1
  185. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +34 -39
  186. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +49 -36
  187. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +20 -8
  188. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +135 -105
  189. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  190. package/src/components/EntityCollectionView/EntityCollectionView.tsx +235 -118
  191. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +7 -4
  192. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  193. package/src/components/EntityCollectionView/useSelectionController.tsx +20 -7
  194. package/src/components/EntityCollectionView/utils.ts +19 -0
  195. package/src/components/EntityJsonPreview.tsx +66 -0
  196. package/src/components/EntityPreview.tsx +83 -62
  197. package/src/components/EntityView.tsx +13 -10
  198. package/src/components/ErrorView.tsx +4 -4
  199. package/src/components/FireCMSLogo.tsx +7 -51
  200. package/src/components/HomePage/DefaultHomePage.tsx +512 -157
  201. package/src/components/HomePage/FavouritesView.tsx +9 -14
  202. package/src/components/HomePage/HomePageDnD.tsx +599 -0
  203. package/src/components/HomePage/NavigationCard.tsx +48 -39
  204. package/src/components/HomePage/NavigationCardBinding.tsx +17 -16
  205. package/src/components/HomePage/NavigationGroup.tsx +144 -30
  206. package/src/components/HomePage/RenameGroupDialog.tsx +117 -0
  207. package/src/components/HomePage/SmallNavigationCard.tsx +5 -6
  208. package/src/components/NotFoundPage.tsx +2 -2
  209. package/src/components/PropertyConfigBadge.tsx +9 -3
  210. package/src/components/PropertyIdCopyTooltip.tsx +47 -0
  211. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +23 -13
  212. package/src/components/ReferenceWidget.tsx +21 -11
  213. package/src/components/SearchIconsView.tsx +10 -7
  214. package/src/components/SelectableTable/SelectableTable.tsx +157 -145
  215. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  216. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +25 -8
  217. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -12
  218. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +93 -24
  219. package/src/components/UnsavedChangesDialog.tsx +46 -0
  220. package/src/components/VirtualTable/VirtualTable.tsx +105 -51
  221. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  222. package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -10
  223. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  224. package/src/components/VirtualTable/VirtualTableProps.tsx +28 -14
  225. package/src/components/VirtualTable/VirtualTableRow.tsx +5 -6
  226. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +5 -5
  227. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +2 -2
  228. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  229. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
  230. package/src/components/VirtualTable/types.tsx +2 -3
  231. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +64 -44
  232. package/src/components/common/index.ts +2 -1
  233. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  234. package/src/components/common/types.tsx +4 -6
  235. package/src/components/common/useColumnsIds.tsx +24 -3
  236. package/src/components/common/useDataSourceTableController.tsx +420 -0
  237. package/src/components/common/useDebouncedCallback.tsx +20 -0
  238. package/src/components/common/useScrollRestoration.tsx +68 -0
  239. package/src/components/common/useTableSearchHelper.ts +53 -12
  240. package/src/components/index.tsx +6 -2
  241. package/src/contexts/BreacrumbsContext.tsx +38 -0
  242. package/src/contexts/DialogsProvider.tsx +5 -4
  243. package/src/contexts/ModeController.tsx +1 -3
  244. package/src/contexts/SnackbarProvider.tsx +2 -0
  245. package/src/core/DefaultAppBar.tsx +219 -0
  246. package/src/core/DefaultDrawer.tsx +185 -0
  247. package/src/core/DrawerNavigationItem.tsx +66 -0
  248. package/src/core/EntityEditView.tsx +435 -470
  249. package/src/core/EntityEditViewFormActions.tsx +329 -0
  250. package/src/core/EntitySidePanel.tsx +88 -21
  251. package/src/core/FireCMS.tsx +74 -58
  252. package/src/core/FireCMSRouter.tsx +17 -0
  253. package/src/core/NavigationRoutes.tsx +28 -38
  254. package/src/core/SideDialogs.tsx +22 -12
  255. package/src/core/field_configs.tsx +26 -13
  256. package/src/core/index.tsx +6 -5
  257. package/src/form/EntityForm.tsx +620 -534
  258. package/src/form/EntityFormActions.tsx +211 -0
  259. package/src/form/PropertyFieldBinding.tsx +88 -45
  260. package/src/form/components/CustomIdField.tsx +9 -3
  261. package/src/form/components/FieldHelperText.tsx +4 -4
  262. package/src/form/components/FormEntry.tsx +22 -0
  263. package/src/form/components/FormLayout.tsx +16 -0
  264. package/src/form/components/LabelWithIcon.tsx +30 -19
  265. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  266. package/src/form/components/StorageItemPreview.tsx +23 -13
  267. package/src/form/components/StorageUploadProgress.tsx +5 -6
  268. package/src/form/components/index.tsx +3 -1
  269. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +34 -19
  270. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +50 -36
  271. package/src/form/field_bindings/BlockFieldBinding.tsx +56 -34
  272. package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -14
  273. package/src/form/field_bindings/KeyValueFieldBinding.tsx +61 -52
  274. package/src/form/field_bindings/MapFieldBinding.tsx +73 -55
  275. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +159 -0
  276. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +26 -21
  277. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +11 -16
  278. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +135 -0
  279. package/src/form/field_bindings/ReferenceFieldBinding.tsx +42 -31
  280. package/src/form/field_bindings/RepeatFieldBinding.tsx +62 -35
  281. package/src/form/field_bindings/SelectFieldBinding.tsx +24 -15
  282. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +257 -199
  283. package/src/form/field_bindings/SwitchFieldBinding.tsx +29 -24
  284. package/src/form/field_bindings/TextFieldBinding.tsx +28 -24
  285. package/src/form/index.tsx +17 -37
  286. package/src/form/useClearRestoreValue.tsx +2 -2
  287. package/src/form/validation.ts +13 -23
  288. package/src/hooks/data/delete.ts +6 -5
  289. package/src/hooks/data/save.ts +26 -33
  290. package/src/hooks/data/useCollectionFetch.tsx +3 -3
  291. package/src/hooks/data/useDataSource.tsx +11 -3
  292. package/src/hooks/data/useEntityFetch.tsx +10 -6
  293. package/src/hooks/index.tsx +2 -0
  294. package/src/hooks/useAuthController.tsx +1 -1
  295. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  296. package/src/hooks/useBrowserTitleAndIcon.tsx +1 -1
  297. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  298. package/src/hooks/useBuildModeController.tsx +22 -29
  299. package/src/hooks/useBuildNavigationController.tsx +440 -119
  300. package/src/hooks/useCollapsedGroups.ts +64 -0
  301. package/src/hooks/useFireCMSContext.tsx +3 -33
  302. package/src/hooks/useLargeLayout.tsx +0 -35
  303. package/src/hooks/useModeController.tsx +1 -2
  304. package/src/hooks/useProjectLog.tsx +32 -10
  305. package/src/hooks/useResolvedNavigationFrom.tsx +10 -12
  306. package/src/hooks/useValidateAuthenticator.tsx +17 -37
  307. package/src/index.ts +1 -0
  308. package/src/internal/useBuildDataSource.ts +79 -85
  309. package/src/internal/useBuildSideDialogsController.tsx +4 -2
  310. package/src/internal/useBuildSideEntityController.tsx +204 -77
  311. package/src/internal/useUnsavedChangesDialog.tsx +127 -91
  312. package/src/preview/PropertyPreview.tsx +34 -25
  313. package/src/preview/PropertyPreviewProps.tsx +7 -1
  314. package/src/preview/components/BooleanPreview.tsx +2 -2
  315. package/src/preview/components/EmptyValue.tsx +1 -1
  316. package/src/preview/components/EnumValuesChip.tsx +2 -2
  317. package/src/preview/components/ImagePreview.tsx +26 -37
  318. package/src/preview/components/ReferencePreview.tsx +26 -36
  319. package/src/preview/components/StorageThumbnail.tsx +5 -1
  320. package/src/preview/components/UrlComponentPreview.tsx +60 -28
  321. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +6 -6
  322. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +7 -5
  323. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +5 -4
  324. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -4
  325. package/src/preview/property_previews/ArrayOneOfPreview.tsx +7 -6
  326. package/src/preview/property_previews/ArrayPropertyPreview.tsx +7 -6
  327. package/src/preview/property_previews/MapPropertyPreview.tsx +12 -11
  328. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +13 -13
  329. package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
  330. package/src/preview/util.ts +10 -10
  331. package/src/routes/CustomCMSRoute.tsx +21 -0
  332. package/src/routes/FireCMSRoute.tsx +246 -0
  333. package/src/routes/HomePageRoute.tsx +17 -0
  334. package/src/types/analytics.ts +3 -0
  335. package/src/types/auth.tsx +9 -13
  336. package/src/types/collections.ts +134 -30
  337. package/src/types/customization_controller.tsx +9 -1
  338. package/src/types/datasource.ts +61 -43
  339. package/src/types/dialogs_controller.tsx +7 -3
  340. package/src/types/entities.ts +12 -2
  341. package/src/types/entity_actions.tsx +86 -10
  342. package/src/types/entity_callbacks.ts +18 -18
  343. package/src/types/entity_overrides.tsx +2 -2
  344. package/src/types/export_import.ts +4 -4
  345. package/src/types/fields.tsx +85 -46
  346. package/src/types/firecms.tsx +18 -4
  347. package/src/types/firecms_context.tsx +1 -1
  348. package/src/types/index.ts +0 -1
  349. package/src/types/navigation.ts +77 -24
  350. package/src/types/permissions.ts +5 -5
  351. package/src/types/plugins.tsx +66 -15
  352. package/src/types/properties.ts +96 -27
  353. package/src/types/property_config.tsx +1 -2
  354. package/src/types/roles.ts +3 -0
  355. package/src/types/side_dialogs_controller.tsx +15 -0
  356. package/src/types/side_entity_controller.tsx +16 -1
  357. package/src/types/storage.ts +83 -1
  358. package/src/types/user.ts +2 -0
  359. package/src/util/builders.ts +10 -8
  360. package/src/util/callbacks.ts +119 -0
  361. package/src/util/createFormexStub.tsx +62 -0
  362. package/src/util/entities.ts +10 -7
  363. package/src/util/entity_actions.ts +28 -0
  364. package/src/util/entity_cache.ts +204 -0
  365. package/src/util/enums.ts +1 -1
  366. package/src/util/icon_list.ts +16 -10
  367. package/src/util/icon_synonyms.ts +3 -100
  368. package/src/util/icons.tsx +36 -11
  369. package/src/util/index.ts +3 -0
  370. package/src/util/join_collections.ts +9 -2
  371. package/src/util/make_properties_editable.ts +13 -5
  372. package/src/util/navigation_from_path.ts +33 -12
  373. package/src/util/navigation_utils.ts +141 -25
  374. package/src/util/objects.ts +90 -33
  375. package/src/util/parent_references_from_path.ts +3 -3
  376. package/src/util/permissions.ts +9 -8
  377. package/src/util/plurals.ts +0 -2
  378. package/src/util/property_utils.tsx +17 -6
  379. package/src/util/references.ts +19 -8
  380. package/src/util/resolutions.ts +122 -48
  381. package/src/util/storage.ts +79 -21
  382. package/src/util/strings.ts +2 -2
  383. package/src/util/useStorageUploadController.tsx +91 -28
  384. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  385. package/dist/components/FireCMSAppBar.d.ts +0 -26
  386. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  387. package/dist/components/VirtualTable/common.d.ts +0 -2
  388. package/dist/core/Drawer.d.ts +0 -23
  389. package/dist/core/Scaffold.d.ts +0 -55
  390. package/dist/core/SideEntityView.d.ts +0 -7
  391. package/dist/form/components/FormikArrayContainer.d.ts +0 -18
  392. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  393. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  394. package/dist/internal/useLocaleConfig.d.ts +0 -1
  395. package/dist/types/appcheck.d.ts +0 -26
  396. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
  397. package/src/components/FireCMSAppBar.tsx +0 -165
  398. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -28
  399. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -225
  400. package/src/core/Drawer.tsx +0 -191
  401. package/src/core/Scaffold.tsx +0 -281
  402. package/src/core/SideEntityView.tsx +0 -38
  403. package/src/form/components/FormikArrayContainer.tsx +0 -44
  404. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
  405. package/src/internal/useBuildCustomizationController.tsx +0 -5
  406. package/src/internal/useLocaleConfig.tsx +0 -18
  407. package/src/types/appcheck.ts +0 -29
  408. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -1,10 +1,10 @@
1
1
  import { useNavigate } from "react-router-dom";
2
2
  import { useNavigationController } from "../../hooks";
3
3
  import { useUserConfigurationPersistence } from "../../hooks/useUserConfigurationPersistence";
4
- import { TopNavigationEntry } from "../../types";
5
- import { Chip, Collapse, StarBorderIcon, StarIcon } from "@firecms/ui";
4
+ import { NavigationEntry } from "../../types";
5
+ import { Chip, Collapse, StarIcon } from "@firecms/ui";
6
6
 
7
- function NavigationChip({ entry }: { entry: TopNavigationEntry }) {
7
+ function NavigationChip({ entry }: { entry: NavigationEntry }) {
8
8
 
9
9
  const navigate = useNavigate();
10
10
  const userConfigurationPersistence = useUserConfigurationPersistence();
@@ -29,16 +29,11 @@ function NavigationChip({ entry }: { entry: TopNavigationEntry }) {
29
29
  return <Chip
30
30
  key={entry.path}
31
31
  onClick={() => navigate(entry.url)}
32
- icon={
33
- favourite
34
- ? <StarIcon
35
- onClick={onIconClick}
36
- size={18}
37
- className={"text-secondary"}/>
38
- : <StarBorderIcon
39
- onClick={onIconClick}
40
- size={18}
41
- className={"text-gray-400 dark:text-gray-500"}/>}>
32
+ icon={<StarIcon
33
+ onClick={onIconClick}
34
+ size={18}
35
+ className={favourite ? "text-secondary" : "text-surface-400 dark:text-surface-500"}/>
36
+ }>
42
37
  {entry.name}
43
38
  </Chip>;
44
39
  }
@@ -53,7 +48,7 @@ export function FavouritesView({ hidden }: { hidden: boolean }) {
53
48
 
54
49
  const favouriteCollections = (userConfigurationPersistence?.favouritePaths ?? [])
55
50
  .map((path) => navigationController.topLevelNavigation?.navigationEntries.find((entry) => entry.path === path))
56
- .filter(Boolean) as TopNavigationEntry[];
51
+ .filter(Boolean) as NavigationEntry[];
57
52
 
58
53
  return <Collapse in={favouriteCollections.length > 0}>
59
54
  <div className="flex flex-row flex-wrap gap-2 pb-2 min-h-[32px]">
@@ -0,0 +1,599 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import {
3
+ Active,
4
+ closestCenter,
5
+ closestCorners,
6
+ CollisionDetection,
7
+ DropAnimation,
8
+ getFirstCollision,
9
+ KeyboardSensor,
10
+ MouseSensor,
11
+ pointerWithin,
12
+ rectIntersection,
13
+ TouchSensor,
14
+ UniqueIdentifier,
15
+ useDndMonitor,
16
+ useDroppable,
17
+ useSensor,
18
+ useSensors
19
+ } from "@dnd-kit/core";
20
+ import {
21
+ AnimateLayoutChanges,
22
+ arrayMove,
23
+ defaultAnimateLayoutChanges,
24
+ rectSortingStrategy,
25
+ SortableContext,
26
+ useSortable
27
+ } from "@dnd-kit/sortable";
28
+ import { CSS } from "@dnd-kit/utilities";
29
+
30
+ import { NavigationCardBinding } from "./NavigationCardBinding";
31
+ import { NavigationEntry } from "../../types";
32
+ import { cls } from "@firecms/ui";
33
+
34
+ const animateLayoutChanges: AnimateLayoutChanges = (args) =>
35
+ defaultAnimateLayoutChanges({
36
+ ...args,
37
+ wasDragging: true
38
+ });
39
+
40
+ const dropAnimationConfig: DropAnimation = {};
41
+
42
+ const cloneSerializableNavigationEntry = (entry: NavigationEntry): NavigationEntry => {
43
+ const clonedEntry: Partial<NavigationEntry> = {
44
+ id: entry.id,
45
+ path: entry.path,
46
+ url: entry.url,
47
+ name: entry.name,
48
+ type: entry.type,
49
+ collection: entry.collection ? { ...entry.collection } : undefined,
50
+ view: entry.view ? { ...entry.view } : undefined,
51
+ ...(entry.group && { group: entry.group }),
52
+ ...(entry.description && { description: entry.description })
53
+ };
54
+ return clonedEntry as NavigationEntry;
55
+ };
56
+
57
+ const cloneItemsForDnd = (items: { name: string; entries: NavigationEntry[] }[]) =>
58
+ items.map((g) => ({
59
+ name: g.name,
60
+ entries: g.entries.map(cloneSerializableNavigationEntry)
61
+ }));
62
+
63
+ /* ─────────────────────────────────────────────────────────── */
64
+ /* Sortable card & group */
65
+
66
+ /* ─────────────────────────────────────────────────────────── */
67
+ export function SortableNavigationCard({
68
+ entry,
69
+ onClick
70
+ }: {
71
+ entry: NavigationEntry;
72
+ onClick?: () => void;
73
+ }) {
74
+ const {
75
+ setNodeRef,
76
+ listeners,
77
+ attributes,
78
+ transform,
79
+ transition,
80
+ isDragging
81
+ } =
82
+ useSortable({
83
+ id: entry.url,
84
+ animateLayoutChanges
85
+ });
86
+
87
+ const style = {
88
+ transform: transform ? CSS.Transform.toString(transform) : undefined,
89
+ transition,
90
+ opacity: isDragging ? 0 : 1
91
+ };
92
+
93
+ return (
94
+ <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
95
+ <NavigationCardBinding {...entry} onClick={onClick}/>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ export function NavigationGroupDroppable({
101
+ id,
102
+ itemIds,
103
+ children,
104
+ isPotentialCardDropTarget = false
105
+ }: {
106
+ id: UniqueIdentifier;
107
+ itemIds: UniqueIdentifier[];
108
+ children: React.ReactNode;
109
+ isPotentialCardDropTarget?: boolean;
110
+ }) {
111
+ const { setNodeRef } = useDroppable({ id });
112
+
113
+ return (
114
+ <div
115
+ ref={setNodeRef}
116
+ className={cls(
117
+ isPotentialCardDropTarget
118
+ ? "p-2 bg-surface-accent-200 dark:bg-surface-accent-800 rounded-lg"
119
+ : undefined,
120
+ "transition-all duration-200 ease-in-out"
121
+ )}
122
+ >
123
+ <SortableContext items={itemIds} strategy={rectSortingStrategy}>
124
+ {children}
125
+ </SortableContext>
126
+ </div>
127
+ );
128
+ }
129
+
130
+ export function SortableNavigationGroup({
131
+ groupName,
132
+ children,
133
+ disabled
134
+ }: {
135
+ groupName: string;
136
+ children: React.ReactNode;
137
+ disabled?: boolean;
138
+ }) {
139
+ const {
140
+ attributes,
141
+ listeners,
142
+ setNodeRef,
143
+ transform,
144
+ transition,
145
+ isDragging
146
+ } =
147
+ useSortable({
148
+ id: groupName,
149
+ animateLayoutChanges,
150
+ disabled
151
+ });
152
+
153
+ const style = {
154
+ transform: transform ? CSS.Transform.toString(transform) : undefined,
155
+ transition,
156
+ opacity: isDragging ? 0 : 1
157
+ };
158
+
159
+ return (
160
+ <div ref={setNodeRef} style={style} {...attributes} {...listeners}>
161
+ {children}
162
+ </div>
163
+ );
164
+ }
165
+
166
+ /* ─────────────────────────────────────────────────────────── */
167
+ /* Main DnD hook */
168
+
169
+ /* ─────────────────────────────────────────────────────────── */
170
+ export function useHomePageDnd({
171
+ items: dndItems,
172
+ setItems: setDndItems,
173
+ disabled,
174
+ onCardMovedBetweenGroups,
175
+ onGroupMoved,
176
+ onNewGroupDrop,
177
+ onPersist
178
+ }: {
179
+ items: { name: string; entries: NavigationEntry[] }[];
180
+ setItems: (
181
+ newItemsOrUpdater:
182
+ | { name: string; entries: NavigationEntry[] }[]
183
+ | ((
184
+ currentItems: { name: string; entries: NavigationEntry[] }[]
185
+ ) => { name: string; entries: NavigationEntry[] }[])
186
+ ) => void;
187
+ disabled: boolean;
188
+ onCardMovedBetweenGroups?: (card: NavigationEntry) => void;
189
+ onGroupMoved?: (groupName: string, oldIndex: number, newIndex: number) => void;
190
+ onNewGroupDrop?: () => void;
191
+ onPersist?: (latest: { name: string; entries: NavigationEntry[] }[]) => void;
192
+ }) {
193
+ /* ---------------- local state ---------------- */
194
+ const [activeId, setActiveId] = useState<UniqueIdentifier | null>(null);
195
+ const [activeIsGroup, setActiveIsGroup] = useState(false);
196
+ const [currentDraggingGroupId, setCurrentDraggingGroupId] =
197
+ useState<UniqueIdentifier | null>(null);
198
+ const [dndKitActiveNode, setDndKitActiveNode] = useState<Active | null>(null);
199
+ const [isDraggingCardOnly, setIsDraggingCardOnly] = useState(false);
200
+ const [dialogOpenForGroup, setDialogOpenForGroup] = useState<string | null>(null);
201
+ const [isHoveringNewGroupDropZone, setIsHoveringNewGroupDropZone] =
202
+ useState(false);
203
+
204
+ /* store interim state for cross-group moves */
205
+ const interimItemsRef = useRef<
206
+ { name: string; entries: NavigationEntry[] }[] | null
207
+ >(null);
208
+ useEffect(() => {
209
+ interimItemsRef.current = dndItems;
210
+ }, [dndItems]);
211
+
212
+ /* ---------------- sensors ---------------- */
213
+ const mouseSensor = useSensor(MouseSensor, { activationConstraint: { distance: 10 } });
214
+ const touchSensor = useSensor(TouchSensor, {
215
+ activationConstraint: {
216
+ delay: 150,
217
+ tolerance: 5
218
+ }
219
+ });
220
+ const keyboardSensor = useSensor(KeyboardSensor);
221
+ const sensors = useSensors(mouseSensor, touchSensor, keyboardSensor);
222
+
223
+ /* ---------------- helpers ---------------- */
224
+ const dndContainers = dndItems.map((g) => g.name);
225
+
226
+ const findDndContainer = useCallback(
227
+ (id: UniqueIdentifier): string | undefined => {
228
+ if (!id) return undefined;
229
+ const group = dndItems.find((g) => g.name === id);
230
+ if (group) return group.name;
231
+ for (const g of dndItems) {
232
+ if (g.entries.some((e) => e.url === id)) return g.name;
233
+ }
234
+ return undefined;
235
+ },
236
+ [dndItems]
237
+ );
238
+
239
+ /* ---------------- collision detection ---------------- */
240
+ const lastOverId = useRef<UniqueIdentifier | null>(null);
241
+ const recentlyMovedToNewContainer = useRef(false);
242
+
243
+ const collisionDetection: CollisionDetection = useCallback(
244
+ (args) => {
245
+ if (disabled || !activeId) return [];
246
+ if (activeIsGroup) {
247
+ const groups = args.droppableContainers.filter((c) =>
248
+ dndItems.some((g) => g.name === c.id)
249
+ );
250
+ if (!groups.length) return [];
251
+ return closestCenter({
252
+ ...args,
253
+ droppableContainers: groups
254
+ });
255
+ }
256
+
257
+ const pointer = pointerWithin(args);
258
+ if (pointer.length) {
259
+ const zone = pointer.find((c) => c.id === "new-group-drop-zone");
260
+ if (zone) return [zone];
261
+
262
+ const container = pointer.find((c) =>
263
+ dndItems.some((g) => g.name === c.id)
264
+ );
265
+ if (container) {
266
+ const itemsIn = dndItems.find((g) => g.name === container.id)
267
+ ?.entries;
268
+ if (itemsIn?.length) {
269
+ const closest = closestCorners({
270
+ ...args,
271
+ droppableContainers: args.droppableContainers.filter(
272
+ (c) => itemsIn.some((e) => e.url === c.id)
273
+ )
274
+ });
275
+ if (closest.length) return closest;
276
+ }
277
+ return [container];
278
+ }
279
+ const first = getFirstCollision(pointer, "id");
280
+ if (first) return [{ id: first }];
281
+ }
282
+
283
+ const rects = rectIntersection(args);
284
+ const zoneRect = rects.find((c) => c.id === "new-group-drop-zone");
285
+ if (zoneRect) return [zoneRect];
286
+
287
+ let overId = getFirstCollision(rects, "id");
288
+ if (overId != null) {
289
+ const overIsContainer = dndItems.some((g) => g.name === overId);
290
+ if (overIsContainer) {
291
+ const itemsIn = dndItems.find((g) => g.name === overId)
292
+ ?.entries;
293
+ if (itemsIn?.length) {
294
+ const closestItem = closestCorners({
295
+ ...args,
296
+ droppableContainers: args.droppableContainers.filter(
297
+ (c) => itemsIn.some((e) => e.url === c.id)
298
+ )
299
+ })[0]?.id;
300
+ if (closestItem) overId = closestItem;
301
+ }
302
+ }
303
+ lastOverId.current = overId;
304
+ return [{ id: overId }];
305
+ }
306
+
307
+ if (
308
+ recentlyMovedToNewContainer.current &&
309
+ lastOverId.current &&
310
+ !activeIsGroup
311
+ )
312
+ return [{ id: lastOverId.current }];
313
+
314
+ return [];
315
+ },
316
+ [activeId, dndItems, disabled, activeIsGroup]
317
+ );
318
+
319
+ /* ---------------- drag handlers ---------------- */
320
+ const handleDragStart = ({ active }: { active: Active }) => {
321
+ setDndKitActiveNode(active);
322
+ if (disabled) return;
323
+
324
+ const isGroup = dndItems.some((g) => g.name === active.id);
325
+ if (!active.data.current) active.data.current = {};
326
+ active.data.current.type = isGroup ? "group" : "item";
327
+
328
+ setActiveId(active.id);
329
+ setActiveIsGroup(isGroup);
330
+ setIsDraggingCardOnly(!isGroup);
331
+ if (isGroup) setCurrentDraggingGroupId(active.id);
332
+ recentlyMovedToNewContainer.current = false;
333
+ };
334
+
335
+ const handleDragOver = ({
336
+ active,
337
+ over
338
+ }: { active: Active; over: any }) => {
339
+ if (disabled || !over) return;
340
+
341
+ const activeIdNow = active.id;
342
+ const overIdNow = over.id;
343
+ if (activeIdNow === overIdNow) return;
344
+ if (activeIsGroup) return;
345
+
346
+ const activeCont = findDndContainer(activeIdNow);
347
+ const overCont = findDndContainer(overIdNow);
348
+ if (!activeCont) return;
349
+
350
+ if (overCont && activeCont !== overCont) {
351
+ recentlyMovedToNewContainer.current = true;
352
+ const newState = cloneItemsForDnd(dndItems);
353
+ const srcIdx = newState.findIndex((g) => g.name === activeCont);
354
+ const tgtIdx = newState.findIndex((g) => g.name === overCont);
355
+ if (srcIdx === -1 || tgtIdx === -1) return;
356
+ const src = newState[srcIdx];
357
+ const tgt = newState[tgtIdx];
358
+ const idxInSrc = src.entries.findIndex((e) => e.url === activeIdNow);
359
+ if (idxInSrc === -1) return;
360
+ const [moved] = src.entries.splice(idxInSrc, 1);
361
+ tgt.entries.push(moved);
362
+ interimItemsRef.current = newState;
363
+ setDndItems(newState);
364
+ } else if (activeCont === overCont) {
365
+ recentlyMovedToNewContainer.current = false;
366
+ }
367
+ };
368
+
369
+ const handleDragEnd = ({
370
+ active,
371
+ over
372
+ }: { active: Active; over: any }) => {
373
+ if (disabled || !over) {
374
+ resetDragState();
375
+ return;
376
+ }
377
+
378
+ const activeIdNow = active.id;
379
+ const overIdNow = over.id;
380
+
381
+ /* ─── group reorder ─── */
382
+ if (activeIsGroup) {
383
+ if (
384
+ activeIdNow !== overIdNow &&
385
+ dndItems.some((g) => g.name === overIdNow)
386
+ ) {
387
+ const from = dndItems.findIndex((g) => g.name === activeIdNow);
388
+ const to = dndItems.findIndex((g) => g.name === overIdNow);
389
+ if (from !== -1 && to !== -1) {
390
+ const newState = arrayMove(dndItems, from, to);
391
+ setDndItems(newState);
392
+ onPersist?.(newState);
393
+ onGroupMoved?.(activeIdNow as string, from, to);
394
+ }
395
+ }
396
+ }
397
+ /* ─── card move ─── */
398
+ else {
399
+ const activeCont = findDndContainer(activeIdNow);
400
+
401
+ /* drop on new-group zone */
402
+ if (overIdNow === "new-group-drop-zone") {
403
+ if (activeCont) {
404
+ const newState = cloneItemsForDnd(dndItems);
405
+ const srcIdx = newState.findIndex((g) => g.name === activeCont);
406
+ if (srcIdx !== -1) {
407
+ const src = newState[srcIdx];
408
+ const idxInSrc = src.entries.findIndex(
409
+ (e) => e.url === activeIdNow
410
+ );
411
+ if (idxInSrc !== -1) {
412
+ const [dragged] = src.entries.splice(idxInSrc, 1);
413
+ if (src.entries.length === 0) newState.splice(srcIdx, 1);
414
+
415
+ let tentative = "New Group";
416
+ let counter = 1;
417
+ while (newState.some((g) => g.name === tentative))
418
+ tentative = `New Group ${counter++}`;
419
+
420
+ newState.push({
421
+ name: tentative,
422
+ entries: [dragged]
423
+ });
424
+ setDndItems(newState);
425
+ onPersist?.(newState);
426
+ setDialogOpenForGroup(tentative);
427
+ onNewGroupDrop?.();
428
+ }
429
+ }
430
+ }
431
+ }
432
+ /* reorder inside same container */
433
+ else {
434
+ const overCont = findDndContainer(overIdNow);
435
+ if (activeCont === overCont) {
436
+ const grpIdx = dndItems.findIndex((g) => g.name === activeCont);
437
+ if (grpIdx !== -1) {
438
+ const group = dndItems[grpIdx];
439
+ const oldIdx = group.entries.findIndex(
440
+ (e) => e.url === activeIdNow
441
+ );
442
+ let newIdx = group.entries.findIndex(
443
+ (e) => e.url === overIdNow
444
+ );
445
+ if (newIdx === -1 && overIdNow === activeCont)
446
+ newIdx = group.entries.length - 1;
447
+ if (
448
+ oldIdx !== -1 &&
449
+ newIdx !== -1 &&
450
+ oldIdx !== newIdx
451
+ ) {
452
+ const reordered = arrayMove(group.entries, oldIdx, newIdx);
453
+ const newState = [...dndItems];
454
+ newState[grpIdx] = {
455
+ ...group,
456
+ entries: reordered
457
+ };
458
+ setDndItems(newState);
459
+ onPersist?.(newState);
460
+ }
461
+ }
462
+ } else if (
463
+ recentlyMovedToNewContainer.current &&
464
+ interimItemsRef.current
465
+ ) {
466
+ onPersist?.(interimItemsRef.current);
467
+ }
468
+
469
+ onCardMovedBetweenGroups?.(
470
+ dndItems
471
+ .flatMap((g) => g.entries)
472
+ .find((e) => e.url === activeIdNow)!
473
+ );
474
+ }
475
+ }
476
+
477
+ resetDragState();
478
+ };
479
+
480
+ const resetDragState = () => {
481
+ setDndKitActiveNode(null);
482
+ setActiveId(null);
483
+ setActiveIsGroup(false);
484
+ setCurrentDraggingGroupId(null);
485
+ setIsDraggingCardOnly(false);
486
+ recentlyMovedToNewContainer.current = false;
487
+ };
488
+
489
+ const handleDragCancel = () => resetDragState();
490
+
491
+ /* ---------------- group rename ---------------- */
492
+ const handleRenameGroup = (oldName: string, newName: string) => {
493
+ setDndItems((current) => {
494
+ const idx = current.findIndex((g) => g.name === oldName);
495
+ if (idx === -1) return current;
496
+ if (current.some((g) => g.name === newName && g.name !== oldName))
497
+ return current;
498
+
499
+ const updated = [...current];
500
+ updated[idx] = {
501
+ ...updated[idx],
502
+ name: newName
503
+ };
504
+ onPersist?.(updated); // <- ensure rename is saved
505
+ return updated;
506
+ });
507
+ };
508
+
509
+ /* ---------------- public API ---------------- */
510
+ const activeItemForOverlay =
511
+ disabled || !activeId || activeIsGroup
512
+ ? null
513
+ : dndItems.flatMap((g) => g.entries).find((e) => e.url === activeId) || null;
514
+
515
+ const activeGroupData =
516
+ disabled || !activeId || !activeIsGroup
517
+ ? null
518
+ : dndItems.find((g) => g.name === activeId) || null;
519
+
520
+ return {
521
+ sensors,
522
+ collisionDetection,
523
+ onDragStart: handleDragStart,
524
+ onDragOver: handleDragOver,
525
+ onDragEnd: handleDragEnd,
526
+ onDragCancel: handleDragCancel,
527
+ dropAnimation: dropAnimationConfig,
528
+ activeItemForOverlay,
529
+ activeGroupData,
530
+ draggingGroupId: currentDraggingGroupId,
531
+ containers: dndContainers,
532
+ dndKitActiveNode,
533
+ isDraggingCardOnly,
534
+ dialogOpenForGroup,
535
+ setDialogOpenForGroup,
536
+ handleRenameGroup,
537
+ isHoveringNewGroupDropZone,
538
+ setIsHoveringNewGroupDropZone
539
+ };
540
+ }
541
+
542
+ /* ─────────────────────────────────────────────────────────── */
543
+ /* New-group drop-zone component */
544
+
545
+ /* ─────────────────────────────────────────────────────────── */
546
+ export function NewGroupDropZone({
547
+ disabled,
548
+ setIsHovering
549
+ }: {
550
+ disabled: boolean;
551
+ setIsHovering: (v: boolean) => void;
552
+ }) {
553
+ const {
554
+ setNodeRef,
555
+ isOver
556
+ } = useDroppable({
557
+ id: "new-group-drop-zone",
558
+ disabled
559
+ });
560
+ const [isVisible, setIsVisible] = useState(false);
561
+
562
+ useDndMonitor({
563
+ onDragStart({ active }) {
564
+ if (disabled) return;
565
+ const tp = active.data.current?.type;
566
+ setIsVisible(tp === "item");
567
+ },
568
+ onDragEnd() {
569
+ setIsVisible(false);
570
+ },
571
+ onDragCancel() {
572
+ setIsVisible(false);
573
+ }
574
+ });
575
+
576
+ useEffect(() => {
577
+ setIsHovering(isOver && isVisible);
578
+ }, [isOver, isVisible, setIsHovering]);
579
+
580
+ if (!isVisible || disabled) return null;
581
+
582
+ return (
583
+ <div
584
+ ref={setNodeRef}
585
+ className={cls(
586
+ "fixed right-8 top-1/2 -translate-y-1/2 w-[200px] h-[120px] border border-dashed rounded-lg flex items-center justify-center transition-all",
587
+ isOver
588
+ ? "bg-surface-accent-100 dark:bg-surface-accent-800 border-surface-300 dark:border-surface-600"
589
+ : "bg-surface-50 dark:bg-surface-900 border-surface-200 dark:border-surface-700"
590
+ )}
591
+ >
592
+ <div className="text-center p-4">
593
+ <span className="block font-medium text-sm">
594
+ Drop here to create a new group
595
+ </span>
596
+ </div>
597
+ </div>
598
+ );
599
+ }