@stesura/react-prosemirror 3.2.11-stesura.1

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 (296) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +939 -0
  3. package/dist/cjs/AbstractEditorView.js +4 -0
  4. package/dist/cjs/ReactEditorView.js +194 -0
  5. package/dist/cjs/StaticEditorView.js +89 -0
  6. package/dist/cjs/browser.js +53 -0
  7. package/dist/cjs/commands/reorderSiblings.js +72 -0
  8. package/dist/cjs/components/ChildNodeViews.js +418 -0
  9. package/dist/cjs/components/CursorWrapper.js +84 -0
  10. package/dist/cjs/components/EditorStateSelectorsProvider.js +90 -0
  11. package/dist/cjs/components/LayoutGroup.js +112 -0
  12. package/dist/cjs/components/NativeWidgetView.js +108 -0
  13. package/dist/cjs/components/OutputSpec.js +121 -0
  14. package/dist/cjs/components/ProseMirror.js +146 -0
  15. package/dist/cjs/components/ProseMirrorDoc.js +74 -0
  16. package/dist/cjs/components/SeparatorHackView.js +99 -0
  17. package/dist/cjs/components/TextNodeView.js +113 -0
  18. package/dist/cjs/components/TrailingHackView.js +87 -0
  19. package/dist/cjs/components/WidgetView.js +94 -0
  20. package/dist/cjs/components/WidgetViewComponentProps.js +4 -0
  21. package/dist/cjs/components/marks/DefaultMarkView.js +70 -0
  22. package/dist/cjs/components/marks/MarkView.js +85 -0
  23. package/dist/cjs/components/marks/MarkViewComponentProps.js +4 -0
  24. package/dist/cjs/components/marks/MarkViewConstructorView.js +116 -0
  25. package/dist/cjs/components/marks/ReactMarkView.js +109 -0
  26. package/dist/cjs/components/nodes/DefaultNodeView.js +68 -0
  27. package/dist/cjs/components/nodes/DocNodeView.js +97 -0
  28. package/dist/cjs/components/nodes/NodeView.js +129 -0
  29. package/dist/cjs/components/nodes/NodeViewComponentProps.js +4 -0
  30. package/dist/cjs/components/nodes/NodeViewConstructorView.js +145 -0
  31. package/dist/cjs/components/nodes/ReactNodeView.js +189 -0
  32. package/dist/cjs/constants.js +33 -0
  33. package/dist/cjs/contexts/ChildDescriptionsContext.js +19 -0
  34. package/dist/cjs/contexts/EditorContext.js +12 -0
  35. package/dist/cjs/contexts/EditorStateContext.js +12 -0
  36. package/dist/cjs/contexts/EditorStateStoreContext.js +45 -0
  37. package/dist/cjs/contexts/IgnoreMutationContext.js +12 -0
  38. package/dist/cjs/contexts/LayoutGroupContext.js +12 -0
  39. package/dist/cjs/contexts/NodeViewContext.js +12 -0
  40. package/dist/cjs/contexts/RenderStoreContext.js +54 -0
  41. package/dist/cjs/contexts/SelectNodeContext.js +12 -0
  42. package/dist/cjs/contexts/StopEventContext.js +12 -0
  43. package/dist/cjs/decorations/ReactWidgetType.js +58 -0
  44. package/dist/cjs/decorations/computeDocDeco.js +44 -0
  45. package/dist/cjs/decorations/internalTypes.js +4 -0
  46. package/dist/cjs/decorations/iterDeco.js +91 -0
  47. package/dist/cjs/decorations/viewDecorations.js +155 -0
  48. package/dist/cjs/dom.js +147 -0
  49. package/dist/cjs/findDOMNode.js +46 -0
  50. package/dist/cjs/hooks/useClientLayoutEffect.js +19 -0
  51. package/dist/cjs/hooks/useComponentEventListeners.js +72 -0
  52. package/dist/cjs/hooks/useEditor.js +130 -0
  53. package/dist/cjs/hooks/useEditorEffect.js +39 -0
  54. package/dist/cjs/hooks/useEditorEventCallback.js +38 -0
  55. package/dist/cjs/hooks/useEditorEventListener.js +34 -0
  56. package/dist/cjs/hooks/useEditorState.js +18 -0
  57. package/dist/cjs/hooks/useEditorStateSelector.js +17 -0
  58. package/dist/cjs/hooks/useEffectEvent.js +34 -0
  59. package/dist/cjs/hooks/useForceUpdate.js +15 -0
  60. package/dist/cjs/hooks/useIgnoreMutation.js +24 -0
  61. package/dist/cjs/hooks/useIsComposingIn.js +25 -0
  62. package/dist/cjs/hooks/useIsEditorStatic.js +15 -0
  63. package/dist/cjs/hooks/useIsNodeSelected.js +21 -0
  64. package/dist/cjs/hooks/useLayoutGroupEffect.js +20 -0
  65. package/dist/cjs/hooks/useMarkViewDescription.js +134 -0
  66. package/dist/cjs/hooks/useNodePos.js +18 -0
  67. package/dist/cjs/hooks/useNodeViewDescription.js +154 -0
  68. package/dist/cjs/hooks/useReactKeys.js +17 -0
  69. package/dist/cjs/hooks/useSelectNode.js +30 -0
  70. package/dist/cjs/hooks/useSetDom.js +57 -0
  71. package/dist/cjs/hooks/useStopEvent.js +24 -0
  72. package/dist/cjs/index.js +85 -0
  73. package/dist/cjs/package.json +3 -0
  74. package/dist/cjs/plugins/beforeInputPlugin.js +356 -0
  75. package/dist/cjs/plugins/reactKeys.js +121 -0
  76. package/dist/cjs/props.js +283 -0
  77. package/dist/cjs/refs.js +28 -0
  78. package/dist/cjs/testing/editorViewTestHelpers.js +109 -0
  79. package/dist/cjs/testing/setupProseMirrorView.js +94 -0
  80. package/dist/cjs/tiptap/ReactProseMirrorNodeView.js +26 -0
  81. package/dist/cjs/tiptap/TiptapEditor.js +34 -0
  82. package/dist/cjs/tiptap/TiptapEditorContent.js +143 -0
  83. package/dist/cjs/tiptap/TiptapEditorView.js +130 -0
  84. package/dist/cjs/tiptap/contexts/TiptapEditorContext.js +12 -0
  85. package/dist/cjs/tiptap/extensions/ReactProseMirror.js +40 -0
  86. package/dist/cjs/tiptap/extensions/ReactProseMirrorCommands.js +21 -0
  87. package/dist/cjs/tiptap/extensions/commands/updateAttributes.js +104 -0
  88. package/dist/cjs/tiptap/hooks/useEditor.js +318 -0
  89. package/dist/cjs/tiptap/hooks/useIsInReactProseMirror.js +15 -0
  90. package/dist/cjs/tiptap/hooks/useTiptapEditor.js +35 -0
  91. package/dist/cjs/tiptap/hooks/useTiptapEditorEffect.js +35 -0
  92. package/dist/cjs/tiptap/hooks/useTiptapEditorEventCallback.js +35 -0
  93. package/dist/cjs/tiptap/index.js +48 -0
  94. package/dist/cjs/tiptap/tiptapNodeView.js +245 -0
  95. package/dist/cjs/viewdesc.js +862 -0
  96. package/dist/esm/AbstractEditorView.js +1 -0
  97. package/dist/esm/ReactEditorView.js +194 -0
  98. package/dist/esm/StaticEditorView.js +79 -0
  99. package/dist/esm/browser.js +43 -0
  100. package/dist/esm/commands/reorderSiblings.js +63 -0
  101. package/dist/esm/components/ChildNodeViews.js +359 -0
  102. package/dist/esm/components/CursorWrapper.js +33 -0
  103. package/dist/esm/components/EditorStateSelectorsProvider.js +31 -0
  104. package/dist/esm/components/LayoutGroup.js +67 -0
  105. package/dist/esm/components/NativeWidgetView.js +57 -0
  106. package/dist/esm/components/OutputSpec.js +71 -0
  107. package/dist/esm/components/ProseMirror.js +95 -0
  108. package/dist/esm/components/ProseMirrorDoc.js +15 -0
  109. package/dist/esm/components/SeparatorHackView.js +48 -0
  110. package/dist/esm/components/TextNodeView.js +103 -0
  111. package/dist/esm/components/TrailingHackView.js +36 -0
  112. package/dist/esm/components/WidgetView.js +43 -0
  113. package/dist/esm/components/WidgetViewComponentProps.js +1 -0
  114. package/dist/esm/components/marks/DefaultMarkView.js +19 -0
  115. package/dist/esm/components/marks/MarkView.js +34 -0
  116. package/dist/esm/components/marks/MarkViewComponentProps.js +1 -0
  117. package/dist/esm/components/marks/MarkViewConstructorView.js +65 -0
  118. package/dist/esm/components/marks/ReactMarkView.js +58 -0
  119. package/dist/esm/components/nodes/DefaultNodeView.js +17 -0
  120. package/dist/esm/components/nodes/DocNodeView.js +46 -0
  121. package/dist/esm/components/nodes/NodeView.js +67 -0
  122. package/dist/esm/components/nodes/NodeViewComponentProps.js +1 -0
  123. package/dist/esm/components/nodes/NodeViewConstructorView.js +94 -0
  124. package/dist/esm/components/nodes/ReactNodeView.js +138 -0
  125. package/dist/esm/constants.js +15 -0
  126. package/dist/esm/contexts/ChildDescriptionsContext.js +9 -0
  127. package/dist/esm/contexts/EditorContext.js +7 -0
  128. package/dist/esm/contexts/EditorStateContext.js +2 -0
  129. package/dist/esm/contexts/EditorStateStoreContext.js +27 -0
  130. package/dist/esm/contexts/IgnoreMutationContext.js +2 -0
  131. package/dist/esm/contexts/LayoutGroupContext.js +2 -0
  132. package/dist/esm/contexts/NodeViewContext.js +2 -0
  133. package/dist/esm/contexts/RenderStoreContext.js +33 -0
  134. package/dist/esm/contexts/SelectNodeContext.js +2 -0
  135. package/dist/esm/contexts/StopEventContext.js +2 -0
  136. package/dist/esm/decorations/ReactWidgetType.js +40 -0
  137. package/dist/esm/decorations/computeDocDeco.js +44 -0
  138. package/dist/esm/decorations/internalTypes.js +1 -0
  139. package/dist/esm/decorations/iterDeco.js +85 -0
  140. package/dist/esm/decorations/viewDecorations.js +155 -0
  141. package/dist/esm/dom.js +110 -0
  142. package/dist/esm/findDOMNode.js +31 -0
  143. package/dist/esm/hooks/useClientLayoutEffect.js +9 -0
  144. package/dist/esm/hooks/useComponentEventListeners.js +87 -0
  145. package/dist/esm/hooks/useEditor.js +128 -0
  146. package/dist/esm/hooks/useEditorEffect.js +46 -0
  147. package/dist/esm/hooks/useEditorEventCallback.js +38 -0
  148. package/dist/esm/hooks/useEditorEventListener.js +28 -0
  149. package/dist/esm/hooks/useEditorState.js +10 -0
  150. package/dist/esm/hooks/useEditorStateSelector.js +14 -0
  151. package/dist/esm/hooks/useEffectEvent.js +24 -0
  152. package/dist/esm/hooks/useForceUpdate.js +8 -0
  153. package/dist/esm/hooks/useIgnoreMutation.js +14 -0
  154. package/dist/esm/hooks/useIsComposingIn.js +17 -0
  155. package/dist/esm/hooks/useIsEditorStatic.js +8 -0
  156. package/dist/esm/hooks/useIsNodeSelected.js +11 -0
  157. package/dist/esm/hooks/useLayoutGroupEffect.js +10 -0
  158. package/dist/esm/hooks/useMarkViewDescription.js +124 -0
  159. package/dist/esm/hooks/useNodePos.js +15 -0
  160. package/dist/esm/hooks/useNodeViewDescription.js +144 -0
  161. package/dist/esm/hooks/useReactKeys.js +7 -0
  162. package/dist/esm/hooks/useSelectNode.js +20 -0
  163. package/dist/esm/hooks/useSetDom.js +47 -0
  164. package/dist/esm/hooks/useStopEvent.js +14 -0
  165. package/dist/esm/index.js +19 -0
  166. package/dist/esm/plugins/beforeInputPlugin.js +346 -0
  167. package/dist/esm/plugins/reactKeys.js +106 -0
  168. package/dist/esm/props.js +267 -0
  169. package/dist/esm/refs.js +18 -0
  170. package/dist/esm/testing/editorViewTestHelpers.js +86 -0
  171. package/dist/esm/testing/setupProseMirrorView.js +76 -0
  172. package/dist/esm/tiptap/ReactProseMirrorNodeView.js +22 -0
  173. package/dist/esm/tiptap/TiptapEditor.js +24 -0
  174. package/dist/esm/tiptap/TiptapEditorContent.js +99 -0
  175. package/dist/esm/tiptap/TiptapEditorView.js +76 -0
  176. package/dist/esm/tiptap/contexts/TiptapEditorContext.js +2 -0
  177. package/dist/esm/tiptap/extensions/ReactProseMirror.js +30 -0
  178. package/dist/esm/tiptap/extensions/ReactProseMirrorCommands.js +11 -0
  179. package/dist/esm/tiptap/extensions/commands/updateAttributes.js +96 -0
  180. package/dist/esm/tiptap/hooks/useEditor.js +308 -0
  181. package/dist/esm/tiptap/hooks/useIsInReactProseMirror.js +9 -0
  182. package/dist/esm/tiptap/hooks/useTiptapEditor.js +31 -0
  183. package/dist/esm/tiptap/hooks/useTiptapEditorEffect.js +42 -0
  184. package/dist/esm/tiptap/hooks/useTiptapEditorEventCallback.js +35 -0
  185. package/dist/esm/tiptap/index.js +9 -0
  186. package/dist/esm/tiptap/tiptapNodeView.js +211 -0
  187. package/dist/esm/viewdesc.js +844 -0
  188. package/dist/tsconfig.tsbuildinfo +1 -0
  189. package/dist/types/AbstractEditorView.d.ts +28 -0
  190. package/dist/types/ReactEditorView.d.ts +102 -0
  191. package/dist/types/StaticEditorView.d.ts +26 -0
  192. package/dist/types/__tests__/viewdesc.test.d.ts +1 -0
  193. package/dist/types/browser.d.ts +15 -0
  194. package/dist/types/commands/__tests__/reorderSiblings.test.d.ts +1 -0
  195. package/dist/types/commands/reorderSiblings.d.ts +14 -0
  196. package/dist/types/components/ChildNodeViews.d.ts +9 -0
  197. package/dist/types/components/CursorWrapper.d.ts +3 -0
  198. package/dist/types/components/EditorStateSelectorsProvider.d.ts +10 -0
  199. package/dist/types/components/LayoutGroup.d.ts +12 -0
  200. package/dist/types/components/NativeWidgetView.d.ts +8 -0
  201. package/dist/types/components/OutputSpec.d.ts +10 -0
  202. package/dist/types/components/ProseMirror.d.ts +14 -0
  203. package/dist/types/components/ProseMirrorDoc.d.ts +16 -0
  204. package/dist/types/components/SeparatorHackView.d.ts +6 -0
  205. package/dist/types/components/TextNodeView.d.ts +27 -0
  206. package/dist/types/components/TrailingHackView.d.ts +6 -0
  207. package/dist/types/components/WidgetView.d.ts +8 -0
  208. package/dist/types/components/WidgetViewComponentProps.d.ts +7 -0
  209. package/dist/types/components/__tests__/ProseMirror.composition.test.d.ts +17 -0
  210. package/dist/types/components/__tests__/ProseMirror.domchange.test.d.ts +1 -0
  211. package/dist/types/components/__tests__/ProseMirror.draw-decoration.test.d.ts +1 -0
  212. package/dist/types/components/__tests__/ProseMirror.draw.test.d.ts +1 -0
  213. package/dist/types/components/__tests__/ProseMirror.memory-leak.test.d.ts +6 -0
  214. package/dist/types/components/__tests__/ProseMirror.mobile.test.d.ts +1 -0
  215. package/dist/types/components/__tests__/ProseMirror.node-view.test.d.ts +1 -0
  216. package/dist/types/components/__tests__/ProseMirror.selection.test.d.ts +1 -0
  217. package/dist/types/components/__tests__/ProseMirror.test.d.ts +1 -0
  218. package/dist/types/components/__tests__/stableContexts.test.d.ts +10 -0
  219. package/dist/types/components/marks/DefaultMarkView.d.ts +3 -0
  220. package/dist/types/components/marks/MarkView.d.ts +10 -0
  221. package/dist/types/components/marks/MarkViewComponentProps.d.ts +11 -0
  222. package/dist/types/components/marks/MarkViewConstructorView.d.ts +12 -0
  223. package/dist/types/components/marks/ReactMarkView.d.ts +12 -0
  224. package/dist/types/components/nodes/DefaultNodeView.d.ts +3 -0
  225. package/dist/types/components/nodes/DocNodeView.d.ts +12 -0
  226. package/dist/types/components/nodes/NodeView.d.ts +14 -0
  227. package/dist/types/components/nodes/NodeViewComponentProps.d.ts +13 -0
  228. package/dist/types/components/nodes/NodeViewConstructorView.d.ts +12 -0
  229. package/dist/types/components/nodes/ReactNodeView.d.ts +13 -0
  230. package/dist/types/constants.d.ts +4 -0
  231. package/dist/types/contexts/ChildDescriptionsContext.d.ts +7 -0
  232. package/dist/types/contexts/EditorContext.d.ts +18 -0
  233. package/dist/types/contexts/EditorStateContext.d.ts +2 -0
  234. package/dist/types/contexts/EditorStateStoreContext.d.ts +9 -0
  235. package/dist/types/contexts/IgnoreMutationContext.d.ts +5 -0
  236. package/dist/types/contexts/LayoutGroupContext.d.ts +5 -0
  237. package/dist/types/contexts/NodeViewContext.d.ts +9 -0
  238. package/dist/types/contexts/RenderStoreContext.d.ts +24 -0
  239. package/dist/types/contexts/SelectNodeContext.d.ts +5 -0
  240. package/dist/types/contexts/StopEventContext.d.ts +5 -0
  241. package/dist/types/contexts/__tests__/DeferredLayoutEffects.test.d.ts +1 -0
  242. package/dist/types/decorations/ReactWidgetType.d.ts +40 -0
  243. package/dist/types/decorations/computeDocDeco.d.ts +14 -0
  244. package/dist/types/decorations/internalTypes.d.ts +20 -0
  245. package/dist/types/decorations/iterDeco.d.ts +3 -0
  246. package/dist/types/decorations/viewDecorations.d.ts +14 -0
  247. package/dist/types/dom.d.ts +22 -0
  248. package/dist/types/findDOMNode.d.ts +3 -0
  249. package/dist/types/hooks/__tests__/useEditorEffect.test.d.ts +1 -0
  250. package/dist/types/hooks/useClientLayoutEffect.d.ts +2 -0
  251. package/dist/types/hooks/useComponentEventListeners.d.ts +34 -0
  252. package/dist/types/hooks/useEditor.d.ts +37 -0
  253. package/dist/types/hooks/useEditorEffect.d.ts +21 -0
  254. package/dist/types/hooks/useEditorEventCallback.d.ts +13 -0
  255. package/dist/types/hooks/useEditorEventListener.d.ts +8 -0
  256. package/dist/types/hooks/useEditorState.d.ts +5 -0
  257. package/dist/types/hooks/useEditorStateSelector.d.ts +10 -0
  258. package/dist/types/hooks/useEffectEvent.d.ts +1 -0
  259. package/dist/types/hooks/useForceUpdate.d.ts +5 -0
  260. package/dist/types/hooks/useIgnoreMutation.d.ts +2 -0
  261. package/dist/types/hooks/useIsComposingIn.d.ts +4 -0
  262. package/dist/types/hooks/useIsEditorStatic.d.ts +5 -0
  263. package/dist/types/hooks/useIsNodeSelected.d.ts +1 -0
  264. package/dist/types/hooks/useLayoutGroupEffect.d.ts +3 -0
  265. package/dist/types/hooks/useMarkViewDescription.d.ts +15 -0
  266. package/dist/types/hooks/useNodePos.d.ts +9 -0
  267. package/dist/types/hooks/useNodeViewDescription.d.ts +16 -0
  268. package/dist/types/hooks/useReactKeys.d.ts +2 -0
  269. package/dist/types/hooks/useSelectNode.d.ts +2 -0
  270. package/dist/types/hooks/useSetDom.d.ts +2 -0
  271. package/dist/types/hooks/useStopEvent.d.ts +2 -0
  272. package/dist/types/index.d.ts +21 -0
  273. package/dist/types/plugins/__tests__/reactKeys.test.d.ts +1 -0
  274. package/dist/types/plugins/beforeInputPlugin.d.ts +2 -0
  275. package/dist/types/plugins/reactKeys.d.ts +23 -0
  276. package/dist/types/props.d.ts +1173 -0
  277. package/dist/types/refs.d.ts +2 -0
  278. package/dist/types/testing/editorViewTestHelpers.d.ts +24 -0
  279. package/dist/types/testing/setupProseMirrorView.d.ts +2 -0
  280. package/dist/types/tiptap/ReactProseMirrorNodeView.d.ts +15 -0
  281. package/dist/types/tiptap/TiptapEditor.d.ts +6 -0
  282. package/dist/types/tiptap/TiptapEditorContent.d.ts +28 -0
  283. package/dist/types/tiptap/TiptapEditorView.d.ts +16 -0
  284. package/dist/types/tiptap/contexts/TiptapEditorContext.d.ts +6 -0
  285. package/dist/types/tiptap/extensions/ReactProseMirror.d.ts +9 -0
  286. package/dist/types/tiptap/extensions/ReactProseMirrorCommands.d.ts +2 -0
  287. package/dist/types/tiptap/extensions/commands/updateAttributes.d.ts +24 -0
  288. package/dist/types/tiptap/hooks/useEditor.d.ts +38 -0
  289. package/dist/types/tiptap/hooks/useIsInReactProseMirror.d.ts +6 -0
  290. package/dist/types/tiptap/hooks/useTiptapEditor.d.ts +11 -0
  291. package/dist/types/tiptap/hooks/useTiptapEditorEffect.d.ts +21 -0
  292. package/dist/types/tiptap/hooks/useTiptapEditorEventCallback.d.ts +13 -0
  293. package/dist/types/tiptap/index.d.ts +9 -0
  294. package/dist/types/tiptap/tiptapNodeView.d.ts +50 -0
  295. package/dist/types/viewdesc.d.ts +179 -0
  296. package/package.json +167 -0
@@ -0,0 +1,346 @@
1
+ import { Fragment, Slice } from "prosemirror-model";
2
+ import { Plugin, TextSelection } from "prosemirror-state";
3
+ import { ReactEditorView } from "../ReactEditorView.js";
4
+ import { browser } from "../browser.js";
5
+ import { CursorWrapper } from "../components/CursorWrapper.js";
6
+ import { widget } from "../decorations/ReactWidgetType.js";
7
+ import { CompositionViewDesc, TextViewDesc, findTextInFragment } from "../viewdesc.js";
8
+ import { reactKeysPluginKey } from "./reactKeys.js";
9
+ function insertText(view, eventData) {
10
+ let options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
11
+ if (eventData === null) return false;
12
+ const from = options.from ?? view.state.selection.from;
13
+ const to = options.to ?? view.state.selection.to;
14
+ if (view.someProp("handleTextInput", (f)=>f(view, from, to, eventData, ()=>view.state.tr.insertText(eventData, from, to)))) {
15
+ return true;
16
+ }
17
+ const { tr } = view.state;
18
+ if (options.marks) tr.ensureMarks(options.marks);
19
+ tr.insertText(eventData, from, to);
20
+ view.dispatch(tr);
21
+ return true;
22
+ }
23
+ // Taken from https://github.com/ProseMirror/prosemirror-gapcursor/blob/master/src/index.ts#L67-L84
24
+ // This is a hack that, when a composition starts while a gap cursor
25
+ // is active, quickly creates an inline context for the composition to
26
+ // happen in, to avoid it being aborted by the DOM selection being
27
+ // moved into a valid position.
28
+ //
29
+ // We can't rely on the actual hack from prosemirror-gapcursor, because
30
+ // it happens too late. We snapshot the DOM during compositionstart, but
31
+ // the gapcursor hack runs in beforeinput (after compositionstart).
32
+ function handleGapCursorComposition(view) {
33
+ // @ts-expect-error Internal property - jsonID
34
+ if (!(view.state.selection.jsonID === "gapcursor")) {
35
+ return;
36
+ }
37
+ const { $from } = view.state.selection;
38
+ const insert = $from.parent.contentMatchAt($from.index())// All schemas _must_ have a text node type
39
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
40
+ .findWrapping(view.state.schema.nodes.text);
41
+ if (!insert) return;
42
+ let fragment = Fragment.empty;
43
+ for(let i = insert.length - 1; i >= 0; i--){
44
+ fragment = Fragment.from(// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
45
+ insert[i].createAndFill(null, fragment));
46
+ }
47
+ const tr = view.state.tr.replace($from.pos, $from.pos, new Slice(fragment, 0, 0));
48
+ tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
49
+ view.dispatch(tr);
50
+ }
51
+ const observeOptions = {
52
+ childList: true,
53
+ characterData: true,
54
+ characterDataOldValue: true,
55
+ attributes: true,
56
+ attributeOldValue: true,
57
+ subtree: true
58
+ };
59
+ export function beforeInputPlugin() {
60
+ let observer = null;
61
+ let preCompositionSnapshot = null;
62
+ function teardownComposition(view, endedAt) {
63
+ view.input.composing = false;
64
+ if (observer) {
65
+ if (view.input.compositionNode && view.dom.contains(view.input.compositionNode)) {
66
+ view.domObserver.queue.push(...observer.takeRecords());
67
+ view.domObserver.flush();
68
+ } else {
69
+ const freezeFrom = reactKeysPluginKey.getState(view.state)?.freezeFrom;
70
+ const frozenNode = freezeFrom == null ? null : view.state.doc.nodeAt(freezeFrom);
71
+ if (freezeFrom != null && frozenNode != null && preCompositionSnapshot) {
72
+ // This is a little hacky — it only works because we always abort
73
+ // compositions if the node after freezeFrom changes, so we can
74
+ // be sure that if a composition was canceled by the user/browser,
75
+ // the content hasn't changed since the composition started
76
+ view.dispatch(view.state.tr.replaceWith(freezeFrom + 1, freezeFrom + 1 + frozenNode.content.size, preCompositionSnapshot));
77
+ }
78
+ }
79
+ observer.disconnect();
80
+ observer = null;
81
+ }
82
+ view.input.compositionEndedAt = endedAt;
83
+ view.input.compositionNode = null;
84
+ view.input.compositionNodes = [];
85
+ view.input.compositionID++;
86
+ }
87
+ function teardownCompositionAndUnfreeze(view, event) {
88
+ teardownComposition(view, event.timeStamp);
89
+ view.dispatch(view.state.tr.setMeta(reactKeysPluginKey, {
90
+ cursorWrapper: null,
91
+ freezeFrom: null
92
+ }));
93
+ }
94
+ return new Plugin({
95
+ view () {
96
+ return {
97
+ update (view) {
98
+ if (!(view instanceof ReactEditorView)) return;
99
+ const frozen = reactKeysPluginKey.getState(view.state)?.freezeFrom != null;
100
+ if (observer && view.composing && !frozen) {
101
+ teardownComposition(view, Date.now());
102
+ }
103
+ }
104
+ };
105
+ },
106
+ props: {
107
+ handleDOMEvents: {
108
+ compositionstart (view) {
109
+ if (!(view instanceof ReactEditorView)) return false;
110
+ const storedMarks = view.state.selection.empty ? view.state.storedMarks : view.state.storedMarks ?? (view.state.selection instanceof TextSelection ? view.state.selection.$from.marksAcross(view.state.selection.$to) : null);
111
+ view.dispatch(view.state.tr.deleteSelection().setStoredMarks(storedMarks));
112
+ handleGapCursorComposition(view);
113
+ const { selection } = view.state;
114
+ const tr = view.state.tr.delete(selection.from, selection.to);
115
+ const $from = tr.doc.resolve(tr.mapping.map(selection.from));
116
+ const isEmptyTextblock = $from.parent.isTextblock && $from.parent.childCount === 0;
117
+ if (storedMarks != null || browser.safari && isEmptyTextblock) {
118
+ view.dispatch(view.state.tr.setMeta(reactKeysPluginKey, {
119
+ cursorWrapper: widget(view.state.selection.from, CursorWrapper, {
120
+ key: "cursor-wrapper",
121
+ ...storedMarks !== null && {
122
+ marks: storedMarks
123
+ },
124
+ side: 0,
125
+ raw: true
126
+ })
127
+ }));
128
+ // Pin the DOM cursor to PM's canonical position before the IME
129
+ // captures wherever the browser happened to leave it. Without this,
130
+ // a cursor at a mark boundary lands in either the left or right text
131
+ // node depending on the user's last navigation direction, and the
132
+ // IME composes into whichever one it found.
133
+ } else if (view.state.selection.empty && view.domSelection()) {
134
+ view.domObserver.disconnectSelection();
135
+ try {
136
+ view.docView.setSelection(view.state.selection.anchor, view.state.selection.head, view, true // force — skip the isEquivalentPosition early-return
137
+ );
138
+ } finally{
139
+ view.domObserver.setCurSelection();
140
+ view.domObserver.connectSelection();
141
+ }
142
+ }
143
+ const freezeFrom = view.state.selection.$from.before();
144
+ view.dispatch(view.state.tr.setMeta(reactKeysPluginKey, {
145
+ freezeFrom
146
+ }));
147
+ const frozenDom = view.nodeDOM(freezeFrom);
148
+ if (!frozenDom) {
149
+ view.dispatch(view.state.tr.setMeta(reactKeysPluginKey, {
150
+ cursorWrapper: null,
151
+ freezeFrom: null
152
+ }));
153
+ return false;
154
+ }
155
+ preCompositionSnapshot = view.state.doc.nodeAt(freezeFrom)?.content ?? null;
156
+ view.input.composing = true;
157
+ observer = new MutationObserver((records)=>{
158
+ if (reactKeysPluginKey.getState(view.state)?.freezeFrom == null) {
159
+ return;
160
+ }
161
+ view.domObserver.queue.push(...records);
162
+ view.domObserver.flush();
163
+ syncCompositionViewDescs(view);
164
+ });
165
+ observer.observe(frozenDom, observeOptions);
166
+ return true;
167
+ },
168
+ compositionupdate () {
169
+ return true;
170
+ },
171
+ compositionend (view, event) {
172
+ if (!(view instanceof ReactEditorView)) return false;
173
+ if (!view.composing) return false;
174
+ teardownCompositionAndUnfreeze(view, event);
175
+ return true;
176
+ },
177
+ contextmenu (view, event) {
178
+ if (!(view instanceof ReactEditorView)) return false;
179
+ if (!view.composing) return false;
180
+ teardownCompositionAndUnfreeze(view, event);
181
+ return false;
182
+ },
183
+ mousedown (view, event) {
184
+ if (!(view instanceof ReactEditorView)) return false;
185
+ if (!view.composing) return false;
186
+ teardownCompositionAndUnfreeze(view, event);
187
+ return false;
188
+ },
189
+ touchstart (view, event) {
190
+ if (!(view instanceof ReactEditorView)) return false;
191
+ if (!view.composing) return false;
192
+ teardownCompositionAndUnfreeze(view, event);
193
+ return false;
194
+ },
195
+ beforeinput (view, event) {
196
+ if (event.inputType !== "insertFromComposition") {
197
+ event.preventDefault();
198
+ }
199
+ switch(event.inputType){
200
+ case "insertParagraph":
201
+ case "insertLineBreak":
202
+ {
203
+ // ProseMirror-view has a hack that runs the Enter event handlers
204
+ // on iOS, to avoid a bug in Safari with calling event.preventDefault() on
205
+ // Enter events.
206
+ //
207
+ // We want to prevent that hack, because we run the Enter event handlers
208
+ // here, where there is no such bug. So we set this flag, which prosemirror-view
209
+ // uses to check whether it should run the deferred event handlers.
210
+ view.input.lastIOSEnter = 0;
211
+ // Fire a synthetic keydown event to trigger ProseMirror's keymap
212
+ const keyEvent = new KeyboardEvent("keydown", {
213
+ bubbles: true,
214
+ cancelable: true,
215
+ key: "Enter",
216
+ code: "Enter",
217
+ keyCode: 13,
218
+ shiftKey: event.inputType === "insertLineBreak"
219
+ });
220
+ // Use someProp to directly call ProseMirror handlers
221
+ return view.someProp("handleKeyDown", (f)=>f(view, keyEvent)) ?? false;
222
+ }
223
+ case "insertReplacementText":
224
+ {
225
+ const ranges = event.getTargetRanges();
226
+ event.dataTransfer?.items[0]?.getAsString((data)=>{
227
+ for (const range of ranges){
228
+ const from = view.posAtDOM(range.startContainer, range.startOffset, 1);
229
+ const to = view.posAtDOM(range.endContainer, range.endOffset, 1);
230
+ insertText(view, data, {
231
+ from,
232
+ to
233
+ });
234
+ }
235
+ });
236
+ break;
237
+ }
238
+ case "insertText":
239
+ {
240
+ const ranges = event.getTargetRanges();
241
+ if (ranges.length === 0 || ranges.length === 1 && ranges[0] && ranges[0].collapsed) {
242
+ insertText(view, event.data);
243
+ } else {
244
+ for (const range of ranges){
245
+ const from = view.posAtDOM(range.startContainer, range.startOffset, 1);
246
+ const to = view.posAtDOM(range.endContainer, range.endOffset, 1);
247
+ insertText(view, event.data, {
248
+ from,
249
+ to
250
+ });
251
+ }
252
+ }
253
+ break;
254
+ }
255
+ case "deleteWordBackward":
256
+ case "deleteHardLineBackward":
257
+ case "deleteSoftLineBackward":
258
+ case "deleteContentBackward":
259
+ case "deleteWordForward":
260
+ case "deleteHardLineForward":
261
+ case "deleteSoftLineForward":
262
+ case "deleteContentForward":
263
+ case "deleteContent":
264
+ {
265
+ const targetRanges = event.getTargetRanges();
266
+ const { tr } = view.state;
267
+ for (const range of targetRanges){
268
+ const start = view.posAtDOM(range.startContainer, range.startOffset);
269
+ const end = view.posAtDOM(range.endContainer, range.endOffset);
270
+ const { doc } = view.state;
271
+ const marks = doc.resolve(start).marksAcross(doc.resolve(end));
272
+ tr.delete(start, end);
273
+ if (marks) {
274
+ tr.ensureMarks(marks);
275
+ }
276
+ }
277
+ view.dispatch(tr);
278
+ break;
279
+ }
280
+ default:
281
+ {
282
+ break;
283
+ }
284
+ }
285
+ return true;
286
+ }
287
+ }
288
+ }
289
+ });
290
+ }
291
+ function syncCompositionViewDescs(view) {
292
+ const compositionNode = view.domObserver.lastChangedTextNode;
293
+ if (!compositionNode) return;
294
+ const freezeFrom = reactKeysPluginKey.getState(view.state)?.freezeFrom;
295
+ if (freezeFrom == null) return;
296
+ const compositionBlock = view.state.doc.nodeAt(freezeFrom);
297
+ if (!compositionBlock) return;
298
+ const compositionBlockDesc = view.docView.descAt(freezeFrom);
299
+ if (!compositionBlockDesc) return;
300
+ const desc = view.docView.nearestDesc(compositionNode);
301
+ compositionBlockDesc.node = compositionBlock;
302
+ if (desc instanceof TextViewDesc) {
303
+ if (compositionNode.nodeValue && desc.node.text !== compositionNode.nodeValue) {
304
+ desc.node = view.state.schema.text(compositionNode.nodeValue, desc.node.marks);
305
+ desc.nodeDOM = compositionNode;
306
+ compositionNode.pmViewDesc = desc;
307
+ }
308
+ return;
309
+ }
310
+ if (desc instanceof CompositionViewDesc) {
311
+ if (compositionNode.nodeValue != null && desc.text !== compositionNode.nodeValue) {
312
+ desc.dom = compositionNode;
313
+ desc.textDOM = compositionNode;
314
+ desc.text = compositionNode.nodeValue;
315
+ compositionNode.pmViewDesc = desc;
316
+ }
317
+ return;
318
+ }
319
+ const parentDesc = desc?.contentDOM ? desc : compositionBlockDesc;
320
+ const children = parentDesc.children;
321
+ // Drop any text or composition desc in this container whose DOM the
322
+ // IME has detached. This covers two cases: a TextViewDesc the IME subsumed
323
+ // into the composition node, and (on Safari, which replaces the whole text
324
+ // node on each composition update) any orphaned composition view
325
+ // desc(s) left over from the previous composition steps.
326
+ for(let i = children.length - 1; i >= 0; i--){
327
+ const c = children[i];
328
+ if (!(c instanceof TextViewDesc) && !(c instanceof CompositionViewDesc)) {
329
+ continue;
330
+ }
331
+ const dom = c.dom;
332
+ if (view.dom.contains(dom)) continue;
333
+ children.splice(i, 1);
334
+ }
335
+ const contentStart = freezeFrom + 1;
336
+ const { from, to } = view.state.selection;
337
+ const textPos = findTextInFragment(compositionBlock.content, compositionNode.nodeValue ?? "", from - contentStart, to - contentStart);
338
+ if (textPos < 0) return;
339
+ const startPos = contentStart + textPos;
340
+ let topDOM = compositionNode;
341
+ while(topDOM.parentNode && topDOM.parentNode !== parentDesc.contentDOM){
342
+ topDOM = topDOM.parentNode;
343
+ }
344
+ const insertIndex = children.findLastIndex((c)=>c.posBefore <= startPos) + 1;
345
+ children.splice(insertIndex, 0, new CompositionViewDesc(parentDesc, ()=>startPos, topDOM, compositionNode, compositionNode.nodeValue ?? ""));
346
+ }
@@ -0,0 +1,106 @@
1
+ import { Plugin, PluginKey } from "prosemirror-state";
2
+ import { AddNodeMarkStep, AttrStep, DocAttrStep, RemoveNodeMarkStep } from "prosemirror-transform";
3
+ import { DecorationSet } from "prosemirror-view";
4
+ import { widget } from "../decorations/ReactWidgetType.js";
5
+ // These steps keep every node's size, so no node moves, appears or
6
+ // disappears. Mark steps are not among them: they can split text nodes,
7
+ // which then need keys.
8
+ const keepsNodePositions = (step)=>step instanceof AttrStep || step instanceof DocAttrStep || step instanceof AddNodeMarkStep || step instanceof RemoveNodeMarkStep;
9
+ export function createNodeKey() {
10
+ const key = Math.floor(Math.random() * 0xffffffffffff).toString(16);
11
+ return key;
12
+ }
13
+ export const reactKeysPluginKey = new PluginKey("@handlewithcare/react-prosemirror/reactKeys");
14
+ /**
15
+ * Tracks a unique key for each (non-text) node in the
16
+ * document, identified by its current position. Keys are
17
+ * (mostly) stable across transaction applications. The
18
+ * key for a given node can be accessed by that node's
19
+ * current position in the document, and vice versa.
20
+ */ export function reactKeys() {
21
+ return new Plugin({
22
+ key: reactKeysPluginKey,
23
+ state: {
24
+ init (_, state) {
25
+ const next = {
26
+ posToKey: new Map(),
27
+ keyToPos: new Map(),
28
+ cursorWrapper: null,
29
+ freezeFrom: null
30
+ };
31
+ state.doc.descendants((_, pos)=>{
32
+ const key = createNodeKey();
33
+ next.posToKey.set(pos, key);
34
+ next.keyToPos.set(key, pos);
35
+ return true;
36
+ });
37
+ return next;
38
+ },
39
+ /**
40
+ * Keeps node keys stable across transactions.
41
+ *
42
+ * To accomplish this, we map each node position forwards
43
+ * through the transaction to identify its current position,
44
+ * and assign its key to that new position, dropping it if the
45
+ * node was deleted.
46
+ */ apply (tr, value, oldState, newState) {
47
+ const meta = tr.getMeta(reactKeysPluginKey);
48
+ const overrides = meta && "overrides" in meta ? meta.overrides : {};
49
+ const cursorWrapper = meta && "cursorWrapper" in meta ? meta.cursorWrapper : undefined;
50
+ const freezeFrom = meta && "freezeFrom" in meta ? meta.freezeFrom : undefined;
51
+ const next = {
52
+ posToKey: new Map(),
53
+ keyToPos: new Map(),
54
+ cursorWrapper: cursorWrapper === undefined ? value.cursorWrapper ? widget(tr.mapping.map(value.cursorWrapper.from, -1), value.cursorWrapper.type.Component, value.cursorWrapper.spec) : null : cursorWrapper,
55
+ freezeFrom: freezeFrom === undefined ? value.freezeFrom !== null ? tr.mapping.map(value.freezeFrom, -1) : null : freezeFrom
56
+ };
57
+ if (value.freezeFrom !== null && next.freezeFrom !== null && tr.getMeta("composition") == null) {
58
+ const oldBlock = oldState.doc.nodeAt(value.freezeFrom);
59
+ const newBlock = newState.doc.nodeAt(next.freezeFrom);
60
+ if (newBlock && !oldBlock?.eq(newBlock)) {
61
+ next.freezeFrom = null;
62
+ next.cursorWrapper = null;
63
+ }
64
+ }
65
+ if (!tr.docChanged || !meta?.overrides && tr.steps.every(keepsNodePositions)) {
66
+ return {
67
+ ...value,
68
+ cursorWrapper: next.cursorWrapper,
69
+ freezeFrom: next.freezeFrom
70
+ };
71
+ }
72
+ const posToKeyEntries = Array.from(value.posToKey.entries()).sort((param, param1)=>{
73
+ let [a] = param, [b] = param1;
74
+ return a - b;
75
+ });
76
+ for (const [pos, key] of posToKeyEntries){
77
+ const override = overrides?.[pos];
78
+ const { pos: newPos, deleted } = override === undefined ? tr.mapping.mapResult(pos) : {
79
+ pos: override,
80
+ deleted: false
81
+ };
82
+ if (deleted) continue;
83
+ next.posToKey.set(newPos, key);
84
+ next.keyToPos.set(key, newPos);
85
+ }
86
+ newState.doc.descendants((_, pos)=>{
87
+ if (next.posToKey.has(pos)) return true;
88
+ const key = createNodeKey();
89
+ next.posToKey.set(pos, key);
90
+ next.keyToPos.set(key, pos);
91
+ return true;
92
+ });
93
+ return next;
94
+ }
95
+ },
96
+ props: {
97
+ decorations (state) {
98
+ const deco = reactKeysPluginKey.getState(state)?.cursorWrapper;
99
+ if (!deco) return DecorationSet.empty;
100
+ return DecorationSet.create(state.doc, [
101
+ deco
102
+ ]);
103
+ }
104
+ }
105
+ });
106
+ }