@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,155 @@
1
+ import { DecorationSet } from "prosemirror-view";
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ const none = [], noSpec = {};
4
+ const empty = DecorationSet.empty;
5
+ // An abstraction that allows the code dealing with decorations to
6
+ // treat multiple DecorationSet objects as if it were a single object
7
+ // with (a subset of) the same interface.
8
+ let DecorationGroup = class DecorationGroup {
9
+ members;
10
+ constructor(members){
11
+ this.members = members;
12
+ }
13
+ map(mapping, doc) {
14
+ const mappedDecos = this.members.map((member)=>member.map(mapping, doc, noSpec));
15
+ return DecorationGroup.from(mappedDecos);
16
+ }
17
+ forChild(offset, child) {
18
+ if (child.isLeaf) return DecorationSet.empty;
19
+ let found = [];
20
+ for(let i = 0; i < this.members.length; i++){
21
+ const result = this.members[i].forChild(offset, child);
22
+ if (result == empty) continue;
23
+ if (result instanceof DecorationGroup) found = found.concat(result.members);
24
+ else found.push(result);
25
+ }
26
+ return DecorationGroup.from(found);
27
+ }
28
+ eq(other) {
29
+ if (!(other instanceof DecorationGroup) || other.members.length != this.members.length) return false;
30
+ for(let i = 0; i < this.members.length; i++)if (!this.members[i].eq(other.members[i])) return false;
31
+ return true;
32
+ }
33
+ locals(node) {
34
+ let result, sorted = true;
35
+ for(let i = 0; i < this.members.length; i++){
36
+ const locals = this.members[i].localsInner(node);
37
+ if (!locals.length) continue;
38
+ if (!result) {
39
+ result = locals;
40
+ } else {
41
+ if (sorted) {
42
+ result = result.slice();
43
+ sorted = false;
44
+ }
45
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
46
+ for(let j = 0; j < locals.length; j++)result.push(locals[j]);
47
+ }
48
+ }
49
+ return result ? removeOverlap(sorted ? result : result.sort(byPos)) : none;
50
+ }
51
+ // Create a group for the given array of decoration sets, or return
52
+ // a single set when possible.
53
+ static from(members) {
54
+ switch(members.length){
55
+ case 0:
56
+ return empty;
57
+ case 1:
58
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
59
+ return members[0];
60
+ default:
61
+ return new DecorationGroup(members.every((m)=>m instanceof DecorationSet) ? members : members.reduce((r, m)=>r.concat(m instanceof DecorationSet ? m : m.members), []));
62
+ }
63
+ }
64
+ forEachSet(f) {
65
+ for(let i = 0; i < this.members.length; i++)// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
66
+ this.members[i].forEachSet(f);
67
+ }
68
+ };
69
+ // Used to sort decorations so that ones with a low start position
70
+ // come first, and within a set with the same start position, those
71
+ // with an smaller end position come first.
72
+ function byPos(a, b) {
73
+ return a.from - b.from || a.to - b.to;
74
+ }
75
+ // Scan a sorted array of decorations for partially overlapping spans,
76
+ // and split those so that only fully overlapping spans are left (to
77
+ // make subsequent rendering easier). Will return the input array if
78
+ // no partially overlapping spans are found (the common case).
79
+ function removeOverlap(spans) {
80
+ let working = spans;
81
+ for(let i = 0; i < working.length - 1; i++){
82
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
83
+ const span = working[i];
84
+ if (span.from != span.to) for(let j = i + 1; j < working.length; j++){
85
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
86
+ const next = working[j];
87
+ if (next.from == span.from) {
88
+ if (next.to != span.to) {
89
+ if (working == spans) working = spans.slice();
90
+ // Followed by a partially overlapping larger span. Split that
91
+ // span.
92
+ working[j] = next.copy(next.from, span.to);
93
+ insertAhead(working, j + 1, next.copy(span.to, next.to));
94
+ }
95
+ continue;
96
+ } else {
97
+ if (next.from < span.to) {
98
+ if (working == spans) working = spans.slice();
99
+ // The end of this one overlaps with a subsequent span. Split
100
+ // this one.
101
+ working[i] = span.copy(span.from, next.from);
102
+ insertAhead(working, j, span.copy(next.from, span.to));
103
+ }
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ return working;
109
+ }
110
+ function insertAhead(array, i, deco) {
111
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112
+ while(i < array.length && byPos(deco, array[i]) > 0)i++;
113
+ array.splice(i, 0, deco);
114
+ }
115
+ const ViewDecorationsCache = new WeakMap();
116
+ /**
117
+ * Produces the DecorationSource for the current state, based
118
+ * on the decorations editor prop.
119
+ *
120
+ * The return value of this function is memoized; if it is to
121
+ * return an equivalent value to the last time it was called for
122
+ * a given EditorView, it will return exactly that previous value.
123
+ *
124
+ * This makes it safe to call in a React render function, even
125
+ * if its result is used in a dependencies array for a hook.
126
+ */ export function viewDecorations(view) {
127
+ const found = [];
128
+ view.someProp("decorations", (f)=>{
129
+ const result = f(view.state);
130
+ if (result && result != empty) found.push(result);
131
+ });
132
+ const previous = ViewDecorationsCache.get(view);
133
+ if (!previous) {
134
+ const result = DecorationGroup.from(found);
135
+ ViewDecorationsCache.set(view, result);
136
+ return result;
137
+ }
138
+ let numPrevious = 0;
139
+ let areSetsEqual = true;
140
+ previous.forEachSet((set)=>{
141
+ const next = found[numPrevious++];
142
+ if (next !== set) {
143
+ areSetsEqual = false;
144
+ }
145
+ });
146
+ if (numPrevious !== found.length) {
147
+ areSetsEqual = false;
148
+ }
149
+ if (!areSetsEqual) {
150
+ const result = DecorationGroup.from(found);
151
+ ViewDecorationsCache.set(view, result);
152
+ return result;
153
+ }
154
+ return previous;
155
+ }
@@ -0,0 +1,110 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ export const domIndex = function(node) {
2
+ for(let index = 0;; index++){
3
+ node = node.previousSibling;
4
+ if (!node) return index;
5
+ }
6
+ };
7
+ export const parentNode = function(node) {
8
+ const parent = node.assignedSlot || node.parentNode;
9
+ return parent && parent.nodeType == 11 ? parent.host : parent;
10
+ };
11
+ let reusedRange = null;
12
+ // Note that this will always return the same range, because DOM range
13
+ // objects are every expensive, and keep slowing down subsequent DOM
14
+ // updates, for some reason.
15
+ export const textRange = function(node, from, to) {
16
+ const range = reusedRange || (reusedRange = document.createRange());
17
+ range.setEnd(node, to == null ? node.nodeValue.length : to);
18
+ range.setStart(node, from || 0);
19
+ return range;
20
+ };
21
+ // Scans forward and backward through DOM positions equivalent to the
22
+ // given one to see if the two are in the same place (i.e. after a
23
+ // text node vs at the end of that text node)
24
+ export const isEquivalentPosition = function(node, off, targetNode, targetOff) {
25
+ return targetNode && (scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1));
26
+ };
27
+ const atomElements = /^(img|br|input|textarea|hr)$/i;
28
+ function scanFor(node, off, targetNode, targetOff, dir) {
29
+ for(;;){
30
+ if (node == targetNode && off == targetOff) return true;
31
+ if (off == (dir < 0 ? 0 : nodeSize(node))) {
32
+ const parent = node.parentNode;
33
+ if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) || node.contentEditable == "false") return false;
34
+ off = domIndex(node) + (dir < 0 ? 0 : 1);
35
+ node = parent;
36
+ } else if (node.nodeType == 1) {
37
+ const child = node.childNodes[off + (dir < 0 ? -1 : 0)];
38
+ if (child.nodeType == 1 && child.contentEditable == "false") {
39
+ if (child.pmViewDesc?.ignoreForSelection) off += dir;
40
+ else return false;
41
+ } else {
42
+ node = child;
43
+ off = dir < 0 ? nodeSize(node) : 0;
44
+ }
45
+ } else {
46
+ return false;
47
+ }
48
+ }
49
+ }
50
+ export function nodeSize(node) {
51
+ return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
52
+ }
53
+ export function isOnEdge(node, offset, parent) {
54
+ for(let atStart = offset == 0, atEnd = offset == nodeSize(node); atStart || atEnd;){
55
+ if (node == parent) return true;
56
+ const index = domIndex(node);
57
+ node = node.parentNode;
58
+ if (!node) return false;
59
+ atStart = atStart && index == 0;
60
+ atEnd = atEnd && index == nodeSize(node);
61
+ }
62
+ return false;
63
+ }
64
+ export function hasBlockDesc(dom) {
65
+ let desc;
66
+ for(let cur = dom; cur; cur = cur.parentNode)if (desc = cur.pmViewDesc) break;
67
+ return desc && desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom);
68
+ }
69
+ // Work around Chrome issue https://bugs.chromium.org/p/chromium/issues/detail?id=447523
70
+ // (isCollapsed inappropriately returns true in shadow dom)
71
+ export const selectionCollapsed = function(domSel) {
72
+ return domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);
73
+ };
74
+ export function keyEvent(keyCode, key) {
75
+ const event = document.createEvent("Event");
76
+ event.initEvent("keydown", true, true);
77
+ event.keyCode = keyCode;
78
+ event.key = event.code = key;
79
+ return event;
80
+ }
81
+ export function deepActiveElement(doc) {
82
+ let elt = doc.activeElement;
83
+ while(elt && elt.shadowRoot)elt = elt.shadowRoot.activeElement;
84
+ return elt;
85
+ }
86
+ export function caretFromPoint(doc, x, y) {
87
+ if (doc.caretPositionFromPoint) {
88
+ try {
89
+ // Firefox throws for this call in hard-to-predict circumstances (#994)
90
+ const pos = doc.caretPositionFromPoint(x, y);
91
+ // Clip the offset, because Chrome will return a text offset
92
+ // into <input> nodes, which can't be treated as a regular DOM
93
+ // offset
94
+ if (pos) return {
95
+ node: pos.offsetNode,
96
+ offset: Math.min(nodeSize(pos.offsetNode), pos.offset)
97
+ };
98
+ } catch (_) {
99
+ // pass
100
+ }
101
+ }
102
+ if (doc.caretRangeFromPoint) {
103
+ const range = doc.caretRangeFromPoint(x, y);
104
+ if (range) return {
105
+ node: range.startContainer,
106
+ offset: Math.min(nodeSize(range.startContainer), range.startOffset)
107
+ };
108
+ }
109
+ return;
110
+ }
@@ -0,0 +1,31 @@
1
+ //@ts-expect-error This module isn't typed
2
+ import { findCurrentHostFiber } from "react-reconciler/reflection.js";
3
+ // https://github.com/facebook/react/blob/main/packages/shared/ReactInstanceMap.js#L18
4
+ export function getInstance(key) {
5
+ return key._reactInternals;
6
+ }
7
+ // https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js#L322
8
+ function getPublicInstance(instance) {
9
+ return instance;
10
+ }
11
+ // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberReconciler.js#L153
12
+ function findHostInstance(component) {
13
+ const fiber = getInstance(component);
14
+ if (fiber === undefined) {
15
+ if (typeof component.render === "function") {
16
+ throw new Error("Unable to find node on an unmounted component.");
17
+ } else {
18
+ const keys = Object.keys(component).join(",");
19
+ throw new Error(`Argument appears to not be a ReactComponent. Keys: ${keys}`);
20
+ }
21
+ }
22
+ const hostFiber = findCurrentHostFiber(fiber);
23
+ if (hostFiber === null) {
24
+ return null;
25
+ }
26
+ return getPublicInstance(hostFiber.stateNode);
27
+ }
28
+ // https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOMClient.js#L43
29
+ export function findDOMNode(componentOrElement) {
30
+ return findHostInstance(componentOrElement);
31
+ }
@@ -0,0 +1,9 @@
1
+ import { useLayoutEffect } from "react";
2
+ export function useClientLayoutEffect() {
3
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
4
+ args[_key] = arguments[_key];
5
+ }
6
+ if (typeof document === "undefined") return;
7
+ // eslint-disable-next-line react-hooks/rules-of-hooks, react-hooks/exhaustive-deps
8
+ useLayoutEffect(...args);
9
+ }
@@ -0,0 +1,87 @@
1
+ /* Copyright (c) The New York Times Company */ import { useCallback, useLayoutEffect, useMemo, useState } from "react";
2
+ import { unstable_batchedUpdates as batch } from "react-dom";
3
+ /**
4
+ * Produces a plugin that can be used with ProseMirror to handle DOM
5
+ * events at the EditorView.dom element.
6
+ *
7
+ * - `reactEventsPlugin` is a ProseMirror plugin for handling DOM events
8
+ * at the EditorView.dom element. It should be passed to `useEditorView`,
9
+ * along with any other plugins.
10
+ *
11
+ * - `registerEventListener` and `unregisterEventListener` should be
12
+ * passed to `EditorContext.Provider`.
13
+ *
14
+ * @privateRemarks
15
+ *
16
+ * This hook uses a combination of mutable and immutable updates to give
17
+ * us precise control over when we re-create the event listeners.
18
+ *
19
+ * The hook has a mutable reference to the set of handlers for each
20
+ * event type, but the set of event types is static. This means that we
21
+ * need to produce a new handleDOMEVents record whenever a new event type is
22
+ * registered. We avoid producing a new record in any other
23
+ * scenario to avoid the performance overhead of re-registering the event
24
+ * listeners in the EditorView.
25
+ *
26
+ * To accomplish this, we shallowly clone the registry whenever a new event
27
+ * type is registered.
28
+ */ export function useComponentEventListeners(handleDOMEventsProp) {
29
+ const [registry, setRegistry] = useState(new Map());
30
+ const registerEventListener = useCallback((eventType, handler)=>{
31
+ const handlers = registry.get(eventType) ?? [];
32
+ handlers.unshift(handler);
33
+ if (!registry.has(eventType)) {
34
+ registry.set(eventType, handlers);
35
+ setRegistry(new Map(registry));
36
+ }
37
+ }, [
38
+ registry
39
+ ]);
40
+ const unregisterEventListener = useCallback((eventType, handler)=>{
41
+ const handlers = registry.get(eventType);
42
+ handlers?.splice(handlers.indexOf(handler), 1);
43
+ }, [
44
+ registry
45
+ ]);
46
+ useLayoutEffect(()=>{
47
+ if (!handleDOMEventsProp) return;
48
+ for (const [eventType, handler] of Object.entries(handleDOMEventsProp)){
49
+ if (!handler) return;
50
+ registerEventListener(eventType, handler);
51
+ }
52
+ return ()=>{
53
+ for (const [eventType, handler] of Object.entries(handleDOMEventsProp)){
54
+ if (!handler) return;
55
+ unregisterEventListener(eventType, handler);
56
+ }
57
+ };
58
+ }, [
59
+ handleDOMEventsProp,
60
+ registerEventListener,
61
+ unregisterEventListener
62
+ ]);
63
+ const handleDOMEvents = useMemo(()=>{
64
+ const domEventHandlers = {};
65
+ for (const [eventType, handlers] of registry.entries()){
66
+ function handleEvent(view, event) {
67
+ for (const handler of handlers){
68
+ let handled = false;
69
+ batch(()=>{
70
+ handled = !!handler(view, event);
71
+ });
72
+ if (handled || event.defaultPrevented) return true;
73
+ }
74
+ return false;
75
+ }
76
+ domEventHandlers[eventType] = handleEvent;
77
+ }
78
+ return domEventHandlers;
79
+ }, [
80
+ registry
81
+ ]);
82
+ return {
83
+ registerEventListener,
84
+ unregisterEventListener,
85
+ handleDOMEvents
86
+ };
87
+ }
@@ -0,0 +1,128 @@
1
+ import { useCallback, useMemo, useRef, useState } from "react";
2
+ import { flushSync } from "react-dom";
3
+ import { ReactEditorView } from "../ReactEditorView.js";
4
+ import { StaticEditorView } from "../StaticEditorView.js";
5
+ import { EMPTY_STATE } from "../constants.js";
6
+ import { createRenderStore } from "../contexts/RenderStoreContext.js";
7
+ import { beforeInputPlugin } from "../plugins/beforeInputPlugin.js";
8
+ import { useClientLayoutEffect } from "./useClientLayoutEffect.js";
9
+ import { useComponentEventListeners } from "./useComponentEventListeners.js";
10
+ import { useEffectEvent } from "./useEffectEvent.js";
11
+ import { useForceUpdate } from "./useForceUpdate.js";
12
+ let didWarnValueDefaultValue = false;
13
+ /**
14
+ * Creates, mounts, and manages a ProseMirror `EditorView`.
15
+ *
16
+ * All state and props updates are executed in a layout effect.
17
+ * To ensure that the EditorState and EditorView are never out of
18
+ * sync, it's important that the EditorView produced by this hook
19
+ * is only accessed through the `useEditorViewEvent` and
20
+ * `useEditorViewLayoutEffect` hooks.
21
+ */ export function useEditor(mount, options) {
22
+ if (process.env.NODE_ENV !== "production") {
23
+ if (options.defaultState !== undefined && options.state !== undefined && !didWarnValueDefaultValue) {
24
+ console.error("A component contains a ProseMirror editor with both state and defaultState props. " + "ProseMirror editors must be either controlled or uncontrolled " + "(specify either the state prop, or the defaultState prop, but not both). " + "Decide between using a controlled or uncontrolled ProseMirror editor " + "and remove one of these props. More info: " + "https://reactjs.org/link/controlled-components");
25
+ didWarnValueDefaultValue = true;
26
+ }
27
+ }
28
+ const flushSyncRef = useRef(true);
29
+ const forceUpdate = useForceUpdate();
30
+ const defaultState = options.defaultState ?? EMPTY_STATE;
31
+ const [_state, setState] = useState(defaultState);
32
+ const state = options.state ?? _state;
33
+ const [renderStore] = useState(createRenderStore);
34
+ const { handleDOMEvents, registerEventListener, unregisterEventListener } = useComponentEventListeners(options.handleDOMEvents);
35
+ const plugins = useMemo(()=>[
36
+ ...options.plugins ?? [],
37
+ beforeInputPlugin()
38
+ ], [
39
+ options.plugins
40
+ ]);
41
+ const dispatchTransaction = useCallback(function dispatchTransaction(tr) {
42
+ const async = tr.getMeta("async");
43
+ if (flushSyncRef.current && !async) {
44
+ flushSync(()=>{
45
+ if (!options.state) {
46
+ setState((s)=>s.apply(tr));
47
+ }
48
+ if (options.dispatchTransaction) {
49
+ options.dispatchTransaction.call(this, tr);
50
+ }
51
+ if (options.stableContexts) {
52
+ renderStore.announce();
53
+ }
54
+ });
55
+ renderStore.announced = false;
56
+ } else {
57
+ if (!options.state) {
58
+ setState((s)=>s.apply(tr));
59
+ }
60
+ if (options.dispatchTransaction) {
61
+ options.dispatchTransaction.call(this, tr);
62
+ }
63
+ }
64
+ }, [
65
+ options.dispatchTransaction,
66
+ options.state,
67
+ options.stableContexts,
68
+ renderStore
69
+ ]);
70
+ const directEditorProps = {
71
+ ...options,
72
+ state,
73
+ plugins,
74
+ dispatchTransaction,
75
+ handleDOMEvents
76
+ };
77
+ const [view, setView] = useState(()=>{
78
+ return new StaticEditorView(directEditorProps);
79
+ });
80
+ const createEditorView = useEffectEvent((mount)=>{
81
+ if (mount && !options.static) {
82
+ const view = new ReactEditorView({
83
+ mount
84
+ }, directEditorProps);
85
+ view.dom.addEventListener("compositionend", forceUpdate);
86
+ return view;
87
+ }
88
+ return new StaticEditorView(directEditorProps);
89
+ });
90
+ useClientLayoutEffect(()=>{
91
+ const view = createEditorView(mount);
92
+ setView(view);
93
+ return ()=>{
94
+ view.destroy();
95
+ };
96
+ }, [
97
+ createEditorView,
98
+ mount
99
+ ]);
100
+ useClientLayoutEffect(()=>{
101
+ // Ensure that the EditorView hasn't been destroyed before
102
+ // running effects. Running effects will reattach selection
103
+ // change listeners if the EditorView has been destroyed.
104
+ if (view instanceof ReactEditorView && !view.isDestroyed && view.domSelection()) {
105
+ flushSyncRef.current = false;
106
+ view.commitPendingEffects();
107
+ flushSyncRef.current = true;
108
+ }
109
+ });
110
+ view.update(directEditorProps);
111
+ const editor = useMemo(()=>({
112
+ view,
113
+ flushSyncRef,
114
+ registerEventListener,
115
+ unregisterEventListener,
116
+ isStatic: options.static ?? false
117
+ }), [
118
+ options.static,
119
+ registerEventListener,
120
+ unregisterEventListener,
121
+ view
122
+ ]);
123
+ return {
124
+ editor,
125
+ state,
126
+ renderStore: options.stableContexts ? renderStore : null
127
+ };
128
+ }
@@ -0,0 +1,46 @@
1
+ /* Copyright (c) The New York Times Company */ import { useContext } from "react";
2
+ import { ReactEditorView } from "../ReactEditorView.js";
3
+ import { EditorContext } from "../contexts/EditorContext.js";
4
+ import { useLayoutGroupEffect } from "./useLayoutGroupEffect.js";
5
+ /**
6
+ * Registers a layout effect to run after the EditorView has
7
+ * been updated with the latest EditorState and Decorations.
8
+ *
9
+ * Effects can take an EditorView instance as an argument.
10
+ * This hook should be used to execute layout effects that
11
+ * depend on the EditorView, such as for positioning DOM
12
+ * nodes based on ProseMirror positions.
13
+ *
14
+ * Layout effects registered with this hook still fire
15
+ * synchronously after all DOM mutations, but they do so
16
+ * _after_ the EditorView has been updated, even when the
17
+ * EditorView lives in an ancestor component.
18
+ *
19
+ * This hook can only be used in a component that is mounted
20
+ * as a child of the TiptapEditorView component, including
21
+ * React node view components.
22
+ */ export function useEditorEffect(effect, dependencies) {
23
+ const { view, flushSyncRef } = useContext(EditorContext);
24
+ // The rules of hooks want `effect` to be included in the
25
+ // dependency list, but dependency issues for `effect` will
26
+ // be caught by the linter at the call-site for
27
+ // `useEditorViewLayoutEffect`.
28
+ // Note: we specifically don't want to re-run the effect
29
+ // every time it changes, because it will most likely
30
+ // be defined inline and run on every re-render.
31
+ useLayoutGroupEffect(()=>{
32
+ if (view instanceof ReactEditorView) {
33
+ flushSyncRef.current = false;
34
+ const result = effect(view);
35
+ flushSyncRef.current = true;
36
+ return result;
37
+ }
38
+ }, // The rules of hooks want to be able to statically
39
+ // verify the dependencies for the effect, but this will
40
+ // have already happened at the call-site.
41
+ // eslint-disable-next-line react-hooks/exhaustive-deps
42
+ dependencies && [
43
+ view,
44
+ ...dependencies
45
+ ]);
46
+ }
@@ -0,0 +1,38 @@
1
+ /* Copyright (c) The New York Times Company */ import { useCallback, useContext, useRef } from "react";
2
+ import { ReactEditorView } from "../ReactEditorView.js";
3
+ import { EditorContext } from "../contexts/EditorContext.js";
4
+ import { useEditorEffect } from "./useEditorEffect.js";
5
+ function assertIsReactEditorView(view) {
6
+ if (view instanceof ReactEditorView) {
7
+ return;
8
+ }
9
+ throw new DOMException("ProseMirror document is not mounted", "InvalidStateError");
10
+ }
11
+ /**
12
+ * Returns a stable function reference to be used as an
13
+ * event handler callback.
14
+ *
15
+ * The callback will be called with the EditorView instance
16
+ * as its first argument.
17
+ *
18
+ * This hook can only be used in a component that is mounted
19
+ * as a child of the TiptapEditorView component, including
20
+ * React node view components.
21
+ */ export function useEditorEventCallback(callback) {
22
+ const ref = useRef(callback);
23
+ const { view } = useContext(EditorContext);
24
+ useEditorEffect(()=>{
25
+ ref.current = callback;
26
+ }, [
27
+ callback
28
+ ]);
29
+ return useCallback(function() {
30
+ for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
31
+ args[_key] = arguments[_key];
32
+ }
33
+ assertIsReactEditorView(view);
34
+ return ref.current.call(this, view, ...args);
35
+ }, [
36
+ view
37
+ ]);
38
+ }
@@ -0,0 +1,28 @@
1
+ /* Copyright (c) The New York Times Company */ import { useCallback, useContext, useRef } from "react";
2
+ import { EditorContext } from "../contexts/EditorContext.js";
3
+ import { useEditorEffect } from "./useEditorEffect.js";
4
+ /**
5
+ * Attaches an event listener at the `EditorView`'s DOM node. See
6
+ * [the ProseMirror docs](https://prosemirror.net/docs/ref/#view.EditorProps.handleDOMEvents)
7
+ * for more details.
8
+ */ export function useEditorEventListener(eventType, handler) {
9
+ const { registerEventListener, unregisterEventListener } = useContext(EditorContext);
10
+ const ref = useRef(handler);
11
+ useEditorEffect(()=>{
12
+ ref.current = handler;
13
+ }, [
14
+ handler
15
+ ]);
16
+ const eventHandler = useCallback(function(view, event) {
17
+ return ref.current.call(this, view, event);
18
+ }, []);
19
+ useEditorEffect(()=>{
20
+ registerEventListener(eventType, eventHandler);
21
+ return ()=>unregisterEventListener(eventType, eventHandler);
22
+ }, [
23
+ eventHandler,
24
+ eventType,
25
+ registerEventListener,
26
+ unregisterEventListener
27
+ ]);
28
+ }
@@ -0,0 +1,10 @@
1
+ /* Copyright (c) The New York Times Company */ import { useContext } from "react";
2
+ import { EditorStateContext } from "../contexts/EditorStateContext.js";
3
+ import { useRenderStore } from "../contexts/RenderStoreContext.js";
4
+ /**
5
+ * Provides access to the current EditorState value.
6
+ */ export function useEditorState() {
7
+ const editorState = useContext(EditorStateContext);
8
+ const store = useRenderStore();
9
+ return store?.state ?? editorState;
10
+ }
@@ -0,0 +1,14 @@
1
+ import { useContext, useSyncExternalStore } from "react";
2
+ import { EditorStateStoreContext } from "../contexts/EditorStateStoreContext.js";
3
+ /**
4
+ * Select a piece of the EditorState, a la Redux’s
5
+ * `useSelector`.
6
+ *
7
+ * This hook will only trigger a re-render of the
8
+ * consuming component if the return value of the selector
9
+ * changes.
10
+ */ export function useEditorStateSelector(selector) {
11
+ const store = useContext(EditorStateStoreContext);
12
+ const getSnapshot = ()=>selector(store.getState());
13
+ return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
14
+ }