@handlewithcare/react-prosemirror 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/LICENSE.txt +12 -0
  2. package/README.md +705 -0
  3. package/dist/cjs/browser.js +53 -0
  4. package/dist/cjs/components/ChildNodeViews.js +376 -0
  5. package/dist/cjs/components/CursorWrapper.js +91 -0
  6. package/dist/cjs/components/CustomNodeView.js +79 -0
  7. package/dist/cjs/components/DocNodeView.js +104 -0
  8. package/dist/cjs/components/LayoutGroup.js +111 -0
  9. package/dist/cjs/components/MarkView.js +115 -0
  10. package/dist/cjs/components/NativeWidgetView.js +109 -0
  11. package/dist/cjs/components/NodeView.js +196 -0
  12. package/dist/cjs/components/NodeViewComponentProps.js +4 -0
  13. package/dist/cjs/components/OutputSpec.js +88 -0
  14. package/dist/cjs/components/ProseMirror.js +103 -0
  15. package/dist/cjs/components/ProseMirrorDoc.js +92 -0
  16. package/dist/cjs/components/SeparatorHackView.js +100 -0
  17. package/dist/cjs/components/TextNodeView.js +112 -0
  18. package/dist/cjs/components/TrailingHackView.js +90 -0
  19. package/dist/cjs/components/WidgetView.js +95 -0
  20. package/dist/cjs/components/WidgetViewComponentProps.js +4 -0
  21. package/dist/cjs/components/__tests__/ProseMirror.composition.test.js +398 -0
  22. package/dist/cjs/components/__tests__/ProseMirror.domchange.test.js +270 -0
  23. package/dist/cjs/components/__tests__/ProseMirror.draw-decoration.test.js +1010 -0
  24. package/dist/cjs/components/__tests__/ProseMirror.draw.test.js +337 -0
  25. package/dist/cjs/components/__tests__/ProseMirror.node-view.test.js +315 -0
  26. package/dist/cjs/components/__tests__/ProseMirror.selection.test.js +444 -0
  27. package/dist/cjs/components/__tests__/ProseMirror.test.js +382 -0
  28. package/dist/cjs/contexts/ChildDescriptorsContext.js +19 -0
  29. package/dist/cjs/contexts/EditorContext.js +12 -0
  30. package/dist/cjs/contexts/EditorStateContext.js +12 -0
  31. package/dist/cjs/contexts/LayoutGroupContext.js +12 -0
  32. package/dist/cjs/contexts/NodeViewContext.js +12 -0
  33. package/dist/cjs/contexts/SelectNodeContext.js +12 -0
  34. package/dist/cjs/contexts/StopEventContext.js +12 -0
  35. package/dist/cjs/contexts/__tests__/DeferredLayoutEffects.test.js +141 -0
  36. package/dist/cjs/decorations/ReactWidgetType.js +58 -0
  37. package/dist/cjs/decorations/computeDocDeco.js +44 -0
  38. package/dist/cjs/decorations/internalTypes.js +4 -0
  39. package/dist/cjs/decorations/iterDeco.js +79 -0
  40. package/dist/cjs/decorations/viewDecorations.js +163 -0
  41. package/dist/cjs/dom.js +142 -0
  42. package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +108 -0
  43. package/dist/cjs/hooks/useClientOnly.js +18 -0
  44. package/dist/cjs/hooks/useComponentEventListeners.js +39 -0
  45. package/dist/cjs/hooks/useEditor.js +287 -0
  46. package/dist/cjs/hooks/useEditorEffect.js +35 -0
  47. package/dist/cjs/hooks/useEditorEventCallback.js +33 -0
  48. package/dist/cjs/hooks/useEditorEventListener.js +34 -0
  49. package/dist/cjs/hooks/useEditorState.js +16 -0
  50. package/dist/cjs/hooks/useForceUpdate.js +15 -0
  51. package/dist/cjs/hooks/useLayoutGroupEffect.js +19 -0
  52. package/dist/cjs/hooks/useNodeViewDescriptor.js +115 -0
  53. package/dist/cjs/hooks/useReactKeys.js +17 -0
  54. package/dist/cjs/hooks/useSelectNode.js +28 -0
  55. package/dist/cjs/hooks/useStopEvent.js +24 -0
  56. package/dist/cjs/index.js +53 -0
  57. package/dist/cjs/package.json +3 -0
  58. package/dist/cjs/plugins/__tests__/reactKeys.test.js +81 -0
  59. package/dist/cjs/plugins/beforeInputPlugin.js +143 -0
  60. package/dist/cjs/plugins/componentEventListeners.js +35 -0
  61. package/dist/cjs/plugins/componentEventListenersPlugin.js +35 -0
  62. package/dist/cjs/plugins/reactKeys.js +96 -0
  63. package/dist/cjs/props.js +269 -0
  64. package/dist/cjs/selection/SelectionDOMObserver.js +174 -0
  65. package/dist/cjs/selection/hasFocusAndSelection.js +35 -0
  66. package/dist/cjs/selection/selectionFromDOM.js +77 -0
  67. package/dist/cjs/selection/selectionToDOM.js +226 -0
  68. package/dist/cjs/ssr.js +85 -0
  69. package/dist/cjs/testing/editorViewTestHelpers.js +111 -0
  70. package/dist/cjs/testing/setupProseMirrorView.js +94 -0
  71. package/dist/cjs/viewdesc.js +664 -0
  72. package/dist/esm/browser.js +43 -0
  73. package/dist/esm/components/ChildNodeViews.js +318 -0
  74. package/dist/esm/components/CursorWrapper.js +40 -0
  75. package/dist/esm/components/CustomNodeView.js +28 -0
  76. package/dist/esm/components/DocNodeView.js +53 -0
  77. package/dist/esm/components/LayoutGroup.js +66 -0
  78. package/dist/esm/components/MarkView.js +64 -0
  79. package/dist/esm/components/NativeWidgetView.js +58 -0
  80. package/dist/esm/components/NodeView.js +145 -0
  81. package/dist/esm/components/NodeViewComponentProps.js +1 -0
  82. package/dist/esm/components/OutputSpec.js +38 -0
  83. package/dist/esm/components/ProseMirror.js +52 -0
  84. package/dist/esm/components/ProseMirrorDoc.js +34 -0
  85. package/dist/esm/components/SeparatorHackView.js +49 -0
  86. package/dist/esm/components/TextNodeView.js +102 -0
  87. package/dist/esm/components/TrailingHackView.js +39 -0
  88. package/dist/esm/components/WidgetView.js +44 -0
  89. package/dist/esm/components/WidgetViewComponentProps.js +1 -0
  90. package/dist/esm/components/__tests__/ProseMirror.composition.test.js +395 -0
  91. package/dist/esm/components/__tests__/ProseMirror.domchange.test.js +266 -0
  92. package/dist/esm/components/__tests__/ProseMirror.draw-decoration.test.js +967 -0
  93. package/dist/esm/components/__tests__/ProseMirror.draw.test.js +294 -0
  94. package/dist/esm/components/__tests__/ProseMirror.node-view.test.js +272 -0
  95. package/dist/esm/components/__tests__/ProseMirror.selection.test.js +440 -0
  96. package/dist/esm/components/__tests__/ProseMirror.test.js +339 -0
  97. package/dist/esm/contexts/ChildDescriptorsContext.js +9 -0
  98. package/dist/esm/contexts/EditorContext.js +7 -0
  99. package/dist/esm/contexts/EditorStateContext.js +2 -0
  100. package/dist/esm/contexts/LayoutGroupContext.js +2 -0
  101. package/dist/esm/contexts/NodeViewContext.js +2 -0
  102. package/dist/esm/contexts/SelectNodeContext.js +2 -0
  103. package/dist/esm/contexts/StopEventContext.js +2 -0
  104. package/dist/esm/contexts/__tests__/DeferredLayoutEffects.test.js +98 -0
  105. package/dist/esm/decorations/ReactWidgetType.js +40 -0
  106. package/dist/esm/decorations/computeDocDeco.js +44 -0
  107. package/dist/esm/decorations/internalTypes.js +1 -0
  108. package/dist/esm/decorations/iterDeco.js +73 -0
  109. package/dist/esm/decorations/viewDecorations.js +163 -0
  110. package/dist/esm/dom.js +105 -0
  111. package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +99 -0
  112. package/dist/esm/hooks/useClientOnly.js +8 -0
  113. package/dist/esm/hooks/useComponentEventListeners.js +54 -0
  114. package/dist/esm/hooks/useEditor.js +278 -0
  115. package/dist/esm/hooks/useEditorEffect.js +38 -0
  116. package/dist/esm/hooks/useEditorEventCallback.js +35 -0
  117. package/dist/esm/hooks/useEditorEventListener.js +28 -0
  118. package/dist/esm/hooks/useEditorState.js +8 -0
  119. package/dist/esm/hooks/useForceUpdate.js +8 -0
  120. package/dist/esm/hooks/useLayoutGroupEffect.js +9 -0
  121. package/dist/esm/hooks/useNodeViewDescriptor.js +105 -0
  122. package/dist/esm/hooks/useReactKeys.js +7 -0
  123. package/dist/esm/hooks/useSelectNode.js +18 -0
  124. package/dist/esm/hooks/useStopEvent.js +14 -0
  125. package/dist/esm/index.js +11 -0
  126. package/dist/esm/plugins/__tests__/reactKeys.test.js +77 -0
  127. package/dist/esm/plugins/beforeInputPlugin.js +133 -0
  128. package/dist/esm/plugins/componentEventListeners.js +25 -0
  129. package/dist/esm/plugins/componentEventListenersPlugin.js +25 -0
  130. package/dist/esm/plugins/reactKeys.js +81 -0
  131. package/dist/esm/props.js +251 -0
  132. package/dist/esm/selection/SelectionDOMObserver.js +164 -0
  133. package/dist/esm/selection/hasFocusAndSelection.js +17 -0
  134. package/dist/esm/selection/selectionFromDOM.js +59 -0
  135. package/dist/esm/selection/selectionToDOM.js +196 -0
  136. package/dist/esm/ssr.js +82 -0
  137. package/dist/esm/testing/editorViewTestHelpers.js +88 -0
  138. package/dist/esm/testing/setupProseMirrorView.js +76 -0
  139. package/dist/esm/viewdesc.js +654 -0
  140. package/dist/tsconfig.tsbuildinfo +1 -0
  141. package/dist/types/browser.d.ts +15 -0
  142. package/dist/types/components/ChildNodeViews.d.ts +9 -0
  143. package/dist/types/components/CursorWrapper.d.ts +5 -0
  144. package/dist/types/components/CustomNodeView.d.ts +21 -0
  145. package/dist/types/components/DocNodeView.d.ts +20 -0
  146. package/dist/types/components/LayoutGroup.d.ts +12 -0
  147. package/dist/types/components/MarkView.d.ts +9 -0
  148. package/dist/types/components/NativeWidgetView.d.ts +8 -0
  149. package/dist/types/components/NodeView.d.ts +11 -0
  150. package/dist/types/components/NodeViewComponentProps.d.ts +12 -0
  151. package/dist/types/components/OutputSpec.d.ts +8 -0
  152. package/dist/types/components/ProseMirror.d.ts +15 -0
  153. package/dist/types/components/ProseMirrorDoc.d.ts +10 -0
  154. package/dist/types/components/SeparatorHackView.d.ts +6 -0
  155. package/dist/types/components/TextNodeView.d.ts +23 -0
  156. package/dist/types/components/TrailingHackView.d.ts +6 -0
  157. package/dist/types/components/WidgetView.d.ts +8 -0
  158. package/dist/types/components/WidgetViewComponentProps.d.ts +6 -0
  159. package/dist/types/components/__tests__/ProseMirror.composition.test.d.ts +1 -0
  160. package/dist/types/components/__tests__/ProseMirror.domchange.test.d.ts +1 -0
  161. package/dist/types/components/__tests__/ProseMirror.draw-decoration.test.d.ts +1 -0
  162. package/dist/types/components/__tests__/ProseMirror.draw.test.d.ts +1 -0
  163. package/dist/types/components/__tests__/ProseMirror.node-view.test.d.ts +1 -0
  164. package/dist/types/components/__tests__/ProseMirror.selection.test.d.ts +1 -0
  165. package/dist/types/components/__tests__/ProseMirror.test.d.ts +1 -0
  166. package/dist/types/contexts/ChildDescriptorsContext.d.ts +6 -0
  167. package/dist/types/contexts/EditorContext.d.ts +14 -0
  168. package/dist/types/contexts/EditorStateContext.d.ts +2 -0
  169. package/dist/types/contexts/LayoutGroupContext.d.ts +5 -0
  170. package/dist/types/contexts/NodeViewContext.d.ts +6 -0
  171. package/dist/types/contexts/SelectNodeContext.d.ts +3 -0
  172. package/dist/types/contexts/StopEventContext.d.ts +3 -0
  173. package/dist/types/contexts/__tests__/DeferredLayoutEffects.test.d.ts +1 -0
  174. package/dist/types/decorations/ReactWidgetType.d.ts +39 -0
  175. package/dist/types/decorations/computeDocDeco.d.ts +13 -0
  176. package/dist/types/decorations/internalTypes.d.ts +16 -0
  177. package/dist/types/decorations/iterDeco.d.ts +3 -0
  178. package/dist/types/decorations/viewDecorations.d.ts +13 -0
  179. package/dist/types/dom.d.ts +22 -0
  180. package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +1 -0
  181. package/dist/types/hooks/useClientOnly.d.ts +1 -0
  182. package/dist/types/hooks/useComponentEventListeners.d.ts +33 -0
  183. package/dist/types/hooks/useEditor.d.ts +66 -0
  184. package/dist/types/hooks/useEditorEffect.d.ts +17 -0
  185. package/dist/types/hooks/useEditorEventCallback.d.ts +15 -0
  186. package/dist/types/hooks/useEditorEventListener.d.ts +8 -0
  187. package/dist/types/hooks/useEditorState.d.ts +5 -0
  188. package/dist/types/hooks/useForceUpdate.d.ts +5 -0
  189. package/dist/types/hooks/useLayoutGroupEffect.d.ts +3 -0
  190. package/dist/types/hooks/useNodeViewDescriptor.d.ts +11 -0
  191. package/dist/types/hooks/useReactKeys.d.ts +5 -0
  192. package/dist/types/hooks/useSelectNode.d.ts +1 -0
  193. package/dist/types/hooks/useStopEvent.d.ts +2 -0
  194. package/dist/types/index.d.ts +12 -0
  195. package/dist/types/plugins/__tests__/reactKeys.test.d.ts +1 -0
  196. package/dist/types/plugins/beforeInputPlugin.d.ts +3 -0
  197. package/dist/types/plugins/componentEventListeners.d.ts +4 -0
  198. package/dist/types/plugins/componentEventListenersPlugin.d.ts +4 -0
  199. package/dist/types/plugins/reactKeys.d.ts +19 -0
  200. package/dist/types/props.d.ts +1174 -0
  201. package/dist/types/selection/SelectionDOMObserver.d.ts +34 -0
  202. package/dist/types/selection/hasFocusAndSelection.d.ts +3 -0
  203. package/dist/types/selection/selectionFromDOM.d.ts +4 -0
  204. package/dist/types/selection/selectionToDOM.d.ts +9 -0
  205. package/dist/types/ssr.d.ts +19 -0
  206. package/dist/types/testing/editorViewTestHelpers.d.ts +23 -0
  207. package/dist/types/testing/setupProseMirrorView.d.ts +2 -0
  208. package/dist/types/viewdesc.d.ts +131 -0
  209. package/package.json +113 -0
@@ -0,0 +1,294 @@
1
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */ function _extends() {
2
+ _extends = Object.assign || function(target) {
3
+ for(var i = 1; i < arguments.length; i++){
4
+ var source = arguments[i];
5
+ for(var key in source){
6
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
7
+ target[key] = source[key];
8
+ }
9
+ }
10
+ }
11
+ return target;
12
+ };
13
+ return _extends.apply(this, arguments);
14
+ }
15
+ import { Schema } from "prosemirror-model";
16
+ import { Plugin } from "prosemirror-state";
17
+ import { doc, h1, hr, img, p, pre, schema, strong } from "prosemirror-test-builder";
18
+ import React, { forwardRef } from "react";
19
+ import { tempEditor } from "../../testing/editorViewTestHelpers.js";
20
+ describe("EditorView draw", ()=>{
21
+ it("updates the DOM", async ()=>{
22
+ const { view } = tempEditor({
23
+ doc: doc(p("foo"))
24
+ });
25
+ view.dispatch(view.state.tr.insertText("bar"));
26
+ expect(view.dom.textContent).toBe("barfoo");
27
+ });
28
+ it("doesn't redraw nodes after changes", async ()=>{
29
+ const { view } = tempEditor({
30
+ doc: doc(h1("foo<a>"), p("bar"))
31
+ });
32
+ const oldP = view.dom.querySelector("p");
33
+ view.dispatch(view.state.tr.insertText("!"));
34
+ expect(view.dom.querySelector("p")).toBe(oldP);
35
+ });
36
+ it("doesn't redraw nodes before changes", async ()=>{
37
+ const { view } = tempEditor({
38
+ doc: doc(p("foo"), h1("bar"))
39
+ });
40
+ const oldP = view.dom.querySelector("p");
41
+ view.dispatch(view.state.tr.insertText("!", 2));
42
+ expect(view.dom.querySelector("p")).toBe(oldP);
43
+ });
44
+ it("doesn't redraw nodes between changes", async ()=>{
45
+ const { view } = tempEditor({
46
+ doc: doc(p("foo"), h1("bar"), pre("baz"))
47
+ });
48
+ const oldP = view.dom.querySelector("p");
49
+ const oldPre = view.dom.querySelector("pre");
50
+ view.dispatch(view.state.tr.insertText("!", 2));
51
+ expect(view.dom.querySelector("p")).toBe(oldP);
52
+ expect(view.dom.querySelector("pre")).toBe(oldPre);
53
+ });
54
+ it("doesn't redraw siblings of a split node", async ()=>{
55
+ const { view } = tempEditor({
56
+ doc: doc(p("foo"), h1("bar"), pre("baz"))
57
+ });
58
+ const oldP = view.dom.querySelector("p");
59
+ const oldPre = view.dom.querySelector("pre");
60
+ view.dispatch(view.state.tr.split(8));
61
+ expect(view.dom.querySelector("p")).toBe(oldP);
62
+ expect(view.dom.querySelector("pre")).toBe(oldPre);
63
+ });
64
+ it("doesn't redraw siblings of a joined node", async ()=>{
65
+ const { view } = tempEditor({
66
+ doc: doc(p("foo"), h1("bar"), h1("x"), pre("baz"))
67
+ });
68
+ const oldP = view.dom.querySelector("p");
69
+ const oldPre = view.dom.querySelector("pre");
70
+ view.dispatch(view.state.tr.join(10));
71
+ expect(view.dom.querySelector("p")).toBe(oldP);
72
+ expect(view.dom.querySelector("pre")).toBe(oldPre);
73
+ });
74
+ it("doesn't redraw after a big deletion", async ()=>{
75
+ const { view } = tempEditor({
76
+ doc: doc(p(), p(), p(), p(), p(), p(), p(), p(), h1("!"), p(), p())
77
+ });
78
+ const oldH = view.dom.querySelector("h1");
79
+ view.dispatch(view.state.tr.delete(2, 14));
80
+ expect(view.dom.querySelector("h1")).toBe(oldH);
81
+ });
82
+ it("adds classes from the attributes prop", async ()=>{
83
+ const { view , rerender } = tempEditor({
84
+ doc: doc(p()),
85
+ attributes: {
86
+ class: "foo bar"
87
+ }
88
+ });
89
+ expect(view.dom.classList.contains("foo")).toBeTruthy();
90
+ expect(view.dom.classList.contains("bar")).toBeTruthy();
91
+ expect(view.dom.classList.contains("ProseMirror")).toBeTruthy();
92
+ rerender({
93
+ attributes: {
94
+ class: "baz"
95
+ }
96
+ });
97
+ expect(!view.dom.classList.contains("foo")).toBeTruthy();
98
+ expect(view.dom.classList.contains("baz")).toBeTruthy();
99
+ });
100
+ it("adds style from the attributes prop", async ()=>{
101
+ const { view } = tempEditor({
102
+ doc: doc(p()),
103
+ attributes: {
104
+ style: "border: 1px solid red;"
105
+ },
106
+ plugins: [
107
+ new Plugin({
108
+ props: {
109
+ attributes: {
110
+ style: "background: red;"
111
+ }
112
+ }
113
+ }),
114
+ new Plugin({
115
+ props: {
116
+ attributes: {
117
+ style: "color: red;"
118
+ }
119
+ }
120
+ })
121
+ ]
122
+ });
123
+ expect(view.dom.style.border).toBe("1px solid red");
124
+ expect(view.dom.style.backgroundColor).toBe("red");
125
+ expect(view.dom.style.color).toBe("red");
126
+ });
127
+ it("can set other attributes", async ()=>{
128
+ const { view , rerender } = tempEditor({
129
+ doc: doc(p()),
130
+ attributes: {
131
+ spellcheck: "false",
132
+ "aria-label": "hello"
133
+ }
134
+ });
135
+ expect(view.dom.spellcheck).toBe(false);
136
+ expect(view.dom.getAttribute("aria-label")).toBe("hello");
137
+ rerender({
138
+ attributes: {
139
+ style: "background-color: yellow"
140
+ }
141
+ });
142
+ expect(view.dom.hasAttribute("aria-label")).toBe(false);
143
+ expect(view.dom.style.backgroundColor).toBe("yellow");
144
+ });
145
+ it("can't set the contenteditable attribute", async ()=>{
146
+ const { view } = tempEditor({
147
+ doc: doc(p()),
148
+ attributes: {
149
+ contenteditable: "false"
150
+ }
151
+ });
152
+ expect(view.dom.contentEditable).toBe("true");
153
+ });
154
+ it("understands the editable prop", async ()=>{
155
+ const { view , rerender } = tempEditor({
156
+ doc: doc(p()),
157
+ editable: ()=>false
158
+ });
159
+ expect(view.dom.contentEditable).toBe("false");
160
+ rerender({
161
+ editable: ()=>true
162
+ });
163
+ expect(view.dom.contentEditable).toBe("true");
164
+ });
165
+ it("doesn't redraw following paragraphs when a paragraph is split", async ()=>{
166
+ const { view } = tempEditor({
167
+ doc: doc(p("abcde"), p("fg"))
168
+ });
169
+ const lastPara = view.dom.lastChild;
170
+ view.dispatch(view.state.tr.split(3));
171
+ expect(view.dom.lastChild).toBe(lastPara);
172
+ });
173
+ it("doesn't greedily match nodes that have another match", async ()=>{
174
+ const { view } = tempEditor({
175
+ doc: doc(p("a"), p("b"), p())
176
+ });
177
+ const secondPara = view.dom.querySelectorAll("p")[1];
178
+ view.dispatch(view.state.tr.split(2));
179
+ expect(view.dom.querySelectorAll("p")[2]).toBe(secondPara);
180
+ });
181
+ it("creates and destroys plugin views", async ()=>{
182
+ const events = [];
183
+ let PluginView = class PluginView {
184
+ update() {
185
+ events.push("update");
186
+ }
187
+ destroy() {
188
+ events.push("destroy");
189
+ }
190
+ };
191
+ const plugin = new Plugin({
192
+ view () {
193
+ events.push("create");
194
+ return new PluginView();
195
+ }
196
+ });
197
+ const { view , unmount } = tempEditor({
198
+ plugins: [
199
+ plugin
200
+ ]
201
+ });
202
+ view.dispatch(view.state.tr.insertText("u"));
203
+ unmount();
204
+ expect(events.join(" ")).toBe("create update destroy");
205
+ });
206
+ it("redraws changed node views", async ()=>{
207
+ const { view , rerender } = tempEditor({
208
+ doc: doc(p("foo"), hr())
209
+ });
210
+ expect(view.dom.querySelector("hr")).toBeTruthy();
211
+ rerender({
212
+ nodeViews: {
213
+ horizontal_rule: /*#__PURE__*/ forwardRef(function HorizontalRule(param, ref) {
214
+ let { nodeProps , ...props } = param;
215
+ return /*#__PURE__*/ React.createElement("var", _extends({
216
+ ref: ref
217
+ }, props));
218
+ })
219
+ }
220
+ });
221
+ expect(!view.dom.querySelector("hr")).toBeTruthy();
222
+ expect(view.dom.querySelector("var")).toBeTruthy();
223
+ });
224
+ it("doesn't get confused by merged nodes", async ()=>{
225
+ const { view } = tempEditor({
226
+ doc: doc(p(strong("one"), " two ", strong("three")))
227
+ });
228
+ view.dispatch(view.state.tr.removeMark(1, 4, schema.marks.strong));
229
+ expect(view.dom.querySelectorAll("strong")).toHaveLength(1);
230
+ });
231
+ it("doesn't redraw too much when marks are present", async ()=>{
232
+ const s = new Schema({
233
+ nodes: {
234
+ doc: {
235
+ content: "paragraph+",
236
+ marks: "m"
237
+ },
238
+ text: {
239
+ group: "inline"
240
+ },
241
+ paragraph: schema.spec.nodes.get("paragraph")
242
+ },
243
+ marks: {
244
+ m: {
245
+ toDOM: ()=>[
246
+ "div",
247
+ {
248
+ class: "m"
249
+ },
250
+ 0
251
+ ],
252
+ parseDOM: [
253
+ {
254
+ tag: "div.m"
255
+ }
256
+ ]
257
+ }
258
+ }
259
+ });
260
+ const paragraphs = [];
261
+ for(let i = 1; i <= 10; i++)paragraphs.push(s.node("paragraph", null, [
262
+ s.text("para " + i)
263
+ ], [
264
+ s.mark("m")
265
+ ]));
266
+ const { view } = tempEditor({
267
+ // @ts-expect-error this is fine
268
+ doc: s.node("doc", null, paragraphs)
269
+ });
270
+ const initialChildren = Array.from(view.dom.querySelectorAll("p"));
271
+ const newParagraphs = [];
272
+ for(let i = -6; i < 0; i++)newParagraphs.push(s.node("paragraph", null, [
273
+ s.text("para " + i)
274
+ ], [
275
+ s.mark("m")
276
+ ]));
277
+ view.dispatch(view.state.tr.replaceWith(0, 8, newParagraphs));
278
+ const currentChildren = Array.from(view.dom.querySelectorAll("p"));
279
+ let sameAtEnd = 0;
280
+ while(sameAtEnd < currentChildren.length && sameAtEnd < initialChildren.length && currentChildren[currentChildren.length - sameAtEnd - 1] == initialChildren[initialChildren.length - sameAtEnd - 1])sameAtEnd++;
281
+ expect(sameAtEnd).toBe(9);
282
+ });
283
+ it("correctly wraps inline nodes with marks", async ()=>{
284
+ const { view } = tempEditor({
285
+ doc: doc(p(strong(img(), " two")))
286
+ });
287
+ const docDom = view.dom;
288
+ const paragraphDom = docDom.firstElementChild;
289
+ const strongDom = paragraphDom.firstElementChild;
290
+ expect(strongDom?.tagName).toBe("STRONG");
291
+ expect(strongDom?.firstElementChild?.tagName).toBe("IMG");
292
+ expect(strongDom?.childNodes.item(1).textContent).toBe(" two");
293
+ });
294
+ });
@@ -0,0 +1,272 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ function _extends() {
2
+ _extends = Object.assign || function(target) {
3
+ for(var i = 1; i < arguments.length; i++){
4
+ var source = arguments[i];
5
+ for(var key in source){
6
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
7
+ target[key] = source[key];
8
+ }
9
+ }
10
+ }
11
+ return target;
12
+ };
13
+ return _extends.apply(this, arguments);
14
+ }
15
+ import { screen } from "@testing-library/react";
16
+ import { Plugin } from "prosemirror-state";
17
+ import { blockquote, br, doc, p } from "prosemirror-test-builder";
18
+ import { Decoration, DecorationSet } from "prosemirror-view";
19
+ import React, { forwardRef, useEffect } from "react";
20
+ import { useEditorState } from "../../hooks/useEditorState.js";
21
+ import { useStopEvent } from "../../hooks/useStopEvent.js";
22
+ import { tempEditor } from "../../testing/editorViewTestHelpers.js";
23
+ describe("nodeViews prop", ()=>{
24
+ it("can replace a node's representation", async ()=>{
25
+ const { view } = tempEditor({
26
+ doc: doc(p("foo", br())),
27
+ nodeViews: {
28
+ hard_break: /*#__PURE__*/ forwardRef(function Var(props, ref) {
29
+ return /*#__PURE__*/ React.createElement("var", {
30
+ ref: ref
31
+ }, props.children);
32
+ })
33
+ }
34
+ });
35
+ expect(view.dom.querySelector("var")).not.toBeNull();
36
+ });
37
+ it("can override drawing of a node's content", async ()=>{
38
+ const { view } = tempEditor({
39
+ doc: doc(p("foo")),
40
+ nodeViews: {
41
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
42
+ return /*#__PURE__*/ React.createElement("p", {
43
+ ref: ref
44
+ }, props.nodeProps.node.textContent.toUpperCase());
45
+ })
46
+ }
47
+ });
48
+ expect(view.dom.querySelector("p").textContent).toBe("FOO");
49
+ view.dispatch(view.state.tr.insertText("a"));
50
+ expect(view.dom.querySelector("p").textContent).toBe("AFOO");
51
+ });
52
+ // React makes this more or less trivial; the render
53
+ // method of the component _is_ the update (and create)
54
+ // method
55
+ // eslint-disable-next-line jest/no-disabled-tests
56
+ it.skip("can register its own update method", async ()=>{
57
+ const { view } = tempEditor({
58
+ doc: doc(p("foo")),
59
+ nodeViews: {
60
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
61
+ return /*#__PURE__*/ React.createElement("p", {
62
+ ref: ref
63
+ }, props.nodeProps.node.textContent.toUpperCase());
64
+ })
65
+ }
66
+ });
67
+ const para = view.dom.querySelector("p");
68
+ view.dispatch(view.state.tr.insertText("a"));
69
+ expect(view.dom.querySelector("p")).toBe(para);
70
+ expect(para.textContent).toBe("AFOO");
71
+ });
72
+ it("allows decoration updates for node views with an update method", async ()=>{
73
+ const { view , rerender } = tempEditor({
74
+ doc: doc(p("foo")),
75
+ nodeViews: {
76
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(param, ref) {
77
+ let { children , nodeProps , ...props } = param;
78
+ return /*#__PURE__*/ React.createElement("p", _extends({
79
+ ref: ref
80
+ }, props), children);
81
+ })
82
+ }
83
+ });
84
+ rerender({
85
+ decorations (state) {
86
+ return DecorationSet.create(state.doc, [
87
+ Decoration.inline(2, 3, {
88
+ someattr: "ok"
89
+ }),
90
+ Decoration.node(0, 5, {
91
+ otherattr: "ok"
92
+ })
93
+ ]);
94
+ }
95
+ });
96
+ expect(view.dom.querySelector("[someattr]")).not.toBeNull();
97
+ expect(view.dom.querySelector("[otherattr]")).not.toBeNull();
98
+ });
99
+ it("can provide a contentDOM property", async ()=>{
100
+ const { view } = tempEditor({
101
+ doc: doc(p("foo")),
102
+ nodeViews: {
103
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
104
+ return(// ContentDOM is inferred from where props.children is rendered
105
+ /*#__PURE__*/ React.createElement("p", {
106
+ ref: ref
107
+ }, props.children));
108
+ })
109
+ }
110
+ });
111
+ const para = view.dom.querySelector("p");
112
+ view.dispatch(view.state.tr.insertText("a"));
113
+ expect(view.dom.querySelector("p")).toBe(para);
114
+ expect(para.textContent).toBe("afoo");
115
+ });
116
+ it("has its destroy method called", async ()=>{
117
+ let destroyed = false;
118
+ const { view } = tempEditor({
119
+ doc: doc(p("foo", br())),
120
+ nodeViews: {
121
+ hard_break: /*#__PURE__*/ forwardRef(function BR(_props, ref) {
122
+ // React implements "destroy methods" with effect
123
+ // hooks
124
+ useEffect(()=>{
125
+ return ()=>{
126
+ destroyed = true;
127
+ };
128
+ }, []);
129
+ return /*#__PURE__*/ React.createElement("br", {
130
+ ref: ref
131
+ });
132
+ })
133
+ }
134
+ });
135
+ expect(destroyed).toBeFalsy();
136
+ view.dispatch(view.state.tr.delete(3, 5));
137
+ expect(destroyed).toBeTruthy();
138
+ });
139
+ it("can query its own position", async ()=>{
140
+ let pos;
141
+ const { view } = tempEditor({
142
+ doc: doc(blockquote(p("abc"), p("foo", br()))),
143
+ nodeViews: {
144
+ hard_break: /*#__PURE__*/ forwardRef(function BR(param, ref) {
145
+ let { nodeProps , children , ...props } = param;
146
+ // trigger a re-render on every updated, otherwise we won't
147
+ // re-render when an updated doesn't directly affect us
148
+ useEditorState();
149
+ pos = nodeProps.getPos();
150
+ return /*#__PURE__*/ React.createElement("br", _extends({
151
+ ref: ref
152
+ }, props));
153
+ })
154
+ }
155
+ });
156
+ expect(pos).toBe(10);
157
+ view.dispatch(view.state.tr.insertText("a"));
158
+ expect(pos).toBe(11);
159
+ });
160
+ it("has access to outer decorations", async ()=>{
161
+ const plugin = new Plugin({
162
+ state: {
163
+ init () {
164
+ return null;
165
+ },
166
+ apply (tr, prev) {
167
+ return tr.getMeta("setDeco") || prev;
168
+ }
169
+ },
170
+ props: {
171
+ decorations (state) {
172
+ const deco = this.getState(state);
173
+ return deco && DecorationSet.create(state.doc, [
174
+ Decoration.inline(0, state.doc.content.size, {}, {
175
+ name: deco
176
+ })
177
+ ]);
178
+ }
179
+ }
180
+ });
181
+ const { view } = tempEditor({
182
+ doc: doc(p("foo", br())),
183
+ plugins: [
184
+ plugin
185
+ ],
186
+ nodeViews: {
187
+ hard_break: /*#__PURE__*/ forwardRef(function Var(props, ref) {
188
+ return /*#__PURE__*/ React.createElement("var", {
189
+ ref: ref
190
+ }, props.nodeProps.decorations.length ? props.nodeProps.decorations[0].spec.name : "[]");
191
+ })
192
+ }
193
+ });
194
+ expect(view.dom.querySelector("var").textContent).toBe("[]");
195
+ view.dispatch(view.state.tr.setMeta("setDeco", "foo"));
196
+ expect(view.dom.querySelector("var").textContent).toBe("foo");
197
+ view.dispatch(view.state.tr.setMeta("setDeco", "bar"));
198
+ expect(view.dom.querySelector("var").textContent).toBe("bar");
199
+ });
200
+ it("provides access to inner decorations in the constructor", async ()=>{
201
+ tempEditor({
202
+ doc: doc(p("foo")),
203
+ nodeViews: {
204
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
205
+ expect(props.nodeProps.innerDecorations.find().map((d)=>`${d.from}-${d.to}`).join()).toBe("1-2");
206
+ return /*#__PURE__*/ React.createElement("p", {
207
+ ref: ref
208
+ }, props.children);
209
+ })
210
+ },
211
+ decorations (state) {
212
+ return DecorationSet.create(state.doc, [
213
+ Decoration.inline(2, 3, {
214
+ someattr: "ok"
215
+ }),
216
+ Decoration.node(0, 5, {
217
+ otherattr: "ok"
218
+ })
219
+ ]);
220
+ }
221
+ });
222
+ });
223
+ it("provides access to inner decorations in the update method", async ()=>{
224
+ let innerDecos = [];
225
+ const { rerender } = tempEditor({
226
+ doc: doc(p("foo")),
227
+ nodeViews: {
228
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(props, ref) {
229
+ innerDecos = props.nodeProps.innerDecorations.find().map((d)=>`${d.from}-${d.to}`);
230
+ return /*#__PURE__*/ React.createElement("p", {
231
+ ref: ref
232
+ }, props.children);
233
+ })
234
+ }
235
+ });
236
+ rerender({
237
+ decorations (state) {
238
+ return DecorationSet.create(state.doc, [
239
+ Decoration.inline(2, 3, {
240
+ someattr: "ok"
241
+ }),
242
+ Decoration.node(0, 5, {
243
+ otherattr: "ok"
244
+ })
245
+ ]);
246
+ }
247
+ });
248
+ expect(innerDecos.join()).toBe("1-2");
249
+ });
250
+ it("can provide a stopEvent hook", async ()=>{
251
+ tempEditor({
252
+ doc: doc(p("input value")),
253
+ nodeViews: {
254
+ paragraph: /*#__PURE__*/ forwardRef(function ParagraphInput(param, ref) {
255
+ let { nodeProps , children , ...props } = param;
256
+ useStopEvent(()=>{
257
+ return true;
258
+ });
259
+ return /*#__PURE__*/ React.createElement("input", _extends({
260
+ ref: ref,
261
+ type: "text",
262
+ defaultValue: nodeProps.node.textContent
263
+ }, props));
264
+ })
265
+ }
266
+ });
267
+ const input = screen.getByDisplayValue("input value");
268
+ input.focus();
269
+ await browser.keys("z");
270
+ expect(await $(input).getValue()).toBe("input valuez");
271
+ });
272
+ });