@firecms/core 3.0.0 → 3.1.0-canary.02232f4

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 (340) hide show
  1. package/README.md +1 -1
  2. package/dist/components/AIIcon.d.ts +16 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
  7. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
  8. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
  9. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  10. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  11. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  12. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  13. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  14. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
  15. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  16. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  18. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  19. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  20. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  21. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  22. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
  23. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  24. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  25. package/dist/components/ErrorBoundary.d.ts +4 -2
  26. package/dist/components/HomePage/DefaultHomePage.d.ts +0 -1
  27. package/dist/components/LanguageToggle.d.ts +1 -0
  28. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  29. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  30. package/dist/components/UnsavedChangesDialog.d.ts +1 -0
  31. package/dist/components/VirtualTable/VirtualTable.performance.test.d.ts +1 -0
  32. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  33. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +4 -1
  34. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  35. package/dist/components/VirtualTable/VirtualTableProps.d.ts +17 -1
  36. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  37. package/dist/components/VirtualTable/types.d.ts +3 -0
  38. package/dist/components/index.d.ts +4 -0
  39. package/dist/contexts/index.d.ts +10 -0
  40. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  41. package/dist/core/index.d.ts +1 -0
  42. package/dist/editor/components/SlashCommandMenu.d.ts +6 -0
  43. package/dist/editor/components/editor-bubble-item.d.ts +8 -0
  44. package/dist/editor/components/editor-bubble.d.ts +8 -0
  45. package/dist/editor/components/image-bubble.d.ts +5 -0
  46. package/dist/editor/components/index.d.ts +16 -0
  47. package/dist/editor/components/table-bubble.d.ts +5 -0
  48. package/dist/editor/editor.d.ts +30 -0
  49. package/dist/editor/extensions/HighlightDecorationExtension.d.ts +24 -0
  50. package/dist/editor/extensions/Image/index.d.ts +6 -0
  51. package/dist/editor/extensions/Image.d.ts +6 -0
  52. package/dist/editor/extensions/TextLoadingDecorationExtension.d.ts +16 -0
  53. package/dist/editor/extensions/clipboard.d.ts +7 -0
  54. package/dist/editor/extensions/custom-keymap.d.ts +1 -0
  55. package/dist/editor/extensions/drag-and-drop.d.ts +9 -0
  56. package/dist/editor/hooks/useProseMirror.d.ts +13 -0
  57. package/dist/editor/hooks/useProseMirrorContext.d.ts +9 -0
  58. package/dist/editor/index.d.ts +2 -0
  59. package/dist/editor/markdown.d.ts +5 -0
  60. package/dist/editor/nodeViews/ImageComponent.d.ts +3 -0
  61. package/dist/editor/nodeViews/ReactNodeView.d.ts +29 -0
  62. package/dist/editor/nodeViews/TaskItemComponent.d.ts +3 -0
  63. package/dist/editor/nodeViews/index.d.ts +6 -0
  64. package/dist/editor/plugins/index.d.ts +2 -0
  65. package/dist/editor/plugins/inputrules.d.ts +6 -0
  66. package/dist/editor/plugins/placeholderPlugin.d.ts +3 -0
  67. package/dist/editor/plugins/slashCommandPlugin.d.ts +12 -0
  68. package/dist/editor/schema.d.ts +2 -0
  69. package/dist/editor/selectors/ai-selector.d.ts +0 -0
  70. package/dist/editor/selectors/color-selector.d.ts +10 -0
  71. package/dist/editor/selectors/link-selector.d.ts +8 -0
  72. package/dist/editor/selectors/node-selector.d.ts +15 -0
  73. package/dist/editor/selectors/text-buttons.d.ts +1 -0
  74. package/dist/editor/types.d.ts +5 -0
  75. package/dist/editor/useProseMirror.d.ts +16 -0
  76. package/dist/editor/utils/prosemirror-utils.d.ts +6 -0
  77. package/dist/editor/utils/remove_classes.d.ts +1 -0
  78. package/dist/editor/utils/useDebouncedCallback.d.ts +1 -0
  79. package/dist/form/components/ErrorFocus.d.ts +1 -1
  80. package/dist/form/components/LocalChangesMenu.d.ts +2 -2
  81. package/dist/form/components/StorageUploadProgress.d.ts +1 -1
  82. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  83. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  84. package/dist/form/validation.d.ts +3 -2
  85. package/dist/hooks/index.d.ts +1 -0
  86. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  87. package/dist/hooks/useBuildNavigationController.d.ts +0 -1
  88. package/dist/hooks/useCollapsedGroups.d.ts +6 -3
  89. package/dist/hooks/useTranslation.d.ts +17 -0
  90. package/dist/i18n/FireCMSi18nProvider.d.ts +33 -0
  91. package/dist/index.d.ts +5 -0
  92. package/dist/index.es.js +31028 -16080
  93. package/dist/index.es.js.map +1 -1
  94. package/dist/index.umd.js +29955 -15028
  95. package/dist/index.umd.js.map +1 -1
  96. package/dist/internal/useRestoreScroll.d.ts +1 -1
  97. package/dist/locales/de.d.ts +2 -0
  98. package/dist/locales/en.d.ts +10 -0
  99. package/dist/locales/es.d.ts +10 -0
  100. package/dist/locales/fr.d.ts +2 -0
  101. package/dist/locales/hi.d.ts +2 -0
  102. package/dist/locales/it.d.ts +2 -0
  103. package/dist/locales/pt.d.ts +7 -0
  104. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  105. package/dist/preview/components/DatePreview.d.ts +13 -3
  106. package/dist/preview/components/ImagePreview.d.ts +5 -1
  107. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  108. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  109. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  110. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  111. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  112. package/dist/types/analytics.d.ts +1 -1
  113. package/dist/types/collections.d.ts +88 -2
  114. package/dist/types/customization_controller.d.ts +2 -1
  115. package/dist/types/datasource.d.ts +0 -1
  116. package/dist/types/entities.d.ts +1 -0
  117. package/dist/types/firecms.d.ts +2 -1
  118. package/dist/types/index.d.ts +1 -0
  119. package/dist/types/navigation.d.ts +2 -2
  120. package/dist/types/plugins.d.ts +69 -1
  121. package/dist/types/properties.d.ts +277 -12
  122. package/dist/types/storage.d.ts +9 -0
  123. package/dist/types/translations.d.ts +669 -0
  124. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  125. package/dist/util/__tests__/objects.test.d.ts +1 -0
  126. package/dist/util/conditions.d.ts +26 -0
  127. package/dist/util/entities.d.ts +2 -3
  128. package/dist/util/index.d.ts +3 -1
  129. package/dist/util/lazy_eager.d.ts +7 -0
  130. package/dist/util/objects.d.ts +1 -0
  131. package/dist/util/property_utils.d.ts +2 -1
  132. package/dist/util/resolutions.d.ts +3 -3
  133. package/dist/util/useStorageUploadController.d.ts +11 -2
  134. package/package.json +52 -12
  135. package/src/app/Scaffold.tsx +20 -19
  136. package/src/components/AIIcon.tsx +41 -0
  137. package/src/components/ArrayContainer.tsx +7 -8
  138. package/src/components/ClearFilterSortButton.tsx +25 -19
  139. package/src/components/ConfirmationDialog.tsx +4 -4
  140. package/src/components/DeleteEntityDialog.tsx +12 -11
  141. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +82 -43
  142. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  143. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  144. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  145. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +6 -3
  146. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +24 -44
  147. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  148. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  149. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
  150. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  151. package/src/components/EntityCollectionView/Board.tsx +324 -0
  152. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  153. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  154. package/src/components/EntityCollectionView/BoardSortableList.tsx +174 -0
  155. package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
  156. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  157. package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
  158. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +706 -0
  159. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +236 -0
  160. package/src/components/EntityCollectionView/EntityCollectionView.tsx +531 -209
  161. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +35 -22
  162. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +86 -15
  163. package/src/components/EntityCollectionView/FiltersDialog.tsx +252 -0
  164. package/src/components/EntityCollectionView/ViewModeToggle.tsx +202 -0
  165. package/src/components/EntityCollectionView/board_types.ts +113 -0
  166. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  167. package/src/components/EntityJsonPreview.tsx +2 -1
  168. package/src/components/EntityPreview.tsx +1 -1
  169. package/src/components/EntityView.tsx +3 -2
  170. package/src/components/ErrorBoundary.tsx +27 -15
  171. package/src/components/ErrorTooltip.tsx +2 -1
  172. package/src/components/HomePage/DefaultHomePage.tsx +65 -22
  173. package/src/components/HomePage/HomePageDnD.tsx +59 -42
  174. package/src/components/HomePage/NavigationCard.tsx +20 -18
  175. package/src/components/HomePage/NavigationGroup.tsx +20 -17
  176. package/src/components/HomePage/RenameGroupDialog.tsx +15 -15
  177. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  178. package/src/components/LanguageToggle.tsx +66 -0
  179. package/src/components/NotFoundPage.tsx +5 -3
  180. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +12 -17
  181. package/src/components/ReferenceWidget.tsx +5 -6
  182. package/src/components/SearchIconsView.tsx +3 -1
  183. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  184. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  185. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +50 -40
  186. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +53 -40
  187. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +60 -58
  188. package/src/components/UnsavedChangesDialog.tsx +6 -6
  189. package/src/components/UserDisplay.tsx +4 -4
  190. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +387 -0
  191. package/src/components/VirtualTable/VirtualTable.tsx +277 -121
  192. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  193. package/src/components/VirtualTable/VirtualTableHeader.tsx +76 -64
  194. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +163 -42
  195. package/src/components/VirtualTable/VirtualTableProps.tsx +21 -2
  196. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  197. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  198. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
  199. package/src/components/VirtualTable/types.tsx +3 -0
  200. package/src/components/common/default_entity_actions.tsx +4 -0
  201. package/src/components/common/useColumnsIds.tsx +95 -3
  202. package/src/components/common/useDataSourceTableController.tsx +12 -4
  203. package/src/components/index.tsx +5 -0
  204. package/src/contexts/BreacrumbsContext.tsx +15 -8
  205. package/src/contexts/index.ts +10 -0
  206. package/src/core/DefaultAppBar.tsx +49 -32
  207. package/src/core/DefaultDrawer.tsx +49 -57
  208. package/src/core/DrawerNavigationGroup.tsx +120 -0
  209. package/src/core/DrawerNavigationItem.tsx +4 -3
  210. package/src/core/EntityEditView.tsx +94 -50
  211. package/src/core/EntityEditViewFormActions.tsx +24 -17
  212. package/src/core/EntitySidePanel.tsx +34 -30
  213. package/src/core/FireCMS.tsx +33 -6
  214. package/src/core/SideDialogs.tsx +4 -2
  215. package/src/core/field_configs.tsx +18 -11
  216. package/src/core/index.tsx +1 -0
  217. package/src/editor/components/SlashCommandMenu.tsx +516 -0
  218. package/src/editor/components/editor-bubble-item.tsx +32 -0
  219. package/src/editor/components/editor-bubble.tsx +118 -0
  220. package/src/editor/components/image-bubble.tsx +156 -0
  221. package/src/editor/components/index.ts +14 -0
  222. package/src/editor/components/table-bubble.tsx +165 -0
  223. package/src/editor/editor.tsx +455 -0
  224. package/src/editor/extensions/HighlightDecorationExtension.ts +114 -0
  225. package/src/editor/extensions/Image/index.ts +133 -0
  226. package/src/editor/extensions/Image.ts +159 -0
  227. package/src/editor/extensions/TextLoadingDecorationExtension.tsx +107 -0
  228. package/src/editor/extensions/clipboard.ts +72 -0
  229. package/src/editor/extensions/custom-keymap.ts +24 -0
  230. package/src/editor/extensions/drag-and-drop.tsx +480 -0
  231. package/src/editor/hooks/useProseMirror.ts +124 -0
  232. package/src/editor/hooks/useProseMirrorContext.ts +15 -0
  233. package/src/editor/index.ts +2 -0
  234. package/src/editor/markdown.ts +172 -0
  235. package/src/editor/nodeViews/ImageComponent.tsx +20 -0
  236. package/src/editor/nodeViews/ReactNodeView.tsx +89 -0
  237. package/src/editor/nodeViews/TaskItemComponent.tsx +29 -0
  238. package/src/editor/nodeViews/index.ts +35 -0
  239. package/src/editor/plugins/index.ts +58 -0
  240. package/src/editor/plugins/inputrules.ts +82 -0
  241. package/src/editor/plugins/placeholderPlugin.ts +55 -0
  242. package/src/editor/plugins/slashCommandPlugin.ts +61 -0
  243. package/src/editor/schema.ts +240 -0
  244. package/src/editor/selectors/ai-selector.tsx +111 -0
  245. package/src/editor/selectors/color-selector.tsx +200 -0
  246. package/src/editor/selectors/link-selector.tsx +118 -0
  247. package/src/editor/selectors/node-selector.tsx +157 -0
  248. package/src/editor/selectors/text-buttons.tsx +86 -0
  249. package/src/editor/types.ts +6 -0
  250. package/src/editor/useProseMirror.ts +126 -0
  251. package/src/editor/utils/prosemirror-utils.ts +108 -0
  252. package/src/editor/utils/remove_classes.ts +17 -0
  253. package/src/editor/utils/useDebouncedCallback.ts +25 -0
  254. package/src/form/EntityForm.tsx +150 -75
  255. package/src/form/EntityFormActions.tsx +19 -12
  256. package/src/form/PropertyFieldBinding.tsx +68 -51
  257. package/src/form/components/ErrorFocus.tsx +3 -3
  258. package/src/form/components/LocalChangesMenu.tsx +19 -19
  259. package/src/form/components/StorageItemPreview.tsx +5 -3
  260. package/src/form/components/StorageUploadProgress.tsx +22 -6
  261. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +18 -5
  262. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +22 -10
  263. package/src/form/field_bindings/BlockFieldBinding.tsx +26 -9
  264. package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -17
  265. package/src/form/field_bindings/KeyValueFieldBinding.tsx +46 -25
  266. package/src/form/field_bindings/MapFieldBinding.tsx +88 -70
  267. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +93 -52
  268. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +15 -1
  269. package/src/form/field_bindings/ReferenceAsStringFieldBinding.tsx +25 -11
  270. package/src/form/field_bindings/ReferenceFieldBinding.tsx +25 -11
  271. package/src/form/field_bindings/RepeatFieldBinding.tsx +21 -6
  272. package/src/form/field_bindings/SelectFieldBinding.tsx +7 -5
  273. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +110 -92
  274. package/src/form/field_bindings/SwitchFieldBinding.tsx +31 -14
  275. package/src/form/field_bindings/TextFieldBinding.tsx +77 -38
  276. package/src/form/field_bindings/UserSelectFieldBinding.tsx +7 -5
  277. package/src/form/validation.ts +245 -160
  278. package/src/hooks/index.tsx +1 -0
  279. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  280. package/src/hooks/useBuildNavigationController.tsx +91 -41
  281. package/src/hooks/useCollapsedGroups.ts +18 -9
  282. package/src/hooks/useTranslation.ts +31 -0
  283. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  284. package/src/i18n/FireCMSi18nProvider.tsx +160 -0
  285. package/src/index.ts +5 -0
  286. package/src/internal/useBuildDataSource.ts +68 -34
  287. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  288. package/src/internal/useBuildSideEntityController.tsx +24 -24
  289. package/src/internal/useRestoreScroll.tsx +26 -14
  290. package/src/locales/de.ts +718 -0
  291. package/src/locales/en.ts +730 -0
  292. package/src/locales/es.ts +730 -0
  293. package/src/locales/fr.ts +718 -0
  294. package/src/locales/hi.ts +718 -0
  295. package/src/locales/it.ts +718 -0
  296. package/src/locales/pt.ts +727 -0
  297. package/src/preview/PropertyPreview.tsx +43 -33
  298. package/src/preview/PropertyPreviewProps.tsx +6 -0
  299. package/src/preview/components/DatePreview.tsx +72 -4
  300. package/src/preview/components/EmptyValue.tsx +1 -1
  301. package/src/preview/components/ImagePreview.tsx +37 -21
  302. package/src/preview/components/ReferencePreview.tsx +8 -2
  303. package/src/preview/components/StorageThumbnail.tsx +16 -12
  304. package/src/preview/components/UrlComponentPreview.tsx +32 -27
  305. package/src/preview/components/UserPreview.tsx +3 -1
  306. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  307. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  308. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  309. package/src/preview/property_previews/MapPropertyPreview.tsx +49 -27
  310. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  311. package/src/routes/CustomCMSRoute.tsx +1 -0
  312. package/src/routes/FireCMSRoute.tsx +87 -65
  313. package/src/types/analytics.ts +10 -0
  314. package/src/types/collections.ts +97 -3
  315. package/src/types/customization_controller.tsx +2 -1
  316. package/src/types/datasource.ts +54 -56
  317. package/src/types/entities.ts +10 -0
  318. package/src/types/firecms.tsx +2 -1
  319. package/src/types/index.ts +1 -0
  320. package/src/types/navigation.ts +2 -2
  321. package/src/types/plugins.tsx +77 -1
  322. package/src/types/properties.ts +369 -37
  323. package/src/types/storage.ts +11 -1
  324. package/src/types/translations.ts +752 -0
  325. package/src/util/__tests__/conditions.test.ts +506 -0
  326. package/src/util/__tests__/objects.test.ts +196 -0
  327. package/src/util/callbacks.ts +6 -3
  328. package/src/util/collections.ts +51 -6
  329. package/src/util/conditions.ts +339 -0
  330. package/src/util/entities.ts +29 -30
  331. package/src/util/entity_cache.ts +2 -1
  332. package/src/util/index.ts +3 -1
  333. package/src/util/join_collections.ts +10 -8
  334. package/src/util/lazy_eager.tsx +33 -0
  335. package/src/util/objects.ts +46 -13
  336. package/src/util/{references.ts → previews.ts} +16 -2
  337. package/src/util/property_utils.tsx +37 -11
  338. package/src/util/resolutions.ts +62 -58
  339. package/src/util/useStorageUploadController.tsx +34 -30
  340. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -0,0 +1,455 @@
1
+ "use client";
2
+ import React, { useEffect, useState, useRef } from "react";
3
+ import { EditorState } from "prosemirror-state";
4
+ import { cls, defaultBorderMixin, Separator, useInjectStyles, TextareaAutosize } from "@firecms/ui";
5
+ import { useTranslation } from "../hooks/useTranslation";
6
+ import { EditorBubble, ImageBubble, SlashCommandMenu, TableBubble, type JSONContent } from "./components";
7
+ import { NodeSelector } from "./selectors/node-selector";
8
+ import { LinkSelector } from "./selectors/link-selector";
9
+ import { TextButtons } from "./selectors/text-buttons";
10
+ import { removeClassesFromJson } from "./utils/remove_classes";
11
+ import { parser, serializer } from "./markdown";
12
+ import { EditorAIController } from "./types";
13
+ import { useProseMirror } from "./hooks/useProseMirror";
14
+ import { ProseMirrorContext } from "./hooks/useProseMirrorContext";
15
+ import { highlightCommands } from "./extensions/HighlightDecorationExtension";
16
+ import { schema } from "./schema";
17
+
18
+ export type CustomEditorComponent = {
19
+ name: string,
20
+ component: React.FC
21
+ };
22
+
23
+ export interface MarkdownEditorConfig {
24
+ html?: boolean;
25
+ transformPastedText?: boolean;
26
+ }
27
+
28
+ export type FireCMSEditorTextSize = "sm" | "base" | "lg";
29
+
30
+ export type FireCMSEditorProps = {
31
+ content?: JSONContent | string,
32
+ onMarkdownContentChange?: (content: string) => void,
33
+ onJsonContentChange?: (content: JSONContent | null) => void,
34
+ onHtmlContentChange?: (content: string) => void,
35
+ handleImageUpload: (file: File) => Promise<string>,
36
+ version?: number,
37
+ textSize?: FireCMSEditorTextSize,
38
+ highlight?: { from: number, to: number },
39
+ aiController?: EditorAIController,
40
+ customComponents?: CustomEditorComponent[];
41
+ disabled?: boolean;
42
+ markdownConfig?: MarkdownEditorConfig;
43
+ };
44
+
45
+ const proseClasses = {
46
+ "sm": "prose-sm",
47
+ "base": "prose-base",
48
+ "lg": "prose-lg"
49
+ }
50
+
51
+ export const FireCMSEditor = ({
52
+ content,
53
+ onJsonContentChange,
54
+ onHtmlContentChange,
55
+ onMarkdownContentChange,
56
+ version,
57
+ textSize = "base",
58
+ highlight,
59
+ handleImageUpload,
60
+ aiController,
61
+ disabled,
62
+ markdownConfig
63
+ }: FireCMSEditorProps) => {
64
+ const { t } = useTranslation();
65
+
66
+ const [openNode, setOpenNode] = useState(false);
67
+ const [openLink, setOpenLink] = useState(false);
68
+
69
+ const [isMarkdownMode, setIsMarkdownMode] = useState(false);
70
+ const [internalMarkdown, setInternalMarkdown] = useState<string>("");
71
+
72
+ useEffect(() => {
73
+ if (!isMarkdownMode) return;
74
+ const timeout = setTimeout(() => {
75
+ if (callbacksRef.current.onMarkdownContentChange) {
76
+ callbacksRef.current.onMarkdownContentChange(internalMarkdown);
77
+ }
78
+ }, 250);
79
+ return () => clearTimeout(timeout);
80
+ }, [internalMarkdown, isMarkdownMode]);
81
+
82
+ const handleToggleMarkdown = () => {
83
+ if (!isMarkdownMode) {
84
+ if (view) {
85
+ setInternalMarkdown(serializer.serialize(view.state.doc));
86
+ }
87
+ setIsMarkdownMode(true);
88
+ } else {
89
+ if (view) {
90
+ const newDoc = parser.parse(internalMarkdown);
91
+ if (newDoc) {
92
+ const tr = view.state.tr.replaceWith(0, view.state.doc.content.size, newDoc.content);
93
+ view.dispatch(tr);
94
+ }
95
+ }
96
+ setIsMarkdownMode(false);
97
+ }
98
+ };
99
+
100
+ const handleMarkdownChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
101
+ setInternalMarkdown(e.target.value);
102
+ };
103
+
104
+ const handleMarkdownBlur = () => {
105
+ const { onMarkdownContentChange, onJsonContentChange } = callbacksRef.current;
106
+ if (onMarkdownContentChange) {
107
+ onMarkdownContentChange(internalMarkdown);
108
+ }
109
+ if (onJsonContentChange) {
110
+ try {
111
+ const newDoc = parser.parse(internalMarkdown);
112
+ if (newDoc) {
113
+ onJsonContentChange(removeClassesFromJson(newDoc.toJSON()) as JSONContent);
114
+ }
115
+ } catch (e) {
116
+ console.warn("Could not parse markdown to JSON", e);
117
+ }
118
+ }
119
+ };
120
+
121
+ useInjectStyles("Editor", cssStyles);
122
+
123
+ const callbacksRef = useRef({ onMarkdownContentChange, onJsonContentChange });
124
+ useEffect(() => {
125
+ callbacksRef.current = { onMarkdownContentChange, onJsonContentChange };
126
+ }, [onMarkdownContentChange, onJsonContentChange]);
127
+
128
+ const flushChanges = (currentState: EditorState) => {
129
+ const { onMarkdownContentChange, onJsonContentChange } = callbacksRef.current;
130
+ if (onMarkdownContentChange) {
131
+ try {
132
+ const markdown = serializer.serialize(currentState.doc);
133
+ onMarkdownContentChange(markdown);
134
+ } catch (e) {
135
+ console.warn("[FireCMSEditor] Could not serialize editor state to markdown:", e);
136
+ }
137
+ }
138
+ if (onJsonContentChange) {
139
+ const jsonContent = removeClassesFromJson(currentState.doc.toJSON()) as JSONContent;
140
+ onJsonContentChange(jsonContent);
141
+ }
142
+ };
143
+
144
+ const { state, view, editorRef } = useProseMirror({
145
+ initialContent: content,
146
+ editable: !disabled,
147
+ handleImageUpload,
148
+ });
149
+
150
+ const doc = state?.doc;
151
+ useEffect(() => {
152
+ if (!state) return;
153
+ const timeout = setTimeout(() => {
154
+ flushChanges(state);
155
+ }, 250);
156
+ return () => clearTimeout(timeout);
157
+ }, [doc]);
158
+
159
+ useEffect(() => {
160
+ if (!view) return;
161
+ const dom = view.dom;
162
+ const handleBlur = () => {
163
+ flushChanges(view.state);
164
+ };
165
+ dom.addEventListener("blur", handleBlur);
166
+ return () => dom.removeEventListener("blur", handleBlur);
167
+ }, [view]);
168
+
169
+
170
+
171
+ useEffect(() => {
172
+ if (view) {
173
+ if (highlight) {
174
+ highlightCommands.toggleAutocompleteHighlight(highlight)(view.state, view.dispatch);
175
+ } else {
176
+ highlightCommands.removeAutocompleteHighlight()(view.state, view.dispatch);
177
+ }
178
+ }
179
+ }, [highlight?.from, highlight?.to]);
180
+
181
+ const proseClass = proseClasses[textSize];
182
+
183
+
184
+
185
+ return (
186
+ <div className="relative min-h-[300px] w-full">
187
+ <button
188
+ type="button"
189
+ onClick={handleToggleMarkdown}
190
+ title={isMarkdownMode ? "Switch to Visual Editor" : "Switch to Markdown"}
191
+ className="absolute top-2 right-2 z-10 px-2 py-1 text-xs font-medium text-surface-400 hover:text-surface-700 dark:text-surface-600 dark:hover:text-surface-300 transition-colors opacity-50 hover:opacity-100 bg-transparent rounded"
192
+ >
193
+ {isMarkdownMode ? "Visual" : "Markdown"}
194
+ </button>
195
+
196
+ <ProseMirrorContext.Provider value={{ state, view }}>
197
+
198
+ <div style={{ display: isMarkdownMode ? "none" : "block" }}>
199
+ <div
200
+ ref={editorRef}
201
+ className={cls(proseClass, "prose-headings:font-title font-default focus:outline-none max-w-full p-12")}
202
+ />
203
+
204
+ {view && (
205
+ <>
206
+ <EditorBubble
207
+ options={{
208
+ placement: "top",
209
+ offset: 6,
210
+ }}
211
+ className={cls("flex w-fit max-w-[90vw] h-10 overflow-hidden rounded border bg-white dark:bg-surface-900 shadow", defaultBorderMixin)}
212
+ >
213
+ <NodeSelector portalContainer={editorRef.current} open={openNode} onOpenChange={setOpenNode} />
214
+ <Separator orientation="vertical" />
215
+ <LinkSelector open={openLink} onOpenChange={setOpenLink} />
216
+ <Separator orientation="vertical" />
217
+ <TextButtons />
218
+ </EditorBubble>
219
+
220
+ <ImageBubble
221
+ options={{
222
+ placement: "bottom",
223
+ offset: 6,
224
+ }}
225
+ />
226
+ <TableBubble />
227
+ </>
228
+ )}
229
+
230
+ <SlashCommandMenu upload={handleImageUpload} aiController={aiController} />
231
+ </div>
232
+
233
+ {isMarkdownMode && (
234
+ <TextareaAutosize
235
+ value={internalMarkdown}
236
+ onChange={handleMarkdownChange as any}
237
+ onBlur={handleMarkdownBlur as any}
238
+ className={cls(
239
+ "w-full h-full min-h-[300px] p-12 bg-transparent resize-none font-mono focus:ring-0",
240
+ proseClass
241
+ )}
242
+ style={{
243
+ tabSize: 4,
244
+ outline: "none",
245
+ border: "none",
246
+ boxShadow: "none"
247
+ }}
248
+ />
249
+ )}
250
+
251
+ </ProseMirrorContext.Provider>
252
+ </div>
253
+ );
254
+ };
255
+
256
+
257
+
258
+ const cssStyles = `
259
+ .ProseMirror {
260
+ box-shadow: none !important;
261
+ }
262
+ .ProseMirror .is-editor-empty:first-child::before {
263
+ content: attr(data-placeholder);
264
+ float: left;
265
+ color: rgb(100 116 139); //500
266
+ pointer-events: none;
267
+ height: 0;
268
+ }
269
+ .ProseMirror .is-empty::before {
270
+ content: attr(data-placeholder);
271
+ float: left;
272
+ color: rgb(100 116 139); //500
273
+ pointer-events: none;
274
+ height: 0;
275
+ }
276
+
277
+ [data-theme="dark"] {
278
+ .ProseMirror .is-empty::before {
279
+ color: rgb(100 116 139); //500
280
+ }
281
+ }
282
+
283
+ .is-empty {
284
+ cursor: text;
285
+ color: rgb(100 116 139); //500
286
+ }
287
+
288
+ .ProseMirror img {
289
+ transition: filter 0.1s ease-in-out;
290
+ &:hover {
291
+ cursor: pointer;
292
+ filter: brightness(90%);
293
+ }
294
+ &.ProseMirror-selectednode {
295
+ filter: brightness(90%);
296
+ box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000) !important;
297
+ }
298
+ }
299
+
300
+ ul[data-type="taskList"] li > label {
301
+ margin-right: 0.2rem;
302
+ user-select: none;
303
+ }
304
+ @media screen and (max-width: 768px) {
305
+ ul[data-type="taskList"] li > label {
306
+ margin-right: 0.5rem;
307
+ }
308
+ }
309
+ [data-theme="dark"] {
310
+ ul[data-type="taskList"] li > label input[type="checkbox"] {
311
+ background-color: rgb(30 41 59);
312
+ border: 2px solid #666;
313
+ &:hover { background-color: rgb(51 65 85); }
314
+ &:active { background-color: rgb(71 85 105); }
315
+ }
316
+ }
317
+ ul[data-type="taskList"] li > label input[type="checkbox"] {
318
+ -webkit-appearance: none;
319
+ appearance: none;
320
+ background-color: white;
321
+ margin: 0;
322
+ cursor: pointer;
323
+ width: 1.2em;
324
+ height: 1.2em;
325
+ position: relative;
326
+ top: 5px;
327
+ border: 2px solid #777;
328
+ border-radius: 0.25em;
329
+ margin-right: 0.3rem;
330
+ display: grid;
331
+ place-content: center;
332
+ &:hover { background-color: rgb(241 245 249); }
333
+ &:active { background-color: rgb(226 232 240); }
334
+ &::before {
335
+ content: "";
336
+ width: 0.65em;
337
+ height: 0.65em;
338
+ transform: scale(0);
339
+ transition: 120ms transform ease-in-out;
340
+ box-shadow: inset 1em 1em;
341
+ transform-origin: center;
342
+ clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
343
+ }
344
+ &:checked::before { transform: scale(1); }
345
+ }
346
+
347
+ [data-theme="dark"] {
348
+ ul[data-type="taskList"] li[data-checked="true"] > div > p {
349
+ color: rgb(226 232 240);
350
+ text-decoration: line-through;
351
+ text-decoration-thickness: 2px;
352
+ }
353
+ }
354
+ ul[data-type="taskList"] li[data-checked="true"] > div > p {
355
+ color: rgb(51 65 85);
356
+ text-decoration: line-through;
357
+ text-decoration-thickness: 2px;
358
+ }
359
+ .tippy-box { max-width: 400px !important; }
360
+
361
+ .ProseMirror:not(.dragging) .ProseMirror-selectednode {
362
+ background-color: rgb(219 234 254);
363
+ transition: background-color 0.2s;
364
+ box-shadow: none;
365
+ }
366
+ [data-theme="dark"] .ProseMirror:not(.dragging) .ProseMirror-selectednode {
367
+ background-color: rgb(51 65 85);
368
+ }
369
+ .prose-base table p { margin: 0; }
370
+
371
+ .drag-handle {
372
+ position: absolute;
373
+ opacity: 1;
374
+ transition: opacity ease-in 0.2s;
375
+ border-radius: 0.25rem;
376
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(128, 128, 128, 0.9)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7,8.44771525 7,9 7,9 C7,9.55228475 7,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E");
377
+ background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem);
378
+ background-repeat: no-repeat;
379
+ background-position: center;
380
+ width: 1.2rem;
381
+ height: 1.5rem;
382
+ z-index: 100;
383
+ cursor: grab;
384
+
385
+ /* Create a hover area around the handle itself that doesn't overlap text */
386
+ &::before {
387
+ content: '';
388
+ position: absolute;
389
+ top: -10px;
390
+ bottom: -10px;
391
+ left: -20px;
392
+ right: 0px;
393
+ z-index: -1;
394
+ }
395
+
396
+ &:hover { background-color: rgb(241 245 249); transition: background-color 0.2s; }
397
+ &:active { background-color: rgb(226 232 240); transition: background-color 0.2s; }
398
+ &.hide { opacity: 0; pointer-events: none; }
399
+ @media screen and (max-width: 600px) { display: none; pointer-events: none; }
400
+ }
401
+ [data-theme="dark"] .drag-handle {
402
+ &:hover { background-color: rgb(51 65 85); }
403
+ &:active { background-color: rgb(51 65 85); }
404
+ }
405
+ .prosemirror-dropcursor-block {
406
+ background-color: var(--color-surface-accent-600);
407
+ }
408
+ [data-theme="dark"] .prosemirror-dropcursor-block {
409
+ background-color: var(--color-surface-accent-300);
410
+ }
411
+
412
+ .ProseMirror table {
413
+ border-collapse: separate;
414
+ border-spacing: 0;
415
+ table-layout: fixed;
416
+ width: 100%;
417
+ margin: 1em 0;
418
+ overflow: hidden;
419
+ border-radius: 0.375rem;
420
+ border: 1px solid #e5e7eb;
421
+ }
422
+ [data-theme="dark"] .ProseMirror table {
423
+ border-color: #374151;
424
+ }
425
+
426
+ .ProseMirror td, .ProseMirror th {
427
+ min-width: 1em;
428
+ padding: 8px 10px;
429
+ vertical-align: top;
430
+ box-sizing: border-box;
431
+ position: relative;
432
+ border-right: 1px solid #e5e7eb;
433
+ border-bottom: 1px solid #e5e7eb;
434
+ }
435
+ [data-theme="dark"] .ProseMirror td, [data-theme="dark"] .ProseMirror th {
436
+ border-right-color: #374151;
437
+ border-bottom-color: #374151;
438
+ }
439
+
440
+ .ProseMirror tr:last-child td, .ProseMirror tr:last-child th {
441
+ border-bottom: none;
442
+ }
443
+ .ProseMirror th:last-child, .ProseMirror td:last-child {
444
+ border-right: none;
445
+ }
446
+
447
+ .ProseMirror th {
448
+ font-weight: 600;
449
+ text-align: left;
450
+ background-color: #f9fafb;
451
+ }
452
+ [data-theme="dark"] .ProseMirror th {
453
+ background-color: #1f2937;
454
+ }
455
+ `;
@@ -0,0 +1,114 @@
1
+ import { Plugin, PluginKey, Transaction, EditorState } from "prosemirror-state";
2
+ import { Decoration, DecorationSet } from "prosemirror-view";
3
+
4
+ export interface HighlightRange {
5
+ from: number
6
+ to: number
7
+ }
8
+
9
+ interface AutocompleteHighlightState {
10
+ highlight?: HighlightRange
11
+ decorationSet?: DecorationSet
12
+ }
13
+
14
+ export const highlightDecorationKey = new PluginKey<AutocompleteHighlightState>("highlightDecoration");
15
+
16
+ function buildDecorationSet(highlight: any, doc: any) {
17
+ const decorations: [any?] = [];
18
+
19
+ if (highlight) {
20
+ decorations.push(
21
+ Decoration.inline(highlight.from, highlight.to, {
22
+ class: "dark:bg-surface-accent-700 bg-surface-accent-300"
23
+ })
24
+ );
25
+ }
26
+ const decorationSet = DecorationSet.create(doc, decorations);
27
+ return decorationSet;
28
+ }
29
+
30
+ /**
31
+ * Commands to toggle the highlight
32
+ */
33
+ export const highlightCommands = {
34
+ toggleAutocompleteHighlight: (range?: HighlightRange) => (state: EditorState, dispatch?: (tr: Transaction) => void): boolean => {
35
+ const { selection } = state;
36
+ const pos = selection.from;
37
+
38
+ if (!dispatch) return false;
39
+
40
+ const tr = state.tr.setMeta(highlightDecorationKey, {
41
+ pos,
42
+ type: "highlightDecoration",
43
+ remove: false,
44
+ range
45
+ });
46
+
47
+ dispatch(tr);
48
+ return true;
49
+ },
50
+
51
+ removeAutocompleteHighlight: () => (state: EditorState, dispatch?: (tr: Transaction) => void): boolean => {
52
+ if (!dispatch) return false;
53
+
54
+ const tr = state.tr.setMeta(highlightDecorationKey, {
55
+ pos: 0,
56
+ type: "highlightDecoration",
57
+ remove: true
58
+ });
59
+
60
+ dispatch(tr);
61
+ return true;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * This plugin is used to highlight the current autocomplete suggestion.
67
+ * It allows to set a range and remove it.
68
+ */
69
+ export const highlightDecorationPlugin = (initialHighlight?: HighlightRange) => {
70
+ return new Plugin<AutocompleteHighlightState>({
71
+ key: highlightDecorationKey,
72
+ state: {
73
+ init: (_, { doc }) => {
74
+ const decorationSet = initialHighlight && doc ? buildDecorationSet(initialHighlight, doc) : DecorationSet.empty;
75
+ return {
76
+ decorationSet,
77
+ highlight: initialHighlight
78
+ };
79
+ },
80
+ apply(transaction, oldState) {
81
+ const action = transaction.getMeta(highlightDecorationKey);
82
+ const highlight = action?.range;
83
+ if (action?.type === "highlightDecoration") {
84
+
85
+ const doc = transaction.doc;
86
+ const { remove } = action;
87
+
88
+ if (remove) {
89
+ return {
90
+ decorationSet: DecorationSet.empty
91
+ };
92
+ }
93
+ const decorationSet = buildDecorationSet(highlight, doc);
94
+ return {
95
+ decorationSet: decorationSet,
96
+ highlight
97
+ }
98
+ } else {
99
+ return oldState
100
+ }
101
+ }
102
+ },
103
+ props: {
104
+ decorations(state) {
105
+ const autocompleteState = this.getState(state);
106
+ if (autocompleteState?.decorationSet) {
107
+ return autocompleteState.decorationSet
108
+ } else {
109
+ return DecorationSet.empty
110
+ }
111
+ }
112
+ }
113
+ });
114
+ };
@@ -0,0 +1,133 @@
1
+ import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
2
+ import { Plugin, PluginKey } from "prosemirror-state";
3
+ import { schema } from "../../schema";
4
+
5
+ export type UploadFn = (image: File) => Promise<string>;
6
+
7
+ export async function onFileRead(view: EditorView, readerEvent: ProgressEvent<FileReader>, pos: number, upload: UploadFn, image: File) {
8
+ // @ts-ignore
9
+ const plugin = view.state.plugins.find((p: Plugin) => p.key === ImagePluginKey.key);
10
+ if (!plugin) {
11
+ console.error("Image plugin not found");
12
+ return;
13
+ }
14
+ let decorationSet = plugin.getState(view.state);
15
+
16
+ const placeholder = document.createElement("div");
17
+ const imageElement = document.createElement("img");
18
+ // basic styling for loading state
19
+ imageElement.setAttribute("class", "opacity-40 rounded-lg border");
20
+ imageElement.src = readerEvent.target?.result as string;
21
+ placeholder.appendChild(imageElement);
22
+
23
+ const deco = Decoration.widget(pos, placeholder);
24
+ decorationSet = decorationSet?.add(view.state.doc, [deco]);
25
+ view.dispatch(view.state.tr.setMeta(plugin, { decorationSet }));
26
+
27
+ // Image Upload Logic
28
+ const src = await upload(image);
29
+ console.debug("Uploaded image", src);
30
+
31
+ // Replace placeholder with actual image
32
+ const imageNode = schema.nodes.image.create({ src });
33
+ const tr = view.state.tr.replaceWith(pos, pos, imageNode);
34
+
35
+ // Remove placeholder decoration
36
+ decorationSet = decorationSet?.remove([deco]);
37
+ tr.setMeta(plugin, { decorationSet });
38
+ view.dispatch(tr);
39
+ }
40
+
41
+ export const ImagePluginKey = new PluginKey("imagePlugin");
42
+
43
+ export const createDropImagePlugin = (upload: UploadFn): Plugin => {
44
+ const plugin: Plugin = new Plugin({
45
+ key: ImagePluginKey,
46
+ state: {
47
+ // Initialize the plugin state with an empty DecorationSet
48
+ init: () => DecorationSet.empty,
49
+ // Apply transactions to update the state
50
+ apply: (tr, old) => {
51
+ // Handle custom transaction steps that update decorations
52
+ const meta = tr.getMeta(plugin);
53
+ if (meta && meta.decorationSet) {
54
+ return meta.decorationSet;
55
+ }
56
+ // Map decorations to the new document structure
57
+ return old.map(tr.mapping, tr.doc);
58
+ }
59
+ },
60
+ props: {
61
+ handleDOMEvents: {
62
+ drop: (view, event) => {
63
+ if (!event.dataTransfer?.files || event.dataTransfer?.files.length === 0) {
64
+ return false;
65
+ }
66
+ event.preventDefault();
67
+
68
+ const files = Array.from(event.dataTransfer.files);
69
+ const images = files.filter(file => /image/i.test(file.type));
70
+
71
+ if (images.length === 0) {
72
+ console.log("No images found in dropped files");
73
+ return false;
74
+ }
75
+
76
+ images.forEach(image => {
77
+ const position = view.posAtCoords({
78
+ left: event.clientX,
79
+ top: event.clientY
80
+ });
81
+ if (!position) return;
82
+
83
+ const reader = new FileReader();
84
+ reader.onload = async (readerEvent) => {
85
+ await onFileRead(view, readerEvent, position.pos, upload, image);
86
+ };
87
+ reader.readAsDataURL(image);
88
+ });
89
+
90
+ return true;
91
+ }
92
+ },
93
+ handlePaste(view, event, slice) {
94
+ const items = Array.from(event.clipboardData?.items || []);
95
+ const pos = view.state.selection.from;
96
+ let anyImageFound = false;
97
+
98
+ items.forEach((item) => {
99
+ const image = item.getAsFile();
100
+ if (image && /image/i.test(item.type)) {
101
+ anyImageFound = true;
102
+ const reader = new FileReader();
103
+
104
+ reader.onload = async (readerEvent) => {
105
+ await onFileRead(view, readerEvent, pos, upload, image);
106
+ };
107
+ reader.readAsDataURL(image);
108
+ }
109
+ });
110
+
111
+ return anyImageFound;
112
+ },
113
+ decorations(state) {
114
+ return plugin.getState(state);
115
+ }
116
+ },
117
+ view(editorView) {
118
+ // This is needed to immediately apply the decoration updates
119
+ return {
120
+ update(view, prevState) {
121
+ const prevDecos = plugin.getState(prevState);
122
+ const newDecos = plugin.getState(view.state);
123
+
124
+ if (prevDecos !== newDecos) {
125
+ view.updateState(view.state);
126
+ }
127
+ }
128
+ };
129
+ }
130
+ });
131
+
132
+ return plugin;
133
+ };