@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,212 @@
1
+ import {describe, expect, it, jest} from '@jest/globals'
2
+ import {render, waitFor} from '@testing-library/react'
3
+ import {createRef, type RefObject} from 'react'
4
+
5
+ import {PortableTextEditorTester, schemaType} from '../../__tests__/PortableTextEditorTester'
6
+ import {getEditableElement, triggerKeyboardEvent} from '../../__tests__/utils'
7
+ import {PortableTextEditor} from '../../PortableTextEditor'
8
+
9
+ const newBlock = {
10
+ _type: 'myTestBlockType',
11
+ _key: '3',
12
+ style: 'normal',
13
+ markDefs: [],
14
+ children: [
15
+ {
16
+ _type: 'span',
17
+ _key: '2',
18
+ text: '',
19
+ marks: [],
20
+ },
21
+ ],
22
+ }
23
+ describe('plugin:withHotkeys: .ArrowDown', () => {
24
+ it('a new block is added if the user is focused on the only block which is void, and presses arrow down.', async () => {
25
+ const initialValue = [
26
+ {
27
+ _key: 'a',
28
+ _type: 'someObject',
29
+ },
30
+ ]
31
+
32
+ const initialSelection = {
33
+ focus: {path: [{_key: 'a'}], offset: 0},
34
+ anchor: {path: [{_key: 'a'}], offset: 0},
35
+ }
36
+
37
+ const editorRef: RefObject<PortableTextEditor> = createRef()
38
+ const onChange = jest.fn()
39
+ const component = render(
40
+ <PortableTextEditorTester
41
+ onChange={onChange}
42
+ ref={editorRef}
43
+ schemaType={schemaType}
44
+ value={initialValue}
45
+ />,
46
+ )
47
+ const element = await getEditableElement(component)
48
+
49
+ const editor = editorRef.current
50
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
51
+ await waitFor(async () => {
52
+ if (editor && inlineType && element) {
53
+ PortableTextEditor.focus(editor)
54
+ PortableTextEditor.select(editor, initialSelection)
55
+ PortableTextEditor.insertBreak(editor)
56
+ await triggerKeyboardEvent('ArrowDown', element)
57
+
58
+ const value = PortableTextEditor.getValue(editor)
59
+ expect(value).toEqual([initialValue[0], newBlock])
60
+ }
61
+ })
62
+ })
63
+ it('a new block is added if the user is focused on the last block which is void, and presses arrow down.', async () => {
64
+ const initialValue = [
65
+ {
66
+ _type: 'myTestBlockType',
67
+ _key: 'a',
68
+ style: 'normal',
69
+ markDefs: [],
70
+ children: [
71
+ {
72
+ _type: 'span',
73
+ _key: 'a1',
74
+ text: 'This is the first block',
75
+ marks: [],
76
+ },
77
+ ],
78
+ },
79
+ {
80
+ _key: 'b',
81
+ _type: 'someObject',
82
+ },
83
+ ]
84
+ const initialSelection = {
85
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 2},
86
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 2},
87
+ }
88
+
89
+ const editorRef: RefObject<PortableTextEditor> = createRef()
90
+ const onChange = jest.fn()
91
+ const component = render(
92
+ <PortableTextEditorTester
93
+ onChange={onChange}
94
+ ref={editorRef}
95
+ schemaType={schemaType}
96
+ value={initialValue}
97
+ />,
98
+ )
99
+ const element = await getEditableElement(component)
100
+
101
+ const editor = editorRef.current
102
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
103
+ await waitFor(async () => {
104
+ if (editor && inlineType && element) {
105
+ PortableTextEditor.focus(editor)
106
+ PortableTextEditor.select(editor, initialSelection)
107
+ await triggerKeyboardEvent('ArrowDown', element)
108
+ const value = PortableTextEditor.getValue(editor)
109
+ // Arrow down on the text block should not add a new block
110
+ expect(value).toEqual(initialValue)
111
+ // Focus on the object block
112
+ PortableTextEditor.select(editor, {
113
+ focus: {path: [{_key: 'b'}], offset: 0},
114
+ anchor: {path: [{_key: 'b'}], offset: 0},
115
+ })
116
+ await triggerKeyboardEvent('ArrowDown', element)
117
+ const value2 = PortableTextEditor.getValue(editor)
118
+ expect(value2).toEqual([
119
+ initialValue[0],
120
+ initialValue[1],
121
+ {
122
+ _type: 'myTestBlockType',
123
+ _key: '3',
124
+ style: 'normal',
125
+ markDefs: [],
126
+ children: [
127
+ {
128
+ _type: 'span',
129
+ _key: '2',
130
+ text: '',
131
+ marks: [],
132
+ },
133
+ ],
134
+ },
135
+ ])
136
+ }
137
+ })
138
+ })
139
+ })
140
+ describe('plugin:withHotkeys: .ArrowUp', () => {
141
+ it('a new block is added at the top, when pressing arrow up, because first block is void, the new block can be deleted with backspace.', async () => {
142
+ const initialValue = [
143
+ {
144
+ _key: 'b',
145
+ _type: 'someObject',
146
+ },
147
+ {
148
+ _type: 'myTestBlockType',
149
+ _key: 'a',
150
+ style: 'normal',
151
+ markDefs: [],
152
+ children: [
153
+ {
154
+ _type: 'span',
155
+ _key: 'a1',
156
+ text: 'This is the first block',
157
+ marks: [],
158
+ },
159
+ ],
160
+ },
161
+ ]
162
+
163
+ const initialSelection = {
164
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 2},
165
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 2},
166
+ }
167
+
168
+ const editorRef: RefObject<PortableTextEditor> = createRef()
169
+ const onChange = jest.fn()
170
+ const component = render(
171
+ <PortableTextEditorTester
172
+ onChange={onChange}
173
+ ref={editorRef}
174
+ schemaType={schemaType}
175
+ value={initialValue}
176
+ />,
177
+ )
178
+ const element = await getEditableElement(component)
179
+
180
+ const editor = editorRef.current
181
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
182
+ await waitFor(async () => {
183
+ if (editor && inlineType && element) {
184
+ PortableTextEditor.focus(editor)
185
+ PortableTextEditor.select(editor, initialSelection)
186
+ await triggerKeyboardEvent('ArrowUp', element)
187
+ // Arrow down on the text block should not add a new block
188
+ expect(PortableTextEditor.getValue(editor)).toEqual(initialValue)
189
+ // Focus on the object block
190
+ PortableTextEditor.select(editor, {
191
+ focus: {path: [{_key: 'b'}], offset: 0},
192
+ anchor: {path: [{_key: 'b'}], offset: 0},
193
+ })
194
+ await triggerKeyboardEvent('ArrowUp', element)
195
+ expect(PortableTextEditor.getValue(editor)).toEqual([
196
+ newBlock,
197
+ initialValue[0],
198
+ initialValue[1],
199
+ ])
200
+ // Pressing arrow up again won't add a new block
201
+ await triggerKeyboardEvent('ArrowUp', element)
202
+ expect(PortableTextEditor.getValue(editor)).toEqual([
203
+ newBlock,
204
+ initialValue[0],
205
+ initialValue[1],
206
+ ])
207
+ await triggerKeyboardEvent('Backspace', element)
208
+ expect(PortableTextEditor.getValue(editor)).toEqual(initialValue)
209
+ }
210
+ })
211
+ })
212
+ })
@@ -0,0 +1,204 @@
1
+ import {describe, expect, it, jest} from '@jest/globals'
2
+ import {render, waitFor} from '@testing-library/react'
3
+ import {createRef, type RefObject} from 'react'
4
+
5
+ import {PortableTextEditorTester, schemaType} from '../../__tests__/PortableTextEditorTester'
6
+ import {PortableTextEditor} from '../../PortableTextEditor'
7
+
8
+ const initialValue = [
9
+ {
10
+ _key: 'a',
11
+ _type: 'myTestBlockType',
12
+ children: [
13
+ {
14
+ _key: 'a1',
15
+ _type: 'span',
16
+ marks: [],
17
+ text: 'Block A',
18
+ },
19
+ ],
20
+ markDefs: [],
21
+ style: 'normal',
22
+ },
23
+ {
24
+ _key: 'b',
25
+ _type: 'myTestBlockType',
26
+ children: [
27
+ {
28
+ _key: 'b1',
29
+ _type: 'span',
30
+ marks: [],
31
+ text: 'Block B',
32
+ },
33
+ ],
34
+ markDefs: [],
35
+ style: 'normal',
36
+ },
37
+ ]
38
+
39
+ describe('plugin:withInsertBreak: "enter"', () => {
40
+ it('keeps text block key if enter is pressed at the start of the block, creating a new one in "before" position', async () => {
41
+ const initialSelection = {
42
+ focus: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 0},
43
+ anchor: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 0},
44
+ }
45
+
46
+ const editorRef: RefObject<PortableTextEditor> = createRef()
47
+ const onChange = jest.fn()
48
+ render(
49
+ <PortableTextEditorTester
50
+ onChange={onChange}
51
+ ref={editorRef}
52
+ schemaType={schemaType}
53
+ value={initialValue}
54
+ />,
55
+ )
56
+ const editor = editorRef.current
57
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
58
+ await waitFor(async () => {
59
+ if (editor && inlineType) {
60
+ PortableTextEditor.focus(editor)
61
+ PortableTextEditor.select(editor, initialSelection)
62
+ PortableTextEditor.insertBreak(editor)
63
+
64
+ const value = PortableTextEditor.getValue(editor)
65
+ expect(value).toEqual([
66
+ initialValue[0],
67
+ {
68
+ _type: 'myTestBlockType',
69
+ _key: '3',
70
+ style: 'normal',
71
+ markDefs: [],
72
+ children: [
73
+ {
74
+ _type: 'span',
75
+ _key: '2',
76
+ text: '',
77
+ marks: [],
78
+ },
79
+ ],
80
+ },
81
+ initialValue[1],
82
+ ])
83
+ }
84
+ })
85
+ })
86
+ it('inserts the new block after if key enter is pressed at the start of the block, creating a new one in "after" position if the block is empty', async () => {
87
+ const initialSelection = {
88
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
89
+ anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
90
+ }
91
+ const emptyBlock = {
92
+ _key: 'a',
93
+ _type: 'myTestBlockType',
94
+ children: [
95
+ {
96
+ _key: 'a1',
97
+ _type: 'span',
98
+ marks: [],
99
+ text: '',
100
+ },
101
+ ],
102
+ markDefs: [],
103
+ style: 'normal',
104
+ }
105
+
106
+ const editorRef: RefObject<PortableTextEditor> = createRef()
107
+ const onChange = jest.fn()
108
+ render(
109
+ <PortableTextEditorTester
110
+ onChange={onChange}
111
+ ref={editorRef}
112
+ schemaType={schemaType}
113
+ value={[emptyBlock]}
114
+ />,
115
+ )
116
+ const editor = editorRef.current
117
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
118
+ await waitFor(async () => {
119
+ if (editor && inlineType) {
120
+ PortableTextEditor.focus(editor)
121
+ PortableTextEditor.select(editor, initialSelection)
122
+ PortableTextEditor.insertBreak(editor)
123
+
124
+ const value = PortableTextEditor.getValue(editor)
125
+ expect(value).toEqual([
126
+ emptyBlock,
127
+ {
128
+ _key: '2',
129
+ _type: 'myTestBlockType',
130
+ markDefs: [],
131
+ style: 'normal',
132
+ children: [
133
+ {
134
+ _key: '1',
135
+ _type: 'span',
136
+ marks: [],
137
+ text: '',
138
+ },
139
+ ],
140
+ },
141
+ ])
142
+ }
143
+ })
144
+ })
145
+ it('splits the text block key if enter is pressed at the middle of the block', async () => {
146
+ const initialSelection = {
147
+ focus: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 2},
148
+ anchor: {path: [{_key: 'b'}, 'children', {_key: 'b1'}], offset: 2},
149
+ }
150
+
151
+ const editorRef: RefObject<PortableTextEditor> = createRef()
152
+ const onChange = jest.fn()
153
+ render(
154
+ <PortableTextEditorTester
155
+ onChange={onChange}
156
+ ref={editorRef}
157
+ schemaType={schemaType}
158
+ value={initialValue}
159
+ />,
160
+ )
161
+ const editor = editorRef.current
162
+ const inlineType = editor?.schemaTypes.inlineObjects.find((t) => t.name === 'someObject')
163
+ await waitFor(async () => {
164
+ if (editor && inlineType) {
165
+ PortableTextEditor.focus(editor)
166
+ PortableTextEditor.select(editor, initialSelection)
167
+ PortableTextEditor.insertBreak(editor)
168
+
169
+ const value = PortableTextEditor.getValue(editor)
170
+ expect(value).toEqual([
171
+ initialValue[0],
172
+ {
173
+ _key: 'b',
174
+ _type: 'myTestBlockType',
175
+ children: [
176
+ {
177
+ _key: 'b1',
178
+ _type: 'span',
179
+ marks: [],
180
+ text: 'Bl',
181
+ },
182
+ ],
183
+ markDefs: [],
184
+ style: 'normal',
185
+ },
186
+ {
187
+ _key: '2',
188
+ _type: 'myTestBlockType',
189
+ markDefs: [],
190
+ style: 'normal',
191
+ children: [
192
+ {
193
+ _key: '1',
194
+ _type: 'span',
195
+ marks: [],
196
+ text: 'ock B',
197
+ },
198
+ ],
199
+ },
200
+ ])
201
+ }
202
+ })
203
+ })
204
+ })
@@ -0,0 +1,133 @@
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 {PortableTextEditorTester, schemaType} from '../../__tests__/PortableTextEditorTester'
7
+ import {PortableTextEditor} from '../../PortableTextEditor'
8
+
9
+ describe('plugin:withPlaceholderBlock', () => {
10
+ describe('removing nodes', () => {
11
+ it("should insert an empty text block if it's removing the only block", async () => {
12
+ const editorRef: RefObject<PortableTextEditor> = createRef()
13
+ const initialValue = [
14
+ {
15
+ _key: '5fc57af23597',
16
+ _type: 'someObject',
17
+ },
18
+ ]
19
+ const onChange = jest.fn()
20
+ await waitFor(() => {
21
+ render(
22
+ <PortableTextEditorTester
23
+ onChange={onChange}
24
+ ref={editorRef}
25
+ schemaType={schemaType}
26
+ value={initialValue}
27
+ />,
28
+ )
29
+ })
30
+
31
+ await waitFor(() => {
32
+ if (editorRef.current) {
33
+ PortableTextEditor.focus(editorRef.current)
34
+
35
+ PortableTextEditor.delete(
36
+ editorRef.current,
37
+ {
38
+ focus: {path: [{_key: '5fc57af23597'}], offset: 0},
39
+ anchor: {path: [{_key: '5fc57af23597'}], offset: 0},
40
+ },
41
+ {mode: 'blocks'},
42
+ )
43
+
44
+ const value = PortableTextEditor.getValue(editorRef.current)
45
+
46
+ expect(value).toEqual([
47
+ {
48
+ _type: 'myTestBlockType',
49
+ _key: '3',
50
+ style: 'normal',
51
+ markDefs: [],
52
+ children: [
53
+ {
54
+ _type: 'span',
55
+ _key: '2',
56
+ text: '',
57
+ marks: [],
58
+ },
59
+ ],
60
+ },
61
+ ])
62
+ }
63
+ })
64
+ })
65
+ it('should not insert a new block if we have more blocks available', async () => {
66
+ const editorRef: RefObject<PortableTextEditor> = createRef()
67
+ const initialValue = [
68
+ {
69
+ _key: '5fc57af23597',
70
+ _type: 'someObject',
71
+ },
72
+ {
73
+ _type: 'myTestBlockType',
74
+ _key: 'existingBlock',
75
+ style: 'normal',
76
+ markDefs: [],
77
+ children: [
78
+ {
79
+ _type: 'span',
80
+ _key: '2',
81
+ text: '',
82
+ marks: [],
83
+ },
84
+ ],
85
+ },
86
+ ]
87
+ const onChange = jest.fn()
88
+ await waitFor(() => {
89
+ render(
90
+ <PortableTextEditorTester
91
+ onChange={onChange}
92
+ ref={editorRef}
93
+ schemaType={schemaType}
94
+ value={initialValue}
95
+ />,
96
+ )
97
+ })
98
+
99
+ await waitFor(() => {
100
+ if (editorRef.current) {
101
+ PortableTextEditor.focus(editorRef.current)
102
+
103
+ PortableTextEditor.delete(
104
+ editorRef.current,
105
+ {
106
+ focus: {path: [{_key: '5fc57af23597'}], offset: 0},
107
+ anchor: {path: [{_key: '5fc57af23597'}], offset: 0},
108
+ },
109
+ {mode: 'blocks'},
110
+ )
111
+
112
+ const value = PortableTextEditor.getValue(editorRef.current)
113
+ expect(value).toEqual([
114
+ {
115
+ _type: 'myTestBlockType',
116
+ _key: 'existingBlock',
117
+ style: 'normal',
118
+ markDefs: [],
119
+ children: [
120
+ {
121
+ _type: 'span',
122
+ _key: '2',
123
+ text: '',
124
+ marks: [],
125
+ },
126
+ ],
127
+ },
128
+ ])
129
+ }
130
+ })
131
+ })
132
+ })
133
+ })
@@ -0,0 +1,65 @@
1
+ import {describe, expect, it, jest} from '@jest/globals'
2
+ import {render, waitFor} from '@testing-library/react'
3
+ import {createRef, type RefObject} from 'react'
4
+
5
+ import {PortableTextEditorTester, schemaType} from '../../__tests__/PortableTextEditorTester'
6
+ import {PortableTextEditor} from '../../PortableTextEditor'
7
+
8
+ describe('plugin:withPortableTextLists', () => {
9
+ it('should return active list styles that cover the whole selection', async () => {
10
+ const editorRef: RefObject<PortableTextEditor> = createRef()
11
+ const initialValue = [
12
+ {
13
+ _key: 'a',
14
+ _type: 'myTestBlockType',
15
+ children: [
16
+ {
17
+ _key: 'a1',
18
+ _type: 'span',
19
+ marks: [],
20
+ text: '12',
21
+ },
22
+ ],
23
+ markDefs: [],
24
+ style: 'normal',
25
+ },
26
+ {
27
+ _key: 'b',
28
+ _type: 'myTestBlockType',
29
+ children: [
30
+ {
31
+ _key: '2',
32
+ _type: 'span',
33
+ marks: [],
34
+ text: '34',
35
+ level: 1,
36
+ listItem: 'bullet',
37
+ },
38
+ ],
39
+ markDefs: [],
40
+ style: 'normal',
41
+ },
42
+ ]
43
+ const onChange = jest.fn()
44
+ await waitFor(() => {
45
+ render(
46
+ <PortableTextEditorTester
47
+ onChange={onChange}
48
+ ref={editorRef}
49
+ schemaType={schemaType}
50
+ value={initialValue}
51
+ />,
52
+ )
53
+ })
54
+ const editor = editorRef.current!
55
+ expect(editor).toBeDefined()
56
+ await waitFor(() => {
57
+ PortableTextEditor.focus(editor)
58
+ PortableTextEditor.select(editor, {
59
+ focus: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 0},
60
+ anchor: {path: [{_key: '2'}, 'children', {_key: '2'}], offset: 2},
61
+ })
62
+ expect(PortableTextEditor.hasListStyle(editor, 'bullet')).toBe(false)
63
+ })
64
+ })
65
+ })