@portabletext/editor 2.20.0 → 2.21.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.
- package/lib/_chunks-dts/index.d.ts +2 -0
- package/lib/index.js +103 -147
- package/lib/index.js.map +1 -1
- package/package.json +8 -8
- package/src/behaviors/behavior.types.event.ts +1 -0
- package/src/editor/plugins/createWithEditableAPI.ts +10 -76
- package/src/editor/plugins/createWithUtils.ts +27 -30
- package/src/internal-utils/operation-to-patches.test.ts +61 -1
- package/src/operations/behavior.operation.insert.block.ts +318 -310
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"slate-dom": "^0.118.1",
|
|
74
74
|
"slate-react": "0.118.2",
|
|
75
75
|
"xstate": "^5.24.0",
|
|
76
|
-
"@portabletext/block-tools": "^4.0.
|
|
76
|
+
"@portabletext/block-tools": "^4.0.2",
|
|
77
77
|
"@portabletext/keyboard-shortcuts": "^2.1.0",
|
|
78
78
|
"@portabletext/patches": "^2.0.0",
|
|
79
79
|
"@portabletext/schema": "^2.0.0"
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
83
83
|
"@sanity/pkg-utils": "^9.0.3",
|
|
84
|
-
"@sanity/schema": "^4.14.
|
|
85
|
-
"@sanity/types": "^4.14.
|
|
84
|
+
"@sanity/schema": "^4.14.2",
|
|
85
|
+
"@sanity/types": "^4.14.2",
|
|
86
86
|
"@types/debug": "^4.1.12",
|
|
87
87
|
"@types/lodash": "^4.17.20",
|
|
88
88
|
"@types/lodash.startcase": "^4.4.9",
|
|
@@ -106,14 +106,14 @@
|
|
|
106
106
|
"vite": "^7.1.12",
|
|
107
107
|
"vitest": "^4.0.6",
|
|
108
108
|
"vitest-browser-react": "^2.0.2",
|
|
109
|
-
"@portabletext/sanity-bridge": "1.2.
|
|
109
|
+
"@portabletext/sanity-bridge": "1.2.2",
|
|
110
110
|
"@portabletext/test": "^1.0.0",
|
|
111
111
|
"racejar": "2.0.0"
|
|
112
112
|
},
|
|
113
113
|
"peerDependencies": {
|
|
114
|
-
"@portabletext/sanity-bridge": "^1.2.
|
|
115
|
-
"@sanity/schema": "^4.14.
|
|
116
|
-
"@sanity/types": "^4.14.
|
|
114
|
+
"@portabletext/sanity-bridge": "^1.2.2",
|
|
115
|
+
"@sanity/schema": "^4.14.2",
|
|
116
|
+
"@sanity/types": "^4.14.2",
|
|
117
117
|
"react": "^18.3 || ^19",
|
|
118
118
|
"rxjs": "^7.8.2"
|
|
119
119
|
},
|
|
@@ -158,6 +158,7 @@ export type SyntheticBehaviorEvent =
|
|
|
158
158
|
block: BlockWithOptionalKey
|
|
159
159
|
placement: InsertPlacement
|
|
160
160
|
select?: 'start' | 'end' | 'none'
|
|
161
|
+
at?: NonNullable<EditorSelection>
|
|
161
162
|
}
|
|
162
163
|
| {
|
|
163
164
|
type: StrictExtract<SyntheticBehaviorEventType, 'insert.child'>
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
slateRangeToSelection,
|
|
26
26
|
} from '../../internal-utils/slate-utils'
|
|
27
27
|
import {toSlateRange} from '../../internal-utils/to-slate-range'
|
|
28
|
-
import {fromSlateValue
|
|
28
|
+
import {fromSlateValue} from '../../internal-utils/values'
|
|
29
29
|
import {getActiveAnnotationsMarks} from '../../selectors/selector.get-active-annotation-marks'
|
|
30
30
|
import {getActiveDecorators} from '../../selectors/selector.get-active-decorators'
|
|
31
31
|
import {getFocusBlock} from '../../selectors/selector.get-focus-block'
|
|
@@ -187,83 +187,17 @@ export function createEditableAPI(
|
|
|
187
187
|
type: TSchemaType,
|
|
188
188
|
value?: {[prop: string]: any},
|
|
189
189
|
): Path => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
value,
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
editor,
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
return editor.selection
|
|
204
|
-
? (slateRangeToSelection({
|
|
205
|
-
schema: editorActor.getSnapshot().context.schema,
|
|
206
|
-
editor,
|
|
207
|
-
range: editor.selection,
|
|
208
|
-
})?.focus.path ?? [])
|
|
209
|
-
: []
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!editor.selection) {
|
|
213
|
-
throw new Error('The editor has no selection')
|
|
214
|
-
}
|
|
215
|
-
const [focusBlock] = Array.from(
|
|
216
|
-
Editor.nodes(editor, {
|
|
217
|
-
at: editor.selection.focus.path.slice(0, 1),
|
|
218
|
-
match: (n) => n._type === types.block.name,
|
|
219
|
-
}),
|
|
220
|
-
)[0] || [undefined]
|
|
221
|
-
if (!focusBlock) {
|
|
222
|
-
throw new Error('No focused text block')
|
|
223
|
-
}
|
|
224
|
-
if (
|
|
225
|
-
type.name !== types.span.name &&
|
|
226
|
-
!types.inlineObjects.some((t) => t.name === type.name)
|
|
227
|
-
) {
|
|
228
|
-
throw new Error(
|
|
229
|
-
'This type cannot be inserted as a child to a text block',
|
|
230
|
-
)
|
|
231
|
-
}
|
|
232
|
-
const block = toSlateValue(
|
|
233
|
-
[
|
|
234
|
-
{
|
|
235
|
-
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
236
|
-
_type: types.block.name,
|
|
237
|
-
children: [
|
|
238
|
-
{
|
|
239
|
-
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
240
|
-
_type: type.name,
|
|
241
|
-
...(value ? value : {}),
|
|
242
|
-
},
|
|
243
|
-
],
|
|
190
|
+
editorActor.send({
|
|
191
|
+
type: 'behavior event',
|
|
192
|
+
behaviorEvent: {
|
|
193
|
+
type: 'insert.child',
|
|
194
|
+
child: {
|
|
195
|
+
_type: type.name,
|
|
196
|
+
...(value ? value : {}),
|
|
244
197
|
},
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)[0] as unknown as SlateElement
|
|
248
|
-
const child = block.children[0]
|
|
249
|
-
const focusChildPath = editor.selection.focus.path.slice(0, 2)
|
|
250
|
-
const isSpanNode = child._type === types.span.name
|
|
251
|
-
const focusNode = Node.get(editor, focusChildPath)
|
|
252
|
-
|
|
253
|
-
// If we are inserting a span, and currently have focus on an inline object,
|
|
254
|
-
// move the selection to the next span (guaranteed by normalizing rules) before inserting it.
|
|
255
|
-
if (isSpanNode && focusNode._type !== types.span.name) {
|
|
256
|
-
debug(
|
|
257
|
-
'Inserting span child next to inline object child, moving selection + 1',
|
|
258
|
-
)
|
|
259
|
-
editor.move({distance: 1, unit: 'character'})
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
Transforms.insertNodes(editor, child, {
|
|
263
|
-
select: true,
|
|
264
|
-
at: editor.selection,
|
|
198
|
+
},
|
|
199
|
+
editor,
|
|
265
200
|
})
|
|
266
|
-
editor.onChange()
|
|
267
201
|
|
|
268
202
|
return editor.selection
|
|
269
203
|
? (slateRangeToSelection({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {toSlateBlock} from '../../internal-utils/values'
|
|
2
2
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
3
3
|
import type {EditorActor} from '../editor-machine'
|
|
4
4
|
|
|
@@ -19,36 +19,33 @@ export function createWithUtils({editorActor}: Options) {
|
|
|
19
19
|
listItem?: string
|
|
20
20
|
level?: number
|
|
21
21
|
}) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
],
|
|
22
|
+
return toSlateBlock(
|
|
23
|
+
{
|
|
24
|
+
_type: editorActor.getSnapshot().context.schema.block.name,
|
|
25
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
26
|
+
style:
|
|
27
|
+
editorActor.getSnapshot().context.schema.styles[0].name || 'normal',
|
|
28
|
+
...(options.listItem ? {listItem: options.listItem} : {}),
|
|
29
|
+
...(options.level ? {level: options.level} : {}),
|
|
30
|
+
markDefs: [],
|
|
31
|
+
children: [
|
|
32
|
+
{
|
|
33
|
+
_type: 'span',
|
|
34
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
35
|
+
text: '',
|
|
36
|
+
marks: options.decorators.filter((decorator) =>
|
|
37
|
+
editorActor
|
|
38
|
+
.getSnapshot()
|
|
39
|
+
.context.schema.decorators.find(
|
|
40
|
+
({name}) => name === decorator,
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
|
|
49
47
|
{schemaTypes: editorActor.getSnapshot().context.schema},
|
|
50
|
-
)
|
|
51
|
-
return block
|
|
48
|
+
)
|
|
52
49
|
}
|
|
53
50
|
return editor
|
|
54
51
|
}
|
|
@@ -2,7 +2,7 @@ import {compileSchemaDefinitionToPortableTextMemberSchemaTypes} from '@portablet
|
|
|
2
2
|
import {compileSchema, defineSchema} from '@portabletext/schema'
|
|
3
3
|
import type {PortableTextTextBlock} from '@sanity/types'
|
|
4
4
|
import {createEditor, type Descendant} from 'slate'
|
|
5
|
-
import {beforeEach, describe, expect, it} from 'vitest'
|
|
5
|
+
import {beforeEach, describe, expect, it, test} from 'vitest'
|
|
6
6
|
import {createActor} from 'xstate'
|
|
7
7
|
import {editorMachine} from '../editor/editor-machine'
|
|
8
8
|
import {withPlugins} from '../editor/plugins/with-plugins'
|
|
@@ -59,6 +59,66 @@ const createDefaultValue = () =>
|
|
|
59
59
|
},
|
|
60
60
|
] as Descendant[]
|
|
61
61
|
|
|
62
|
+
describe(insertNodePatch.name, () => {
|
|
63
|
+
test('Scenario: Inserting block object on empty editor', () => {
|
|
64
|
+
expect(
|
|
65
|
+
insertNodePatch(
|
|
66
|
+
compileSchema(defineSchema({blockObjects: [{name: 'image'}]})),
|
|
67
|
+
[
|
|
68
|
+
{
|
|
69
|
+
_key: 'k2',
|
|
70
|
+
_type: 'image',
|
|
71
|
+
children: [
|
|
72
|
+
{
|
|
73
|
+
_key: 'void-child',
|
|
74
|
+
_type: 'span',
|
|
75
|
+
marks: [],
|
|
76
|
+
text: '',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
value: {},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
{
|
|
83
|
+
type: 'insert_node',
|
|
84
|
+
path: [0],
|
|
85
|
+
node: {
|
|
86
|
+
_key: 'k2',
|
|
87
|
+
_type: 'image',
|
|
88
|
+
children: [
|
|
89
|
+
{
|
|
90
|
+
_key: 'void-child',
|
|
91
|
+
_type: 'span',
|
|
92
|
+
marks: [],
|
|
93
|
+
text: '',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
value: {},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
[],
|
|
100
|
+
),
|
|
101
|
+
).toEqual([
|
|
102
|
+
{
|
|
103
|
+
path: [],
|
|
104
|
+
type: 'setIfMissing',
|
|
105
|
+
value: [],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
path: [0],
|
|
109
|
+
type: 'insert',
|
|
110
|
+
items: [
|
|
111
|
+
{
|
|
112
|
+
_key: 'k2',
|
|
113
|
+
_type: 'image',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
position: 'before',
|
|
117
|
+
},
|
|
118
|
+
])
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
62
122
|
describe('operationToPatches', () => {
|
|
63
123
|
beforeEach(() => {
|
|
64
124
|
editor.children = createDefaultValue()
|