@firecms/core 3.1.0-canary.1df3b2c → 3.1.0-canary.75005e4

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 (209) hide show
  1. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  2. package/dist/components/EntityCollectionView/CollectionDataErrorBanner.d.ts +4 -0
  3. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +5 -10
  4. package/dist/components/ErrorBoundary.d.ts +4 -2
  5. package/dist/components/HomePage/DefaultHomePage.d.ts +0 -1
  6. package/dist/components/LanguageToggle.d.ts +1 -0
  7. package/dist/components/UnsavedChangesDialog.d.ts +1 -0
  8. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +1 -1
  9. package/dist/components/index.d.ts +1 -0
  10. package/dist/core/DrawerNavigationGroup.d.ts +2 -2
  11. package/dist/editor/components/SlashCommandMenu.d.ts +6 -0
  12. package/dist/editor/components/editor-bubble-item.d.ts +8 -0
  13. package/dist/editor/components/editor-bubble.d.ts +8 -0
  14. package/dist/editor/components/index.d.ts +14 -0
  15. package/dist/editor/editor.d.ts +30 -0
  16. package/dist/editor/extensions/HighlightDecorationExtension.d.ts +24 -0
  17. package/dist/editor/extensions/Image/index.d.ts +6 -0
  18. package/dist/editor/extensions/Image.d.ts +6 -0
  19. package/dist/editor/extensions/TextLoadingDecorationExtension.d.ts +16 -0
  20. package/dist/editor/extensions/clipboard.d.ts +7 -0
  21. package/dist/editor/extensions/custom-keymap.d.ts +1 -0
  22. package/dist/editor/extensions/drag-and-drop.d.ts +9 -0
  23. package/dist/editor/hooks/useProseMirror.d.ts +14 -0
  24. package/dist/editor/hooks/useProseMirrorContext.d.ts +9 -0
  25. package/dist/editor/index.d.ts +2 -0
  26. package/dist/editor/markdown.d.ts +5 -0
  27. package/dist/editor/nodeViews/ImageComponent.d.ts +3 -0
  28. package/dist/editor/nodeViews/ReactNodeView.d.ts +29 -0
  29. package/dist/editor/nodeViews/TaskItemComponent.d.ts +3 -0
  30. package/dist/editor/nodeViews/index.d.ts +6 -0
  31. package/dist/editor/plugins/index.d.ts +2 -0
  32. package/dist/editor/plugins/inputrules.d.ts +6 -0
  33. package/dist/editor/plugins/placeholderPlugin.d.ts +3 -0
  34. package/dist/editor/plugins/slashCommandPlugin.d.ts +11 -0
  35. package/dist/editor/schema.d.ts +2 -0
  36. package/dist/editor/selectors/ai-selector.d.ts +0 -0
  37. package/dist/editor/selectors/color-selector.d.ts +10 -0
  38. package/dist/editor/selectors/link-selector.d.ts +8 -0
  39. package/dist/editor/selectors/node-selector.d.ts +15 -0
  40. package/dist/editor/selectors/text-buttons.d.ts +1 -0
  41. package/dist/editor/types.d.ts +5 -0
  42. package/dist/editor/useProseMirror.d.ts +16 -0
  43. package/dist/editor/utils/prosemirror-utils.d.ts +6 -0
  44. package/dist/editor/utils/remove_classes.d.ts +1 -0
  45. package/dist/editor/utils/useDebouncedCallback.d.ts +1 -0
  46. package/dist/form/components/ErrorFocus.d.ts +1 -1
  47. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  48. package/dist/hooks/index.d.ts +1 -0
  49. package/dist/hooks/useBuildNavigationController.d.ts +0 -1
  50. package/dist/hooks/useCollapsedGroups.d.ts +3 -3
  51. package/dist/hooks/useTranslation.d.ts +17 -0
  52. package/dist/i18n/FireCMSi18nProvider.d.ts +33 -0
  53. package/dist/index.d.ts +4 -0
  54. package/dist/index.es.js +11441 -2215
  55. package/dist/index.es.js.map +1 -1
  56. package/dist/index.umd.js +11423 -2216
  57. package/dist/index.umd.js.map +1 -1
  58. package/dist/internal/useRestoreScroll.d.ts +1 -1
  59. package/dist/locales/de.d.ts +2 -0
  60. package/dist/locales/en.d.ts +10 -0
  61. package/dist/locales/es.d.ts +10 -0
  62. package/dist/locales/fr.d.ts +2 -0
  63. package/dist/locales/hi.d.ts +2 -0
  64. package/dist/locales/it.d.ts +2 -0
  65. package/dist/locales/pt.d.ts +7 -0
  66. package/dist/types/analytics.d.ts +1 -1
  67. package/dist/types/collections.d.ts +8 -0
  68. package/dist/types/customization_controller.d.ts +2 -1
  69. package/dist/types/firecms.d.ts +2 -1
  70. package/dist/types/index.d.ts +1 -0
  71. package/dist/types/navigation.d.ts +2 -2
  72. package/dist/types/plugins.d.ts +23 -0
  73. package/dist/types/translations.d.ts +646 -0
  74. package/dist/util/entities.d.ts +1 -1
  75. package/dist/util/resolutions.d.ts +2 -2
  76. package/package.json +47 -13
  77. package/src/app/Scaffold.tsx +7 -5
  78. package/src/components/AIIcon.tsx +3 -1
  79. package/src/components/ArrayContainer.tsx +6 -4
  80. package/src/components/ClearFilterSortButton.tsx +6 -3
  81. package/src/components/ConfirmationDialog.tsx +4 -2
  82. package/src/components/DeleteEntityDialog.tsx +10 -7
  83. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +6 -3
  84. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -1
  85. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  86. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +3 -2
  87. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  88. package/src/components/EntityCollectionView/BoardSortableList.tsx +3 -1
  89. package/src/components/EntityCollectionView/CollectionDataErrorBanner.tsx +43 -0
  90. package/src/components/EntityCollectionView/EntityBoardCard.tsx +1 -1
  91. package/src/components/EntityCollectionView/EntityCard.tsx +4 -0
  92. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +39 -46
  93. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +17 -25
  94. package/src/components/EntityCollectionView/EntityCollectionView.tsx +73 -31
  95. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -3
  96. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +4 -2
  97. package/src/components/EntityCollectionView/FiltersDialog.tsx +8 -5
  98. package/src/components/EntityCollectionView/ViewModeToggle.tsx +37 -37
  99. package/src/components/EntityView.tsx +3 -2
  100. package/src/components/ErrorBoundary.tsx +27 -15
  101. package/src/components/HomePage/DefaultHomePage.tsx +19 -13
  102. package/src/components/HomePage/HomePageDnD.tsx +3 -1
  103. package/src/components/HomePage/NavigationGroup.tsx +3 -1
  104. package/src/components/HomePage/RenameGroupDialog.tsx +15 -13
  105. package/src/components/LanguageToggle.tsx +66 -0
  106. package/src/components/NotFoundPage.tsx +5 -3
  107. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +9 -7
  108. package/src/components/ReferenceWidget.tsx +3 -2
  109. package/src/components/SearchIconsView.tsx +3 -1
  110. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +11 -0
  111. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +15 -2
  112. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +11 -0
  113. package/src/components/UnsavedChangesDialog.tsx +6 -4
  114. package/src/components/VirtualTable/VirtualTable.performance.test.tsx +1 -0
  115. package/src/components/VirtualTable/VirtualTable.tsx +116 -113
  116. package/src/components/VirtualTable/VirtualTableHeader.tsx +54 -52
  117. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +1 -1
  118. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +3 -3
  119. package/src/components/common/default_entity_actions.tsx +4 -0
  120. package/src/components/common/useDataSourceTableController.tsx +12 -4
  121. package/src/components/index.tsx +1 -0
  122. package/src/core/DefaultAppBar.tsx +15 -11
  123. package/src/core/DefaultDrawer.tsx +8 -2
  124. package/src/core/DrawerNavigationGroup.tsx +5 -3
  125. package/src/core/EntityEditView.tsx +4 -3
  126. package/src/core/EntityEditViewFormActions.tsx +24 -17
  127. package/src/core/EntitySidePanel.tsx +32 -29
  128. package/src/core/FireCMS.tsx +33 -6
  129. package/src/core/field_configs.tsx +14 -9
  130. package/src/editor/components/SlashCommandMenu.tsx +348 -0
  131. package/src/editor/components/editor-bubble-item.tsx +32 -0
  132. package/src/editor/components/editor-bubble.tsx +118 -0
  133. package/src/editor/components/index.ts +12 -0
  134. package/src/editor/editor.tsx +307 -0
  135. package/src/editor/extensions/HighlightDecorationExtension.ts +114 -0
  136. package/src/editor/extensions/Image/index.ts +133 -0
  137. package/src/editor/extensions/Image.ts +144 -0
  138. package/src/editor/extensions/TextLoadingDecorationExtension.tsx +107 -0
  139. package/src/editor/extensions/clipboard.ts +72 -0
  140. package/src/editor/extensions/custom-keymap.ts +24 -0
  141. package/src/editor/extensions/drag-and-drop.tsx +472 -0
  142. package/src/editor/hooks/useProseMirror.ts +115 -0
  143. package/src/editor/hooks/useProseMirrorContext.ts +15 -0
  144. package/src/editor/index.ts +2 -0
  145. package/src/editor/markdown.ts +110 -0
  146. package/src/editor/nodeViews/ImageComponent.tsx +20 -0
  147. package/src/editor/nodeViews/ReactNodeView.tsx +89 -0
  148. package/src/editor/nodeViews/TaskItemComponent.tsx +29 -0
  149. package/src/editor/nodeViews/index.ts +35 -0
  150. package/src/editor/plugins/index.ts +55 -0
  151. package/src/editor/plugins/inputrules.ts +82 -0
  152. package/src/editor/plugins/placeholderPlugin.ts +55 -0
  153. package/src/editor/plugins/slashCommandPlugin.ts +49 -0
  154. package/src/editor/schema.ts +228 -0
  155. package/src/editor/selectors/ai-selector.tsx +111 -0
  156. package/src/editor/selectors/color-selector.tsx +200 -0
  157. package/src/editor/selectors/link-selector.tsx +118 -0
  158. package/src/editor/selectors/node-selector.tsx +157 -0
  159. package/src/editor/selectors/text-buttons.tsx +86 -0
  160. package/src/editor/types.ts +6 -0
  161. package/src/editor/useProseMirror.ts +126 -0
  162. package/src/editor/utils/prosemirror-utils.ts +78 -0
  163. package/src/editor/utils/remove_classes.ts +17 -0
  164. package/src/editor/utils/useDebouncedCallback.ts +25 -0
  165. package/src/form/EntityForm.tsx +76 -63
  166. package/src/form/EntityFormActions.tsx +19 -12
  167. package/src/form/PropertyFieldBinding.tsx +6 -5
  168. package/src/form/components/ErrorFocus.tsx +3 -3
  169. package/src/form/components/LocalChangesMenu.tsx +13 -13
  170. package/src/form/components/StorageItemPreview.tsx +3 -2
  171. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -4
  172. package/src/form/field_bindings/BlockFieldBinding.tsx +5 -2
  173. package/src/form/field_bindings/KeyValueFieldBinding.tsx +23 -18
  174. package/src/form/field_bindings/MapFieldBinding.tsx +4 -3
  175. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +4 -4
  176. package/src/form/field_bindings/RepeatFieldBinding.tsx +3 -1
  177. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +87 -85
  178. package/src/hooks/index.tsx +1 -0
  179. package/src/hooks/useBuildNavigationController.tsx +49 -22
  180. package/src/hooks/useCollapsedGroups.ts +7 -6
  181. package/src/hooks/useTranslation.ts +31 -0
  182. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  183. package/src/i18n/FireCMSi18nProvider.tsx +160 -0
  184. package/src/index.ts +4 -0
  185. package/src/internal/useBuildDataSource.ts +1 -2
  186. package/src/internal/useBuildSideEntityController.tsx +22 -20
  187. package/src/locales/de.ts +691 -0
  188. package/src/locales/en.ts +703 -0
  189. package/src/locales/es.ts +703 -0
  190. package/src/locales/fr.ts +691 -0
  191. package/src/locales/hi.ts +691 -0
  192. package/src/locales/it.ts +691 -0
  193. package/src/locales/pt.ts +700 -0
  194. package/src/preview/PropertyPreview.tsx +1 -0
  195. package/src/preview/components/UrlComponentPreview.tsx +4 -2
  196. package/src/preview/components/UserPreview.tsx +3 -1
  197. package/src/types/analytics.ts +10 -0
  198. package/src/types/collections.ts +9 -0
  199. package/src/types/customization_controller.tsx +2 -1
  200. package/src/types/firecms.tsx +2 -1
  201. package/src/types/index.ts +1 -0
  202. package/src/types/navigation.ts +2 -2
  203. package/src/types/plugins.tsx +26 -0
  204. package/src/types/translations.ts +725 -0
  205. package/src/util/entities.ts +1 -1
  206. package/src/util/join_collections.ts +10 -8
  207. package/src/util/previews.ts +2 -2
  208. package/src/util/property_utils.tsx +1 -1
  209. package/src/util/resolutions.ts +5 -3
@@ -0,0 +1,144 @@
1
+ import { cls, defaultBorderMixin } from "@firecms/ui";
2
+ import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
3
+ import { Plugin, PluginKey } from "prosemirror-state";
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
+
9
+ const { schema } = view.state;
10
+
11
+ // @ts-ignore
12
+ const plugin = view.state.plugins.find((p: Plugin) => p.key === ImagePluginKey.key);
13
+ if (!plugin) {
14
+ console.error("Image plugin not found");
15
+ return;
16
+ }
17
+ let decorationSet = plugin.getState(view.state);
18
+
19
+ const placeholder = document.createElement("div");
20
+ const imageElement = document.createElement("img");
21
+ imageElement.setAttribute("class", "opacity-40 rounded-lg border " + defaultBorderMixin);
22
+ imageElement.src = readerEvent.target?.result as string;
23
+ placeholder.appendChild(imageElement);
24
+
25
+ const deco = Decoration.widget(pos, placeholder);
26
+ decorationSet = decorationSet?.add(view.state.doc, [deco]);
27
+ view.dispatch(view.state.tr.setMeta(plugin, { decorationSet }));
28
+
29
+ // Image Upload Logic
30
+ const src = await upload(image);
31
+ console.debug("Uploaded image", src);
32
+
33
+ // Replace placeholder with actual image
34
+ const imageNode = schema.nodes.image.create({ src });
35
+ const tr = view.state.tr.replaceWith(pos, pos, imageNode);
36
+
37
+ // Remove placeholder decoration
38
+ decorationSet = decorationSet?.remove([deco]);
39
+ tr.setMeta(plugin, { decorationSet });
40
+ view.dispatch(tr);
41
+ }
42
+
43
+ export const ImagePluginKey = new PluginKey("imagePlugin");
44
+
45
+ export const createDropImagePlugin = (upload: UploadFn): Plugin => {
46
+ const plugin: Plugin = new Plugin({
47
+ key: ImagePluginKey,
48
+ state: {
49
+ // Initialize the plugin state with an empty DecorationSet
50
+ init: () => DecorationSet.empty,
51
+ // Apply transactions to update the state
52
+ apply: (tr, old) => {
53
+ // Handle custom transaction steps that update decorations
54
+ const meta = tr.getMeta(plugin);
55
+ if (meta && meta.decorationSet) {
56
+ return meta.decorationSet;
57
+ }
58
+ // Map decorations to the new document structure
59
+ return old.map(tr.mapping, tr.doc);
60
+ }
61
+ },
62
+ props: {
63
+ handleDOMEvents: {
64
+ dragover: (view: EditorView, event: DragEvent) => {
65
+ if (event.dataTransfer?.types?.includes("Files")) {
66
+ event.preventDefault();
67
+ return true;
68
+ }
69
+ return false;
70
+ },
71
+ drop: (view: EditorView, event: DragEvent) => {
72
+ if (!event.dataTransfer?.files || event.dataTransfer?.files.length === 0) {
73
+ return false;
74
+ }
75
+ event.preventDefault();
76
+
77
+ const files = Array.from(event.dataTransfer.files);
78
+ const images = files.filter(file => /image/i.test(file.type));
79
+
80
+ if (images.length === 0) {
81
+ console.log("No images found in dropped files");
82
+ return false;
83
+ }
84
+
85
+ images.forEach(image => {
86
+ const position = view.posAtCoords({
87
+ left: event.clientX,
88
+ top: event.clientY
89
+ });
90
+ if (!position) return;
91
+
92
+ const reader = new FileReader();
93
+ reader.onload = async (readerEvent) => {
94
+ await onFileRead(view as any, readerEvent, position.pos, upload, image);
95
+ };
96
+ reader.readAsDataURL(image);
97
+ });
98
+
99
+ return true;
100
+ }
101
+ },
102
+ handlePaste(view: EditorView, event: ClipboardEvent, slice: any) {
103
+ const items = Array.from(event.clipboardData?.items || []);
104
+ const pos = view.state.selection.from;
105
+ let anyImageFound = false;
106
+
107
+ items
108
+ .filter((item) => item.type.startsWith("image/"))
109
+ .forEach((item) => {
110
+ const image = item.getAsFile();
111
+ if (image) {
112
+ anyImageFound = true;
113
+ const reader = new FileReader();
114
+ reader.onload = async (readerEvent) => {
115
+ await onFileRead(view as any, readerEvent, pos, upload, image);
116
+ };
117
+ reader.readAsDataURL(image);
118
+ }
119
+ });
120
+
121
+ return anyImageFound;
122
+ },
123
+ decorations(state) {
124
+ return plugin.getState(state);
125
+ }
126
+ },
127
+ view(editorView) {
128
+ return {
129
+ update(view, prevState) {
130
+ const prevDecos = plugin.getState(prevState);
131
+ const newDecos = plugin.getState(view.state);
132
+
133
+ if (prevDecos !== newDecos) {
134
+ view.updateState(view.state);
135
+ }
136
+ }
137
+ };
138
+ }
139
+ });
140
+
141
+ return plugin;
142
+ };
143
+
144
+
@@ -0,0 +1,107 @@
1
+ import { Plugin, PluginKey, Transaction, EditorState } from "prosemirror-state";
2
+ import { Decoration, DecorationSet } from "prosemirror-view";
3
+
4
+ // Define and export the plugin key
5
+ export const loadingDecorationKey = new PluginKey<LoadingDecorationState>("loadingDecoration");
6
+
7
+ interface LoadingDecorationState {
8
+ decorationSet: DecorationSet;
9
+ hasDecoration: boolean;
10
+ }
11
+
12
+ export const textLoadingCommands = {
13
+ toggleLoadingDecoration: (state: EditorState, dispatch: ((tr: Transaction) => void) | undefined, loadingHtml?: string): boolean => {
14
+ const { selection } = state;
15
+ const pos = selection.from;
16
+
17
+ if (!dispatch) return false;
18
+
19
+ const tr = state.tr.setMeta(loadingDecorationKey, {
20
+ pos,
21
+ type: "loadingDecoration",
22
+ remove: false,
23
+ loadingHtml
24
+ });
25
+
26
+ dispatch(tr);
27
+ return true;
28
+ },
29
+
30
+ removeLoadingDecoration: (state: EditorState, dispatch: ((tr: Transaction) => void) | undefined): boolean => {
31
+ if (!dispatch) return false;
32
+
33
+ const tr = state.tr.setMeta(loadingDecorationKey, {
34
+ pos: 0, // We can pass any position as it will remove the entire decoration set
35
+ type: "loadingDecoration",
36
+ remove: true
37
+ });
38
+
39
+ dispatch(tr);
40
+ return true;
41
+ }
42
+ };
43
+
44
+ /**
45
+ * This plugin is used to display streaming content from an LLM.
46
+ */
47
+ export const textLoadingDecorationPlugin = () => {
48
+ return new Plugin<LoadingDecorationState>({
49
+ key: loadingDecorationKey,
50
+
51
+ state: {
52
+ init() {
53
+ return {
54
+ decorationSet: DecorationSet.empty,
55
+ hasDecoration: false
56
+ };
57
+ },
58
+
59
+ apply(tr, oldState) {
60
+ const action = tr.getMeta(loadingDecorationKey);
61
+
62
+ if (action?.type === "loadingDecoration") {
63
+ const { pos, remove, loadingHtml } = action;
64
+
65
+ if (remove) {
66
+ return {
67
+ decorationSet: DecorationSet.empty,
68
+ hasDecoration: false
69
+ };
70
+ }
71
+
72
+ const decoration = Decoration.widget(pos, () => {
73
+ const container = document.createElement("span");
74
+ container.className = "loading-decoration";
75
+
76
+ // Sanitize and append HTML
77
+ if (loadingHtml) {
78
+ container.innerHTML = loadingHtml;
79
+ } else {
80
+ const span = document.createElement("span");
81
+ span.innerText = "loading...";
82
+ container.appendChild(span);
83
+ }
84
+
85
+ return container;
86
+ });
87
+
88
+ return {
89
+ decorationSet: DecorationSet.empty.add(tr.doc, [decoration]),
90
+ hasDecoration: true
91
+ };
92
+ }
93
+
94
+ return {
95
+ decorationSet: oldState.decorationSet.map(tr.mapping, tr.doc),
96
+ hasDecoration: oldState.hasDecoration
97
+ };
98
+ }
99
+ },
100
+
101
+ props: {
102
+ decorations(state) {
103
+ return this.getState(state)?.decorationSet || DecorationSet.empty;
104
+ }
105
+ }
106
+ });
107
+ };
@@ -0,0 +1,72 @@
1
+ import { DOMSerializer, Slice } from "prosemirror-model"
2
+ import { EditorView } from "prosemirror-view";
3
+
4
+ export function serializeForClipboard(view: EditorView, slice: Slice) {
5
+ view.someProp("transformCopied", f => {
6
+ slice = f(slice!, view)
7
+ })
8
+
9
+ const context = [];
10
+ let {
11
+ content,
12
+ openStart,
13
+ openEnd
14
+ } = slice
15
+ while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild!.childCount == 1) {
16
+ openStart--
17
+ openEnd--
18
+ const node = content.firstChild!
19
+ // @ts-ignore
20
+ context.push(node.type.name, node.attrs != node.type.defaultAttrs ? node.attrs : null)
21
+ content = node.content
22
+ }
23
+
24
+ const serializer = view.someProp("clipboardSerializer") || DOMSerializer.fromSchema(view.state.schema)
25
+ const doc = detachedDoc(), wrap = doc.createElement("div")
26
+ wrap.appendChild(serializer.serializeFragment(content, { document: doc }))
27
+
28
+ let firstChild = wrap.firstChild, needsWrap, wrappers = 0
29
+ while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
30
+ for (let i = needsWrap.length - 1; i >= 0; i--) {
31
+ const wrapper = doc.createElement(needsWrap[i])
32
+ while (wrap.firstChild) wrapper.appendChild(wrap.firstChild)
33
+ wrap.appendChild(wrapper)
34
+ wrappers++
35
+ }
36
+ firstChild = wrap.firstChild
37
+ }
38
+
39
+ if (firstChild && firstChild.nodeType == 1)
40
+ (firstChild as HTMLElement).setAttribute(
41
+ "data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`)
42
+
43
+ const text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
44
+ slice.content.textBetween(0, slice.content.size, "\n\n")
45
+
46
+ return {
47
+ dom: wrap,
48
+ text,
49
+ slice
50
+ }
51
+ }
52
+
53
+ // Trick from jQuery -- some elements must be wrapped in other
54
+ // elements for innerHTML to work. I.e. if you do `div.innerHTML =
55
+ // "<td>..</td>"` the table cells are ignored.
56
+ const wrapMap: { [node: string]: string[] } = {
57
+ thead: ["table"],
58
+ tbody: ["table"],
59
+ tfoot: ["table"],
60
+ caption: ["table"],
61
+ colgroup: ["table"],
62
+ col: ["table", "colgroup"],
63
+ tr: ["table", "tbody"],
64
+ td: ["table", "tbody", "tr"],
65
+ th: ["table", "tbody", "tr"]
66
+ }
67
+
68
+ let _detachedDoc: Document | null = null
69
+
70
+ function detachedDoc() {
71
+ return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
72
+ }
@@ -0,0 +1,24 @@
1
+ import { keymap } from "prosemirror-keymap";
2
+
3
+ export const customKeymapPlugin = () => {
4
+ return keymap({
5
+ "Mod-a": (state, dispatch) => {
6
+ const { tr } = state;
7
+ const startSelectionPos = tr.selection.from;
8
+ const endSelectionPos = tr.selection.to;
9
+ const startNodePos = tr.selection.$from.start();
10
+ const endNodePos = tr.selection.$to.end();
11
+
12
+ const isCurrentTextSelectionNotExtendedToNodeBoundaries =
13
+ startSelectionPos > startNodePos || endSelectionPos < endNodePos;
14
+
15
+ if (isCurrentTextSelectionNotExtendedToNodeBoundaries) {
16
+ if (dispatch) {
17
+ dispatch(tr.setSelection((state.selection.constructor as any).create(state.doc, startNodePos, endNodePos)));
18
+ }
19
+ return true;
20
+ }
21
+ return false;
22
+ },
23
+ });
24
+ };