@portabletext/editor 1.1.1 → 1.1.3
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.
- package/README.md +3 -0
- package/lib/index.d.mts +1668 -1
- package/lib/index.d.ts +1668 -1
- package/lib/index.esm.js +320 -172
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +320 -173
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +320 -172
- package/lib/index.mjs.map +1 -1
- package/package.json +23 -23
- package/src/editor/Editable.tsx +32 -34
- package/src/editor/PortableTextEditor.tsx +23 -7
- package/src/editor/__tests__/PortableTextEditor.test.tsx +9 -9
- package/src/editor/__tests__/PortableTextEditorTester.tsx +2 -5
- package/src/editor/__tests__/RangeDecorations.test.tsx +2 -2
- package/src/editor/__tests__/handleClick.test.tsx +27 -7
- package/src/editor/__tests__/insert-block.test.tsx +4 -4
- package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +7 -7
- package/src/editor/__tests__/self-solving.test.tsx +176 -0
- package/src/editor/components/Leaf.tsx +28 -23
- package/src/editor/components/Synchronizer.tsx +60 -32
- package/src/editor/editor-machine.ts +195 -0
- package/src/editor/hooks/usePortableTextEditorSelection.tsx +12 -14
- package/src/editor/hooks/useSyncValue.test.tsx +9 -9
- package/src/editor/hooks/useSyncValue.ts +14 -13
- package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +1 -1
- package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +28 -28
- package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +17 -17
- package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +8 -8
- package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +5 -5
- package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +2 -2
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +46 -46
- package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +22 -11
- package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +9 -9
- package/src/editor/plugins/createWithEditableAPI.ts +5 -7
- package/src/editor/plugins/createWithInsertData.ts +4 -9
- package/src/editor/plugins/createWithObjectKeys.ts +7 -0
- package/src/editor/plugins/createWithPatches.ts +5 -6
- package/src/editor/plugins/createWithPortableTextBlockStyle.ts +10 -2
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +40 -36
- package/src/editor/plugins/createWithPortableTextSelections.ts +4 -5
- package/src/editor/plugins/createWithSchemaTypes.ts +9 -0
- package/src/editor/plugins/index.ts +18 -8
- package/src/index.ts +9 -3
- package/src/utils/__tests__/dmpToOperations.test.ts +1 -1
- package/src/utils/__tests__/operationToPatches.test.ts +61 -61
- package/src/utils/__tests__/patchToOperations.test.ts +39 -39
- package/src/utils/__tests__/ranges.test.ts +1 -1
- package/src/utils/__tests__/valueNormalization.test.tsx +13 -2
- package/src/utils/__tests__/values.test.ts +17 -17
- package/src/utils/applyPatch.ts +4 -10
- package/src/utils/validateValue.ts +0 -22
- package/src/editor/__tests__/utils.ts +0 -44
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {beforeEach, describe, expect, it} from '@jest/globals'
|
|
2
1
|
import type {Patch} from '@portabletext/patches'
|
|
3
2
|
import {noop} from 'lodash'
|
|
4
3
|
import {createEditor, type Descendant} from 'slate'
|
|
4
|
+
import {beforeEach, describe, expect, it} from 'vitest'
|
|
5
5
|
import {keyGenerator, PortableTextEditor} from '../..'
|
|
6
6
|
import {schemaType} from '../../editor/__tests__/PortableTextEditorTester'
|
|
7
7
|
import {withPlugins} from '../../editor/plugins'
|
|
@@ -70,21 +70,21 @@ describe('operationToPatches', () => {
|
|
|
70
70
|
patchToOperations(editor, p)
|
|
71
71
|
})
|
|
72
72
|
expect(editor.children).toMatchInlineSnapshot(`
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
[
|
|
74
|
+
{
|
|
75
75
|
"__inline": false,
|
|
76
76
|
"_key": "c01739b0d03b",
|
|
77
77
|
"_type": "image",
|
|
78
|
-
"children":
|
|
79
|
-
|
|
78
|
+
"children": [
|
|
79
|
+
{
|
|
80
80
|
"_key": "${VOID_CHILD_KEY}",
|
|
81
81
|
"_type": "span",
|
|
82
|
-
"marks":
|
|
82
|
+
"marks": [],
|
|
83
83
|
"text": "",
|
|
84
84
|
},
|
|
85
85
|
],
|
|
86
|
-
"value":
|
|
87
|
-
"asset":
|
|
86
|
+
"value": {
|
|
87
|
+
"asset": {
|
|
88
88
|
"_ref": "image-f52f71bc1df46e080dabe43a8effe8ccfb5f21de-4032x3024-png",
|
|
89
89
|
"_type": "reference",
|
|
90
90
|
},
|
|
@@ -93,7 +93,7 @@ describe('operationToPatches', () => {
|
|
|
93
93
|
]
|
|
94
94
|
`)
|
|
95
95
|
})
|
|
96
|
-
it('will not create operations for insertion inside
|
|
96
|
+
it('will not create operations for insertion inside blocks', () => {
|
|
97
97
|
editor.children = [
|
|
98
98
|
{
|
|
99
99
|
_type: 'someType',
|
|
@@ -127,31 +127,31 @@ describe('operationToPatches', () => {
|
|
|
127
127
|
patchToOperations(editor, p)
|
|
128
128
|
})
|
|
129
129
|
expect(editor.children).toMatchInlineSnapshot(`
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
[
|
|
131
|
+
{
|
|
132
132
|
"__inline": false,
|
|
133
133
|
"_key": "c01739b0d03b",
|
|
134
134
|
"_type": "someType",
|
|
135
|
-
"children":
|
|
136
|
-
|
|
135
|
+
"children": [
|
|
136
|
+
{
|
|
137
137
|
"_key": "${VOID_CHILD_KEY}",
|
|
138
138
|
"_type": "span",
|
|
139
|
-
"marks":
|
|
139
|
+
"marks": [],
|
|
140
140
|
"text": "",
|
|
141
141
|
},
|
|
142
142
|
],
|
|
143
|
-
"value":
|
|
144
|
-
"asset":
|
|
143
|
+
"value": {
|
|
144
|
+
"asset": {
|
|
145
145
|
"_ref": "image-f52f71bc1df46e080dabe43a8effe8ccfb5f21de-4032x3024-png",
|
|
146
146
|
"_type": "reference",
|
|
147
147
|
},
|
|
148
|
-
"nestedArray":
|
|
148
|
+
"nestedArray": [],
|
|
149
149
|
},
|
|
150
150
|
},
|
|
151
151
|
]
|
|
152
152
|
`)
|
|
153
153
|
})
|
|
154
|
-
it('will not create operations for removal inside
|
|
154
|
+
it('will not create operations for removal inside blocks', () => {
|
|
155
155
|
editor.children = [
|
|
156
156
|
{
|
|
157
157
|
_type: 'someType',
|
|
@@ -190,26 +190,26 @@ describe('operationToPatches', () => {
|
|
|
190
190
|
patchToOperations(editor, p)
|
|
191
191
|
})
|
|
192
192
|
expect(editor.children).toMatchInlineSnapshot(`
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
[
|
|
194
|
+
{
|
|
195
195
|
"__inline": false,
|
|
196
196
|
"_key": "c01739b0d03b",
|
|
197
197
|
"_type": "someType",
|
|
198
|
-
"children":
|
|
199
|
-
|
|
198
|
+
"children": [
|
|
199
|
+
{
|
|
200
200
|
"_key": "${VOID_CHILD_KEY}",
|
|
201
201
|
"_type": "span",
|
|
202
|
-
"marks":
|
|
202
|
+
"marks": [],
|
|
203
203
|
"text": "",
|
|
204
204
|
},
|
|
205
205
|
],
|
|
206
|
-
"value":
|
|
207
|
-
"asset":
|
|
206
|
+
"value": {
|
|
207
|
+
"asset": {
|
|
208
208
|
"_ref": "image-f52f71bc1df46e080dabe43a8effe8ccfb5f21de-4032x3024-png",
|
|
209
209
|
"_type": "reference",
|
|
210
210
|
},
|
|
211
|
-
"nestedArray":
|
|
212
|
-
|
|
211
|
+
"nestedArray": [
|
|
212
|
+
{
|
|
213
213
|
"_key": "foo",
|
|
214
214
|
"_type": "nestedValue",
|
|
215
215
|
},
|
|
@@ -219,7 +219,7 @@ describe('operationToPatches', () => {
|
|
|
219
219
|
]
|
|
220
220
|
`)
|
|
221
221
|
})
|
|
222
|
-
it('will not create operations for setting data inside
|
|
222
|
+
it('will not create operations for setting data inside blocks', () => {
|
|
223
223
|
editor.children = [
|
|
224
224
|
{
|
|
225
225
|
_key: '1335959d4d03',
|
|
@@ -265,34 +265,34 @@ describe('operationToPatches', () => {
|
|
|
265
265
|
patchToOperations(editor, p)
|
|
266
266
|
})
|
|
267
267
|
expect(editor.children).toMatchInlineSnapshot(`
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
[
|
|
269
|
+
{
|
|
270
270
|
"_key": "1335959d4d03",
|
|
271
271
|
"_type": "block",
|
|
272
|
-
"children":
|
|
273
|
-
|
|
272
|
+
"children": [
|
|
273
|
+
{
|
|
274
274
|
"_key": "9bd868adcd6b",
|
|
275
275
|
"_type": "span",
|
|
276
|
-
"marks":
|
|
276
|
+
"marks": [],
|
|
277
277
|
"text": "1 ",
|
|
278
278
|
},
|
|
279
|
-
|
|
279
|
+
{
|
|
280
280
|
"_key": "6f75d593f3fc",
|
|
281
281
|
"_type": "span",
|
|
282
|
-
"marks":
|
|
282
|
+
"marks": [
|
|
283
283
|
"11de7fcea659",
|
|
284
284
|
],
|
|
285
285
|
"text": "2",
|
|
286
286
|
},
|
|
287
|
-
|
|
287
|
+
{
|
|
288
288
|
"_key": "033618a7f081",
|
|
289
289
|
"_type": "span",
|
|
290
|
-
"marks":
|
|
290
|
+
"marks": [],
|
|
291
291
|
"text": " 3",
|
|
292
292
|
},
|
|
293
293
|
],
|
|
294
|
-
"markDefs":
|
|
295
|
-
|
|
294
|
+
"markDefs": [
|
|
295
|
+
{
|
|
296
296
|
"_key": "11de7fcea659",
|
|
297
297
|
"_type": "link",
|
|
298
298
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {describe, expect, it, jest} from '@jest/globals'
|
|
2
1
|
import {render, waitFor} from '@testing-library/react'
|
|
3
2
|
import {createRef, type RefObject} from 'react'
|
|
3
|
+
import {describe, expect, it, vi} from 'vitest'
|
|
4
4
|
import {
|
|
5
5
|
PortableTextEditorTester,
|
|
6
6
|
schemaType,
|
|
@@ -25,7 +25,7 @@ describe('values: normalization', () => {
|
|
|
25
25
|
markDefs: [],
|
|
26
26
|
},
|
|
27
27
|
]
|
|
28
|
-
const onChange =
|
|
28
|
+
const onChange = vi.fn()
|
|
29
29
|
render(
|
|
30
30
|
<PortableTextEditorTester
|
|
31
31
|
onChange={onChange}
|
|
@@ -34,6 +34,17 @@ describe('values: normalization', () => {
|
|
|
34
34
|
value={initialValue}
|
|
35
35
|
/>,
|
|
36
36
|
)
|
|
37
|
+
|
|
38
|
+
await waitFor(() => {
|
|
39
|
+
if (editorRef.current) {
|
|
40
|
+
expect(onChange).toHaveBeenCalledWith({
|
|
41
|
+
type: 'value',
|
|
42
|
+
value: initialValue,
|
|
43
|
+
})
|
|
44
|
+
expect(onChange).toHaveBeenCalledWith({type: 'ready'})
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
37
48
|
await waitFor(() => {
|
|
38
49
|
if (editorRef.current) {
|
|
39
50
|
PortableTextEditor.focus(editorRef.current)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {describe, expect, it} from '
|
|
1
|
+
import {describe, expect, it} from 'vitest'
|
|
2
2
|
import {schemaType} from '../../editor/__tests__/PortableTextEditorTester'
|
|
3
3
|
import {getPortableTextMemberSchemaTypes} from '../getPortableTextMemberSchemaTypes'
|
|
4
4
|
import {fromSlateValue, toSlateValue} from '../values'
|
|
@@ -59,12 +59,12 @@ describe('toSlateValue', () => {
|
|
|
59
59
|
{schemaTypes},
|
|
60
60
|
)
|
|
61
61
|
expect(result).toMatchInlineSnapshot(`
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
[
|
|
63
|
+
{
|
|
64
64
|
"_key": "123",
|
|
65
65
|
"_type": "myTestBlockType",
|
|
66
|
-
"children":
|
|
67
|
-
|
|
66
|
+
"children": [
|
|
67
|
+
{
|
|
68
68
|
"_key": "1231",
|
|
69
69
|
"_type": "span",
|
|
70
70
|
"text": "123",
|
|
@@ -76,7 +76,7 @@ Array [
|
|
|
76
76
|
`)
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
it('given type is block and has custom
|
|
79
|
+
it('given type is block and has custom in children', () => {
|
|
80
80
|
const result = toSlateValue(
|
|
81
81
|
[
|
|
82
82
|
{
|
|
@@ -102,30 +102,30 @@ Array [
|
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
expect(result).toMatchInlineSnapshot(`
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
[
|
|
106
|
+
{
|
|
107
107
|
"_key": "123",
|
|
108
108
|
"_type": "myTestBlockType",
|
|
109
|
-
"children":
|
|
110
|
-
|
|
109
|
+
"children": [
|
|
110
|
+
{
|
|
111
111
|
"_key": "1231",
|
|
112
112
|
"_type": "span",
|
|
113
113
|
"text": "123",
|
|
114
114
|
},
|
|
115
|
-
|
|
115
|
+
{
|
|
116
116
|
"__inline": true,
|
|
117
117
|
"_key": "1232",
|
|
118
118
|
"_type": "image",
|
|
119
|
-
"children":
|
|
120
|
-
|
|
119
|
+
"children": [
|
|
120
|
+
{
|
|
121
121
|
"_key": "void-child",
|
|
122
122
|
"_type": "span",
|
|
123
|
-
"marks":
|
|
123
|
+
"marks": [],
|
|
124
124
|
"text": "",
|
|
125
125
|
},
|
|
126
126
|
],
|
|
127
|
-
"value":
|
|
128
|
-
"asset":
|
|
127
|
+
"value": {
|
|
128
|
+
"asset": {
|
|
129
129
|
"_ref": "ref-123",
|
|
130
130
|
},
|
|
131
131
|
},
|
|
@@ -213,7 +213,7 @@ describe('fromSlateValue', () => {
|
|
|
213
213
|
])
|
|
214
214
|
})
|
|
215
215
|
|
|
216
|
-
it('has
|
|
216
|
+
it('has equality', () => {
|
|
217
217
|
const keyMap = {}
|
|
218
218
|
const value = [
|
|
219
219
|
{
|
package/src/utils/applyPatch.ts
CHANGED
|
@@ -47,8 +47,6 @@ const debugVerbose = debug.enabled && true
|
|
|
47
47
|
export function createApplyPatch(
|
|
48
48
|
schemaTypes: PortableTextMemberSchemaTypes,
|
|
49
49
|
): (editor: PortableTextSlateEditor, patch: Patch) => boolean {
|
|
50
|
-
let previousPatch: Patch | undefined
|
|
51
|
-
|
|
52
50
|
return (editor: PortableTextSlateEditor, patch: Patch): boolean => {
|
|
53
51
|
let changed = false
|
|
54
52
|
|
|
@@ -66,7 +64,7 @@ export function createApplyPatch(
|
|
|
66
64
|
changed = insertPatch(editor, patch, schemaTypes)
|
|
67
65
|
break
|
|
68
66
|
case 'unset':
|
|
69
|
-
changed = unsetPatch(editor, patch
|
|
67
|
+
changed = unsetPatch(editor, patch)
|
|
70
68
|
break
|
|
71
69
|
case 'set':
|
|
72
70
|
changed = setPatch(editor, patch)
|
|
@@ -80,7 +78,7 @@ export function createApplyPatch(
|
|
|
80
78
|
} catch (err) {
|
|
81
79
|
console.error(err)
|
|
82
80
|
}
|
|
83
|
-
|
|
81
|
+
|
|
84
82
|
return changed
|
|
85
83
|
}
|
|
86
84
|
}
|
|
@@ -308,18 +306,14 @@ function setPatch(editor: PortableTextSlateEditor, patch: SetPatch) {
|
|
|
308
306
|
return true
|
|
309
307
|
}
|
|
310
308
|
|
|
311
|
-
function unsetPatch(
|
|
312
|
-
editor: PortableTextSlateEditor,
|
|
313
|
-
patch: UnsetPatch,
|
|
314
|
-
previousPatch?: Patch,
|
|
315
|
-
) {
|
|
309
|
+
function unsetPatch(editor: PortableTextSlateEditor, patch: UnsetPatch) {
|
|
316
310
|
// Value
|
|
317
311
|
if (patch.path.length === 0) {
|
|
318
312
|
debug('Removing everything')
|
|
319
313
|
debugState(editor, 'before')
|
|
320
314
|
const previousSelection = editor.selection
|
|
321
315
|
Transforms.deselect(editor)
|
|
322
|
-
editor.children.forEach((
|
|
316
|
+
editor.children.forEach((_child, i) => {
|
|
323
317
|
Transforms.removeNodes(editor, {at: [i]})
|
|
324
318
|
})
|
|
325
319
|
Transforms.insertNodes(editor, editor.pteCreateTextBlock({decorators: []}))
|
|
@@ -10,7 +10,6 @@ import type {
|
|
|
10
10
|
InvalidValueResolution,
|
|
11
11
|
PortableTextMemberSchemaTypes,
|
|
12
12
|
} from '../types/editor'
|
|
13
|
-
import {EMPTY_MARKDEFS} from './values'
|
|
14
13
|
|
|
15
14
|
export interface Validation {
|
|
16
15
|
valid: boolean
|
|
@@ -227,28 +226,7 @@ export function validateValue(
|
|
|
227
226
|
}
|
|
228
227
|
return true
|
|
229
228
|
}
|
|
230
|
-
// Test that markDefs are valid if they exists
|
|
231
|
-
if (blk.markDefs && !Array.isArray(blk.markDefs)) {
|
|
232
|
-
resolution = {
|
|
233
|
-
patches: [
|
|
234
|
-
set({...textBlock, markDefs: EMPTY_MARKDEFS}, [
|
|
235
|
-
{_key: textBlock._key},
|
|
236
|
-
]),
|
|
237
|
-
],
|
|
238
|
-
description: `Block has invalid required property 'markDefs'.`,
|
|
239
|
-
action: 'Add empty markDefs array',
|
|
240
|
-
item: textBlock,
|
|
241
229
|
|
|
242
|
-
i18n: {
|
|
243
|
-
description:
|
|
244
|
-
'inputs.portable-text.invalid-value.missing-or-invalid-markdefs.description',
|
|
245
|
-
action:
|
|
246
|
-
'inputs.portable-text.invalid-value.missing-or-invalid-markdefs.action',
|
|
247
|
-
values: {key: textBlock._key},
|
|
248
|
-
},
|
|
249
|
-
}
|
|
250
|
-
return true
|
|
251
|
-
}
|
|
252
230
|
const allUsedMarks = uniq(
|
|
253
231
|
flatten(
|
|
254
232
|
textBlock.children
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// This utils are inspired from https://github.dev/mwood23/slate-test-utils/blob/master/src/buildTestHarness.tsx
|
|
2
|
-
import {fireEvent, type render} from '@testing-library/react'
|
|
3
|
-
import {parseHotkey} from 'is-hotkey-esm'
|
|
4
|
-
import {act} from 'react'
|
|
5
|
-
|
|
6
|
-
export async function triggerKeyboardEvent(
|
|
7
|
-
hotkey: string,
|
|
8
|
-
element: Element,
|
|
9
|
-
): Promise<void> {
|
|
10
|
-
const eventProps = parseHotkey(hotkey)
|
|
11
|
-
const values = hotkey.split('+')
|
|
12
|
-
|
|
13
|
-
fireEvent(
|
|
14
|
-
element,
|
|
15
|
-
new window.KeyboardEvent('keydown', {
|
|
16
|
-
key: values[values.length - 1],
|
|
17
|
-
code: `${eventProps.which}`,
|
|
18
|
-
keyCode: eventProps.which,
|
|
19
|
-
bubbles: true,
|
|
20
|
-
...eventProps,
|
|
21
|
-
}),
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function getEditableElement(
|
|
26
|
-
component: ReturnType<typeof render>,
|
|
27
|
-
): Promise<Element> {
|
|
28
|
-
await act(async () => component)
|
|
29
|
-
const element = component.container.querySelector(
|
|
30
|
-
'[data-slate-editor="true"]',
|
|
31
|
-
)
|
|
32
|
-
if (!element) {
|
|
33
|
-
throw new Error('Could not find element')
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Manually add this because JSDom doesn't implement this and Slate checks for it
|
|
37
|
-
* internally before doing stuff.
|
|
38
|
-
*
|
|
39
|
-
* https://github.com/jsdom/jsdom/issues/1670
|
|
40
|
-
*/
|
|
41
|
-
// @ts-ignore
|
|
42
|
-
element.isContentEditable = true
|
|
43
|
-
return element
|
|
44
|
-
}
|