@portabletext/editor 2.7.2 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs +3 -1
  2. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +1 -1
  3. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs +10 -4
  4. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs.map +1 -1
  5. package/lib/_chunks-cjs/util.merge-text-blocks.cjs +0 -1
  6. package/lib/_chunks-cjs/util.merge-text-blocks.cjs.map +1 -1
  7. package/lib/_chunks-cjs/util.slice-blocks.cjs +60 -9
  8. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  9. package/lib/_chunks-dts/behavior.types.action.d.cts +149 -149
  10. package/lib/_chunks-dts/behavior.types.action.d.ts +86 -86
  11. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +4 -2
  12. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +1 -1
  13. package/lib/_chunks-es/selector.is-selection-expanded.js +10 -4
  14. package/lib/_chunks-es/selector.is-selection-expanded.js.map +1 -1
  15. package/lib/_chunks-es/util.merge-text-blocks.js +0 -1
  16. package/lib/_chunks-es/util.merge-text-blocks.js.map +1 -1
  17. package/lib/_chunks-es/util.slice-blocks.js +56 -8
  18. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  19. package/lib/index.cjs +94 -131
  20. package/lib/index.cjs.map +1 -1
  21. package/lib/index.js +90 -128
  22. package/lib/index.js.map +1 -1
  23. package/lib/plugins/index.d.cts +3 -3
  24. package/lib/selectors/index.d.cts +13 -3
  25. package/lib/selectors/index.d.ts +13 -3
  26. package/package.json +13 -14
  27. package/src/behaviors/behavior.abstract.insert.ts +58 -1
  28. package/src/behaviors/behavior.abstract.split.ts +0 -1
  29. package/src/behaviors/behavior.core.annotations.ts +24 -2
  30. package/src/behaviors/behavior.core.ts +1 -1
  31. package/src/behaviors/behavior.types.event.ts +18 -18
  32. package/src/converters/converter.portable-text.ts +0 -1
  33. package/src/converters/converter.text-html.serialize.test.ts +27 -17
  34. package/src/converters/converter.text-html.ts +0 -1
  35. package/src/converters/converter.text-plain.test.ts +1 -1
  36. package/src/converters/converter.text-plain.ts +0 -1
  37. package/src/editor/Editable.tsx +0 -1
  38. package/src/editor/plugins/createWithEditableAPI.ts +16 -0
  39. package/src/internal-utils/parse-blocks.test.ts +23 -23
  40. package/src/internal-utils/parse-blocks.ts +13 -24
  41. package/src/internal-utils/test-editor.tsx +15 -21
  42. package/src/operations/behavior.operation.annotation.add.ts +2 -13
  43. package/src/operations/behavior.operation.block.set.ts +1 -1
  44. package/src/operations/behavior.operation.block.unset.ts +2 -2
  45. package/src/operations/behavior.operation.insert.block.ts +1 -1
  46. package/src/operations/behavior.operations.ts +0 -18
  47. package/src/plugins/plugin.internal.auto-close-brackets.test.tsx +25 -71
  48. package/src/plugins/plugin.markdown.test.tsx +12 -30
  49. package/src/selectors/selector.get-selected-value.test.ts +748 -0
  50. package/src/selectors/selector.get-selected-value.ts +28 -7
  51. package/src/selectors/selector.get-trimmed-selection.test.ts +0 -1
  52. package/src/selectors/selector.is-active-annotation.test.ts +320 -0
  53. package/src/selectors/selector.is-active-annotation.ts +24 -0
  54. package/src/utils/util.merge-text-blocks.ts +1 -1
  55. package/src/utils/util.slice-blocks.ts +36 -3
  56. package/src/editor/__tests__/PortableTextEditor.test.tsx +0 -430
  57. package/src/editor/__tests__/PortableTextEditorTester.tsx +0 -58
  58. package/src/editor/__tests__/RangeDecorations.test.tsx +0 -213
  59. package/src/editor/__tests__/insert-block.test.tsx +0 -224
  60. package/src/editor/__tests__/self-solving.test.tsx +0 -183
  61. package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +0 -298
  62. package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +0 -177
  63. package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +0 -538
  64. package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +0 -162
  65. package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +0 -65
  66. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +0 -612
  67. package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +0 -103
  68. package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +0 -147
  69. package/src/internal-utils/__tests__/valueNormalization.test.tsx +0 -79
  70. package/src/operations/behavior.operation.insert-inline-object.ts +0 -59
  71. package/src/operations/behavior.operation.insert-span.ts +0 -48
  72. package/src/utils/util.slice-blocks.test.ts +0 -465
@@ -0,0 +1,748 @@
1
+ import {compileSchema, defineSchema} from '@portabletext/schema'
2
+ import {createTestKeyGenerator} from '@portabletext/test'
3
+ import type {PortableTextBlock, PortableTextTextBlock} from '@sanity/types'
4
+ import {describe, expect, test} from 'vitest'
5
+ import {getSelectedValue} from '.'
6
+ import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
7
+
8
+ const b1: PortableTextTextBlock = {
9
+ _type: 'block',
10
+ _key: 'b1',
11
+ children: [
12
+ {
13
+ _type: 'span',
14
+ _key: 'b1c1',
15
+ text: 'foo',
16
+ marks: [],
17
+ },
18
+ {
19
+ _type: 'span',
20
+ _key: 'b1c2',
21
+ text: 'bar',
22
+ marks: [],
23
+ },
24
+ ],
25
+ markDefs: [],
26
+ style: 'normal',
27
+ }
28
+ const b2: PortableTextBlock = {
29
+ _type: 'image',
30
+ _key: 'b2',
31
+ src: 'https://example.com/image.jpg',
32
+ alt: 'Example',
33
+ }
34
+ const b3: PortableTextTextBlock = {
35
+ _type: 'block',
36
+ _key: 'b3',
37
+ children: [
38
+ {
39
+ _type: 'span',
40
+ _key: 'b3c1',
41
+ text: 'baz',
42
+ marks: [],
43
+ },
44
+ ],
45
+ markDefs: [],
46
+ style: 'normal',
47
+ }
48
+ const b4: PortableTextTextBlock = {
49
+ _type: 'block',
50
+ _key: 'b4',
51
+ children: [
52
+ {
53
+ _type: 'span',
54
+ _key: 'b4c1',
55
+ text: 'fizz',
56
+ marks: [],
57
+ },
58
+ {
59
+ _type: 'stock-ticker',
60
+ _key: 'b4c2',
61
+ symbol: 'AAPL',
62
+ },
63
+ {
64
+ _type: 'span',
65
+ _key: 'b4c3',
66
+ text: 'buzz',
67
+ marks: [],
68
+ },
69
+ ],
70
+ markDefs: [],
71
+ style: 'normal',
72
+ }
73
+
74
+ const schema = compileSchema(
75
+ defineSchema({
76
+ blockObjects: [{name: 'image'}],
77
+ inlineObjects: [{name: 'stock-ticker'}],
78
+ }),
79
+ )
80
+ const blocks: Array<PortableTextBlock> = [b1, b2, b3, b4]
81
+
82
+ describe(getSelectedValue.name, () => {
83
+ test('sensible defaults', () => {
84
+ expect(
85
+ getSelectedValue(
86
+ createTestSnapshot({
87
+ context: {
88
+ schema,
89
+ selection: null,
90
+ value: [],
91
+ },
92
+ }),
93
+ ),
94
+ ).toEqual([])
95
+ expect(
96
+ getSelectedValue(
97
+ createTestSnapshot({
98
+ context: {
99
+ schema,
100
+ selection: null,
101
+ value: [],
102
+ },
103
+ }),
104
+ ),
105
+ ).toEqual([])
106
+ })
107
+
108
+ test('slicing a single block', () => {
109
+ expect(
110
+ getSelectedValue(
111
+ createTestSnapshot({
112
+ context: {
113
+ schema,
114
+ selection: {
115
+ anchor: {
116
+ path: [
117
+ {_key: b1._key},
118
+ 'children',
119
+ {_key: b1.children[0]._key},
120
+ ],
121
+ offset: 0,
122
+ },
123
+ focus: {
124
+ path: [
125
+ {_key: b1._key},
126
+ 'children',
127
+ {_key: b1.children[0]._key},
128
+ ],
129
+ offset: 3,
130
+ },
131
+ },
132
+ value: blocks,
133
+ },
134
+ }),
135
+ ),
136
+ ).toEqual([
137
+ {
138
+ ...b1,
139
+ children: [b1.children[0]],
140
+ },
141
+ ])
142
+ })
143
+
144
+ test('slicing a single span', () => {
145
+ expect(
146
+ getSelectedValue(
147
+ createTestSnapshot({
148
+ context: {
149
+ schema,
150
+ selection: {
151
+ anchor: {
152
+ path: [
153
+ {_key: b1._key},
154
+ 'children',
155
+ {_key: b1.children[0]._key},
156
+ ],
157
+ offset: 1,
158
+ },
159
+ focus: {
160
+ path: [
161
+ {_key: b1._key},
162
+ 'children',
163
+ {_key: b1.children[0]._key},
164
+ ],
165
+ offset: 2,
166
+ },
167
+ },
168
+ value: blocks,
169
+ },
170
+ }),
171
+ ),
172
+ ).toEqual([
173
+ {
174
+ ...b1,
175
+ children: [
176
+ {
177
+ ...b1.children[0],
178
+ text: 'o',
179
+ },
180
+ ],
181
+ },
182
+ ])
183
+ })
184
+
185
+ test('starting and ending selection on a block object', () => {
186
+ expect(
187
+ getSelectedValue(
188
+ createTestSnapshot({
189
+ context: {
190
+ schema,
191
+ selection: {
192
+ anchor: {
193
+ path: [{_key: b2._key}],
194
+ offset: 0,
195
+ },
196
+ focus: {
197
+ path: [{_key: b2._key}],
198
+ offset: 0,
199
+ },
200
+ },
201
+ value: blocks,
202
+ },
203
+ }),
204
+ ),
205
+ ).toEqual([b2])
206
+ })
207
+
208
+ test('starting selection on a block object', () => {
209
+ expect(
210
+ getSelectedValue(
211
+ createTestSnapshot({
212
+ context: {
213
+ schema,
214
+ selection: {
215
+ anchor: {
216
+ path: [{_key: b2._key}],
217
+ offset: 0,
218
+ },
219
+ focus: {
220
+ path: [
221
+ {_key: b3._key},
222
+ 'children',
223
+ {_key: b3.children[0]._key},
224
+ ],
225
+ offset: 3,
226
+ },
227
+ },
228
+ value: blocks,
229
+ },
230
+ }),
231
+ ),
232
+ ).toEqual([b2, b3])
233
+ })
234
+
235
+ test('ending selection on a block object', () => {
236
+ expect(
237
+ getSelectedValue(
238
+ createTestSnapshot({
239
+ context: {
240
+ schema,
241
+ selection: {
242
+ anchor: {
243
+ path: [
244
+ {_key: b1._key},
245
+ 'children',
246
+ {_key: b1.children[0]._key},
247
+ ],
248
+ offset: 3,
249
+ },
250
+ focus: {
251
+ path: [{_key: b2._key}],
252
+ offset: 0,
253
+ },
254
+ },
255
+ value: blocks,
256
+ },
257
+ }),
258
+ ),
259
+ ).toEqual([
260
+ {
261
+ ...b1,
262
+ children: [
263
+ {
264
+ ...b1.children[0],
265
+ text: '',
266
+ },
267
+ ...b1.children.slice(1),
268
+ ],
269
+ },
270
+ blocks[1],
271
+ ])
272
+ })
273
+
274
+ test('slicing across block object', () => {
275
+ expect(
276
+ getSelectedValue(
277
+ createTestSnapshot({
278
+ context: {
279
+ schema,
280
+ selection: {
281
+ anchor: {
282
+ path: [
283
+ {_key: b1._key},
284
+ 'children',
285
+ {_key: b1.children[0]._key},
286
+ ],
287
+ offset: 0,
288
+ },
289
+ focus: {
290
+ path: [
291
+ {_key: b3._key},
292
+ 'children',
293
+ {_key: b3.children[0]._key},
294
+ ],
295
+ offset: 3,
296
+ },
297
+ },
298
+ value: blocks,
299
+ },
300
+ }),
301
+ ),
302
+ ).toEqual([b1, b2, b3])
303
+ })
304
+
305
+ test('starting and ending mid-span', () => {
306
+ expect(
307
+ getSelectedValue(
308
+ createTestSnapshot({
309
+ context: {
310
+ schema,
311
+ selection: {
312
+ anchor: {
313
+ path: [
314
+ {_key: b3._key},
315
+ 'children',
316
+ {_key: b3.children[0]._key},
317
+ ],
318
+ offset: 2,
319
+ },
320
+ focus: {
321
+ path: [
322
+ {_key: b4._key},
323
+ 'children',
324
+ {_key: b4.children[0]._key},
325
+ ],
326
+ offset: 1,
327
+ },
328
+ },
329
+ value: blocks,
330
+ },
331
+ }),
332
+ ),
333
+ ).toEqual([
334
+ {
335
+ ...b3,
336
+ children: [
337
+ {
338
+ ...b3.children[0],
339
+ text: 'z',
340
+ },
341
+ ],
342
+ },
343
+ {
344
+ ...b4,
345
+ children: [
346
+ {
347
+ ...b4.children[0],
348
+ text: 'f',
349
+ },
350
+ ],
351
+ },
352
+ ])
353
+ })
354
+
355
+ test('starting mid-span and ending end-span', () => {
356
+ expect(
357
+ getSelectedValue(
358
+ createTestSnapshot({
359
+ context: {
360
+ schema,
361
+ selection: {
362
+ anchor: {
363
+ path: [
364
+ {_key: b3._key},
365
+ 'children',
366
+ {_key: b3.children[0]._key},
367
+ ],
368
+ offset: 2,
369
+ },
370
+ focus: {
371
+ path: [
372
+ {_key: b4._key},
373
+ 'children',
374
+ {_key: b4.children[0]._key},
375
+ ],
376
+ offset: 4,
377
+ },
378
+ },
379
+ value: blocks,
380
+ },
381
+ }),
382
+ ),
383
+ ).toEqual([
384
+ {
385
+ ...b3,
386
+ children: [
387
+ {
388
+ ...b3.children[0],
389
+ text: 'z',
390
+ },
391
+ ],
392
+ },
393
+ {
394
+ ...b4,
395
+ children: [
396
+ {
397
+ ...b4.children[0],
398
+ },
399
+ ],
400
+ },
401
+ ])
402
+ })
403
+
404
+ test('starting on inline object', () => {
405
+ expect(
406
+ getSelectedValue(
407
+ createTestSnapshot({
408
+ context: {
409
+ schema,
410
+ selection: {
411
+ anchor: {
412
+ path: [
413
+ {_key: b4._key},
414
+ 'children',
415
+ {_key: b4.children[1]._key},
416
+ ],
417
+ offset: 0,
418
+ },
419
+ focus: {
420
+ path: [
421
+ {_key: b4._key},
422
+ 'children',
423
+ {_key: b4.children[2]._key},
424
+ ],
425
+ offset: 4,
426
+ },
427
+ },
428
+ value: blocks,
429
+ },
430
+ }),
431
+ ),
432
+ ).toEqual([
433
+ {
434
+ ...b4,
435
+ children: [b4.children[1], b4.children[2]],
436
+ },
437
+ ])
438
+ })
439
+
440
+ test('ending on inline object', () => {
441
+ expect(
442
+ getSelectedValue(
443
+ createTestSnapshot({
444
+ context: {
445
+ schema,
446
+ selection: {
447
+ anchor: {
448
+ path: [
449
+ {_key: b4._key},
450
+ 'children',
451
+ {_key: b4.children[0]._key},
452
+ ],
453
+ offset: 0,
454
+ },
455
+ focus: {
456
+ path: [
457
+ {_key: b4._key},
458
+ 'children',
459
+ {_key: b4.children[1]._key},
460
+ ],
461
+ offset: 0,
462
+ },
463
+ },
464
+ value: blocks,
465
+ },
466
+ }),
467
+ ),
468
+ ).toEqual([
469
+ {
470
+ ...b4,
471
+ children: [b4.children[0], b4.children[1]],
472
+ },
473
+ ])
474
+ })
475
+
476
+ test('starting and ending on inline object', () => {
477
+ expect(
478
+ getSelectedValue(
479
+ createTestSnapshot({
480
+ context: {
481
+ schema,
482
+ selection: {
483
+ anchor: {
484
+ path: [
485
+ {_key: b4._key},
486
+ 'children',
487
+ {_key: b4.children[1]._key},
488
+ ],
489
+ offset: 0,
490
+ },
491
+ focus: {
492
+ path: [
493
+ {_key: b4._key},
494
+ 'children',
495
+ {_key: b4.children[1]._key},
496
+ ],
497
+ offset: 0,
498
+ },
499
+ },
500
+ value: blocks,
501
+ },
502
+ }),
503
+ ),
504
+ ).toEqual([
505
+ {
506
+ ...b4,
507
+ children: [b4.children[1]],
508
+ },
509
+ ])
510
+ })
511
+
512
+ test('slicing text block with custom props', () => {
513
+ expect(
514
+ getSelectedValue(
515
+ createTestSnapshot({
516
+ context: {
517
+ schema,
518
+ selection: {
519
+ anchor: {
520
+ path: [{_key: 'b0'}, 'children', {_key: 's0'}],
521
+ offset: 7,
522
+ },
523
+ focus: {
524
+ path: [{_key: 'b0'}, 'children', {_key: 's0'}],
525
+ offset: 12,
526
+ },
527
+ },
528
+ value: [
529
+ {
530
+ _key: 'b0',
531
+ _type: 'block',
532
+ children: [
533
+ {_key: 's0', _type: 'span', text: 'Hello, world!', marks: []},
534
+ ],
535
+ markDefs: [],
536
+ style: 'normal',
537
+ _map: {},
538
+ },
539
+ ],
540
+ },
541
+ }),
542
+ ),
543
+ ).toEqual([
544
+ {
545
+ _key: 'b0',
546
+ _type: 'block',
547
+ children: [{_key: 's0', _type: 'span', text: 'world', marks: []}],
548
+ markDefs: [],
549
+ style: 'normal',
550
+ _map: {},
551
+ },
552
+ ])
553
+ })
554
+
555
+ test('slicing span with custom props', () => {
556
+ expect(
557
+ getSelectedValue(
558
+ createTestSnapshot({
559
+ context: {
560
+ schema,
561
+ selection: {
562
+ anchor: {
563
+ path: [{_key: 'b0'}, 'children', {_key: 's0'}],
564
+ offset: 7,
565
+ },
566
+ focus: {
567
+ path: [{_key: 'b0'}, 'children', {_key: 's0'}],
568
+ offset: 12,
569
+ },
570
+ },
571
+ value: [
572
+ {
573
+ _key: 'b0',
574
+ _type: 'block',
575
+ children: [
576
+ {
577
+ _key: 's0',
578
+ _type: 'span',
579
+ text: 'Hello, world!',
580
+ _map: {},
581
+ marks: [],
582
+ },
583
+ ],
584
+ markDefs: [],
585
+ style: 'normal',
586
+ },
587
+ ],
588
+ },
589
+ }),
590
+ ),
591
+ ).toEqual([
592
+ {
593
+ _key: 'b0',
594
+ _type: 'block',
595
+ children: [
596
+ {_key: 's0', _type: 'span', text: 'world', _map: {}, marks: []},
597
+ ],
598
+ markDefs: [],
599
+ style: 'normal',
600
+ },
601
+ ])
602
+ })
603
+
604
+ test('filters out unused markDefs', () => {
605
+ const keyGenerator = createTestKeyGenerator()
606
+ const linkAKey = keyGenerator()
607
+ const linkBKey = keyGenerator()
608
+ const block0Key = keyGenerator()
609
+ const bazKey = keyGenerator()
610
+ const block4Key = keyGenerator()
611
+ const oneMoreLineKey = keyGenerator()
612
+ const value = [
613
+ {
614
+ _type: 'block',
615
+ _key: block0Key,
616
+ children: [
617
+ {
618
+ _type: 'span',
619
+ _key: keyGenerator(),
620
+ text: 'foo ',
621
+ marks: [],
622
+ },
623
+ {
624
+ _type: 'span',
625
+ _key: keyGenerator(),
626
+ text: 'bar',
627
+ marks: [linkAKey],
628
+ },
629
+ {
630
+ _type: 'span',
631
+ _key: bazKey,
632
+ text: ' baz',
633
+ marks: [],
634
+ },
635
+ ],
636
+ markDefs: [
637
+ {
638
+ _type: 'link',
639
+ _key: linkAKey,
640
+ href: 'https://example.com',
641
+ },
642
+ ],
643
+ style: 'normal',
644
+ },
645
+ {
646
+ _key: keyGenerator(),
647
+ _type: 'image',
648
+ },
649
+ {
650
+ _key: keyGenerator(),
651
+ _type: 'block',
652
+ children: [
653
+ {
654
+ _type: 'span',
655
+ _key: keyGenerator(),
656
+ text: 'fizz',
657
+ marks: ['strong'],
658
+ },
659
+ {
660
+ _type: 'span',
661
+ _key: keyGenerator(),
662
+ text: ' buzz',
663
+ marks: [linkBKey],
664
+ },
665
+ ],
666
+ markDefs: [
667
+ {
668
+ _type: 'link',
669
+ _key: linkBKey,
670
+ href: 'https://example.com',
671
+ },
672
+ ],
673
+ style: 'normal',
674
+ },
675
+ {
676
+ _key: keyGenerator(),
677
+ _type: 'break',
678
+ },
679
+ {
680
+ _key: block4Key,
681
+ _type: 'block',
682
+ children: [
683
+ {
684
+ _type: 'span',
685
+ _key: oneMoreLineKey,
686
+ text: 'one more line',
687
+ },
688
+ ],
689
+ style: 'normal',
690
+ markDefs: [],
691
+ },
692
+ ]
693
+
694
+ const snapshot = createTestSnapshot({
695
+ context: {
696
+ value,
697
+ keyGenerator,
698
+ schema: compileSchema(
699
+ defineSchema({
700
+ annotations: [
701
+ {name: 'link', fields: [{name: 'href', type: 'string'}]},
702
+ ],
703
+ decorators: [{name: 'strong'}],
704
+ }),
705
+ ),
706
+ selection: {
707
+ anchor: {
708
+ path: [{_key: block0Key}, 'children', {_key: bazKey}],
709
+ offset: 0,
710
+ },
711
+ focus: {
712
+ path: [{_key: block4Key}, 'children', {_key: oneMoreLineKey}],
713
+ offset: 3,
714
+ },
715
+ },
716
+ },
717
+ })
718
+
719
+ expect(getSelectedValue(snapshot)).toEqual([
720
+ {
721
+ ...value[0],
722
+ children: [
723
+ {
724
+ _type: 'span',
725
+ _key: bazKey,
726
+ text: ' baz',
727
+ marks: [],
728
+ },
729
+ ],
730
+ markDefs: [],
731
+ },
732
+ value[1],
733
+ value[2],
734
+ value[3],
735
+ {
736
+ ...value[4],
737
+ children: [
738
+ {
739
+ _type: 'span',
740
+ _key: oneMoreLineKey,
741
+ text: 'one',
742
+ marks: [],
743
+ },
744
+ ],
745
+ },
746
+ ])
747
+ })
748
+ })