@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
package/README.md ADDED
@@ -0,0 +1,939 @@
1
+ # React ProseMirror
2
+
3
+ <p align="center">
4
+ <img src="react-prosemirror-logo.png" alt="React ProseMirror Logo" width="120px" height="120px"/>
5
+ <br>
6
+ <em>A fully featured library for safely integrating ProseMirror and React.</em>
7
+ <br>
8
+ </p>
9
+
10
+ [![Join the chat at https://gitter.im/nytimes/react-prosemirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nytimes/react-prosemirror?utm_source=badge&utm_medium=badge&utm_content=badge)
11
+
12
+ > **This is `@stesura/react-prosemirror`, a fork of
13
+ > [`@handlewithcare/react-prosemirror`](https://github.com/handlewithcarecollective/react-prosemirror).**
14
+ > Each release is an upstream release plus a few commits for large documents,
15
+ > versioned `<upstream>-stesura.<n>`. What differs from upstream:
16
+ >
17
+ > - Node, mark, text and widget views place their view description among their
18
+ > siblings with a binary search, instead of re-sorting the whole sibling list
19
+ > as each one mounts (quadratic in the number of siblings).
20
+ > - The `reactKeys` plugin keeps its key tables for transactions that only
21
+ > change attributes or node marks, instead of remapping every position.
22
+ > - `<ProseMirror>` takes an opt-in `stableContexts` prop; see
23
+ > [`ProseMirror`](#prosemirror).
24
+ >
25
+ > The rest of this README is upstream's. Where it imports from
26
+ > `@handlewithcare/react-prosemirror`, import from `@stesura/react-prosemirror`,
27
+ > and do not install both: two copies of the library do not share their React
28
+ > contexts.
29
+
30
+ ## Installation
31
+
32
+ _Note_: React ProseMirror releases are coupled to specific prosemirror-view
33
+ releases, and are not guaranteed to work with other versions of
34
+ prosemirror-view. Ensure that your version of prosemirror-view matches the
35
+ version in React ProseMirror's peer dependencies!
36
+
37
+ _Note_: React ProseMirror does not require a specific version of React, React
38
+ DOM, or React Reconciler. **However**, you must ensure that your React
39
+ Reconciler version matches your React/React DOM versions.
40
+
41
+ | React version | React Reconciler version |
42
+ | --------------- | ------------------------ |
43
+ | 19.x | 0.32.0 |
44
+ | >= 18.2.0, < 19 | 0.29.0 |
45
+ | 18.1.x | 0.28.0 |
46
+ | 18.0.x | 0.27.0 |
47
+ | 17.x | 0.26.1 |
48
+
49
+ npm:
50
+
51
+ ```sh
52
+ npm install @handlewithcare/react-prosemirror \
53
+ react@^19.1.0 \
54
+ react-dom@^19.1.0 \
55
+ react-reconciler@0.32.0 \
56
+ prosemirror-view@1.42.3 \
57
+ prosemirror-state \
58
+ prosemirror-model
59
+ ```
60
+
61
+ yarn:
62
+
63
+ ```sh
64
+ yarn add @handlewithcare/react-prosemirror \
65
+ react@^19.1.0 \
66
+ react-dom@^19.1.0 \
67
+ react-reconciler@0.32.0 \
68
+ prosemirror-view@1.42.3 \
69
+ prosemirror-state \
70
+ prosemirror-model
71
+ ```
72
+
73
+ _Note_: React ProseMirror needs the prosemirror-view stylesheet just as a
74
+ vanilla ProseMirror set up would. How this stylesheet gets imported can vary
75
+ based on the application, but may be as simple as:
76
+
77
+ ```css
78
+ /* editor.css */
79
+ @import "prosemirror-view/style/prosemirror.css";
80
+ ```
81
+
82
+ Or:
83
+
84
+ ```ts
85
+ // Editor.tsx
86
+ import "prosemirror-view/style/prosemirror.css";
87
+ ```
88
+
89
+ <!-- toc -->
90
+
91
+ - [The Problem](#the-problem)
92
+ - [The Solution](#the-solution)
93
+ - [Rendering ProseMirror Views within React](#rendering-prosemirror-views-within-react)
94
+ - [`useEditorEffect`](#useeditoreffect)
95
+ - [`useEditorEventCallback`](#useeditoreventcallback)
96
+ - [`useEditorEventListener`](#useeditoreventlistener)
97
+ - [Building node views with React](#building-node-views-with-react)
98
+ - [API](#api)
99
+ - [`ProseMirror`](#prosemirror)
100
+ - [`ProseMirrorDoc`](#prosemirrordoc)
101
+ - [`useEditorState`](#useeditorstate)
102
+ - [`useEditorEventCallback`](#useeditoreventcallback-1)
103
+ - [`useEditorEventListener`](#useeditoreventlistener-1)
104
+ - [`useEditorEffect`](#useeditoreffect-1)
105
+ - [`NodeViewComponentProps`](#nodeviewcomponentprops)
106
+ - [`useEditorStateSelector`](#useeditorstateselector)
107
+ - [`useNodePos`](#usenodepos)
108
+ - [`useStopEvent`](#usestopevent)
109
+ - [`useIgnoreMutation`](#useignoremutation)
110
+ - [`useSelectNode`](#useselectnode)
111
+ - [`useIsNodeSelected`](#useisnodeselected)
112
+ - [`useIsComposingIn`](#useiscomposingin)
113
+ - [`widget`](#widget)
114
+ - [`reorderSiblings`](#reordersiblings)
115
+ - [When should I use this?](#when-should-i-use-this)
116
+ - [Migrations](#migrations)
117
+ - [Looking for someone to collaborate with?](#looking-for-someone-to-collaborate-with)
118
+ - [Sponsors](#sponsors)
119
+
120
+ <!-- tocstop -->
121
+
122
+ Already using Tiptap, and interesting in using React ProseMirror as the React
123
+ integration? Check out [the Tiptap integration docs](./src/tiptap/README.md)!
124
+
125
+ ## The Problem
126
+
127
+ To make updates efficient, React separates updates into phases so that it can
128
+ process updates in batches. In the first phase, application code renders a
129
+ virtual document. In the second phase, the React DOM renderer finalizes the
130
+ update by reconciling the real document with the virtual document.
131
+
132
+ On the other hand, the ProseMirror View library renders ProseMirror documents in
133
+ a single-phase update. Unlike React, it also allows built-in editing features of
134
+ the browser to modify the document under some circumstances, deriving state
135
+ updates from view updates rather than the other way around.
136
+
137
+ It is possible to use both React DOM and ProseMirror View, but using React DOM
138
+ to render ProseMirror View components safely requires careful consideration of
139
+ differences between the rendering approaches taken by each framework. The first
140
+ phase of a React update should be free of side effects, which requires that
141
+ updates to the ProseMirror View happen in the second phase. This means that
142
+ during the first phase, React components actually have access to a different
143
+ (newer) version of the EditorState than the one in the EditorView. As a result
144
+ code that dispatches transactions may dispatch transactions based on incorrect
145
+ state. Code that invokes methods of the ProseMirror view may make bad
146
+ assumptions about its state that cause incorrect behavior or errors.
147
+
148
+ It's also challenging to effectively use React to define node views for
149
+ ProseMirror documents. Both ProseMirror and React expect to have full control
150
+ over their respective parts of the DOM. They both modify and destroy DOM nodes
151
+ as needed. Previous solutions (including previous iterations of this library)
152
+ have attempted to work around this power struggle by producing wrapper elements
153
+ to hand to ProseMirror, and then mounting React nodes within these (usually with
154
+ React Portals).
155
+
156
+ This approach works, but tenuously. Having additional nodes in the document that
157
+ ProseMirror isn't strictly aware of can cause issues with its change detection
158
+ system, leading to challenging edge cases.
159
+ [Here's an example](https://github.com/nytimes/react-prosemirror/issues/42).
160
+ These extra wrapping elements also make it challenging to produce semantic
161
+ markup and introduce challenges when styling.
162
+
163
+ ## The Solution
164
+
165
+ This library provides an alternate implementation of ProseMirror's EditorView.
166
+ It uses React as the rendering engine, rather than ProseMirror's home-brewed DOM
167
+ update system. This allows us to provide a more comfortable integration with
168
+ ProseMirror's powerful data model, transformations, and event management
169
+ systems.
170
+
171
+ ### Rendering ProseMirror Views within React
172
+
173
+ This library provides a set of React contexts and hooks for consuming them that
174
+ ensure safe access to the EditorView from React components. This allows us to
175
+ build React applications that contain ProseMirror Views, even when the
176
+ EditorState is lifted into React state, or a global state management system like
177
+ Redux.
178
+
179
+ The simplest way to make use of these contexts is with the `<ProseMirror />`
180
+ component. The `<ProseMirror />` component can be used controlled (via the
181
+ `state` prop) or uncontrolled (via the `defaultState` prop).
182
+
183
+ ```tsx
184
+ import { EditorState } from "prosemirror-state";
185
+ import {
186
+ ProseMirror,
187
+ ProseMirrorDoc,
188
+ reactKeys,
189
+ } from "@handlewithcare/react-prosemirror";
190
+
191
+ export function ProseMirrorEditor() {
192
+ return (
193
+ <ProseMirror
194
+ defaultState={EditorState.create({
195
+ schema,
196
+ plugins: [
197
+ // The reactKeys plugin is required for the ProseMirror component to work!
198
+ reactKeys(),
199
+ ],
200
+ })}
201
+ >
202
+ <ProseMirrorDoc />
203
+ </ProseMirror>
204
+ );
205
+ }
206
+ ```
207
+
208
+ The EditorState can also easily be lifted out of the ProseMirror component and
209
+ passed as a prop.
210
+
211
+ ```tsx
212
+ import { EditorState } from "prosemirror-state";
213
+ import { schema } from "prosemirror-schema-basic";
214
+ import {
215
+ ProseMirror,
216
+ ProseMirrorDoc,
217
+ reactKeys,
218
+ } from "@handlewithcare/react-prosemirror";
219
+
220
+ export function ProseMirrorEditor() {
221
+ const [editorState, setEditorState] = useState(
222
+ EditorState.create({ schema, plugins: [reactKeys()] })
223
+ );
224
+
225
+ return (
226
+ <ProseMirror
227
+ state={editorState}
228
+ dispatchTransaction={(tr) => {
229
+ setEditorState((s) => s.apply(tr));
230
+ }}
231
+ >
232
+ <ProseMirrorDoc />
233
+ </ProseMirror>
234
+ );
235
+ }
236
+ ```
237
+
238
+ The `EditorView` interface exposes several useful methods that provide access to
239
+ the DOM or data derived from its layout, such as `coordsFromPos`. These methods
240
+ should only be accessed outside the render cycle, to ensure that the DOM has
241
+ been updated to match the latest state. React ProseMirror provides two hooks to
242
+ enable this access pattern: `useEditorEffect` and `useEditorEventCallback`. Both
243
+ of these hooks can be used from any children of the ProseMirror component.
244
+
245
+ #### `useEditorEffect`
246
+
247
+ Often, it's necessary to position React components relative to specific
248
+ positions in the ProseMirror document. For example, you might have some widget
249
+ that needs to be positioned at the user's cursor. In order to ensure that this
250
+ positioning happens when the DOM is in sync with the latest EditorState, we can
251
+ use `useEditorEffect`.
252
+
253
+ ```tsx
254
+ // SelectionWidget.tsx
255
+ import { useRef } from "react";
256
+ import { useEditorEffect } from "@handlewithcare/react-prosemirror";
257
+
258
+ export function SelectionWidget() {
259
+ const ref = useRef();
260
+
261
+ useEditorEffect((view) => {
262
+ if (!view || !ref.current) return;
263
+
264
+ const viewClientRect = view.dom.getBoundingClientRect();
265
+ const coords = view.coordsAtPos(view.state.selection.anchor));
266
+
267
+ ref.current.style.top = coords.top - viewClientRect.top;
268
+ ref.current.style.left = coords.left - viewClientRect.left;
269
+ })
270
+
271
+ return (
272
+ <div
273
+ ref={ref}
274
+ style={{
275
+ position: "absolute"
276
+ }}
277
+ />
278
+ );
279
+ }
280
+
281
+ // ProseMirrorEditor.tsx
282
+ import {
283
+ ProseMirror,
284
+ ProseMirrorDoc,
285
+ reactKeys
286
+ } from "@handlewithcare/react-prosemirror";
287
+ import { EditorState } from "prosemirror-state";
288
+ import { schema } from "prosemirror-schema-basic";
289
+
290
+ import { SelectionWidget } from "./SelectionWidget.tsx";
291
+
292
+ export function ProseMirrorEditor() {
293
+ const [editorState, setEditorState] = useState(
294
+ EditorState.create({ schema, plugins: [reactKeys()] })
295
+ );
296
+
297
+ return (
298
+ <ProseMirror
299
+ state={editorState}
300
+ dispatchTransaction={(tr) => {
301
+ setEditorState(s => s.apply(tr))
302
+ }}
303
+ >
304
+ <ProseMirrorDoc />
305
+ {/*
306
+ We have to mount all components that need to access the
307
+ EditorView as children of the ProseMirror component
308
+ */}
309
+ <SelectionWidget />
310
+ </ProseMirror>
311
+ );
312
+ }
313
+ ```
314
+
315
+ #### `useEditorEventCallback`
316
+
317
+ It's also often necessary to dispatch transactions or execute side effects in
318
+ response to user actions, like mouse clicks and keyboard events.
319
+
320
+ You can use `useEditorEventCallback` to create a stable function reference that
321
+ can safely access the latest value of the `EditorView`.
322
+
323
+ _Note_: if you need to respond to keyboard events from _within_ the
324
+ `contenteditable` element, you should instead use
325
+ [`useEditorEventListener`](#useEditorEventListener).
326
+
327
+ ```tsx
328
+ // BoldButton.tsx
329
+ import { toggleMark } from "prosemirror-commands";
330
+ import { useEditorEventCallback } from "@handlewithcare/react-prosemirror";
331
+
332
+ export function BoldButton() {
333
+ const onClick = useEditorEventCallback((view) => {
334
+ if (!view) return;
335
+ const toggleBoldMark = toggleMark(view.state.schema.marks.bold);
336
+ toggleBoldMark(view.state, view.dispatch, view);
337
+ });
338
+
339
+ return <button onClick={onClick}>Bold</button>;
340
+ }
341
+
342
+ // ProseMirrorEditor.tsx
343
+ import {
344
+ ProseMirror,
345
+ ProseMirrorDoc,
346
+ reactKeys,
347
+ } from "@handlewithcare/react-prosemirror";
348
+ import { EditorState } from "prosemirror-state";
349
+ import { schema } from "prosemirror-schema-basic";
350
+
351
+ import { BoldButton } from "./BoldButton.tsx";
352
+
353
+ export function ProseMirrorEditor() {
354
+ const [editorState, setEditorState] = useState(
355
+ EditorState.create({ schema, plugins: [reactKeys()] })
356
+ );
357
+
358
+ return (
359
+ <ProseMirror
360
+ state={editorState}
361
+ dispatchTransaction={(tr) => {
362
+ setEditorState((s) => s.apply(tr));
363
+ }}
364
+ >
365
+ <ProseMirrorDoc />
366
+ {/*
367
+ We have to mount all components that need to access the
368
+ EditorView as children of the ProseMirror component
369
+ */}
370
+ <BoldButton />
371
+ </ProseMirror>
372
+ );
373
+ }
374
+ ```
375
+
376
+ #### `useEditorEventListener`
377
+
378
+ `useEditorEventCallback` produces functions that can be passed to React
379
+ components as event handlers. If you need to listen to events that originate
380
+ _within the `contenteditable` node_, however, those event listeners need to be
381
+ registered with the `EditorView`'s `handleDOMEvents` prop.
382
+
383
+ You can use the `useEditorEventListener` hook to accomplish this. It takes an
384
+ `eventType` and an event listener. The event listener follows the usual
385
+ semantics for ProseMirror's `handleDOMEvents` prop:
386
+
387
+ - Returning `true` or calling `event.preventDefault` will prevent other
388
+ listeners from running.
389
+ - Returning `true` will not automatically call `event.preventDefault`; if you
390
+ want to prevent the default contenteditable behavior, you must call
391
+ `event.preventDefault`.
392
+
393
+ You can use this hook to implement custom behavior in your node views:
394
+
395
+ ```tsx
396
+ import {
397
+ useEditorEventListener,
398
+ NodeViewComponentProps,
399
+ useMergedDOMRefs,
400
+ } from "@handlewithcare/react-prosemirror";
401
+
402
+ function Paragraph({ children, nodeProps, ref, ...props }) {
403
+ useEditorEventListener("keydown", (view, event) => {
404
+ const { pos, node } = nodeProps;
405
+
406
+ if (event.code !== "ArrowDown") {
407
+ return false;
408
+ }
409
+ const nodeEnd = pos + node.nodeSize;
410
+ const { selection } = view.state;
411
+ if (selection.anchor < pos || selection.anchor > nodeEnd) {
412
+ return false;
413
+ }
414
+ event.preventDefault();
415
+ alert("No down keys allowed!");
416
+ return true;
417
+ });
418
+
419
+ return (
420
+ <p {...props} ref={useMergedDOMRefs(ref, nodeProps.contentDOMRef)}>
421
+ {children}
422
+ </p>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ### Building node views with React
428
+
429
+ The other way to integrate React and ProseMirror is to have ProseMirror render
430
+ node views using React components. Because React ProseMirror renders the
431
+ ProseMirror document with React, node view components don't need to do anything
432
+ special other than fulfill the
433
+ [`NodeViewComponentProps`](#nodeviewcomponentprops) interface.
434
+
435
+ ```tsx
436
+ import {
437
+ ProseMirror,
438
+ ProseMirrorDoc,
439
+ useEditorEventCallback,
440
+ NodeViewComponentProps,
441
+ useMergedDOMRefs,
442
+ reactKeys,
443
+ } from "@handlewithcare/react-prosemirror";
444
+ import { EditorState } from "prosemirror-state";
445
+ import { schema } from "prosemirror-schema-basic";
446
+
447
+ // Paragraph is more or less a normal React component, taking and rendering
448
+ // its children. Some guidelines:
449
+ //
450
+ // - All node view components _must_ pass refs to their top-level
451
+ // DOM elements.
452
+ // - All node view components that render children _must_ pass nodeProps.contentDOMRef
453
+ // to the parent element of `children`. If this is also the top-level DOM
454
+ // element, use `useMergedDOMRefs` to apply both refs
455
+ // - All node view components _should_ spread all of the props that they
456
+ // receive onto their top-level DOM elements; this is required for node Decorations
457
+ // that apply attributes rather than wrapping nodes in an additional element.
458
+ //
459
+ // Note: we are accessing `ref` as a prop here, which has been available since React 19.
460
+ // If you are using React <=18, you will need to use forwardRef to access `ref`.
461
+ function Paragraph({ children, nodeProps, ref, ...props }) {
462
+ const onClick = useEditorEventCallback((view) =>
463
+ view.dispatch(view.state.tr.deleteSelection())
464
+ );
465
+
466
+ return (
467
+ <p
468
+ {...props}
469
+ ref={useMergedDOMRefs(ref, nodeProps.contentDOMRef)}
470
+ onClick={onClick}
471
+ >
472
+ {children}
473
+ </p>
474
+ );
475
+ }
476
+
477
+ // **IMPORTANT**: Define nodeViewComponents _outside_ of your editor
478
+ // component. It should be a stable reference.
479
+ //
480
+ // If you need to define it within a React component for some reason,
481
+ // ensure that it is properly memoized with `useMemo` or the React Compiler.
482
+ const nodeViewComponents = {
483
+ paragraph: Paragraph,
484
+ };
485
+
486
+ function ProseMirrorEditor() {
487
+ return (
488
+ <ProseMirror
489
+ defaultState={EditorState.create({ schema, plugins: [reactKeys()] })}
490
+ nodeViewComponents={nodeViewComponents}
491
+ >
492
+ <ProseMirrorDoc />
493
+ </ProseMirror>
494
+ );
495
+ }
496
+ ```
497
+
498
+ If your node view component is more complex, and the top level DOM element does
499
+ not directly render `children`, use `ref` and `nodeProps.contentDOMRef`
500
+ separately:
501
+
502
+ ```tsx
503
+ function FancyParagraph({ children, nodeProps, ref, ...props }) {
504
+ const onClick = useEditorEventCallback((view) =>
505
+ view.dispatch(view.state.tr.deleteSelection())
506
+ );
507
+
508
+ return (
509
+ <div
510
+ {...props}
511
+ className={cx(props.className, "fancy-paragraph")}
512
+ ref={ref}
513
+ onClick={onClick}
514
+ >
515
+ <p ref={nodeProps.contentDOMRef}>{children}</p>
516
+ </div>
517
+ );
518
+ }
519
+ ```
520
+
521
+ ## API
522
+
523
+ ### `ProseMirror`
524
+
525
+ ```tsx
526
+ type ProseMirror = (
527
+ props: DirectEditorProps &
528
+ ({ defaultState: EditorState } | { state: EditorState }) & {
529
+ children: ReactNode;
530
+ nodeViewComponents?: {
531
+ [nodeType: string]: ComponentType<NodeViewComponentProps>;
532
+ };
533
+ nodeViews?: {
534
+ [nodeType: string]: NodeViewConstructor;
535
+ };
536
+ markViewComponents?: {
537
+ [markType: string]: ComponentType<MarkViewComponentProps>;
538
+ };
539
+ markViews?: {
540
+ [markType: string]: MarkViewConstructor;
541
+ };
542
+ stableContexts?: boolean;
543
+ }
544
+ ) => JSX.Element;
545
+ ```
546
+
547
+ Renders the ProseMirror editor.
548
+
549
+ `stableContexts` (this fork only, default `false`): by default each transaction
550
+ gives `useEditorState` and `ProseMirrorDoc` new context values, and React then
551
+ searches every memoised node view in the document for consumers of those
552
+ contexts, even though none of the node views re-render. In a large document that
553
+ search is a large share of each keystroke. With `stableContexts`, a transaction
554
+ dispatched synchronously keeps the context values the same, and the consumers
555
+ re-render through a subscription in the same commit instead.
556
+
557
+ It is for synchronous dispatch only. Leave it off if any transaction carries the
558
+ `async` meta (`tr.setMeta("async", true)`, which lets React render the update
559
+ without `flushSync`): the new values are written during render, which is only
560
+ safe when every render commits. A state change that does not come through
561
+ `dispatchTransaction`, such as a new `state` prop from a collaboration step,
562
+ changes the contexts either way.
563
+
564
+ Example usage:
565
+
566
+ ```tsx
567
+ import { EditorState } from "prosemirror-state";
568
+ import {
569
+ ProseMirror,
570
+ ProseMirrorDoc,
571
+ reactKeys,
572
+ } from "@handlewithcare/react-prosemirror";
573
+
574
+ export function ProseMirrorEditor() {
575
+ return (
576
+ <ProseMirror
577
+ defaultState={EditorState.create({ schema, plugins: [reactKeys()] })}
578
+ >
579
+ <ProseMirrorDoc />
580
+ </ProseMirror>
581
+ );
582
+ }
583
+ ```
584
+
585
+ ### `ProseMirrorDoc`
586
+
587
+ ```tsx
588
+ type ProseMirrorDoc = (props: { as?: ReactElement }) => JSX.Element;
589
+ ```
590
+
591
+ Renders the actual editable ProseMirror document.
592
+
593
+ This **must** be passed as a child to the `ProseMirror` component. It may be
594
+ wrapped in any other components, and other children may be passed before or
595
+ after.
596
+
597
+ Example usage:
598
+
599
+ ```tsx
600
+ import { EditorState } from "prosemirror-state";
601
+ import {
602
+ ProseMirror,
603
+ ProseMirrorDoc,
604
+ reactKeys,
605
+ } from "@handlewithcare/react-prosemirror";
606
+
607
+ export function ProseMirrorEditor() {
608
+ return (
609
+ <ProseMirror
610
+ defaultState={EditorState.create({ schema, plugins: [reactKeys()] })}
611
+ >
612
+ <ToolBar />
613
+ <SomeWrapper>
614
+ <ProseMirrorDoc as="article" />
615
+ </SomeWrapper>
616
+ <Footnotes />
617
+ </ProseMirror>
618
+ );
619
+ }
620
+ ```
621
+
622
+ ### `useEditorState`
623
+
624
+ ```tsx
625
+ type useEditorState = () => EditorState | null;
626
+ ```
627
+
628
+ Provides access to the current EditorState value.
629
+
630
+ ### `useEditorEventCallback`
631
+
632
+ ```tsx
633
+ type useEditorEventCallback = <T extends unknown[]>(
634
+ callback: (view: EditorView | null, ...args: T) => void
635
+ ) => void;
636
+ ```
637
+
638
+ Returns a stable function reference to be used as an event handler callback.
639
+
640
+ The callback will be called with the EditorView instance as its first argument.
641
+
642
+ This hook is dependent on both the `EditorContext.Provider` and the
643
+ `LayoutGroup`. It can only be used in a component that is mounted as a child of
644
+ both of these providers.
645
+
646
+ ### `useEditorEventListener`
647
+
648
+ ```tsx
649
+ type useEditorEventListener = <EventType extends DOMEventMap>(
650
+ eventType: EventType,
651
+ listener: (view: EditorView, event: DOMEventMap[EventType]) => boolean
652
+ ) => void;
653
+ ```
654
+
655
+ Attaches an event listener at the `EditorView`'s DOM node. See
656
+ [the ProseMirror docs](https://prosemirror.net/docs/ref/#view.EditorProps.handleDOMEvents)
657
+ for more details.
658
+
659
+ ### `useEditorEffect`
660
+
661
+ ```tsx
662
+ type useEditorEffect = (
663
+ effect: (editorView: EditorView | null) => void | (() => void),
664
+ dependencies?: React.DependencyList
665
+ ) => void;
666
+ ```
667
+
668
+ Registers a layout effect to run after the EditorView has been updated with the
669
+ latest EditorState and Decorations.
670
+
671
+ Effects can take an EditorView instance as an argument. This hook should be used
672
+ to execute layout effects that depend on the EditorView, such as for positioning
673
+ DOM nodes based on ProseMirror positions.
674
+
675
+ Layout effects registered with this hook still fire synchronously after all DOM
676
+ mutations, but they do so _after_ the EditorView has been updated, even when the
677
+ EditorView lives in an ancestor component.
678
+
679
+ Example usage:
680
+
681
+ ```tsx
682
+ import { useRef } from "react"
683
+ import { useEditorEffect } from "@handlewithcare/react-prosemirror"
684
+
685
+ export function SelectionWidget() {
686
+ const ref = useRef()
687
+
688
+ useEditorEffect((view) => {
689
+ if (!view || !ref.current) return
690
+
691
+ const viewClientRect = view.dom.getBoundingClientRect()
692
+ const coords = view.coordsAtPos(view.state.selection.anchor))
693
+
694
+ ref.current.style.top = coords.top - viewClientRect.top;
695
+ ref.current.style.left = coords.left - viewClientRect.left;
696
+ })
697
+
698
+ return (
699
+ <div
700
+ ref={ref}
701
+ style={{
702
+ position: "absolute"
703
+ }}
704
+ />
705
+ )
706
+ }
707
+ ```
708
+
709
+ ### `NodeViewComponentProps`
710
+
711
+ ```tsx
712
+ interface NodeViewComponentProps extends AllHTMLAttributes<HTMLElement> = {
713
+ nodeProps: {
714
+ decorations: readonly Decoration[];
715
+ innerDecorations: DecorationSource;
716
+ node: Node;
717
+ getPos: () => number;
718
+ contentDOMRef: Exclude<Ref<any>, null>;
719
+ };
720
+ ref: LegacyRef<any>;
721
+ };
722
+ ```
723
+
724
+ The props that will be passed to all node view components. These props map
725
+ directly to the arguments passed to
726
+ [`NodeViewConstructor` functions](https://prosemirror.net/docs/ref/#view.NodeViewConstructor)
727
+ by the default ProseMirror EditorView implementation.
728
+
729
+ Node view components may also be passed _any_ other valid HTML attribute props,
730
+ and should pass them through to their top-level DOM element.
731
+
732
+ In addition to accepting these props, all node view components _must_ pass their
733
+ ref to their top-level DOM element. All node view components that render their
734
+ `children` _must_ pass `nodeProps.contentDOMRef` to the parent element of
735
+ `children`.
736
+
737
+ [See the above example](#building-node-views-with-react) for more details.
738
+
739
+ ### `useEditorStateSelector`
740
+
741
+ ```ts
742
+ type useEditorStateSelector<Result> = (selector: (state: EditorState) => Result): Result
743
+ ```
744
+
745
+ Select a piece of the EditorState, a la Redux’s `useSelector`.
746
+
747
+ This hook will only trigger a re-render of the consuming component if the return
748
+ value of the selector changes.
749
+
750
+ The provided selector must return the same value when it receieves the same
751
+ inputs. If the selector creates and returns a new object when it runs, you'll
752
+ enter a rerender loop.
753
+
754
+ ### `useNodePos`
755
+
756
+ ```ts
757
+ type useNodePos = () => number;
758
+ ```
759
+
760
+ Like prosemirror-view’s `NodeViewConstructor` API, React ProseMirror passes a
761
+ `getPos` function to all node view components. This function will return the
762
+ current position of the node in the document.
763
+
764
+ `getPos` is guaranteed to always return the correct value for the current node,
765
+ but it will not subscribe a node view component to updates to its position. This
766
+ means that _it is only safe to use `getPos` in a callback or effect_. It is
767
+ _not_ safe to use in a render function, because changes to the node's position
768
+ will not trigger a re-render of the node view component.
769
+
770
+ It’s best to avoid relying on the node’s position in the render function,
771
+ because that will require that your node view component re-render on every
772
+ update to the document. But if you have an infrequently used node, or small
773
+ enough documents that you don't have to worry about this, you can use the
774
+ `useNodePos` function to get an up-to-date node position after every document
775
+ update.
776
+
777
+ ### `useStopEvent`
778
+
779
+ ```tsx
780
+ type useStopEvent = (stopEvent: (this: NodeView, view: EditorView, event: Event) => boolean): void
781
+ ```
782
+
783
+ This hook can be used within a node view component to register a
784
+ [stopEvent handler](https://prosemirror.net/docs/ref/#view.NodeView.stopEvent).
785
+ Events for which this returns true are not handled by the editor.
786
+
787
+ ### `useIgnoreMutation`
788
+
789
+ ```tsx
790
+ type useIgnoreMutation = (ignoreMutation: (this: NodeView | MarkView, view: EditorView, mutation: ViewMutationRecord) => boolean): void
791
+ ```
792
+
793
+ This hook can be used within a node view or mark view component to register an
794
+ [ignoreMutation handler](https://prosemirror.net/docs/ref/#view.NodeView.ignoreMutation).
795
+ Mutations for which this returns true are not handled by the editor.
796
+
797
+ ### `useSelectNode`
798
+
799
+ ```tsx
800
+ type useSelectNode = (selectNode: () => void, deselectNode?: () => void): void
801
+ ```
802
+
803
+ This hook can be used within a node view component to register
804
+ [selectNode and deselectNode handlers](https://prosemirror.net/docs/ref/#view.NodeView.selectNode).
805
+ The selectNode handler will only be called when a NodeSelection is created whose
806
+ node is this one.
807
+
808
+ ### `useIsNodeSelected`
809
+
810
+ ```tsx
811
+ type useIsNodeSelected = (): boolean
812
+ ```
813
+
814
+ This hook can be used within a node view component to subscribe to a boolean
815
+ value determining whether this node is selected. The hook will return true when
816
+ a NodeSelection is created whose node is this one.
817
+
818
+ ### `useIsComposingIn`
819
+
820
+ ```tsx
821
+ type useIsComposingIn = (): boolean
822
+ ```
823
+
824
+ This hook can be used within a node view component to subscribe to a boolean
825
+ value determining whether an IME composition is active inside the node.
826
+
827
+ ### `widget`
828
+
829
+ ```ts
830
+ type widget = (
831
+ pos: number,
832
+ component: ForwardRefExoticComponent<
833
+ RefAttributes<HTMLElement> & WidgetComponentProps
834
+ >,
835
+ spec?: ReactWidgetSpec
836
+ ) => Decoration(pos, pos, new ReactWidgetType(component, spec))
837
+ ```
838
+
839
+ Like ProseMirror View's `Decoration.widget`, but with support for React
840
+ components.
841
+
842
+ ### `reorderSiblings`
843
+
844
+ A [command](https://prosemirror.net/docs/ref/#state.Command) creator that can be
845
+ used to reorder adjacent nodes in a document. The command creator takes two
846
+ arguments:
847
+
848
+ - `pos` — The `start` position of the parent of the nodes being reordered
849
+ - `order` — The new order for the nodes, expressed as an array of indices. For
850
+ example, to swap the first two nodes in a set of three, `order` would be set
851
+ to `[1, 0, 2]`. To move the first node to the end, and keep the other two in
852
+ relative order, set `order` to `[1, 2, 0]`.
853
+
854
+ ```ts
855
+ type reorderSiblings = (pos: number, order: number[]): Command
856
+ ```
857
+
858
+ #### When should I use this?
859
+
860
+ In order to maintain the React state across node view components, React
861
+ ProseMirror uses the `reactKeys` plugin to track node positions across
862
+ transactions and provide them with stable keys. During a reorder, for example
863
+ when two nodes are swapped, ProseMirror is unable to track the positions across
864
+ the resulting delete and insert steps, and so the `reactKeys` plugin will assign
865
+ new keys to the nodes, causing their node view components to be remounted.
866
+
867
+ Sometimes, such as when using a drag-and-drop library like `framer-motion`,
868
+ remounting the component being dragged can cause issues. The `reorderSiblings`
869
+ command provides additional metadata to React ProseMirror that allows it to
870
+ properly track the new positions for the reordered nodes, allowing it to reuse
871
+ the same keys. This prevents any issues that could be caused by unexpected
872
+ component remounts.
873
+
874
+ ## Migrations
875
+
876
+ - [Migrating from v1 to v2](migration-guides/v2.md)
877
+ - [Migrating from v2 to v3](migration-guides/v3.md)
878
+
879
+ ## Looking for someone to collaborate with?
880
+
881
+ Reach out to [Handle with Care](https://handlewithcare.dev/#get-in-touch)! We're
882
+ a product development collective with years of experience bringing excellent
883
+ ideas to life. We love React and ProseMirror, and we're always looking for new
884
+ folks to work with!
885
+
886
+ <!-- NOTE: This section is autogenerated. Do not manually edit.-->
887
+ <!--sponsorsstart-->
888
+
889
+ ## Sponsors
890
+
891
+ The following companies, organizations, and individuals support Pitter Patter's
892
+ ongoing development.
893
+
894
+ Sponsors receive regular updates about development progress, including previews
895
+ of upcoming features, priority getting issues addressed as we release features,
896
+ and a direct line of communication to us for support. Funders above a certain
897
+ threshold join our steering committee — a lightweight governance model where
898
+ significant contributors help shape our roadmap priorities.
899
+
900
+ [Become a Sponsor](https://handlewithcare.dev/pitter-patter/#become-a-sponsor)
901
+
902
+ <h3>Sponsors</h3>
903
+
904
+ <table>
905
+ <tbody>
906
+ <tr>
907
+ <td align="center" valign="top" >
908
+ <a href="https://moment.dev/">
909
+ <img src="https://media.githubusercontent.com/media/handlewithcarecollective/pitter-patter-sponsors/main/logos/Moment.png" alt="Moment" height="128">
910
+ <br>
911
+ Moment
912
+ </a>
913
+ </td>
914
+ <td align="center" valign="top" >
915
+ <a href="https://www.lingco.io/">
916
+ <img src="https://media.githubusercontent.com/media/handlewithcarecollective/pitter-patter-sponsors/main/logos/Lingco.png" alt="Lingco" height="128">
917
+ <br>
918
+ Lingco
919
+ </a>
920
+ </td>
921
+ <td align="center" valign="top" >
922
+ <a href="https://dskrpt.de/">
923
+ <img src="https://media.githubusercontent.com/media/handlewithcarecollective/pitter-patter-sponsors/main/logos/Dskrpt.png" alt="dskrpt" height="128">
924
+ <br>
925
+ dskrpt
926
+ </a>
927
+ </td>
928
+ <td align="center" valign="top" >
929
+ <a href="https://char.com/">
930
+ <img src="https://media.githubusercontent.com/media/handlewithcarecollective/pitter-patter-sponsors/main/logos/Fastrepl.png" alt="Fastrepl" height="128">
931
+ <br>
932
+ Fastrepl
933
+ </a>
934
+ </td>
935
+ </tr>
936
+ </tbody>
937
+ </table>
938
+
939
+ <!--sponsorsend-->