@portabletext/editor 0.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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/lib/index.d.mts +911 -0
  4. package/lib/index.d.ts +911 -0
  5. package/lib/index.esm.js +4896 -0
  6. package/lib/index.esm.js.map +1 -0
  7. package/lib/index.js +4874 -0
  8. package/lib/index.js.map +1 -0
  9. package/lib/index.mjs +4896 -0
  10. package/lib/index.mjs.map +1 -0
  11. package/package.json +119 -0
  12. package/src/editor/Editable.tsx +683 -0
  13. package/src/editor/PortableTextEditor.tsx +308 -0
  14. package/src/editor/__tests__/PortableTextEditor.test.tsx +386 -0
  15. package/src/editor/__tests__/PortableTextEditorTester.tsx +116 -0
  16. package/src/editor/__tests__/RangeDecorations.test.tsx +115 -0
  17. package/src/editor/__tests__/handleClick.test.tsx +218 -0
  18. package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +389 -0
  19. package/src/editor/__tests__/utils.ts +39 -0
  20. package/src/editor/components/DraggableBlock.tsx +287 -0
  21. package/src/editor/components/Element.tsx +279 -0
  22. package/src/editor/components/Leaf.tsx +288 -0
  23. package/src/editor/components/SlateContainer.tsx +81 -0
  24. package/src/editor/components/Synchronizer.tsx +190 -0
  25. package/src/editor/hooks/usePortableTextEditor.ts +23 -0
  26. package/src/editor/hooks/usePortableTextEditorKeyGenerator.ts +24 -0
  27. package/src/editor/hooks/usePortableTextEditorSelection.ts +22 -0
  28. package/src/editor/hooks/usePortableTextEditorValue.ts +16 -0
  29. package/src/editor/hooks/usePortableTextReadOnly.ts +20 -0
  30. package/src/editor/hooks/useSyncValue.test.tsx +125 -0
  31. package/src/editor/hooks/useSyncValue.ts +372 -0
  32. package/src/editor/nodes/DefaultAnnotation.tsx +16 -0
  33. package/src/editor/nodes/DefaultObject.tsx +15 -0
  34. package/src/editor/nodes/index.ts +189 -0
  35. package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +244 -0
  36. package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +142 -0
  37. package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +346 -0
  38. package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +162 -0
  39. package/src/editor/plugins/__tests__/withHotkeys.test.tsx +212 -0
  40. package/src/editor/plugins/__tests__/withInsertBreak.test.tsx +204 -0
  41. package/src/editor/plugins/__tests__/withPlaceholderBlock.test.tsx +133 -0
  42. package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +65 -0
  43. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +1377 -0
  44. package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +91 -0
  45. package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +115 -0
  46. package/src/editor/plugins/createWithEditableAPI.ts +573 -0
  47. package/src/editor/plugins/createWithHotKeys.ts +304 -0
  48. package/src/editor/plugins/createWithInsertBreak.ts +45 -0
  49. package/src/editor/plugins/createWithInsertData.ts +359 -0
  50. package/src/editor/plugins/createWithMaxBlocks.ts +24 -0
  51. package/src/editor/plugins/createWithObjectKeys.ts +63 -0
  52. package/src/editor/plugins/createWithPatches.ts +274 -0
  53. package/src/editor/plugins/createWithPlaceholderBlock.ts +36 -0
  54. package/src/editor/plugins/createWithPortableTextBlockStyle.ts +91 -0
  55. package/src/editor/plugins/createWithPortableTextLists.ts +160 -0
  56. package/src/editor/plugins/createWithPortableTextMarkModel.ts +441 -0
  57. package/src/editor/plugins/createWithPortableTextSelections.ts +65 -0
  58. package/src/editor/plugins/createWithSchemaTypes.ts +76 -0
  59. package/src/editor/plugins/createWithUndoRedo.ts +494 -0
  60. package/src/editor/plugins/createWithUtils.ts +81 -0
  61. package/src/editor/plugins/index.ts +155 -0
  62. package/src/index.ts +11 -0
  63. package/src/patch/PatchEvent.ts +33 -0
  64. package/src/patch/applyPatch.ts +29 -0
  65. package/src/patch/array.ts +89 -0
  66. package/src/patch/arrayInsert.ts +27 -0
  67. package/src/patch/object.ts +39 -0
  68. package/src/patch/patches.ts +53 -0
  69. package/src/patch/primitive.ts +43 -0
  70. package/src/patch/string.ts +51 -0
  71. package/src/types/editor.ts +576 -0
  72. package/src/types/options.ts +17 -0
  73. package/src/types/patch.ts +65 -0
  74. package/src/types/slate.ts +25 -0
  75. package/src/utils/__tests__/dmpToOperations.test.ts +181 -0
  76. package/src/utils/__tests__/operationToPatches.test.ts +421 -0
  77. package/src/utils/__tests__/patchToOperations.test.ts +293 -0
  78. package/src/utils/__tests__/ranges.test.ts +18 -0
  79. package/src/utils/__tests__/valueNormalization.test.tsx +62 -0
  80. package/src/utils/__tests__/values.test.ts +253 -0
  81. package/src/utils/applyPatch.ts +407 -0
  82. package/src/utils/bufferUntil.ts +15 -0
  83. package/src/utils/debug.ts +12 -0
  84. package/src/utils/getPortableTextMemberSchemaTypes.ts +100 -0
  85. package/src/utils/operationToPatches.ts +357 -0
  86. package/src/utils/patches.ts +36 -0
  87. package/src/utils/paths.ts +60 -0
  88. package/src/utils/ranges.ts +77 -0
  89. package/src/utils/schema.ts +8 -0
  90. package/src/utils/selection.ts +65 -0
  91. package/src/utils/ucs2Indices.ts +67 -0
  92. package/src/utils/validateValue.ts +394 -0
  93. package/src/utils/values.ts +208 -0
  94. package/src/utils/weakMaps.ts +24 -0
  95. package/src/utils/withChanges.ts +25 -0
  96. package/src/utils/withPreserveKeys.ts +14 -0
  97. package/src/utils/withoutPatching.ts +14 -0
@@ -0,0 +1,1377 @@
1
+ import {describe, expect, it, jest} from '@jest/globals'
2
+ /* eslint-disable max-nested-callbacks */
3
+ import {render, waitFor} from '@testing-library/react'
4
+ import {createRef, type RefObject} from 'react'
5
+
6
+ import {type EditorSelection} from '../../../types/editor'
7
+ import {
8
+ PortableTextEditorTester,
9
+ schemaType,
10
+ schemaTypeWithColorAndLink,
11
+ } from '../../__tests__/PortableTextEditorTester'
12
+ import {PortableTextEditor} from '../../PortableTextEditor'
13
+
14
+ describe('plugin:withPortableTextMarksModel', () => {
15
+ describe('normalization', () => {
16
+ it('merges adjacent spans correctly when removing annotations', async () => {
17
+ const editorRef: RefObject<PortableTextEditor> = createRef()
18
+ const initialValue = [
19
+ {
20
+ _key: '5fc57af23597',
21
+ _type: 'myTestBlockType',
22
+ children: [
23
+ {
24
+ _key: 'be1c67c6971a',
25
+ _type: 'span',
26
+ marks: [],
27
+ text: 'This is a ',
28
+ },
29
+ {
30
+ _key: '11c8c9f783a8',
31
+ _type: 'span',
32
+ marks: ['fde1fd54b544'],
33
+ text: 'link',
34
+ },
35
+ {
36
+ _key: '576c748e0cd2',
37
+ _type: 'span',
38
+ marks: [],
39
+ text: ', this is ',
40
+ },
41
+ {
42
+ _key: 'f3d73d3833bf',
43
+ _type: 'span',
44
+ marks: ['7b6d3d5de30c'],
45
+ text: 'another',
46
+ },
47
+ {
48
+ _key: '73b01f13c2ec',
49
+ _type: 'span',
50
+ marks: [],
51
+ text: ', and this is ',
52
+ },
53
+ {
54
+ _key: '13eb0d467c82',
55
+ _type: 'span',
56
+ marks: ['93a1d24eade0'],
57
+ text: 'a third',
58
+ },
59
+ ],
60
+ markDefs: [
61
+ {
62
+ _key: 'fde1fd54b544',
63
+ _type: 'link',
64
+ url: '1',
65
+ },
66
+ {
67
+ _key: '7b6d3d5de30c',
68
+ _type: 'link',
69
+ url: '2',
70
+ },
71
+ {
72
+ _key: '93a1d24eade0',
73
+ _type: 'link',
74
+ url: '3',
75
+ },
76
+ ],
77
+ style: 'normal',
78
+ },
79
+ ]
80
+
81
+ const onChange = jest.fn()
82
+ await waitFor(() => {
83
+ render(
84
+ <PortableTextEditorTester
85
+ onChange={onChange}
86
+ ref={editorRef}
87
+ schemaType={schemaType}
88
+ value={initialValue}
89
+ />,
90
+ )
91
+ })
92
+
93
+ await waitFor(() => {
94
+ if (editorRef.current) {
95
+ PortableTextEditor.focus(editorRef.current)
96
+ PortableTextEditor.select(editorRef.current, {
97
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: '11c8c9f783a8'}], offset: 4},
98
+ anchor: {path: [{_key: '5fc57af23597'}, 'children', {_key: '11c8c9f783a8'}], offset: 0},
99
+ })
100
+ // eslint-disable-next-line max-nested-callbacks
101
+ const linkType = editorRef.current.schemaTypes.annotations.find((a) => a.name === 'link')
102
+ if (!linkType) {
103
+ throw new Error('No link type found')
104
+ }
105
+ PortableTextEditor.removeAnnotation(editorRef.current, linkType)
106
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
107
+ {
108
+ _key: '5fc57af23597',
109
+ _type: 'myTestBlockType',
110
+ children: [
111
+ {
112
+ _key: 'be1c67c6971a',
113
+ _type: 'span',
114
+ marks: [],
115
+ text: 'This is a link, this is ',
116
+ },
117
+ {
118
+ _key: 'f3d73d3833bf',
119
+ _type: 'span',
120
+ marks: ['7b6d3d5de30c'],
121
+ text: 'another',
122
+ },
123
+ {
124
+ _key: '73b01f13c2ec',
125
+ _type: 'span',
126
+ marks: [],
127
+ text: ', and this is ',
128
+ },
129
+ {
130
+ _key: '13eb0d467c82',
131
+ _type: 'span',
132
+ marks: ['93a1d24eade0'],
133
+ text: 'a third',
134
+ },
135
+ ],
136
+ markDefs: [
137
+ {
138
+ _key: '7b6d3d5de30c',
139
+ _type: 'link',
140
+ url: '2',
141
+ },
142
+ {
143
+ _key: '93a1d24eade0',
144
+ _type: 'link',
145
+ url: '3',
146
+ },
147
+ ],
148
+ style: 'normal',
149
+ },
150
+ ])
151
+ }
152
+ })
153
+ })
154
+
155
+ it('splits correctly when adding marks', async () => {
156
+ const editorRef: RefObject<PortableTextEditor> = createRef()
157
+ const initialValue = [
158
+ {
159
+ _key: 'a',
160
+ _type: 'myTestBlockType',
161
+ children: [
162
+ {
163
+ _key: 'a1',
164
+ _type: 'span',
165
+ marks: [],
166
+ text: '123',
167
+ },
168
+ ],
169
+ markDefs: [],
170
+ style: 'normal',
171
+ },
172
+ {
173
+ _key: 'b',
174
+ _type: 'myTestBlockType',
175
+ children: [
176
+ {
177
+ _key: 'b1',
178
+ _type: 'span',
179
+ marks: [],
180
+ text: '123',
181
+ },
182
+ ],
183
+ markDefs: [],
184
+ style: 'normal',
185
+ },
186
+ ]
187
+ const onChange = jest.fn()
188
+ await waitFor(() => {
189
+ render(
190
+ <PortableTextEditorTester
191
+ onChange={onChange}
192
+ ref={editorRef}
193
+ schemaType={schemaType}
194
+ value={initialValue}
195
+ />,
196
+ )
197
+ })
198
+ await waitFor(() => {
199
+ if (editorRef.current) {
200
+ const editor = editorRef.current
201
+ PortableTextEditor.focus(editor)
202
+ PortableTextEditor.select(editor, {
203
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
204
+ anchor: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 1},
205
+ })
206
+ PortableTextEditor.toggleMark(editor, 'strong')
207
+ const value = PortableTextEditor.getValue(editor)
208
+ expect(value).toMatchInlineSnapshot(`
209
+ Array [
210
+ Object {
211
+ "_key": "a",
212
+ "_type": "myTestBlockType",
213
+ "children": Array [
214
+ Object {
215
+ "_key": "a1",
216
+ "_type": "span",
217
+ "marks": Array [
218
+ "strong",
219
+ ],
220
+ "text": "123",
221
+ },
222
+ ],
223
+ "markDefs": Array [],
224
+ "style": "normal",
225
+ },
226
+ Object {
227
+ "_key": "b",
228
+ "_type": "myTestBlockType",
229
+ "children": Array [
230
+ Object {
231
+ "_key": "b1",
232
+ "_type": "span",
233
+ "marks": Array [
234
+ "strong",
235
+ ],
236
+ "text": "1",
237
+ },
238
+ Object {
239
+ "_key": "1",
240
+ "_type": "span",
241
+ "marks": Array [],
242
+ "text": "23",
243
+ },
244
+ ],
245
+ "markDefs": Array [],
246
+ "style": "normal",
247
+ },
248
+ ]
249
+ `)
250
+ }
251
+ })
252
+ })
253
+ it('merges children correctly when toggling marks in various ranges', async () => {
254
+ const editorRef: RefObject<PortableTextEditor> = createRef()
255
+ const initialValue = [
256
+ {
257
+ _key: 'a',
258
+ _type: 'myTestBlockType',
259
+ children: [
260
+ {
261
+ _key: 'a1',
262
+ _type: 'span',
263
+ marks: [],
264
+ text: '1234',
265
+ },
266
+ ],
267
+ markDefs: [],
268
+ style: 'normal',
269
+ },
270
+ ]
271
+ const onChange = jest.fn()
272
+ await waitFor(() => {
273
+ render(
274
+ <PortableTextEditorTester
275
+ onChange={onChange}
276
+ ref={editorRef}
277
+ schemaType={schemaType}
278
+ value={initialValue}
279
+ />,
280
+ )
281
+ })
282
+ const editor = editorRef.current!
283
+ expect(editor).toBeDefined()
284
+ await waitFor(() => {
285
+ PortableTextEditor.focus(editor)
286
+ PortableTextEditor.select(editor, {
287
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
288
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 4},
289
+ })
290
+ PortableTextEditor.toggleMark(editor, 'strong')
291
+ expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
292
+ Array [
293
+ Object {
294
+ "_key": "a",
295
+ "_type": "myTestBlockType",
296
+ "children": Array [
297
+ Object {
298
+ "_key": "a1",
299
+ "_type": "span",
300
+ "marks": Array [
301
+ "strong",
302
+ ],
303
+ "text": "1234",
304
+ },
305
+ ],
306
+ "markDefs": Array [],
307
+ "style": "normal",
308
+ },
309
+ ]
310
+ `)
311
+ })
312
+ await waitFor(() => {
313
+ if (editorRef.current) {
314
+ PortableTextEditor.select(editorRef.current, {
315
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 1},
316
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 3},
317
+ })
318
+ PortableTextEditor.toggleMark(editorRef.current, 'strong')
319
+ expect(PortableTextEditor.getValue(editorRef.current)).toMatchInlineSnapshot(`
320
+ Array [
321
+ Object {
322
+ "_key": "a",
323
+ "_type": "myTestBlockType",
324
+ "children": Array [
325
+ Object {
326
+ "_key": "a1",
327
+ "_type": "span",
328
+ "marks": Array [
329
+ "strong",
330
+ ],
331
+ "text": "1",
332
+ },
333
+ Object {
334
+ "_key": "2",
335
+ "_type": "span",
336
+ "marks": Array [],
337
+ "text": "23",
338
+ },
339
+ Object {
340
+ "_key": "1",
341
+ "_type": "span",
342
+ "marks": Array [
343
+ "strong",
344
+ ],
345
+ "text": "4",
346
+ },
347
+ ],
348
+ "markDefs": Array [],
349
+ "style": "normal",
350
+ },
351
+ ]
352
+ `)
353
+ }
354
+ })
355
+ await waitFor(() => {
356
+ if (editor) {
357
+ PortableTextEditor.select(editor, {
358
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
359
+ anchor: {path: [{_key: 'a'}, 'children', {_key: '1'}], offset: 1},
360
+ })
361
+ PortableTextEditor.toggleMark(editor, 'strong')
362
+ expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
363
+ Array [
364
+ Object {
365
+ "_key": "a",
366
+ "_type": "myTestBlockType",
367
+ "children": Array [
368
+ Object {
369
+ "_key": "a1",
370
+ "_type": "span",
371
+ "marks": Array [
372
+ "strong",
373
+ ],
374
+ "text": "1234",
375
+ },
376
+ ],
377
+ "markDefs": Array [],
378
+ "style": "normal",
379
+ },
380
+ ]
381
+ `)
382
+ }
383
+ })
384
+ })
385
+ it('toggles marks on children with annotation marks correctly', async () => {
386
+ const editorRef: RefObject<PortableTextEditor> = createRef()
387
+ const initialValue = [
388
+ {
389
+ _key: 'a',
390
+ _type: 'myTestBlockType',
391
+ children: [
392
+ {
393
+ _key: 'a1',
394
+ _type: 'span',
395
+ marks: ['abc'],
396
+ text: 'A link',
397
+ },
398
+ {
399
+ _key: 'a2',
400
+ _type: 'span',
401
+ marks: [],
402
+ text: ', not a link',
403
+ },
404
+ ],
405
+ markDefs: [
406
+ {
407
+ _type: 'link',
408
+ _key: 'abc',
409
+ href: 'http://www.link.com',
410
+ },
411
+ ],
412
+ style: 'normal',
413
+ },
414
+ ]
415
+ const onChange = jest.fn()
416
+ await waitFor(() => {
417
+ render(
418
+ <PortableTextEditorTester
419
+ onChange={onChange}
420
+ ref={editorRef}
421
+ schemaType={schemaType}
422
+ value={initialValue}
423
+ />,
424
+ )
425
+ })
426
+ const editor = editorRef.current!
427
+ expect(editor).toBeDefined()
428
+
429
+ await waitFor(() => {
430
+ PortableTextEditor.focus(editor)
431
+ PortableTextEditor.select(editor, {
432
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
433
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'b1'}], offset: 12},
434
+ })
435
+ PortableTextEditor.toggleMark(editor, 'strong')
436
+ expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
437
+ Array [
438
+ Object {
439
+ "_key": "a",
440
+ "_type": "myTestBlockType",
441
+ "children": Array [
442
+ Object {
443
+ "_key": "a1",
444
+ "_type": "span",
445
+ "marks": Array [
446
+ "abc",
447
+ "strong",
448
+ ],
449
+ "text": "A link",
450
+ },
451
+ Object {
452
+ "_key": "a2",
453
+ "_type": "span",
454
+ "marks": Array [
455
+ "strong",
456
+ ],
457
+ "text": ", not a link",
458
+ },
459
+ ],
460
+ "markDefs": Array [
461
+ Object {
462
+ "_key": "abc",
463
+ "_type": "link",
464
+ "href": "http://www.link.com",
465
+ },
466
+ ],
467
+ "style": "normal",
468
+ },
469
+ ]
470
+ `)
471
+ })
472
+ })
473
+
474
+ it('merges blocks correctly when containing links', async () => {
475
+ const editorRef: RefObject<PortableTextEditor> = createRef()
476
+ const initialValue = [
477
+ {
478
+ _key: '5fc57af23597',
479
+ _type: 'myTestBlockType',
480
+ children: [
481
+ {
482
+ _key: 'be1c67c6971a',
483
+ _type: 'span',
484
+ marks: [],
485
+ text: 'This is a ',
486
+ },
487
+ {
488
+ _key: '11c8c9f783a8',
489
+ _type: 'span',
490
+ marks: ['fde1fd54b544'],
491
+ text: 'link',
492
+ },
493
+ ],
494
+ markDefs: [
495
+ {
496
+ _key: 'fde1fd54b544',
497
+ _type: 'link',
498
+ url: '1',
499
+ },
500
+ ],
501
+ style: 'normal',
502
+ },
503
+ {
504
+ _key: '7cd53af36712',
505
+ _type: 'myTestBlockType',
506
+ children: [
507
+ {
508
+ _key: '576c748e0cd2',
509
+ _type: 'span',
510
+ marks: [],
511
+ text: 'This is ',
512
+ },
513
+ {
514
+ _key: 'f3d73d3833bf',
515
+ _type: 'span',
516
+ marks: ['7b6d3d5de30c'],
517
+ text: 'another',
518
+ },
519
+ ],
520
+ markDefs: [
521
+ {
522
+ _key: '7b6d3d5de30c',
523
+ _type: 'link',
524
+ url: '2',
525
+ },
526
+ ],
527
+ style: 'normal',
528
+ },
529
+ ]
530
+ const sel: EditorSelection = {
531
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: '11c8c9f783a8'}], offset: 4},
532
+ anchor: {path: [{_key: '7cd53af36712'}, 'children', {_key: '576c748e0cd2'}], offset: 0},
533
+ }
534
+ const onChange = jest.fn()
535
+ await waitFor(() => {
536
+ render(
537
+ <PortableTextEditorTester
538
+ onChange={onChange}
539
+ ref={editorRef}
540
+ schemaType={schemaType}
541
+ value={initialValue}
542
+ />,
543
+ )
544
+ })
545
+ const editor = editorRef.current!
546
+ expect(editor).toBeDefined()
547
+ await waitFor(() => {
548
+ PortableTextEditor.select(editor, sel)
549
+ PortableTextEditor.delete(editor, sel)
550
+ expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
551
+ Array [
552
+ Object {
553
+ "_key": "5fc57af23597",
554
+ "_type": "myTestBlockType",
555
+ "children": Array [
556
+ Object {
557
+ "_key": "be1c67c6971a",
558
+ "_type": "span",
559
+ "marks": Array [],
560
+ "text": "This is a ",
561
+ },
562
+ Object {
563
+ "_key": "11c8c9f783a8",
564
+ "_type": "span",
565
+ "marks": Array [
566
+ "fde1fd54b544",
567
+ ],
568
+ "text": "link",
569
+ },
570
+ Object {
571
+ "_key": "576c748e0cd2",
572
+ "_type": "span",
573
+ "marks": Array [],
574
+ "text": "This is ",
575
+ },
576
+ Object {
577
+ "_key": "f3d73d3833bf",
578
+ "_type": "span",
579
+ "marks": Array [
580
+ "7b6d3d5de30c",
581
+ ],
582
+ "text": "another",
583
+ },
584
+ ],
585
+ "markDefs": Array [
586
+ Object {
587
+ "_key": "fde1fd54b544",
588
+ "_type": "link",
589
+ "url": "1",
590
+ },
591
+ Object {
592
+ "_key": "7b6d3d5de30c",
593
+ "_type": "link",
594
+ "url": "2",
595
+ },
596
+ ],
597
+ "style": "normal",
598
+ },
599
+ ]
600
+ `)
601
+ })
602
+ })
603
+
604
+ it('resets markDefs when splitting a block in the beginning', async () => {
605
+ const editorRef: RefObject<PortableTextEditor> = createRef()
606
+ const initialValue = [
607
+ {
608
+ _key: '1987f99da4a2',
609
+ _type: 'myTestBlockType',
610
+ children: [
611
+ {
612
+ _key: '3693e789451c',
613
+ _type: 'span',
614
+ marks: [],
615
+ text: '1',
616
+ },
617
+ ],
618
+ markDefs: [],
619
+ style: 'normal',
620
+ },
621
+ {
622
+ _key: '2f55670a03bb',
623
+ _type: 'myTestBlockType',
624
+ children: [
625
+ {
626
+ _key: '9f5ed7dee7ab',
627
+ _type: 'span',
628
+ marks: ['bab319ad3a9d'],
629
+ text: '2',
630
+ },
631
+ ],
632
+ markDefs: [
633
+ {
634
+ _key: 'bab319ad3a9d',
635
+ _type: 'link',
636
+ href: 'http://www.123.com',
637
+ },
638
+ ],
639
+ style: 'normal',
640
+ },
641
+ ]
642
+ const sel: EditorSelection = {
643
+ focus: {path: [{_key: '2f55670a03bb'}, 'children', {_key: '9f5ed7dee7ab'}], offset: 0},
644
+ anchor: {path: [{_key: '2f55670a03bb'}, 'children', {_key: '9f5ed7dee7ab'}], offset: 0},
645
+ }
646
+ const onChange = jest.fn()
647
+ await waitFor(() => {
648
+ render(
649
+ <PortableTextEditorTester
650
+ onChange={onChange}
651
+ ref={editorRef}
652
+ schemaType={schemaType}
653
+ value={initialValue}
654
+ />,
655
+ )
656
+ })
657
+
658
+ const editor = editorRef.current!
659
+ expect(editor).toBeDefined()
660
+
661
+ await waitFor(() => {
662
+ PortableTextEditor.select(editor, sel)
663
+ PortableTextEditor.focus(editor)
664
+ PortableTextEditor.insertBreak(editor)
665
+ expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
666
+ Array [
667
+ Object {
668
+ "_key": "1987f99da4a2",
669
+ "_type": "myTestBlockType",
670
+ "children": Array [
671
+ Object {
672
+ "_key": "3693e789451c",
673
+ "_type": "span",
674
+ "marks": Array [],
675
+ "text": "1",
676
+ },
677
+ ],
678
+ "markDefs": Array [],
679
+ "style": "normal",
680
+ },
681
+ Object {
682
+ "_key": "3",
683
+ "_type": "myTestBlockType",
684
+ "children": Array [
685
+ Object {
686
+ "_key": "2",
687
+ "_type": "span",
688
+ "marks": Array [],
689
+ "text": "",
690
+ },
691
+ ],
692
+ "markDefs": Array [],
693
+ "style": "normal",
694
+ },
695
+ Object {
696
+ "_key": "2f55670a03bb",
697
+ "_type": "myTestBlockType",
698
+ "children": Array [
699
+ Object {
700
+ "_key": "9f5ed7dee7ab",
701
+ "_type": "span",
702
+ "marks": Array [
703
+ "bab319ad3a9d",
704
+ ],
705
+ "text": "2",
706
+ },
707
+ ],
708
+ "markDefs": Array [
709
+ Object {
710
+ "_key": "bab319ad3a9d",
711
+ "_type": "link",
712
+ "href": "http://www.123.com",
713
+ },
714
+ ],
715
+ "style": "normal",
716
+ },
717
+ ]
718
+ `)
719
+ })
720
+ })
721
+ })
722
+ describe('selection', () => {
723
+ it('should emit a new selection object when toggling marks, even though the value is the same', async () => {
724
+ const editorRef: RefObject<PortableTextEditor> = createRef()
725
+ const initialValue = [
726
+ {
727
+ _key: '1987f99da4a2',
728
+ _type: 'myTestBlockType',
729
+ children: [
730
+ {
731
+ _key: '3693e789451c',
732
+ _type: 'span',
733
+ marks: [],
734
+ text: '',
735
+ },
736
+ ],
737
+ markDefs: [],
738
+ style: 'normal',
739
+ },
740
+ ]
741
+ const onChange = jest.fn()
742
+
743
+ await waitFor(() => {
744
+ render(
745
+ <PortableTextEditorTester
746
+ onChange={onChange}
747
+ ref={editorRef}
748
+ schemaType={schemaType}
749
+ value={initialValue}
750
+ />,
751
+ )
752
+ })
753
+
754
+ const editor = editorRef.current!
755
+ expect(editor).toBeDefined()
756
+
757
+ await waitFor(() => {
758
+ PortableTextEditor.focus(editor)
759
+ })
760
+ const currentSelectionObject = PortableTextEditor.getSelection(editor)
761
+
762
+ await waitFor(() => {
763
+ PortableTextEditor.toggleMark(editor, 'strong')
764
+ })
765
+ const nextSelectionObject = PortableTextEditor.getSelection(editor)
766
+ expect(currentSelectionObject).toEqual(nextSelectionObject)
767
+ expect(currentSelectionObject === nextSelectionObject).toBe(false)
768
+ expect(onChange).toHaveBeenCalledWith({type: 'selection', selection: nextSelectionObject})
769
+ })
770
+
771
+ it('should return active marks that cover the whole selection', async () => {
772
+ const editorRef: RefObject<PortableTextEditor> = createRef()
773
+ const initialValue = [
774
+ {
775
+ _key: 'a',
776
+ _type: 'myTestBlockType',
777
+ children: [
778
+ {
779
+ _key: 'a1',
780
+ _type: 'span',
781
+ marks: ['strong'],
782
+ text: '12',
783
+ },
784
+ {
785
+ _key: '2',
786
+ _type: 'span',
787
+ marks: [],
788
+ text: '34',
789
+ },
790
+ ],
791
+ markDefs: [{_key: 'strong', _type: 'strong'}],
792
+ style: 'normal',
793
+ },
794
+ ]
795
+ const onChange = jest.fn()
796
+ await waitFor(() => {
797
+ render(
798
+ <PortableTextEditorTester
799
+ onChange={onChange}
800
+ ref={editorRef}
801
+ schemaType={schemaType}
802
+ value={initialValue}
803
+ />,
804
+ )
805
+ })
806
+ const editor = editorRef.current!
807
+ expect(editor).toBeDefined()
808
+ await waitFor(() => {
809
+ PortableTextEditor.focus(editor)
810
+ PortableTextEditor.select(editor, {
811
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
812
+ anchor: {path: [{_key: 'a'}, 'children', {_key: '2'}], offset: 2},
813
+ })
814
+ expect(PortableTextEditor.isMarkActive(editor, 'strong')).toBe(false)
815
+ PortableTextEditor.toggleMark(editor, 'strong')
816
+ expect(PortableTextEditor.isMarkActive(editor, 'strong')).toBe(true)
817
+ })
818
+ })
819
+
820
+ it('should return active annotation types that cover the whole selection', async () => {
821
+ const editorRef: RefObject<PortableTextEditor> = createRef()
822
+ const initialValue = [
823
+ {
824
+ _key: 'a',
825
+ _type: 'myTestBlockType',
826
+ children: [
827
+ {
828
+ _key: 'a1',
829
+ _type: 'span',
830
+ marks: ['bab319ad3a9d'],
831
+ text: '12',
832
+ },
833
+ {
834
+ _key: '2',
835
+ _type: 'span',
836
+ marks: [],
837
+ text: '34',
838
+ },
839
+ ],
840
+ markDefs: [
841
+ {
842
+ _key: 'bab319ad3a9d',
843
+ _type: 'link',
844
+ href: 'http://www.123.com',
845
+ },
846
+ ],
847
+ style: 'normal',
848
+ },
849
+ ]
850
+ const onChange = jest.fn()
851
+ await waitFor(() => {
852
+ render(
853
+ <PortableTextEditorTester
854
+ onChange={onChange}
855
+ ref={editorRef}
856
+ schemaType={schemaType}
857
+ value={initialValue}
858
+ />,
859
+ )
860
+ })
861
+ const editor = editorRef.current!
862
+ expect(editor).toBeDefined()
863
+ await waitFor(() => {
864
+ PortableTextEditor.focus(editor)
865
+ PortableTextEditor.select(editor, {
866
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
867
+ anchor: {path: [{_key: 'a'}, 'children', {_key: '2'}], offset: 2},
868
+ })
869
+ expect(PortableTextEditor.isAnnotationActive(editor, 'link')).toBe(false)
870
+ })
871
+ })
872
+ })
873
+
874
+ describe('removing annotations', () => {
875
+ it('removes the markDefs if the annotation is no longer in use', async () => {
876
+ const editorRef: RefObject<PortableTextEditor> = createRef()
877
+ const initialValue = [
878
+ {
879
+ _key: '5fc57af23597',
880
+ _type: 'myTestBlockType',
881
+ children: [
882
+ {
883
+ _key: 'be1c67c6971a',
884
+ _type: 'span',
885
+ marks: ['fde1fd54b544'],
886
+ text: 'This is a link',
887
+ },
888
+ ],
889
+ markDefs: [
890
+ {
891
+ _key: 'fde1fd54b544',
892
+ _type: 'link',
893
+ url: '1',
894
+ },
895
+ ],
896
+ style: 'normal',
897
+ },
898
+ ]
899
+ const onChange = jest.fn()
900
+ await waitFor(() => {
901
+ render(
902
+ <PortableTextEditorTester
903
+ onChange={onChange}
904
+ ref={editorRef}
905
+ schemaType={schemaType}
906
+ value={initialValue}
907
+ />,
908
+ )
909
+ })
910
+
911
+ await waitFor(() => {
912
+ if (editorRef.current) {
913
+ PortableTextEditor.focus(editorRef.current)
914
+ PortableTextEditor.select(editorRef.current, {
915
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}], offset: 14},
916
+ anchor: {path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}], offset: 0},
917
+ })
918
+ // // eslint-disable-next-line max-nested-callbacks
919
+ const linkType = editorRef.current.schemaTypes.annotations.find((a) => a.name === 'link')
920
+ if (!linkType) {
921
+ throw new Error('No link type found')
922
+ }
923
+ PortableTextEditor.removeAnnotation(editorRef.current, linkType)
924
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
925
+ {
926
+ _key: '5fc57af23597',
927
+ _type: 'myTestBlockType',
928
+ children: [
929
+ {
930
+ _key: 'be1c67c6971a',
931
+ _type: 'span',
932
+ marks: [],
933
+ text: 'This is a link',
934
+ },
935
+ ],
936
+ markDefs: [],
937
+ style: 'normal',
938
+ },
939
+ ])
940
+ }
941
+ })
942
+ })
943
+ it('preserves the markDefs if the annotation will continue in use', async () => {
944
+ const editorRef: RefObject<PortableTextEditor> = createRef()
945
+ const initialValue = [
946
+ {
947
+ _key: '5fc57af23597',
948
+ _type: 'myTestBlockType',
949
+ children: [
950
+ {
951
+ _key: 'be1c67c6971a',
952
+ _type: 'span',
953
+ marks: ['fde1fd54b544'],
954
+ text: 'This is a link',
955
+ },
956
+ ],
957
+ markDefs: [
958
+ {
959
+ _key: 'fde1fd54b544',
960
+ _type: 'link',
961
+ url: '1',
962
+ },
963
+ ],
964
+ style: 'normal',
965
+ },
966
+ ]
967
+ const onChange = jest.fn()
968
+ await waitFor(() => {
969
+ render(
970
+ <PortableTextEditorTester
971
+ onChange={onChange}
972
+ ref={editorRef}
973
+ schemaType={schemaType}
974
+ value={initialValue}
975
+ />,
976
+ )
977
+ })
978
+
979
+ await waitFor(() => {
980
+ if (editorRef.current) {
981
+ PortableTextEditor.focus(editorRef.current)
982
+ PortableTextEditor.select(editorRef.current, {
983
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}], offset: 10},
984
+ anchor: {
985
+ path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}],
986
+ offset: 0,
987
+ },
988
+ })
989
+ // // eslint-disable-next-line max-nested-callbacks
990
+ const linkType = editorRef.current.schemaTypes.annotations.find((a) => a.name === 'link')
991
+ if (!linkType) {
992
+ throw new Error('No link type found')
993
+ }
994
+ PortableTextEditor.removeAnnotation(editorRef.current, linkType)
995
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
996
+ {
997
+ _key: '5fc57af23597',
998
+ _type: 'myTestBlockType',
999
+ children: [
1000
+ {
1001
+ _key: 'be1c67c6971a',
1002
+ _type: 'span',
1003
+ marks: [],
1004
+ text: 'This is a ',
1005
+ },
1006
+ {
1007
+ _key: '1',
1008
+ marks: ['fde1fd54b544'],
1009
+ _type: 'span',
1010
+ text: 'link',
1011
+ },
1012
+ ],
1013
+ markDefs: [
1014
+ {
1015
+ _key: 'fde1fd54b544',
1016
+ _type: 'link',
1017
+ url: '1',
1018
+ },
1019
+ ],
1020
+ style: 'normal',
1021
+ },
1022
+ ])
1023
+ }
1024
+ })
1025
+ })
1026
+ it('removes the mark from the correct place', async () => {
1027
+ const editorRef: RefObject<PortableTextEditor> = createRef()
1028
+ const initialValue = [
1029
+ {
1030
+ _key: '5fc57af23597',
1031
+ _type: 'myTestBlockType',
1032
+ children: [
1033
+ {
1034
+ _key: 'be1c67c6971a',
1035
+ _type: 'span',
1036
+ marks: ['fde1fd54b544'],
1037
+ text: 'This is a link',
1038
+ },
1039
+ ],
1040
+ markDefs: [
1041
+ {
1042
+ _key: 'fde1fd54b544',
1043
+ _type: 'link',
1044
+ url: '1',
1045
+ },
1046
+ ],
1047
+ style: 'normal',
1048
+ },
1049
+ ]
1050
+ const onChange = jest.fn()
1051
+ await waitFor(() => {
1052
+ render(
1053
+ <PortableTextEditorTester
1054
+ onChange={onChange}
1055
+ ref={editorRef}
1056
+ schemaType={schemaType}
1057
+ value={initialValue}
1058
+ />,
1059
+ )
1060
+ })
1061
+
1062
+ await waitFor(() => {
1063
+ if (editorRef.current) {
1064
+ PortableTextEditor.focus(editorRef.current)
1065
+ // Selects `a link` from `This is a link`, so the mark should be kept in the first span.
1066
+ PortableTextEditor.select(editorRef.current, {
1067
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}], offset: 14},
1068
+ anchor: {
1069
+ path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}],
1070
+ offset: 8,
1071
+ },
1072
+ })
1073
+
1074
+ // // eslint-disable-next-line max-nested-callbacks
1075
+ const linkType = editorRef.current.schemaTypes.annotations.find((a) => a.name === 'link')
1076
+ if (!linkType) {
1077
+ throw new Error('No link type found')
1078
+ }
1079
+ PortableTextEditor.removeAnnotation(editorRef.current, linkType)
1080
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
1081
+ {
1082
+ _key: '5fc57af23597',
1083
+ _type: 'myTestBlockType',
1084
+ children: [
1085
+ {
1086
+ _key: 'be1c67c6971a',
1087
+ _type: 'span',
1088
+ marks: ['fde1fd54b544'],
1089
+ text: 'This is ',
1090
+ },
1091
+ {
1092
+ _key: '1',
1093
+ _type: 'span',
1094
+ marks: [],
1095
+ text: 'a link',
1096
+ },
1097
+ ],
1098
+ markDefs: [
1099
+ {
1100
+ _key: 'fde1fd54b544',
1101
+ _type: 'link',
1102
+ url: '1',
1103
+ },
1104
+ ],
1105
+ style: 'normal',
1106
+ },
1107
+ ])
1108
+ }
1109
+ })
1110
+ })
1111
+ it('preserves other marks that apply to the spans', async () => {
1112
+ const editorRef: RefObject<PortableTextEditor> = createRef()
1113
+ const initialValue = [
1114
+ {
1115
+ _key: '5fc57af23597',
1116
+ _type: 'myTestBlockType',
1117
+ children: [
1118
+ {
1119
+ _key: 'be1c67c6971a',
1120
+ _type: 'span',
1121
+ marks: ['fde1fd54b544', '7b6d3d5de30c'],
1122
+ text: 'This is a link',
1123
+ },
1124
+ ],
1125
+ markDefs: [
1126
+ {
1127
+ _key: 'fde1fd54b544',
1128
+ _type: 'link',
1129
+ url: '1',
1130
+ },
1131
+ {
1132
+ _key: '7b6d3d5de30c',
1133
+ _type: 'color',
1134
+ color: 'blue',
1135
+ },
1136
+ ],
1137
+ style: 'normal',
1138
+ },
1139
+ ]
1140
+ const onChange = jest.fn()
1141
+ await waitFor(() => {
1142
+ render(
1143
+ <PortableTextEditorTester
1144
+ onChange={onChange}
1145
+ ref={editorRef}
1146
+ schemaType={schemaTypeWithColorAndLink}
1147
+ value={initialValue}
1148
+ />,
1149
+ )
1150
+ })
1151
+
1152
+ await waitFor(() => {
1153
+ if (editorRef.current) {
1154
+ PortableTextEditor.focus(editorRef.current)
1155
+ // Selects `a link` from `This is a link`, so the mark should be kept in the first span, color mark in both.
1156
+ PortableTextEditor.select(editorRef.current, {
1157
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}], offset: 14},
1158
+ anchor: {
1159
+ path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}],
1160
+ offset: 8,
1161
+ },
1162
+ })
1163
+
1164
+ // // eslint-disable-next-line max-nested-callbacks
1165
+ const linkType = editorRef.current.schemaTypes.annotations.find((a) => a.name === 'link')
1166
+ if (!linkType) {
1167
+ throw new Error('No link type found')
1168
+ }
1169
+ PortableTextEditor.removeAnnotation(editorRef.current, linkType)
1170
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
1171
+ {
1172
+ _key: '5fc57af23597',
1173
+ _type: 'myTestBlockType',
1174
+ children: [
1175
+ {
1176
+ _key: 'be1c67c6971a',
1177
+ _type: 'span',
1178
+ marks: ['fde1fd54b544', '7b6d3d5de30c'], // It has both marks, the link was only removed from the second span
1179
+ text: 'This is ',
1180
+ },
1181
+ {
1182
+ _key: '1',
1183
+ _type: 'span',
1184
+ marks: ['7b6d3d5de30c'],
1185
+ text: 'a link',
1186
+ },
1187
+ ],
1188
+ markDefs: [
1189
+ {
1190
+ _key: 'fde1fd54b544',
1191
+ _type: 'link',
1192
+ url: '1',
1193
+ },
1194
+ {
1195
+ _key: '7b6d3d5de30c',
1196
+ _type: 'color',
1197
+ color: 'blue',
1198
+ },
1199
+ ],
1200
+ style: 'normal',
1201
+ },
1202
+ ])
1203
+
1204
+ // removes the color from both
1205
+ PortableTextEditor.select(editorRef.current, {
1206
+ focus: {path: [{_key: '5fc57af23597'}, 'children', {_key: '1'}], offset: 6},
1207
+ anchor: {
1208
+ path: [{_key: '5fc57af23597'}, 'children', {_key: 'be1c67c6971a'}],
1209
+ offset: 0,
1210
+ },
1211
+ })
1212
+ const colorType = editorRef.current.schemaTypes.annotations.find(
1213
+ (a) => a.name === 'color',
1214
+ )
1215
+ if (!colorType) {
1216
+ throw new Error('No color type found')
1217
+ }
1218
+
1219
+ PortableTextEditor.removeAnnotation(editorRef.current, colorType)
1220
+
1221
+ expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
1222
+ {
1223
+ _key: '5fc57af23597',
1224
+ _type: 'myTestBlockType',
1225
+ children: [
1226
+ {
1227
+ _key: 'be1c67c6971a',
1228
+ _type: 'span',
1229
+ marks: ['fde1fd54b544'], // The color was removed from both
1230
+ text: 'This is ',
1231
+ },
1232
+ {
1233
+ _key: '1',
1234
+ _type: 'span',
1235
+ marks: [], // The color was removed from both
1236
+ text: 'a link',
1237
+ },
1238
+ ],
1239
+ markDefs: [
1240
+ {
1241
+ _key: 'fde1fd54b544',
1242
+ _type: 'link',
1243
+ url: '1',
1244
+ },
1245
+ ],
1246
+ style: 'normal',
1247
+ },
1248
+ ])
1249
+ }
1250
+ })
1251
+ })
1252
+ })
1253
+
1254
+ describe('removing nodes', () => {
1255
+ it("should insert an empty text block if it's removing the only block", async () => {
1256
+ const editorRef: RefObject<PortableTextEditor> = createRef()
1257
+ const initialValue = [
1258
+ {
1259
+ _key: '5fc57af23597',
1260
+ _type: 'someObject',
1261
+ },
1262
+ ]
1263
+ const onChange = jest.fn()
1264
+ await waitFor(() => {
1265
+ render(
1266
+ <PortableTextEditorTester
1267
+ onChange={onChange}
1268
+ ref={editorRef}
1269
+ schemaType={schemaType}
1270
+ value={initialValue}
1271
+ />,
1272
+ )
1273
+ })
1274
+
1275
+ await waitFor(() => {
1276
+ if (editorRef.current) {
1277
+ PortableTextEditor.focus(editorRef.current)
1278
+
1279
+ PortableTextEditor.delete(
1280
+ editorRef.current,
1281
+ {
1282
+ focus: {path: [{_key: '5fc57af23597'}], offset: 0},
1283
+ anchor: {path: [{_key: '5fc57af23597'}], offset: 0},
1284
+ },
1285
+ {mode: 'blocks'},
1286
+ )
1287
+
1288
+ const value = PortableTextEditor.getValue(editorRef.current)
1289
+
1290
+ expect(value).toEqual([
1291
+ {
1292
+ _type: 'myTestBlockType',
1293
+ _key: '3',
1294
+ style: 'normal',
1295
+ markDefs: [],
1296
+ children: [
1297
+ {
1298
+ _type: 'span',
1299
+ _key: '2',
1300
+ text: '',
1301
+ marks: [],
1302
+ },
1303
+ ],
1304
+ },
1305
+ ])
1306
+ }
1307
+ })
1308
+ })
1309
+ it('should not insert a new block if we have more blocks available', async () => {
1310
+ const editorRef: RefObject<PortableTextEditor> = createRef()
1311
+ const initialValue = [
1312
+ {
1313
+ _key: '5fc57af23597',
1314
+ _type: 'someObject',
1315
+ },
1316
+ {
1317
+ _type: 'myTestBlockType',
1318
+ _key: 'existingBlock',
1319
+ style: 'normal',
1320
+ markDefs: [],
1321
+ children: [
1322
+ {
1323
+ _type: 'span',
1324
+ _key: '2',
1325
+ text: '',
1326
+ marks: [],
1327
+ },
1328
+ ],
1329
+ },
1330
+ ]
1331
+ const onChange = jest.fn()
1332
+ await waitFor(() => {
1333
+ render(
1334
+ <PortableTextEditorTester
1335
+ onChange={onChange}
1336
+ ref={editorRef}
1337
+ schemaType={schemaType}
1338
+ value={initialValue}
1339
+ />,
1340
+ )
1341
+ })
1342
+
1343
+ await waitFor(() => {
1344
+ if (editorRef.current) {
1345
+ PortableTextEditor.focus(editorRef.current)
1346
+
1347
+ PortableTextEditor.delete(
1348
+ editorRef.current,
1349
+ {
1350
+ focus: {path: [{_key: '5fc57af23597'}], offset: 0},
1351
+ anchor: {path: [{_key: '5fc57af23597'}], offset: 0},
1352
+ },
1353
+ {mode: 'blocks'},
1354
+ )
1355
+
1356
+ const value = PortableTextEditor.getValue(editorRef.current)
1357
+ expect(value).toEqual([
1358
+ {
1359
+ _type: 'myTestBlockType',
1360
+ _key: 'existingBlock',
1361
+ style: 'normal',
1362
+ markDefs: [],
1363
+ children: [
1364
+ {
1365
+ _type: 'span',
1366
+ _key: '2',
1367
+ text: '',
1368
+ marks: [],
1369
+ },
1370
+ ],
1371
+ },
1372
+ ])
1373
+ }
1374
+ })
1375
+ })
1376
+ })
1377
+ })