@portabletext/editor 1.26.0 → 1.26.2
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/lib/index.cjs +38 -11
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +38 -11
- package/lib/index.js.map +1 -1
- package/package.json +14 -14
- package/src/behavior-actions/behavior.action.insert.block.ts +5 -1
- package/src/converters/converter.portable-text.ts +5 -1
- package/src/editor/__tests__/handleClick.test.tsx +2 -2
- package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +1 -1
- package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +12 -12
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +30 -37
- package/src/editor/plugins/createWithObjectKeys.ts +18 -2
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +3 -0
- package/src/internal-utils/parse-blocks.ts +36 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.2",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -67,21 +67,21 @@
|
|
|
67
67
|
"get-random-values-esm": "^1.0.2",
|
|
68
68
|
"lodash": "^4.17.21",
|
|
69
69
|
"lodash.startcase": "^4.4.0",
|
|
70
|
-
"react-compiler-runtime": "19.0.0-beta-
|
|
70
|
+
"react-compiler-runtime": "19.0.0-beta-27714ef-20250124",
|
|
71
71
|
"slate": "0.112.0",
|
|
72
72
|
"slate-dom": "^0.111.0",
|
|
73
73
|
"slate-react": "0.112.1",
|
|
74
74
|
"use-effect-event": "^1.0.2",
|
|
75
75
|
"xstate": "^5.19.2",
|
|
76
|
-
"@portabletext/block-tools": "1.1.
|
|
76
|
+
"@portabletext/block-tools": "1.1.3",
|
|
77
77
|
"@portabletext/patches": "1.1.2"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@portabletext/toolkit": "^2.0.16",
|
|
81
81
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
82
82
|
"@sanity/pkg-utils": "^7.0.2",
|
|
83
|
-
"@sanity/schema": "^3.71.
|
|
84
|
-
"@sanity/types": "^3.71.
|
|
83
|
+
"@sanity/schema": "^3.71.2",
|
|
84
|
+
"@sanity/types": "^3.71.2",
|
|
85
85
|
"@testing-library/jest-dom": "^6.6.3",
|
|
86
86
|
"@testing-library/react": "^16.2.0",
|
|
87
87
|
"@types/debug": "^4.1.12",
|
|
@@ -92,25 +92,25 @@
|
|
|
92
92
|
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
93
93
|
"@typescript-eslint/parser": "^8.18.1",
|
|
94
94
|
"@vitejs/plugin-react": "^4.3.4",
|
|
95
|
-
"@vitest/browser": "^3.0.
|
|
96
|
-
"@vitest/coverage-istanbul": "^3.0.
|
|
97
|
-
"babel-plugin-react-compiler": "19.0.0-beta-
|
|
95
|
+
"@vitest/browser": "^3.0.4",
|
|
96
|
+
"@vitest/coverage-istanbul": "^3.0.4",
|
|
97
|
+
"babel-plugin-react-compiler": "19.0.0-beta-27714ef-20250124",
|
|
98
98
|
"eslint": "8.57.1",
|
|
99
|
-
"eslint-plugin-react-compiler": "19.0.0-beta-
|
|
99
|
+
"eslint-plugin-react-compiler": "19.0.0-beta-27714ef-20250124",
|
|
100
100
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
101
101
|
"jsdom": "^26.0.0",
|
|
102
102
|
"react": "^19.0.0",
|
|
103
103
|
"react-dom": "^19.0.0",
|
|
104
104
|
"rxjs": "^7.8.1",
|
|
105
105
|
"typescript": "5.7.3",
|
|
106
|
-
"vite": "^6.0.
|
|
107
|
-
"vitest": "^3.0.
|
|
106
|
+
"vite": "^6.0.11",
|
|
107
|
+
"vitest": "^3.0.4",
|
|
108
108
|
"vitest-browser-react": "^0.0.4",
|
|
109
|
-
"racejar": "1.1.
|
|
109
|
+
"racejar": "1.1.2"
|
|
110
110
|
},
|
|
111
111
|
"peerDependencies": {
|
|
112
|
-
"@sanity/schema": "^3.71.
|
|
113
|
-
"@sanity/types": "^3.71.
|
|
112
|
+
"@sanity/schema": "^3.71.2",
|
|
113
|
+
"@sanity/types": "^3.71.2",
|
|
114
114
|
"react": "^16.9 || ^17 || ^18 || ^19",
|
|
115
115
|
"rxjs": "^7.8.1"
|
|
116
116
|
},
|
|
@@ -6,7 +6,11 @@ import type {BehaviorActionImplementation} from './behavior.actions'
|
|
|
6
6
|
export const insertBlockActionImplementation: BehaviorActionImplementation<
|
|
7
7
|
'insert.block'
|
|
8
8
|
> = ({context, action}) => {
|
|
9
|
-
const parsedBlock = parseBlock({
|
|
9
|
+
const parsedBlock = parseBlock({
|
|
10
|
+
block: action.block,
|
|
11
|
+
context,
|
|
12
|
+
options: {refreshKeys: false},
|
|
13
|
+
})
|
|
10
14
|
|
|
11
15
|
if (!parsedBlock) {
|
|
12
16
|
throw new Error(`Failed to parse block ${JSON.stringify(action.block)}`)
|
|
@@ -38,7 +38,11 @@ export const converterPortableText = defineConverter({
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const parsedBlocks = blocks.flatMap((block) => {
|
|
41
|
-
const parsedBlock = parseBlock({
|
|
41
|
+
const parsedBlock = parseBlock({
|
|
42
|
+
context,
|
|
43
|
+
block,
|
|
44
|
+
options: {refreshKeys: true},
|
|
45
|
+
})
|
|
42
46
|
return parsedBlock ? [parsedBlock] : []
|
|
43
47
|
})
|
|
44
48
|
|
|
@@ -28,7 +28,7 @@ async function getEditableElement(
|
|
|
28
28
|
describe('adds empty text block if its needed', () => {
|
|
29
29
|
const newBlock = {
|
|
30
30
|
_type: 'myTestBlockType',
|
|
31
|
-
_key: '
|
|
31
|
+
_key: '1',
|
|
32
32
|
style: 'normal',
|
|
33
33
|
markDefs: [],
|
|
34
34
|
children: [
|
|
@@ -96,7 +96,7 @@ describe('adds empty text block if its needed', () => {
|
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
_type: 'myTestBlockType',
|
|
99
|
-
_key: '
|
|
99
|
+
_key: '1',
|
|
100
100
|
style: 'normal',
|
|
101
101
|
markDefs: [],
|
|
102
102
|
children: [
|
|
@@ -337,7 +337,7 @@ describe('when PTE would display warnings, instead it self solves', () => {
|
|
|
337
337
|
PortableTextEditor.focus(editorRef.current)
|
|
338
338
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
339
339
|
{
|
|
340
|
-
_key: '
|
|
340
|
+
_key: '3',
|
|
341
341
|
_type: 'myTestBlockType',
|
|
342
342
|
children: [{_key: '4', _type: 'span', marks: [], text: ''}],
|
|
343
343
|
markDefs: [],
|
|
@@ -111,12 +111,12 @@ describe('plugin:withEditableAPI: .insertChild()', () => {
|
|
|
111
111
|
text: 'Block A',
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
|
-
_key: '
|
|
114
|
+
_key: '2',
|
|
115
115
|
_type: 'someObject',
|
|
116
116
|
color: 'red',
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
|
-
_key: '
|
|
119
|
+
_key: '3',
|
|
120
120
|
_type: 'span',
|
|
121
121
|
marks: [],
|
|
122
122
|
text: '',
|
|
@@ -155,12 +155,12 @@ describe('plugin:withEditableAPI: .insertChild()', () => {
|
|
|
155
155
|
text: 'Block A',
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
|
-
_key: '
|
|
158
|
+
_key: '2',
|
|
159
159
|
_type: 'someObject',
|
|
160
160
|
color: 'red',
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
|
-
_key: '
|
|
163
|
+
_key: '5',
|
|
164
164
|
_type: 'span',
|
|
165
165
|
marks: [],
|
|
166
166
|
text: ' ',
|
|
@@ -172,8 +172,8 @@ describe('plugin:withEditableAPI: .insertChild()', () => {
|
|
|
172
172
|
])
|
|
173
173
|
|
|
174
174
|
expect(PortableTextEditor.getSelection(editorRef.current)).toEqual({
|
|
175
|
-
anchor: {path: [{_key: 'a'}, 'children', {_key: '
|
|
176
|
-
focus: {path: [{_key: 'a'}, 'children', {_key: '
|
|
175
|
+
anchor: {path: [{_key: 'a'}, 'children', {_key: '5'}], offset: 1},
|
|
176
|
+
focus: {path: [{_key: 'a'}, 'children', {_key: '5'}], offset: 1},
|
|
177
177
|
backward: false,
|
|
178
178
|
})
|
|
179
179
|
}
|
|
@@ -240,7 +240,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
240
240
|
await waitFor(() => {
|
|
241
241
|
if (editorRef.current) {
|
|
242
242
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
243
|
-
{_key: '
|
|
243
|
+
{_key: '1', _type: 'someObject', color: 'red'},
|
|
244
244
|
])
|
|
245
245
|
}
|
|
246
246
|
})
|
|
@@ -292,7 +292,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
292
292
|
if (editorRef.current) {
|
|
293
293
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
294
294
|
...initialValue,
|
|
295
|
-
{_key: '
|
|
295
|
+
{_key: '1', _type: 'someObject', color: 'red'},
|
|
296
296
|
])
|
|
297
297
|
}
|
|
298
298
|
})
|
|
@@ -345,7 +345,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
345
345
|
await waitFor(() => {
|
|
346
346
|
if (editorRef.current) {
|
|
347
347
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
348
|
-
{_key: '
|
|
348
|
+
{_key: '1', _type: 'someObject', color: 'red'},
|
|
349
349
|
...initialValue,
|
|
350
350
|
])
|
|
351
351
|
}
|
|
@@ -402,7 +402,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
402
402
|
if (editorRef.current) {
|
|
403
403
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
404
404
|
...value,
|
|
405
|
-
{_key: '
|
|
405
|
+
{_key: '1', _type: 'someObject', color: 'yellow'},
|
|
406
406
|
])
|
|
407
407
|
}
|
|
408
408
|
})
|
|
@@ -455,7 +455,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
455
455
|
if (editorRef.current) {
|
|
456
456
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
457
457
|
value[0],
|
|
458
|
-
{_key: '
|
|
458
|
+
{_key: '1', _type: 'someObject', color: 'yellow'},
|
|
459
459
|
value[1],
|
|
460
460
|
])
|
|
461
461
|
}
|
|
@@ -504,7 +504,7 @@ describe('plugin:withEditableAPI: .insertBlock()', () => {
|
|
|
504
504
|
if (editorRef.current) {
|
|
505
505
|
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
506
506
|
value[0],
|
|
507
|
-
{_key: '
|
|
507
|
+
{_key: '1', _type: 'someObject', color: 'yellow'},
|
|
508
508
|
])
|
|
509
509
|
}
|
|
510
510
|
})
|
|
@@ -73,41 +73,34 @@ describe('plugin:withPortableTextMarksModel', () => {
|
|
|
73
73
|
anchor: {path: [{_key: 'a'}, 'children', {_key: 'a1'}], offset: 3},
|
|
74
74
|
})
|
|
75
75
|
PortableTextEditor.toggleMark(editorRef.current, 'strong')
|
|
76
|
-
expect(PortableTextEditor.getValue(editorRef.current))
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
"markDefs": [],
|
|
107
|
-
"style": "normal",
|
|
108
|
-
},
|
|
109
|
-
]
|
|
110
|
-
`)
|
|
76
|
+
expect(PortableTextEditor.getValue(editorRef.current)).toEqual([
|
|
77
|
+
{
|
|
78
|
+
_key: 'a',
|
|
79
|
+
_type: 'myTestBlockType',
|
|
80
|
+
children: [
|
|
81
|
+
{
|
|
82
|
+
_key: 'a1',
|
|
83
|
+
_type: 'span',
|
|
84
|
+
marks: ['strong'],
|
|
85
|
+
text: '1',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
_key: '2',
|
|
89
|
+
_type: 'span',
|
|
90
|
+
marks: [],
|
|
91
|
+
text: '23',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
_key: '1',
|
|
95
|
+
_type: 'span',
|
|
96
|
+
marks: ['strong'],
|
|
97
|
+
text: '4',
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
markDefs: [],
|
|
101
|
+
style: 'normal',
|
|
102
|
+
},
|
|
103
|
+
])
|
|
111
104
|
}
|
|
112
105
|
})
|
|
113
106
|
await waitFor(() => {
|
|
@@ -461,11 +454,11 @@ describe('plugin:withPortableTextMarksModel', () => {
|
|
|
461
454
|
style: 'normal',
|
|
462
455
|
},
|
|
463
456
|
{
|
|
464
|
-
_key: '
|
|
457
|
+
_key: '1',
|
|
465
458
|
_type: 'myTestBlockType',
|
|
466
459
|
children: [
|
|
467
460
|
{
|
|
468
|
-
_key: '
|
|
461
|
+
_key: '2',
|
|
469
462
|
_type: 'span',
|
|
470
463
|
marks: [],
|
|
471
464
|
text: '',
|
|
@@ -43,11 +43,19 @@ export function createWithObjectKeys(
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
if (operation.type === 'split_node') {
|
|
46
|
+
const existingKeys = [...Node.descendants(editor)].map(
|
|
47
|
+
([node]) => node._key,
|
|
48
|
+
)
|
|
49
|
+
|
|
46
50
|
apply({
|
|
47
51
|
...operation,
|
|
48
52
|
properties: {
|
|
49
53
|
...operation.properties,
|
|
50
|
-
_key:
|
|
54
|
+
_key:
|
|
55
|
+
operation.properties._key === undefined ||
|
|
56
|
+
existingKeys.includes(operation.properties._key)
|
|
57
|
+
? editorActor.getSnapshot().context.keyGenerator()
|
|
58
|
+
: operation.properties._key,
|
|
51
59
|
},
|
|
52
60
|
})
|
|
53
61
|
|
|
@@ -56,11 +64,19 @@ export function createWithObjectKeys(
|
|
|
56
64
|
|
|
57
65
|
if (operation.type === 'insert_node') {
|
|
58
66
|
if (!Editor.isEditor(operation.node)) {
|
|
67
|
+
const existingKeys = [...Node.descendants(editor)].map(
|
|
68
|
+
([node]) => node._key,
|
|
69
|
+
)
|
|
70
|
+
|
|
59
71
|
apply({
|
|
60
72
|
...operation,
|
|
61
73
|
node: {
|
|
62
74
|
...operation.node,
|
|
63
|
-
_key:
|
|
75
|
+
_key:
|
|
76
|
+
operation.node._key === undefined ||
|
|
77
|
+
existingKeys.includes(operation.node._key)
|
|
78
|
+
? editorActor.getSnapshot().context.keyGenerator()
|
|
79
|
+
: operation.node._key,
|
|
64
80
|
},
|
|
65
81
|
})
|
|
66
82
|
|
|
@@ -361,6 +361,7 @@ export function createWithPortableTextMarkModel(
|
|
|
361
361
|
) {
|
|
362
362
|
Transforms.insertNodes(editor, {
|
|
363
363
|
...op.node,
|
|
364
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
364
365
|
marks:
|
|
365
366
|
op.node.marks?.filter(
|
|
366
367
|
(mark) => !annotationsEnding.includes(mark),
|
|
@@ -382,6 +383,7 @@ export function createWithPortableTextMarkModel(
|
|
|
382
383
|
) {
|
|
383
384
|
Transforms.insertNodes(editor, {
|
|
384
385
|
...op.node,
|
|
386
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
385
387
|
marks:
|
|
386
388
|
op.node.marks?.filter(
|
|
387
389
|
(mark) => !annotationsStarting.includes(mark),
|
|
@@ -403,6 +405,7 @@ export function createWithPortableTextMarkModel(
|
|
|
403
405
|
) {
|
|
404
406
|
Transforms.insertNodes(editor, {
|
|
405
407
|
...op.node,
|
|
408
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
406
409
|
marks: nextSpanDecorators,
|
|
407
410
|
})
|
|
408
411
|
return
|
|
@@ -9,9 +9,13 @@ import {isTypedObject} from './asserters'
|
|
|
9
9
|
export function parseBlock({
|
|
10
10
|
context,
|
|
11
11
|
block,
|
|
12
|
+
options,
|
|
12
13
|
}: {
|
|
13
14
|
context: Pick<EditorContext, 'keyGenerator' | 'schema'>
|
|
14
15
|
block: unknown
|
|
16
|
+
options: {
|
|
17
|
+
refreshKeys: boolean
|
|
18
|
+
}
|
|
15
19
|
}): PortableTextBlock | undefined {
|
|
16
20
|
if (!isTypedObject(block)) {
|
|
17
21
|
return undefined
|
|
@@ -26,10 +30,36 @@ export function parseBlock({
|
|
|
26
30
|
return undefined
|
|
27
31
|
}
|
|
28
32
|
|
|
29
|
-
if (
|
|
33
|
+
if (block._type !== context.schema.block.name) {
|
|
34
|
+
const _key = options.refreshKeys
|
|
35
|
+
? context.keyGenerator()
|
|
36
|
+
: typeof block._key === 'string'
|
|
37
|
+
? block._key
|
|
38
|
+
: context.keyGenerator()
|
|
30
39
|
return {
|
|
31
40
|
...block,
|
|
32
|
-
_key
|
|
41
|
+
_key,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!isPortableTextTextBlock(block)) {
|
|
46
|
+
return {
|
|
47
|
+
_type: context.schema.block.name,
|
|
48
|
+
_key: options.refreshKeys
|
|
49
|
+
? context.keyGenerator()
|
|
50
|
+
: typeof block._key === 'string'
|
|
51
|
+
? block._key
|
|
52
|
+
: context.keyGenerator(),
|
|
53
|
+
children: [
|
|
54
|
+
{
|
|
55
|
+
_key: context.keyGenerator(),
|
|
56
|
+
_type: context.schema.span.name,
|
|
57
|
+
text: '',
|
|
58
|
+
marks: [],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
markDefs: [],
|
|
62
|
+
style: context.schema.styles[0].value,
|
|
33
63
|
}
|
|
34
64
|
}
|
|
35
65
|
|
|
@@ -40,7 +70,7 @@ export function parseBlock({
|
|
|
40
70
|
(annotation) => annotation.name === markDef._type,
|
|
41
71
|
)
|
|
42
72
|
) {
|
|
43
|
-
const _key = context.keyGenerator()
|
|
73
|
+
const _key = options.refreshKeys ? context.keyGenerator() : markDef._key
|
|
44
74
|
markDefKeyMap.set(markDef._key, _key)
|
|
45
75
|
|
|
46
76
|
return [
|
|
@@ -72,7 +102,7 @@ export function parseBlock({
|
|
|
72
102
|
return [
|
|
73
103
|
{
|
|
74
104
|
...child,
|
|
75
|
-
_key: context.keyGenerator(),
|
|
105
|
+
_key: options.refreshKeys ? context.keyGenerator() : child._key,
|
|
76
106
|
},
|
|
77
107
|
]
|
|
78
108
|
}
|
|
@@ -94,7 +124,7 @@ export function parseBlock({
|
|
|
94
124
|
return [
|
|
95
125
|
{
|
|
96
126
|
...child,
|
|
97
|
-
_key: context.keyGenerator(),
|
|
127
|
+
_key: options.refreshKeys ? context.keyGenerator() : child._key,
|
|
98
128
|
marks,
|
|
99
129
|
},
|
|
100
130
|
]
|
|
@@ -102,7 +132,7 @@ export function parseBlock({
|
|
|
102
132
|
|
|
103
133
|
const parsedBlock = {
|
|
104
134
|
...block,
|
|
105
|
-
_key: context.keyGenerator(),
|
|
135
|
+
_key: options.refreshKeys ? context.keyGenerator() : block._key,
|
|
106
136
|
children:
|
|
107
137
|
children.length > 0
|
|
108
138
|
? children
|