@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,967 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ // TODO: figure out whether it's possible to support native
2
+ // widgets. Right now, I'm not sure how we'd do it without
3
+ // wrapping them in another element, which would re-introduce
4
+ // all of the issues we had before with node views.
5
+ //
6
+ // For now, we've updated the factory in this file to use
7
+ // our React widgets.
8
+ function _extends() {
9
+ _extends = Object.assign || function(target) {
10
+ for(var i = 1; i < arguments.length; i++){
11
+ var source = arguments[i];
12
+ for(var key in source){
13
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
14
+ target[key] = source[key];
15
+ }
16
+ }
17
+ }
18
+ return target;
19
+ };
20
+ return _extends.apply(this, arguments);
21
+ }
22
+ import { Schema } from "prosemirror-model";
23
+ import { Plugin, TextSelection } from "prosemirror-state";
24
+ import { blockquote, doc, em, h1, hr, img, p, schema, strong } from "prosemirror-test-builder";
25
+ import { Decoration, DecorationSet } from "prosemirror-view";
26
+ import React, { forwardRef, useEffect } from "react";
27
+ import { widget } from "../../decorations/ReactWidgetType.js";
28
+ import { useEditorEffect } from "../../hooks/useEditorEffect.js";
29
+ import { tempEditor } from "../../testing/editorViewTestHelpers.js";
30
+ const Widget = /*#__PURE__*/ forwardRef(function Widget(param, ref) {
31
+ let { widget , getPos , ...props } = param;
32
+ return /*#__PURE__*/ React.createElement("button", _extends({
33
+ ref: ref
34
+ }, props), "ω");
35
+ });
36
+ function make(str) {
37
+ if (typeof str != "string") return str;
38
+ const match = /^(\d+)(?:-(\d+))?-(.+)$/.exec(str);
39
+ if (match[3] == "widget") {
40
+ return widget(+match[1], Widget, {
41
+ key: str
42
+ });
43
+ }
44
+ return Decoration.inline(+match[1], +match[2], {
45
+ class: match[3]
46
+ });
47
+ }
48
+ function decoPlugin(decos) {
49
+ return new Plugin({
50
+ state: {
51
+ init (config) {
52
+ return config.doc ? DecorationSet.create(config.doc, decos.map(make)) : DecorationSet.empty;
53
+ },
54
+ apply (tr, set, state) {
55
+ if (tr.docChanged) set = set.map(tr.mapping, tr.doc);
56
+ const change = tr.getMeta("updateDecorations");
57
+ if (change) {
58
+ if (change.remove) set = set.remove(change.remove);
59
+ if (change.add) set = set.add(state.doc, change.add);
60
+ }
61
+ return set;
62
+ }
63
+ },
64
+ props: {
65
+ decorations (state) {
66
+ return this.getState(state);
67
+ }
68
+ }
69
+ });
70
+ }
71
+ function updateDeco(view, add, remove) {
72
+ view.dispatch(view.state.tr.setMeta("updateDecorations", {
73
+ add,
74
+ remove
75
+ }));
76
+ }
77
+ describe("Decoration drawing", ()=>{
78
+ it("draws inline decorations", async ()=>{
79
+ const { view } = tempEditor({
80
+ doc: doc(p("foobar")),
81
+ plugins: [
82
+ decoPlugin([
83
+ "2-5-foo"
84
+ ])
85
+ ]
86
+ });
87
+ const found = view.dom.querySelector(".foo");
88
+ await expect(found).not.toBeNull();
89
+ await expect(found.textContent).toBe("oob");
90
+ });
91
+ it("draws wrapping decorations", async ()=>{
92
+ const { view } = tempEditor({
93
+ doc: doc(p("foo")),
94
+ plugins: [
95
+ decoPlugin([
96
+ Decoration.inline(1, 5, {
97
+ nodeName: "i"
98
+ })
99
+ ])
100
+ ]
101
+ });
102
+ const found = view.dom.querySelector("i");
103
+ expect(found && found.innerHTML).toBe("foo");
104
+ });
105
+ it("draws node decorations", async ()=>{
106
+ const { view } = tempEditor({
107
+ doc: doc(p("foo"), p("bar")),
108
+ plugins: [
109
+ decoPlugin([
110
+ Decoration.node(5, 10, {
111
+ class: "cls"
112
+ })
113
+ ])
114
+ ]
115
+ });
116
+ const found = view.dom.querySelectorAll(".cls");
117
+ expect(found).toHaveLength(1);
118
+ expect(found[0].nodeName).toBe("P");
119
+ expect(found[0].previousSibling.nodeName).toBe("P");
120
+ });
121
+ it("can update multi-level wrapping decorations", async ()=>{
122
+ const d2 = Decoration.inline(1, 5, {
123
+ nodeName: "i",
124
+ class: "b"
125
+ });
126
+ const { view } = tempEditor({
127
+ doc: doc(p("hello")),
128
+ plugins: [
129
+ decoPlugin([
130
+ Decoration.inline(1, 5, {
131
+ nodeName: "i",
132
+ class: "a"
133
+ }),
134
+ d2
135
+ ])
136
+ ]
137
+ });
138
+ expect(view.dom.querySelectorAll("i")).toHaveLength(2);
139
+ updateDeco(view, [
140
+ Decoration.inline(1, 5, {
141
+ nodeName: "i",
142
+ class: "c"
143
+ })
144
+ ], [
145
+ d2
146
+ ]);
147
+ const iNodes = view.dom.querySelectorAll("i");
148
+ expect(iNodes).toHaveLength(2);
149
+ expect(Array.prototype.map.call(iNodes, (n)=>n.className).sort().join()).toBe("a,c");
150
+ });
151
+ it("draws overlapping inline decorations", async ()=>{
152
+ const { view } = tempEditor({
153
+ doc: doc(p("abcdef")),
154
+ plugins: [
155
+ decoPlugin([
156
+ "3-5-foo",
157
+ "4-6-bar",
158
+ "1-7-baz"
159
+ ])
160
+ ]
161
+ });
162
+ const baz = view.dom.querySelectorAll(".baz");
163
+ expect(baz).toHaveLength(5);
164
+ expect(Array.prototype.map.call(baz, (x)=>x.textContent).join("-")).toBe("ab-c-d-e-f");
165
+ function classes(n) {
166
+ return n.className.split(" ").sort().join(" ");
167
+ }
168
+ expect(classes(baz[1])).toBe("baz foo");
169
+ expect(classes(baz[2])).toBe("bar baz foo");
170
+ expect(classes(baz[3])).toBe("bar baz");
171
+ });
172
+ it("draws multiple widgets", async ()=>{
173
+ const { view } = tempEditor({
174
+ doc: doc(p("foobar")),
175
+ plugins: [
176
+ decoPlugin([
177
+ "1-widget",
178
+ "4-widget",
179
+ "7-widget"
180
+ ])
181
+ ]
182
+ });
183
+ const found = view.dom.querySelectorAll("button");
184
+ expect(found).toHaveLength(3);
185
+ expect(found[0].nextSibling.textContent).toBe("foo");
186
+ expect(found[1].nextSibling.textContent).toBe("bar");
187
+ expect(found[2].previousSibling.textContent).toBe("bar");
188
+ });
189
+ it("orders widgets by their side option", async ()=>{
190
+ const { view } = tempEditor({
191
+ doc: doc(p("foobar")),
192
+ plugins: [
193
+ decoPlugin([
194
+ widget(4, /*#__PURE__*/ forwardRef(function B(param, ref) {
195
+ let { widget , getPos , ...props } = param;
196
+ return /*#__PURE__*/ React.createElement("span", _extends({
197
+ ref: ref
198
+ }, props), "B");
199
+ }), {
200
+ key: "widget-b"
201
+ }),
202
+ widget(4, /*#__PURE__*/ forwardRef(function A(param, ref) {
203
+ let { widget , getPos , ...props } = param;
204
+ return /*#__PURE__*/ React.createElement("span", _extends({
205
+ ref: ref
206
+ }, props), "A");
207
+ }), {
208
+ side: -100,
209
+ key: "widget-a"
210
+ }),
211
+ widget(4, /*#__PURE__*/ forwardRef(function C(param, ref) {
212
+ let { widget , getPos , ...props } = param;
213
+ return /*#__PURE__*/ React.createElement("span", _extends({
214
+ ref: ref
215
+ }, props), "C");
216
+ }), {
217
+ side: 2,
218
+ key: "widget-c"
219
+ })
220
+ ])
221
+ ]
222
+ });
223
+ expect(view.dom.textContent).toBe("fooABCbar");
224
+ });
225
+ it("draws a widget in an empty node", async ()=>{
226
+ const { view } = tempEditor({
227
+ doc: doc(p()),
228
+ plugins: [
229
+ decoPlugin([
230
+ "1-widget"
231
+ ])
232
+ ]
233
+ });
234
+ expect(view.dom.querySelectorAll("button")).toHaveLength(1);
235
+ });
236
+ it("draws widgets on node boundaries", async ()=>{
237
+ const { view } = tempEditor({
238
+ doc: doc(p("foo", em("bar"))),
239
+ plugins: [
240
+ decoPlugin([
241
+ "4-widget"
242
+ ])
243
+ ]
244
+ });
245
+ expect(view.dom.querySelectorAll("button")).toHaveLength(1);
246
+ });
247
+ it("draws decorations from multiple plugins", async ()=>{
248
+ const { view } = tempEditor({
249
+ doc: doc(p("foo", em("bar"))),
250
+ plugins: [
251
+ decoPlugin([
252
+ "2-widget"
253
+ ]),
254
+ decoPlugin([
255
+ "6-widget"
256
+ ])
257
+ ]
258
+ });
259
+ expect(view.dom.querySelectorAll("button")).toHaveLength(2);
260
+ });
261
+ it("calls widget destroy methods", async ()=>{
262
+ let destroyed = false;
263
+ const DestroyableWidget = /*#__PURE__*/ forwardRef(function DestroyableWidget(param, ref) {
264
+ let { widget , getPos , ...props } = param;
265
+ useEffect(()=>{
266
+ destroyed = true;
267
+ });
268
+ return /*#__PURE__*/ React.createElement("button", _extends({
269
+ ref: ref
270
+ }, props));
271
+ });
272
+ const { view } = tempEditor({
273
+ doc: doc(p("abc")),
274
+ plugins: [
275
+ decoPlugin([
276
+ widget(2, DestroyableWidget, {
277
+ key: "destroyable-widget"
278
+ })
279
+ ])
280
+ ]
281
+ });
282
+ view.dispatch(view.state.tr.delete(1, 4));
283
+ expect(destroyed).toBeTruthy();
284
+ });
285
+ it("draws inline decorations spanning multiple parents", async ()=>{
286
+ const { view } = tempEditor({
287
+ doc: doc(p("long first ", em("p"), "aragraph"), p("two")),
288
+ plugins: [
289
+ decoPlugin([
290
+ "7-25-foo"
291
+ ])
292
+ ]
293
+ });
294
+ const foos = view.dom.querySelectorAll(".foo");
295
+ expect(foos).toHaveLength(4);
296
+ expect(foos[0].textContent).toBe("irst ");
297
+ expect(foos[1].textContent).toBe("p");
298
+ expect(foos[2].textContent).toBe("aragraph");
299
+ expect(foos[3].textContent).toBe("tw");
300
+ });
301
+ it("draws inline decorations across empty paragraphs", async ()=>{
302
+ const { view } = tempEditor({
303
+ doc: doc(p("first"), p(), p("second")),
304
+ plugins: [
305
+ decoPlugin([
306
+ "3-12-foo"
307
+ ])
308
+ ]
309
+ });
310
+ const foos = view.dom.querySelectorAll(".foo");
311
+ expect(foos).toHaveLength(2);
312
+ expect(foos[0].textContent).toBe("rst");
313
+ expect(foos[1].textContent).toBe("se");
314
+ });
315
+ it("can handle inline decorations ending at the start or end of a node", async ()=>{
316
+ const { view } = tempEditor({
317
+ doc: doc(p(), p()),
318
+ plugins: [
319
+ decoPlugin([
320
+ "1-3-foo"
321
+ ])
322
+ ]
323
+ });
324
+ expect(view.dom.querySelector(".foo")).toBeNull();
325
+ });
326
+ it("can draw decorations with multiple classes", async ()=>{
327
+ const { view } = tempEditor({
328
+ doc: doc(p("foo")),
329
+ plugins: [
330
+ decoPlugin([
331
+ "1-4-foo bar"
332
+ ])
333
+ ]
334
+ });
335
+ expect(view.dom.querySelectorAll(".foo")).toHaveLength(1);
336
+ expect(view.dom.querySelectorAll(".bar")).toHaveLength(1);
337
+ });
338
+ it("supports overlapping inline decorations", async ()=>{
339
+ const { view } = tempEditor({
340
+ doc: doc(p("foobar")),
341
+ plugins: [
342
+ decoPlugin([
343
+ "1-3-foo",
344
+ "2-5-bar"
345
+ ])
346
+ ]
347
+ });
348
+ const foos = view.dom.querySelectorAll(".foo");
349
+ const bars = view.dom.querySelectorAll(".bar");
350
+ expect(foos).toHaveLength(2);
351
+ expect(bars).toHaveLength(2);
352
+ expect(foos[0].textContent).toBe("f");
353
+ expect(foos[1].textContent).toBe("o");
354
+ expect(bars[0].textContent).toBe("o");
355
+ expect(bars[1].textContent).toBe("ob");
356
+ });
357
+ it("doesn't redraw when irrelevant decorations change", async ()=>{
358
+ const { view } = tempEditor({
359
+ doc: doc(p("foo"), p("baz")),
360
+ plugins: [
361
+ decoPlugin([
362
+ "7-8-foo"
363
+ ])
364
+ ]
365
+ });
366
+ const para2 = view.dom.lastChild;
367
+ updateDeco(view, [
368
+ make("2-3-bar")
369
+ ]);
370
+ expect(view.dom.lastChild).toBe(para2);
371
+ expect(view.dom.querySelector(".bar")).not.toBeNull();
372
+ });
373
+ it("doesn't redraw when irrelevant content changes", async ()=>{
374
+ const { view } = tempEditor({
375
+ doc: doc(p("foo"), p("baz")),
376
+ plugins: [
377
+ decoPlugin([
378
+ "7-8-foo"
379
+ ])
380
+ ]
381
+ });
382
+ const para2 = view.dom.lastChild;
383
+ view.dispatch(view.state.tr.delete(2, 3));
384
+ view.dispatch(view.state.tr.delete(2, 3));
385
+ expect(view.dom.lastChild).toBe(para2);
386
+ });
387
+ it("can add a widget on a node boundary", async ()=>{
388
+ const { view } = tempEditor({
389
+ doc: doc(p("foo", em("bar"))),
390
+ plugins: [
391
+ decoPlugin([])
392
+ ]
393
+ });
394
+ updateDeco(view, [
395
+ make("4-widget")
396
+ ]);
397
+ expect(view.dom.querySelectorAll("button")).toHaveLength(1);
398
+ });
399
+ it("can remove a widget on a node boundary", async ()=>{
400
+ const dec = make("4-widget");
401
+ const { view } = tempEditor({
402
+ doc: doc(p("foo", em("bar"))),
403
+ plugins: [
404
+ decoPlugin([
405
+ dec
406
+ ])
407
+ ]
408
+ });
409
+ updateDeco(view, null, [
410
+ dec
411
+ ]);
412
+ expect(view.dom.querySelector("button")).toBeNull();
413
+ });
414
+ it("can remove the class from a text node", async ()=>{
415
+ const dec = make("1-4-foo");
416
+ const { view } = tempEditor({
417
+ doc: doc(p("abc")),
418
+ plugins: [
419
+ decoPlugin([
420
+ dec
421
+ ])
422
+ ]
423
+ });
424
+ expect(view.dom.querySelector(".foo")).not.toBeNull();
425
+ updateDeco(view, null, [
426
+ dec
427
+ ]);
428
+ expect(view.dom.querySelector(".foo")).toBeNull();
429
+ });
430
+ it("can remove the class from part of a text node", async ()=>{
431
+ const dec = make("2-4-foo");
432
+ const { view } = tempEditor({
433
+ doc: doc(p("abcd")),
434
+ plugins: [
435
+ decoPlugin([
436
+ dec
437
+ ])
438
+ ]
439
+ });
440
+ expect(view.dom.querySelector(".foo")).not.toBeNull();
441
+ updateDeco(view, null, [
442
+ dec
443
+ ]);
444
+ expect(view.dom.querySelector(".foo")).toBeNull();
445
+ expect(view.dom.firstChild.innerHTML).toBe("abcd");
446
+ });
447
+ it("can change the class for part of a text node", async ()=>{
448
+ const dec = make("2-4-foo");
449
+ const { view } = tempEditor({
450
+ doc: doc(p("abcd")),
451
+ plugins: [
452
+ decoPlugin([
453
+ dec
454
+ ])
455
+ ]
456
+ });
457
+ expect(view.dom.querySelector(".foo")).not.toBeNull();
458
+ updateDeco(view, [
459
+ make("2-4-bar")
460
+ ], [
461
+ dec
462
+ ]);
463
+ expect(view.dom.querySelector(".foo")).toBeNull();
464
+ expect(view.dom.querySelector(".bar")).not.toBeNull();
465
+ });
466
+ it("draws a widget added in the middle of a text node", async ()=>{
467
+ const { view } = tempEditor({
468
+ doc: doc(p("foo")),
469
+ plugins: [
470
+ decoPlugin([])
471
+ ]
472
+ });
473
+ updateDeco(view, [
474
+ make("3-widget")
475
+ ]);
476
+ expect(view.dom.firstChild.textContent).toBe("foωo");
477
+ });
478
+ it("can update a text node around a widget", async ()=>{
479
+ const { view } = tempEditor({
480
+ doc: doc(p("bar")),
481
+ plugins: [
482
+ decoPlugin([
483
+ "3-widget"
484
+ ])
485
+ ]
486
+ });
487
+ view.dispatch(view.state.tr.delete(1, 2));
488
+ expect(view.dom.querySelectorAll("button")).toHaveLength(1);
489
+ expect(view.dom.firstChild.textContent).toBe("aωr");
490
+ });
491
+ it("can update a text node with an inline decoration", async ()=>{
492
+ const { view } = tempEditor({
493
+ doc: doc(p("bar")),
494
+ plugins: [
495
+ decoPlugin([
496
+ "1-3-foo"
497
+ ])
498
+ ]
499
+ });
500
+ view.dispatch(view.state.tr.delete(1, 2));
501
+ const foo = view.dom.querySelector(".foo");
502
+ expect(foo).not.toBeNull();
503
+ expect(foo.textContent).toBe("a");
504
+ expect(foo.nextSibling.textContent).toBe("r");
505
+ });
506
+ it("correctly redraws a partially decorated node when a widget is added", async ()=>{
507
+ const { view } = tempEditor({
508
+ doc: doc(p("one", em("two"))),
509
+ plugins: [
510
+ decoPlugin([
511
+ "1-6-foo"
512
+ ])
513
+ ]
514
+ });
515
+ updateDeco(view, [
516
+ make("6-widget")
517
+ ]);
518
+ const foos = view.dom.querySelectorAll(".foo");
519
+ expect(foos).toHaveLength(2);
520
+ expect(foos[0].textContent).toBe("one");
521
+ expect(foos[1].textContent).toBe("tw");
522
+ });
523
+ it("correctly redraws when skipping split text node", async ()=>{
524
+ const { view } = tempEditor({
525
+ doc: doc(p("foo")),
526
+ plugins: [
527
+ decoPlugin([
528
+ "3-widget",
529
+ "3-4-foo"
530
+ ])
531
+ ]
532
+ });
533
+ updateDeco(view, [
534
+ make("4-widget")
535
+ ]);
536
+ expect(view.dom.querySelectorAll("button")).toHaveLength(2);
537
+ });
538
+ it("drops removed node decorations from the view", async ()=>{
539
+ const deco = Decoration.node(1, 6, {
540
+ class: "cls"
541
+ });
542
+ const { view } = tempEditor({
543
+ doc: doc(blockquote(p("foo"), p("bar"))),
544
+ plugins: [
545
+ decoPlugin([
546
+ deco
547
+ ])
548
+ ]
549
+ });
550
+ updateDeco(view, null, [
551
+ deco
552
+ ]);
553
+ expect(view.dom.querySelector(".cls")).toBeNull();
554
+ });
555
+ it("can update a node's attributes without replacing the node", async ()=>{
556
+ const deco = Decoration.node(0, 5, {
557
+ title: "title",
558
+ class: "foo"
559
+ });
560
+ const { view } = tempEditor({
561
+ doc: doc(p("foo")),
562
+ plugins: [
563
+ decoPlugin([
564
+ deco
565
+ ])
566
+ ]
567
+ });
568
+ const para = view.dom.querySelector("p");
569
+ updateDeco(view, [
570
+ Decoration.node(0, 5, {
571
+ class: "foo bar"
572
+ })
573
+ ], [
574
+ deco
575
+ ]);
576
+ expect(view.dom.querySelector("p")).toBe(para);
577
+ expect(para.className).toBe("foo bar");
578
+ expect(para.title).toBeFalsy();
579
+ });
580
+ it("can add and remove CSS custom properties from a node", async ()=>{
581
+ const deco = Decoration.node(0, 5, {
582
+ style: "--my-custom-property:36px"
583
+ });
584
+ const { view } = tempEditor({
585
+ doc: doc(p("foo")),
586
+ plugins: [
587
+ decoPlugin([
588
+ deco
589
+ ])
590
+ ]
591
+ });
592
+ expect(view.dom.querySelector("p").style.getPropertyValue("--my-custom-property")).toBe("36px");
593
+ updateDeco(view, null, [
594
+ deco
595
+ ]);
596
+ expect(view.dom.querySelector("p").style.getPropertyValue("--my-custom-property")).toBe("");
597
+ });
598
+ it("updates decorated nodes even if a widget is added before them", async ()=>{
599
+ const { view } = tempEditor({
600
+ doc: doc(p("a"), p("b")),
601
+ plugins: [
602
+ decoPlugin([])
603
+ ]
604
+ });
605
+ const lastP = view.dom.querySelectorAll("p")[1];
606
+ updateDeco(view, [
607
+ make("3-widget"),
608
+ Decoration.node(3, 6, {
609
+ style: "color: red"
610
+ })
611
+ ]);
612
+ expect(lastP.style.color).toBe("red");
613
+ });
614
+ it("doesn't redraw nodes when a widget before them is replaced", async ()=>{
615
+ const w0 = make("3-widget");
616
+ const { view } = tempEditor({
617
+ doc: doc(h1("a"), p("b")),
618
+ plugins: [
619
+ decoPlugin([
620
+ w0
621
+ ])
622
+ ]
623
+ });
624
+ const initialP = view.dom.querySelector("p");
625
+ view.dispatch(view.state.tr.setMeta("updateDecorations", {
626
+ add: [
627
+ make("3-widget")
628
+ ],
629
+ remove: [
630
+ w0
631
+ ]
632
+ }).insertText("c", 5));
633
+ expect(view.dom.querySelector("p")).toBe(initialP);
634
+ });
635
+ it("can add and remove inline style", async ()=>{
636
+ const deco = Decoration.inline(1, 6, {
637
+ style: "color: rgba(0,10,200,.4); text-decoration: underline"
638
+ });
639
+ const { view } = tempEditor({
640
+ doc: doc(p("al", img(), "lo")),
641
+ plugins: [
642
+ decoPlugin([
643
+ deco
644
+ ])
645
+ ]
646
+ });
647
+ expect(view.dom.querySelector("img").style.color).toMatch(/rgba/);
648
+ expect(view.dom.querySelector("img").previousSibling.style.textDecoration).toBe("underline");
649
+ updateDeco(view, null, [
650
+ deco
651
+ ]);
652
+ expect(view.dom.querySelector("img").style.color).toBe("");
653
+ expect(view.dom.querySelector("img").style.textDecoration).toBe("");
654
+ });
655
+ it("passes decorations to a node view", async ()=>{
656
+ let current = "";
657
+ const { view } = tempEditor({
658
+ doc: doc(p("foo"), hr()),
659
+ plugins: [
660
+ decoPlugin([])
661
+ ],
662
+ nodeViews: {
663
+ horizontal_rule: /*#__PURE__*/ forwardRef(function HR(param, ref) {
664
+ let { nodeProps , children , ...props } = param;
665
+ current = nodeProps.decorations.map((d)=>d.spec.name).join();
666
+ return /*#__PURE__*/ React.createElement("hr", _extends({
667
+ ref: ref
668
+ }, props));
669
+ })
670
+ }
671
+ });
672
+ const a = Decoration.node(5, 6, {}, {
673
+ name: "a"
674
+ });
675
+ updateDeco(view, [
676
+ a
677
+ ], []);
678
+ expect(current).toBe("a");
679
+ updateDeco(view, [
680
+ Decoration.node(5, 6, {}, {
681
+ name: "b"
682
+ }),
683
+ Decoration.node(5, 6, {}, {
684
+ name: "c"
685
+ })
686
+ ], [
687
+ a
688
+ ]);
689
+ expect(current).toBe("b,c");
690
+ });
691
+ it("draws the specified marks around a widget", async ()=>{
692
+ const { view } = tempEditor({
693
+ doc: doc(p("foobar")),
694
+ plugins: [
695
+ decoPlugin([
696
+ widget(4, /*#__PURE__*/ forwardRef(function Img(param, ref) {
697
+ let { widget , getPos , ...props } = param;
698
+ return /*#__PURE__*/ React.createElement("img", _extends({}, props, {
699
+ ref: ref
700
+ }));
701
+ }), {
702
+ marks: [
703
+ schema.mark("em")
704
+ ],
705
+ key: "img-widget"
706
+ })
707
+ ])
708
+ ]
709
+ });
710
+ expect(view.dom.querySelector("em img")).not.toBeNull();
711
+ });
712
+ it("draws widgets inside the marks for their side", async ()=>{
713
+ const { view } = tempEditor({
714
+ doc: doc(p(em("foo"), strong("bar"))),
715
+ plugins: [
716
+ decoPlugin([
717
+ widget(4, /*#__PURE__*/ forwardRef(function Img(param, ref) {
718
+ let { widget , getPos , ...props } = param;
719
+ return /*#__PURE__*/ React.createElement("img", _extends({}, props, {
720
+ ref: ref
721
+ }));
722
+ }), {
723
+ side: -1,
724
+ key: "img-widget"
725
+ })
726
+ ]),
727
+ decoPlugin([
728
+ widget(4, /*#__PURE__*/ forwardRef(function BR(param, ref) {
729
+ let { widget , getPos , ...props } = param;
730
+ return /*#__PURE__*/ React.createElement("br", _extends({}, props, {
731
+ ref: ref
732
+ }));
733
+ }), {
734
+ key: "br-widget"
735
+ })
736
+ ]),
737
+ decoPlugin([
738
+ widget(7, /*#__PURE__*/ forwardRef(function Span(param, ref) {
739
+ let { widget , getPos , ...props } = param;
740
+ return /*#__PURE__*/ React.createElement("span", _extends({}, props, {
741
+ ref: ref
742
+ }));
743
+ }), {
744
+ side: 1,
745
+ key: "span-widget"
746
+ })
747
+ ])
748
+ ]
749
+ });
750
+ expect(view.dom.querySelector("em img")).not.toBeNull();
751
+ expect(view.dom.querySelector("strong img")).toBeNull();
752
+ expect(view.dom.querySelector("strong br")).not.toBeNull();
753
+ expect(view.dom.querySelector("em br")).toBeNull();
754
+ expect(view.dom.querySelector("strong span")).toBeNull();
755
+ });
756
+ it("draws decorations inside node views", async ()=>{
757
+ const { view } = tempEditor({
758
+ doc: doc(p("foo")),
759
+ nodeViews: {
760
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(param, ref) {
761
+ let { nodeProps , children , ...props } = param;
762
+ return /*#__PURE__*/ React.createElement("p", _extends({
763
+ ref: ref
764
+ }, props), children);
765
+ })
766
+ },
767
+ plugins: [
768
+ decoPlugin([
769
+ widget(2, /*#__PURE__*/ forwardRef(function Img(param, ref) {
770
+ let { widget , getPos , ...props } = param;
771
+ return /*#__PURE__*/ React.createElement("img", _extends({}, props, {
772
+ ref: ref
773
+ }));
774
+ }), {
775
+ key: "img-widget"
776
+ })
777
+ ])
778
+ ]
779
+ });
780
+ expect(view.dom.querySelector("img")).not.toBeNull();
781
+ });
782
+ it("can delay widget drawing to render time", async ()=>{
783
+ const { view } = tempEditor({
784
+ doc: doc(p("hi")),
785
+ decorations (state) {
786
+ return DecorationSet.create(state.doc, [
787
+ widget(3, /*#__PURE__*/ forwardRef(function Span(param, ref) {
788
+ let { widget , getPos , ...props } = param;
789
+ useEditorEffect((view)=>{
790
+ expect(view.state).toBe(state);
791
+ });
792
+ return /*#__PURE__*/ React.createElement("span", _extends({}, props, {
793
+ ref: ref
794
+ }), "!");
795
+ }), {
796
+ key: "span-widget"
797
+ })
798
+ ]);
799
+ }
800
+ });
801
+ expect(view.dom.textContent).toBe("hi!");
802
+ });
803
+ it("supports widgets querying their own position", async ()=>{
804
+ tempEditor({
805
+ doc: doc(p("hi")),
806
+ decorations (state) {
807
+ return DecorationSet.create(state.doc, [
808
+ widget(3, /*#__PURE__*/ forwardRef(function Widget(param, ref) {
809
+ let { widget , getPos , ...props } = param;
810
+ expect(getPos()).toBe(3);
811
+ return /*#__PURE__*/ React.createElement("button", _extends({
812
+ ref: ref
813
+ }, props), "ω");
814
+ }), {
815
+ key: "button-widget"
816
+ })
817
+ ]);
818
+ }
819
+ });
820
+ });
821
+ it("doesn't redraw widgets with matching keys", async ()=>{
822
+ const { view } = tempEditor({
823
+ doc: doc(p("hi")),
824
+ decorations (state) {
825
+ return DecorationSet.create(state.doc, [
826
+ widget(2, Widget, {
827
+ key: "myButton"
828
+ })
829
+ ]);
830
+ }
831
+ });
832
+ const widgetDOM = view.dom.querySelector("button");
833
+ view.dispatch(view.state.tr.insertText("!", 2, 2));
834
+ expect(view.dom.querySelector("button")).toBe(widgetDOM);
835
+ });
836
+ it("doesn't redraw widgets with identical specs", async ()=>{
837
+ const { view } = tempEditor({
838
+ doc: doc(p("hi")),
839
+ decorations (state) {
840
+ return DecorationSet.create(state.doc, [
841
+ widget(2, Widget, {
842
+ side: 1,
843
+ key: "widget"
844
+ })
845
+ ]);
846
+ }
847
+ });
848
+ const widgetDOM = view.dom.querySelector("button");
849
+ view.dispatch(view.state.tr.insertText("!", 2, 2));
850
+ expect(view.dom.querySelector("button")).toBe(widgetDOM);
851
+ });
852
+ it("doesn't get confused by split text nodes", async ()=>{
853
+ const { view } = tempEditor({
854
+ doc: doc(p("abab")),
855
+ decorations (state) {
856
+ return state.selection.from <= 1 ? null : DecorationSet.create(view.state.doc, [
857
+ Decoration.inline(1, 2, {
858
+ class: "foo"
859
+ }),
860
+ Decoration.inline(3, 4, {
861
+ class: "foo"
862
+ })
863
+ ]);
864
+ }
865
+ });
866
+ view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, 5)));
867
+ expect(view.dom.textContent).toBe("abab");
868
+ });
869
+ it("only draws inline decorations on the innermost level", async ()=>{
870
+ const s = new Schema({
871
+ nodes: {
872
+ doc: {
873
+ content: "(text | thing)*"
874
+ },
875
+ text: {},
876
+ thing: {
877
+ inline: true,
878
+ content: "text*",
879
+ toDOM: ()=>[
880
+ "strong",
881
+ 0
882
+ ],
883
+ parseDOM: [
884
+ {
885
+ tag: "strong"
886
+ }
887
+ ]
888
+ }
889
+ }
890
+ });
891
+ const { view } = tempEditor({
892
+ doc: s.node("doc", null, [
893
+ s.text("abc"),
894
+ s.node("thing", null, [
895
+ s.text("def")
896
+ ]),
897
+ s.text("ghi")
898
+ ]),
899
+ decorations: (s)=>DecorationSet.create(s.doc, [
900
+ Decoration.inline(1, 10, {
901
+ class: "dec"
902
+ })
903
+ ])
904
+ });
905
+ const styled = view.dom.querySelectorAll(".dec");
906
+ expect(styled).toHaveLength(3);
907
+ expect(Array.prototype.map.call(styled, (n)=>n.textContent).join()).toBe("bc,def,gh");
908
+ expect(styled[1].parentNode.nodeName).toBe("STRONG");
909
+ });
910
+ it("can handle nodeName decoration overlapping with classes", async ()=>{
911
+ const { view } = tempEditor({
912
+ doc: doc(p("one two three")),
913
+ plugins: [
914
+ decoPlugin([
915
+ Decoration.inline(2, 13, {
916
+ class: "foo"
917
+ }),
918
+ Decoration.inline(5, 8, {
919
+ nodeName: "em"
920
+ })
921
+ ])
922
+ ]
923
+ });
924
+ expect(view.dom.firstChild.innerHTML).toBe('o<span class="foo">ne </span><em class="foo">two</em><span class="foo"> thre</span>e');
925
+ });
926
+ it("can handle combining decorations from parent editors in child editors", async ()=>{
927
+ let decosFromFirstEditor;
928
+ let { view } = tempEditor({
929
+ doc: doc(p("one two three")),
930
+ plugins: [
931
+ decoPlugin([
932
+ Decoration.inline(2, 13, {
933
+ class: "foo"
934
+ })
935
+ ]),
936
+ decoPlugin([
937
+ Decoration.inline(2, 13, {
938
+ class: "bar"
939
+ })
940
+ ])
941
+ ],
942
+ nodeViews: {
943
+ paragraph: /*#__PURE__*/ forwardRef(function Paragraph(param, ref) {
944
+ let { nodeProps , children , ...props } = param;
945
+ decosFromFirstEditor = nodeProps.innerDecorations;
946
+ return /*#__PURE__*/ React.createElement("p", _extends({
947
+ ref: ref
948
+ }, props), children);
949
+ })
950
+ }
951
+ });
952
+ ({ view } = tempEditor({
953
+ doc: doc(p("one two three")),
954
+ plugins: [
955
+ decoPlugin([
956
+ Decoration.inline(1, 12, {
957
+ class: "baz"
958
+ })
959
+ ])
960
+ ],
961
+ decorations: ()=>decosFromFirstEditor
962
+ }));
963
+ expect(view.dom.querySelectorAll(".foo")).toHaveLength(1);
964
+ expect(view.dom.querySelectorAll(".bar")).toHaveLength(1);
965
+ expect(view.dom.querySelectorAll(".baz")).toHaveLength(1);
966
+ });
967
+ });