@handlewithcare/react-prosemirror 2.5.3 → 2.6.0-tiptap.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 (66) hide show
  1. package/README.md +2 -3
  2. package/dist/cjs/components/__tests__/ProseMirror.composition.test.js +398 -0
  3. package/dist/cjs/components/__tests__/ProseMirror.domchange.test.js +270 -0
  4. package/dist/cjs/components/__tests__/ProseMirror.draw-decoration.test.js +1010 -0
  5. package/dist/cjs/components/__tests__/ProseMirror.draw.test.js +337 -0
  6. package/dist/cjs/components/__tests__/ProseMirror.node-view.test.js +315 -0
  7. package/dist/cjs/components/__tests__/ProseMirror.selection.test.js +444 -0
  8. package/dist/cjs/components/__tests__/ProseMirror.test.js +382 -0
  9. package/dist/cjs/contexts/__tests__/DeferredLayoutEffects.test.js +141 -0
  10. package/dist/cjs/hooks/__tests__/useEditorViewLayoutEffect.test.js +108 -0
  11. package/dist/cjs/hooks/useClientOnly.js +19 -0
  12. package/dist/cjs/plugins/__tests__/reactKeys.test.js +81 -0
  13. package/dist/cjs/selection/SelectionDOMObserver.js +171 -0
  14. package/dist/cjs/selection/hasFocusAndSelection.js +35 -0
  15. package/dist/cjs/selection/selectionFromDOM.js +77 -0
  16. package/dist/cjs/selection/selectionToDOM.js +226 -0
  17. package/dist/cjs/ssr.js +85 -0
  18. package/dist/cjs/tiptap/TiptapEditorContent.js +93 -0
  19. package/dist/cjs/tiptap/TiptapEditorView.js +84 -0
  20. package/dist/cjs/tiptap/hooks/useTiptapEditorEffect.js +27 -0
  21. package/dist/cjs/tiptap/hooks/useTiptapEditorEventCallback.js +26 -0
  22. package/dist/cjs/tiptap/index.js +32 -0
  23. package/dist/cjs/tiptap/tiptapNodeView.js +181 -0
  24. package/dist/esm/components/__tests__/ProseMirror.composition.test.js +395 -0
  25. package/dist/esm/components/__tests__/ProseMirror.domchange.test.js +266 -0
  26. package/dist/esm/components/__tests__/ProseMirror.draw-decoration.test.js +967 -0
  27. package/dist/esm/components/__tests__/ProseMirror.draw.test.js +294 -0
  28. package/dist/esm/components/__tests__/ProseMirror.node-view.test.js +272 -0
  29. package/dist/esm/components/__tests__/ProseMirror.selection.test.js +440 -0
  30. package/dist/esm/components/__tests__/ProseMirror.test.js +339 -0
  31. package/dist/esm/contexts/__tests__/DeferredLayoutEffects.test.js +98 -0
  32. package/dist/esm/hooks/__tests__/useEditorViewLayoutEffect.test.js +99 -0
  33. package/dist/esm/hooks/useClientOnly.js +9 -0
  34. package/dist/esm/hooks/useEditorEffect.js +4 -0
  35. package/dist/esm/hooks/useEditorEventCallback.js +3 -5
  36. package/dist/esm/plugins/__tests__/reactKeys.test.js +77 -0
  37. package/dist/esm/selection/SelectionDOMObserver.js +161 -0
  38. package/dist/esm/selection/hasFocusAndSelection.js +17 -0
  39. package/dist/esm/selection/selectionFromDOM.js +59 -0
  40. package/dist/esm/selection/selectionToDOM.js +196 -0
  41. package/dist/esm/ssr.js +82 -0
  42. package/dist/esm/tiptap/TiptapEditorContent.js +42 -0
  43. package/dist/esm/tiptap/TiptapEditorView.js +35 -0
  44. package/dist/esm/tiptap/hooks/useTiptapEditorEffect.js +34 -0
  45. package/dist/esm/tiptap/hooks/useTiptapEditorEventCallback.js +26 -0
  46. package/dist/esm/tiptap/index.js +5 -0
  47. package/dist/esm/tiptap/tiptapNodeView.js +149 -0
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/dist/types/constants.d.ts +1 -1
  50. package/dist/types/hooks/__tests__/useEditorViewLayoutEffect.test.d.ts +1 -0
  51. package/dist/types/hooks/useClientOnly.d.ts +1 -0
  52. package/dist/types/hooks/useEditorEffect.d.ts +4 -0
  53. package/dist/types/hooks/useEditorEventCallback.d.ts +3 -5
  54. package/dist/types/props.d.ts +26 -26
  55. package/dist/types/selection/SelectionDOMObserver.d.ts +33 -0
  56. package/dist/types/selection/hasFocusAndSelection.d.ts +3 -0
  57. package/dist/types/selection/selectionFromDOM.d.ts +4 -0
  58. package/dist/types/selection/selectionToDOM.d.ts +9 -0
  59. package/dist/types/ssr.d.ts +19 -0
  60. package/dist/types/tiptap/TiptapEditorContent.d.ts +7 -0
  61. package/dist/types/tiptap/TiptapEditorView.d.ts +13 -0
  62. package/dist/types/tiptap/hooks/useTiptapEditorEffect.d.ts +21 -0
  63. package/dist/types/tiptap/hooks/useTiptapEditorEventCallback.d.ts +13 -0
  64. package/dist/types/tiptap/index.d.ts +5 -0
  65. package/dist/types/tiptap/tiptapNodeView.d.ts +48 -0
  66. package/package.json +8 -1
package/README.md CHANGED
@@ -693,15 +693,14 @@ export function SelectionWidget() {
693
693
  ### `NodeViewComponentProps`
694
694
 
695
695
  ```tsx
696
- type NodeViewComponentProps = {
696
+ interface NodeViewComponentProps extends AllHTMLAttributes<HTMLElement> = {
697
697
  nodeProps: {
698
698
  decorations: readonly Decoration[];
699
699
  innerDecorations: DecorationSource;
700
700
  node: Node;
701
- children?: ReactNode | ReactNode[];
702
701
  getPos: () => number;
703
702
  };
704
- } & HTMLAttributes<HTMLElement>;
703
+ };
705
704
  ```
706
705
 
707
706
  The props that will be passed to all node view components. These props map
@@ -0,0 +1,398 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ const _prosemirrorTestBuilder = require("prosemirror-test-builder");
6
+ const _prosemirrorView = require("prosemirror-view");
7
+ const _editorViewTestHelpersJs = require("../../testing/editorViewTestHelpers.js");
8
+ function endComposition(view, forceUpdate) {
9
+ (0, _prosemirrorView["__endComposition"])(view, forceUpdate);
10
+ }
11
+ function event(pm, type) {
12
+ pm.dom.dispatchEvent(new CompositionEvent(type));
13
+ }
14
+ function edit(node) {
15
+ let text = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "", from = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : node.nodeValue.length, to = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : from;
16
+ const val = node.nodeValue;
17
+ node.nodeValue = val.slice(0, from) + text + val.slice(to);
18
+ document.getSelection().collapse(node, from + text.length);
19
+ return node;
20
+ }
21
+ function hasCompositionNode(_pm) {
22
+ let { focusNode } = document.getSelection();
23
+ while(focusNode && !focusNode.pmViewDesc)focusNode = focusNode.parentNode;
24
+ return focusNode && focusNode.pmViewDesc.constructor.name == "CompositionViewDesc";
25
+ }
26
+ function compose(pm, start, update) {
27
+ let options = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {};
28
+ event(pm, "compositionstart");
29
+ expect(pm.composing).toBeTruthy();
30
+ let node;
31
+ const sel = document.getSelection();
32
+ for(let i = -1; i < update.length; i++){
33
+ if (i < 0) node = start();
34
+ else update[i](node);
35
+ const { focusNode , focusOffset } = sel;
36
+ // @ts-expect-error Internal property
37
+ pm.domObserver.flush();
38
+ if (options.cancel && i == update.length - 1) {
39
+ expect(hasCompositionNode(pm)).toBeFalsy();
40
+ } else {
41
+ expect(node.parentNode && pm.dom.contains(node.parentNode)).toBeTruthy();
42
+ expect(sel.focusNode === focusNode).toBeTruthy();
43
+ expect(sel.focusOffset === focusOffset).toBeTruthy();
44
+ if (options.node) expect(hasCompositionNode(pm)).toBeTruthy();
45
+ }
46
+ }
47
+ event(pm, "compositionend");
48
+ if (options.end) {
49
+ options.end(node);
50
+ // @ts-expect-error Internal property
51
+ pm.domObserver.flush();
52
+ }
53
+ endComposition(pm);
54
+ expect(pm.composing).toBeFalsy();
55
+ expect(hasCompositionNode(pm)).toBeFalsy();
56
+ }
57
+ // function wordDeco(state: EditorState) {
58
+ // const re = /\w+/g,
59
+ // deco: Decoration[] = [];
60
+ // state.doc.descendants((node, pos) => {
61
+ // if (node.isText)
62
+ // for (let m; (m = re.exec(node.text!)); )
63
+ // deco.push(
64
+ // Decoration.inline(pos + m.index, pos + m.index + m[0].length, {
65
+ // class: "word",
66
+ // })
67
+ // );
68
+ // });
69
+ // return DecorationSet.create(state.doc, deco);
70
+ // }
71
+ // const wordHighlighter = new Plugin({
72
+ // props: { decorations: wordDeco },
73
+ // });
74
+ // const Widget = forwardRef(function Widget(
75
+ // { widget, pos, ...props }: WidgetViewComponentProps,
76
+ // ref: Ref<HTMLElement>
77
+ // ) {
78
+ // return (
79
+ // <var ref={ref} {...props}>
80
+ // ×
81
+ // </var>
82
+ // );
83
+ // });
84
+ // function widgets(positions: number[], sides: number[]) {
85
+ // return new Plugin({
86
+ // state: {
87
+ // init(state) {
88
+ // const deco = positions.map((p, i) =>
89
+ // widget(p, Widget, { side: sides[i] })
90
+ // );
91
+ // return DecorationSet.create(state.doc!, deco);
92
+ // },
93
+ // apply(tr, deco) {
94
+ // return deco.map(tr.mapping, tr.doc);
95
+ // },
96
+ // },
97
+ // props: {
98
+ // decorations(this: Plugin, state) {
99
+ // return this.getState(state);
100
+ // },
101
+ // },
102
+ // });
103
+ // }
104
+ // These unfortunately aren't working at the moment, though
105
+ // composition seems to be working generally.
106
+ describe.skip("EditorView composition", ()=>{
107
+ it("supports composition in an empty block", ()=>{
108
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
109
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("<a>"))
110
+ });
111
+ compose(pm, ()=>edit(pm.dom.firstChild.appendChild(document.createTextNode("a"))), [
112
+ (n)=>edit(n, "b"),
113
+ (n)=>edit(n, "c")
114
+ ], {
115
+ node: true
116
+ });
117
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("abc")));
118
+ });
119
+ it("supports composition at end of block", ()=>{
120
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
121
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo"))
122
+ });
123
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "foo")), [
124
+ (n)=>edit(n, "!"),
125
+ (n)=>edit(n, "?")
126
+ ]);
127
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo!?")));
128
+ });
129
+ it("supports composition at end of block in a new node", ()=>{
130
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
131
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo"))
132
+ });
133
+ compose(pm, ()=>edit(pm.dom.firstChild.appendChild(document.createTextNode("!"))), [
134
+ (n)=>edit(n, "?")
135
+ ], // $$FORK: We don't use composition view descriptors except for in initially empty nodes
136
+ {
137
+ node: false
138
+ });
139
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo!?")));
140
+ });
141
+ it("supports composition at start of block in a new node", ()=>{
142
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
143
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo"))
144
+ });
145
+ compose(pm, ()=>{
146
+ const p = pm.dom.firstChild;
147
+ return edit(p.insertBefore(document.createTextNode("!"), p.firstChild));
148
+ }, [
149
+ (n)=>edit(n, "?")
150
+ ], // $$FORK: We don't use composition view descriptors except for in initially empty nodes
151
+ {
152
+ node: false
153
+ });
154
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("!?foo")));
155
+ });
156
+ it("supports composition inside existing text", ()=>{
157
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
158
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("foo"))
159
+ });
160
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "foo")), [
161
+ (n)=>edit(n, "x", 1),
162
+ (n)=>edit(n, "y", 2),
163
+ (n)=>edit(n, "z", 3)
164
+ ]);
165
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("fxyzoo")));
166
+ });
167
+ // TODO: Offset out of bound
168
+ // eslint-disable-next-line jest/no-disabled-tests
169
+ it.skip("can deal with Android-style newline-after-composition", ()=>{
170
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
171
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("abcdef"))
172
+ });
173
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "abcdef")), [
174
+ (n)=>edit(n, "x", 3),
175
+ (n)=>edit(n, "y", 4)
176
+ ], {
177
+ end: (n)=>{
178
+ const line = pm.dom.appendChild(document.createElement("div"));
179
+ line.textContent = "def";
180
+ n.nodeValue = "abcxy";
181
+ document.getSelection().collapse(line, 0);
182
+ }
183
+ });
184
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("abcxy"), (0, _prosemirrorTestBuilder.p)("def")));
185
+ });
186
+ it("handles replacement of existing words", ()=>{
187
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
188
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one two three"))
189
+ });
190
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "one two three"), "five", 4, 7), [
191
+ (n)=>edit(n, "seven", 4, 8),
192
+ (n)=>edit(n, "zero", 4, 9)
193
+ ]);
194
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one zero three")));
195
+ });
196
+ it("handles composition inside marks", ()=>{
197
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
198
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one ", (0, _prosemirrorTestBuilder.em)("two")))
199
+ });
200
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "two"), "o"), [
201
+ (n)=>edit(n, "o"),
202
+ (n)=>edit(n, "w")
203
+ ]);
204
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one ", (0, _prosemirrorTestBuilder.em)("twooow"))));
205
+ });
206
+ it.skip("handles composition in a mark that has multiple children", ()=>{
207
+ const { view: pm } = (0, _editorViewTestHelpersJs.tempEditor)({
208
+ doc: (0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one ", (0, _prosemirrorTestBuilder.em)("two", (0, _prosemirrorTestBuilder.strong)(" three"))))
209
+ });
210
+ compose(pm, ()=>edit((0, _editorViewTestHelpersJs.findTextNode)(pm.dom, "two"), "o"), [
211
+ (n)=>edit(n, "o"),
212
+ (n)=>edit(n, "w")
213
+ ]);
214
+ expect(pm.state.doc).toEqualNode((0, _prosemirrorTestBuilder.doc)((0, _prosemirrorTestBuilder.p)("one ", (0, _prosemirrorTestBuilder.em)("twooow", (0, _prosemirrorTestBuilder.strong)(" three")))));
215
+ });
216
+ // it("supports composition in a cursor wrapper", () => {
217
+ // const { view: pm } = tempEditor({ doc: doc(p("<a>")) });
218
+ // pm.dispatch(pm.state.tr.addStoredMark(schema.marks.em.create()));
219
+ // compose(
220
+ // pm,
221
+ // () =>
222
+ // edit(pm.dom.firstChild!.appendChild(document.createTextNode("")), "a"),
223
+ // [(n) => edit(n, "b"), (n) => edit(n, "c")],
224
+ // { node: true }
225
+ // );
226
+ // ist(pm.state.doc, doc(p(em("abc"))), eq);
227
+ // });
228
+ // it("handles composition in a multi-child mark with a cursor wrapper", () => {
229
+ // const { view: pm } = requireFocus(
230
+ // tempEditor({ doc: doc(p("one ", em("two<a>", strong(" three")))) })
231
+ // );
232
+ // pm.dispatch(pm.state.tr.addStoredMark(schema.marks.code.create()));
233
+ // const emNode = pm.dom.querySelector("em")!;
234
+ // compose(
235
+ // pm,
236
+ // () =>
237
+ // edit(
238
+ // emNode.insertBefore(
239
+ // document.createTextNode(""),
240
+ // emNode.querySelector("strong")
241
+ // ),
242
+ // "o"
243
+ // ),
244
+ // [(n) => edit(n, "o"), (n) => edit(n, "w")],
245
+ // { node: true }
246
+ // );
247
+ // ist(
248
+ // pm.state.doc,
249
+ // doc(p("one ", em("two", code("oow"), strong(" three")))),
250
+ // eq
251
+ // );
252
+ // });
253
+ // it("doesn't get interrupted by changes in decorations", () => {
254
+ // const { view: pm } = requireFocus(
255
+ // tempEditor({ doc: doc(p("foo ...")), plugins: [wordHighlighter] })
256
+ // );
257
+ // compose(pm, () => edit(findTextNode(pm.dom, " ...")!), [
258
+ // (n) => edit(n, "hi", 1, 4),
259
+ // ]);
260
+ // ist(pm.state.doc, doc(p("foo hi")), eq);
261
+ // });
262
+ // it("works inside highlighted text", () => {
263
+ // const { view: pm } = requireFocus(
264
+ // tempEditor({ doc: doc(p("one two")), plugins: [wordHighlighter] })
265
+ // );
266
+ // compose(pm, () => edit(findTextNode(pm.dom, "one")!, "x"), [
267
+ // (n) => edit(n, "y"),
268
+ // (n) => edit(n, "."),
269
+ // ]);
270
+ // ist(pm.state.doc, doc(p("onexy. two")), eq);
271
+ // });
272
+ // it("can handle compositions spanning multiple nodes", () => {
273
+ // const { view: pm } = requireFocus(
274
+ // tempEditor({ doc: doc(p("one two")), plugins: [wordHighlighter] })
275
+ // );
276
+ // compose(
277
+ // pm,
278
+ // () => edit(findTextNode(pm.dom, "two")!, "a"),
279
+ // [(n) => edit(n, "b"), (n) => edit(n, "c")],
280
+ // {
281
+ // end: (n: Text) => {
282
+ // n.parentNode!.previousSibling!.remove();
283
+ // n.parentNode!.previousSibling!.remove();
284
+ // return edit(n, "xyzone ", 0);
285
+ // },
286
+ // }
287
+ // );
288
+ // ist(pm.state.doc, doc(p("xyzone twoabc")), eq);
289
+ // });
290
+ // it("doesn't overwrite widgets next to the composition", () => {
291
+ // const { view: pm } = requireFocus(
292
+ // tempEditor({ doc: doc(p("")), plugins: [widgets([1, 1], [-1, 1])] })
293
+ // );
294
+ // compose(
295
+ // pm,
296
+ // () => {
297
+ // const p = pm.dom.firstChild!;
298
+ // return edit(p.insertBefore(document.createTextNode("a"), p.lastChild));
299
+ // },
300
+ // [(n) => edit(n, "b", 0, 1)],
301
+ // {
302
+ // end: () => {
303
+ // ist(pm.dom.querySelectorAll("var").length, 2);
304
+ // },
305
+ // }
306
+ // );
307
+ // ist(pm.state.doc, doc(p("b")), eq);
308
+ // });
309
+ // it("cancels composition when a change fully overlaps with it", () => {
310
+ // const { view: pm } = requireFocus(
311
+ // tempEditor({ doc: doc(p("one"), p("two"), p("three")) })
312
+ // );
313
+ // compose(
314
+ // pm,
315
+ // () => edit(findTextNode(pm.dom, "two")!, "x"),
316
+ // [() => pm.dispatch(pm.state.tr.insertText("---", 3, 13))],
317
+ // { cancel: true }
318
+ // );
319
+ // ist(pm.state.doc, doc(p("on---hree")), eq);
320
+ // });
321
+ // it("cancels composition when a change partially overlaps with it", () => {
322
+ // const { view: pm } = requireFocus(
323
+ // tempEditor({ doc: doc(p("one"), p("two"), p("three")) })
324
+ // );
325
+ // compose(
326
+ // pm,
327
+ // () => edit(findTextNode(pm.dom, "two")!, "x", 0),
328
+ // [() => pm.dispatch(pm.state.tr.insertText("---", 7, 15))],
329
+ // { cancel: true }
330
+ // );
331
+ // ist(pm.state.doc, doc(p("one"), p("x---ee")), eq);
332
+ // });
333
+ // it("cancels composition when a change happens inside of it", () => {
334
+ // const { view: pm } = requireFocus(
335
+ // tempEditor({ doc: doc(p("one"), p("two"), p("three")) })
336
+ // );
337
+ // compose(
338
+ // pm,
339
+ // () => edit(findTextNode(pm.dom, "two")!, "x", 0),
340
+ // [() => pm.dispatch(pm.state.tr.insertText("!", 7, 8))],
341
+ // { cancel: true }
342
+ // );
343
+ // ist(pm.state.doc, doc(p("one"), p("x!wo"), p("three")), eq);
344
+ // });
345
+ // it("doesn't cancel composition when a change happens elsewhere", () => {
346
+ // const { view: pm } = requireFocus(
347
+ // tempEditor({ doc: doc(p("one"), p("two"), p("three")) })
348
+ // );
349
+ // compose(pm, () => edit(findTextNode(pm.dom, "two")!, "x", 0), [
350
+ // (n) => edit(n, "y", 1),
351
+ // () => pm.dispatch(pm.state.tr.insertText("!", 2, 3)),
352
+ // (n) => edit(n, "z", 2),
353
+ // ]);
354
+ // ist(pm.state.doc, doc(p("o!e"), p("xyztwo"), p("three")), eq);
355
+ // });
356
+ // it("handles compositions rapidly following each other", () => {
357
+ // const { view: pm } = tempEditor({ doc: doc(p("one"), p("two")) });
358
+ // event(pm, "compositionstart");
359
+ // const one = findTextNode(pm.dom, "one")!;
360
+ // edit(one, "!");
361
+ // pm.domObserver.flush();
362
+ // event(pm, "compositionend");
363
+ // one.nodeValue = "one!!";
364
+ // const L2 = pm.dom.lastChild;
365
+ // event(pm, "compositionstart");
366
+ // const two = findTextNode(pm.dom, "two")!;
367
+ // ist(pm.dom.lastChild, L2);
368
+ // edit(two, ".");
369
+ // pm.domObserver.flush();
370
+ // ist(document.getSelection()!.focusNode, two);
371
+ // ist(document.getSelection()!.focusOffset, 4);
372
+ // ist(pm.composing);
373
+ // event(pm, "compositionend");
374
+ // pm.domObserver.flush();
375
+ // ist(pm.state.doc, doc(p("one!!"), p("two.")), eq);
376
+ // });
377
+ // function crossParagraph(first = false) {
378
+ // const { view: pm } = requireFocus(
379
+ // tempEditor({ doc: doc(p("one <a>two"), p("three"), p("four<b> five")) })
380
+ // );
381
+ // compose(
382
+ // pm,
383
+ // () => {
384
+ // for (let i = 0; i < 2; i++)
385
+ // pm.dom.removeChild(first ? pm.dom.lastChild! : pm.dom.firstChild!);
386
+ // const target = pm.dom.firstChild!.firstChild as Text;
387
+ // target.nodeValue = "one A five";
388
+ // document.getSelection()!.collapse(target, 4);
389
+ // return target;
390
+ // },
391
+ // [(n) => edit(n, "B", 4, 5), (n) => edit(n, "C", 4, 5)]
392
+ // );
393
+ // ist(pm.state.doc, doc(p("one C five")), eq);
394
+ // }
395
+ // it("can handle cross-paragraph compositions", () => crossParagraph(true));
396
+ // it("can handle cross-paragraph compositions (keeping the last paragraph)", () =>
397
+ // crossParagraph(false));
398
+ });