@portabletext/editor 1.0.18 → 1.1.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.
- package/lib/index.d.mts +140 -66
- package/lib/index.d.ts +140 -66
- package/lib/index.esm.js +1164 -410
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +1164 -410
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1164 -410
- package/lib/index.mjs.map +1 -1
- package/package.json +8 -4
- package/src/editor/Editable.tsx +107 -36
- package/src/editor/PortableTextEditor.tsx +47 -12
- package/src/editor/__tests__/PortableTextEditor.test.tsx +42 -15
- package/src/editor/__tests__/PortableTextEditorTester.tsx +50 -38
- package/src/editor/__tests__/RangeDecorations.test.tsx +0 -1
- package/src/editor/__tests__/handleClick.test.tsx +28 -9
- package/src/editor/__tests__/insert-block.test.tsx +22 -6
- package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +30 -62
- package/src/editor/__tests__/utils.ts +10 -3
- package/src/editor/components/DraggableBlock.tsx +36 -13
- package/src/editor/components/Element.tsx +59 -17
- package/src/editor/components/Leaf.tsx +106 -68
- package/src/editor/components/SlateContainer.tsx +12 -5
- package/src/editor/components/Synchronizer.tsx +5 -2
- package/src/editor/hooks/usePortableTextEditor.ts +2 -2
- package/src/editor/hooks/usePortableTextEditorSelection.tsx +9 -3
- package/src/editor/hooks/useSyncValue.test.tsx +9 -4
- package/src/editor/hooks/useSyncValue.ts +199 -130
- package/src/editor/nodes/DefaultAnnotation.tsx +6 -3
- package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +25 -7
- package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +26 -9
- package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +15 -5
- package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +60 -19
- package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +4 -2
- package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +4 -2
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +61 -550
- package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +6 -3
- package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +30 -13
- package/src/editor/plugins/createWithEditableAPI.ts +354 -115
- package/src/editor/plugins/createWithHotKeys.ts +41 -121
- package/src/editor/plugins/createWithInsertBreak.ts +166 -27
- package/src/editor/plugins/createWithInsertData.ts +60 -23
- package/src/editor/plugins/createWithMaxBlocks.ts +5 -2
- package/src/editor/plugins/createWithObjectKeys.ts +7 -3
- package/src/editor/plugins/createWithPatches.ts +60 -16
- package/src/editor/plugins/createWithPlaceholderBlock.ts +7 -3
- package/src/editor/plugins/createWithPortableTextBlockStyle.ts +17 -7
- package/src/editor/plugins/createWithPortableTextLists.ts +21 -8
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +301 -155
- package/src/editor/plugins/createWithPortableTextSelections.ts +4 -2
- package/src/editor/plugins/createWithSchemaTypes.ts +25 -9
- package/src/editor/plugins/createWithUndoRedo.ts +107 -24
- package/src/editor/plugins/createWithUtils.ts +32 -10
- package/src/editor/plugins/index.ts +31 -10
- package/src/types/editor.ts +44 -15
- package/src/types/options.ts +4 -2
- package/src/types/slate.ts +2 -2
- package/src/utils/__tests__/dmpToOperations.test.ts +38 -13
- package/src/utils/__tests__/operationToPatches.test.ts +3 -2
- package/src/utils/__tests__/patchToOperations.test.ts +15 -4
- package/src/utils/__tests__/ranges.test.ts +8 -3
- package/src/utils/__tests__/valueNormalization.test.tsx +12 -4
- package/src/utils/__tests__/values.test.ts +0 -1
- package/src/utils/applyPatch.ts +71 -20
- package/src/utils/getPortableTextMemberSchemaTypes.ts +30 -15
- package/src/utils/operationToPatches.ts +126 -43
- package/src/utils/paths.ts +24 -7
- package/src/utils/ranges.ts +12 -5
- package/src/utils/selection.ts +19 -7
- package/src/utils/validateValue.ts +118 -45
- package/src/utils/values.ts +31 -10
- package/src/utils/weakMaps.ts +18 -8
- package/src/utils/withChanges.ts +4 -2
- package/src/editor/plugins/__tests__/withHotkeys.test.tsx +0 -212
- package/src/editor/plugins/__tests__/withInsertBreak.test.tsx +0 -220
- package/src/editor/plugins/__tests__/withPlaceholderBlock.test.tsx +0 -133
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
diffMatchPatch,
|
|
3
3
|
insert,
|
|
4
|
-
type InsertPosition,
|
|
5
|
-
type Patch,
|
|
6
4
|
set,
|
|
7
5
|
setIfMissing,
|
|
8
6
|
unset,
|
|
7
|
+
type InsertPosition,
|
|
8
|
+
type Patch,
|
|
9
9
|
} from '@portabletext/patches'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
type Path,
|
|
12
|
+
type PortableTextSpan,
|
|
13
|
+
type PortableTextTextBlock,
|
|
14
|
+
} from '@sanity/types'
|
|
11
15
|
import {get, isUndefined, omitBy} from 'lodash'
|
|
12
16
|
import {
|
|
17
|
+
Text,
|
|
13
18
|
type Descendant,
|
|
14
19
|
type InsertNodeOperation,
|
|
15
20
|
type InsertTextOperation,
|
|
@@ -19,17 +24,20 @@ import {
|
|
|
19
24
|
type RemoveTextOperation,
|
|
20
25
|
type SetNodeOperation,
|
|
21
26
|
type SplitNodeOperation,
|
|
22
|
-
Text,
|
|
23
27
|
} from 'slate'
|
|
24
|
-
|
|
25
28
|
import {type PatchFunctions} from '../editor/plugins/createWithPatches'
|
|
26
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
type PortableTextMemberSchemaTypes,
|
|
31
|
+
type PortableTextSlateEditor,
|
|
32
|
+
} from '../types/editor'
|
|
27
33
|
import {debugWithName} from './debug'
|
|
28
34
|
import {fromSlateValue} from './values'
|
|
29
35
|
|
|
30
36
|
const debug = debugWithName('operationToPatches')
|
|
31
37
|
|
|
32
|
-
export function createOperationToPatches(
|
|
38
|
+
export function createOperationToPatches(
|
|
39
|
+
types: PortableTextMemberSchemaTypes,
|
|
40
|
+
): PatchFunctions {
|
|
33
41
|
const textBlockName = types.block.name
|
|
34
42
|
function insertTextPatch(
|
|
35
43
|
editor: PortableTextSlateEditor,
|
|
@@ -40,7 +48,8 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
40
48
|
debug('Operation', JSON.stringify(operation, null, 2))
|
|
41
49
|
}
|
|
42
50
|
const block =
|
|
43
|
-
editor.isTextBlock(editor.children[operation.path[0]]) &&
|
|
51
|
+
editor.isTextBlock(editor.children[operation.path[0]]) &&
|
|
52
|
+
editor.children[operation.path[0]]
|
|
44
53
|
if (!block) {
|
|
45
54
|
throw new Error('Could not find block')
|
|
46
55
|
}
|
|
@@ -51,9 +60,15 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
51
60
|
if (!textChild) {
|
|
52
61
|
throw new Error('Could not find child')
|
|
53
62
|
}
|
|
54
|
-
const path: Path = [
|
|
63
|
+
const path: Path = [
|
|
64
|
+
{_key: block._key},
|
|
65
|
+
'children',
|
|
66
|
+
{_key: textChild._key},
|
|
67
|
+
'text',
|
|
68
|
+
]
|
|
55
69
|
const prevBlock = beforeValue[operation.path[0]]
|
|
56
|
-
const prevChild =
|
|
70
|
+
const prevChild =
|
|
71
|
+
editor.isTextBlock(prevBlock) && prevBlock.children[operation.path[1]]
|
|
57
72
|
const prevText = editor.isTextSpan(prevChild) ? prevChild.text : ''
|
|
58
73
|
const patch = diffMatchPatch(prevText, textChild.text, path)
|
|
59
74
|
return patch.value.length ? [patch] : []
|
|
@@ -68,23 +83,36 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
68
83
|
if (!block) {
|
|
69
84
|
throw new Error('Could not find block')
|
|
70
85
|
}
|
|
71
|
-
const child =
|
|
72
|
-
|
|
86
|
+
const child =
|
|
87
|
+
(editor.isTextBlock(block) && block.children[operation.path[1]]) ||
|
|
88
|
+
undefined
|
|
89
|
+
const textChild: PortableTextSpan | undefined = editor.isTextSpan(child)
|
|
90
|
+
? child
|
|
91
|
+
: undefined
|
|
73
92
|
if (child && !textChild) {
|
|
74
93
|
throw new Error('Expected span')
|
|
75
94
|
}
|
|
76
95
|
if (!textChild) {
|
|
77
96
|
throw new Error('Could not find child')
|
|
78
97
|
}
|
|
79
|
-
const path: Path = [
|
|
98
|
+
const path: Path = [
|
|
99
|
+
{_key: block._key},
|
|
100
|
+
'children',
|
|
101
|
+
{_key: textChild._key},
|
|
102
|
+
'text',
|
|
103
|
+
]
|
|
80
104
|
const beforeBlock = beforeValue[operation.path[0]]
|
|
81
|
-
const prevTextChild =
|
|
105
|
+
const prevTextChild =
|
|
106
|
+
editor.isTextBlock(beforeBlock) && beforeBlock.children[operation.path[1]]
|
|
82
107
|
const prevText = editor.isTextSpan(prevTextChild) && prevTextChild.text
|
|
83
108
|
const patch = diffMatchPatch(prevText || '', textChild.text, path)
|
|
84
109
|
return patch.value ? [patch] : []
|
|
85
110
|
}
|
|
86
111
|
|
|
87
|
-
function setNodePatch(
|
|
112
|
+
function setNodePatch(
|
|
113
|
+
editor: PortableTextSlateEditor,
|
|
114
|
+
operation: SetNodeOperation,
|
|
115
|
+
) {
|
|
88
116
|
if (operation.path.length === 1) {
|
|
89
117
|
const block = editor.children[operation.path[0]]
|
|
90
118
|
if (typeof block._key !== 'string') {
|
|
@@ -94,7 +122,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
94
122
|
{...editor.children[operation.path[0]], ...operation.newProperties},
|
|
95
123
|
isUndefined,
|
|
96
124
|
) as unknown as Descendant
|
|
97
|
-
return [
|
|
125
|
+
return [
|
|
126
|
+
set(fromSlateValue([setNode], textBlockName)[0], [{_key: block._key}]),
|
|
127
|
+
]
|
|
98
128
|
} else if (operation.path.length === 2) {
|
|
99
129
|
const block = editor.children[operation.path[0]]
|
|
100
130
|
if (editor.isTextBlock(block)) {
|
|
@@ -109,11 +139,23 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
109
139
|
if (keys.length === 1 && keyName === '_key') {
|
|
110
140
|
const val = get(operation.newProperties, keyName)
|
|
111
141
|
patches.push(
|
|
112
|
-
set(val, [
|
|
142
|
+
set(val, [
|
|
143
|
+
{_key: blockKey},
|
|
144
|
+
'children',
|
|
145
|
+
block.children.indexOf(child),
|
|
146
|
+
keyName,
|
|
147
|
+
]),
|
|
113
148
|
)
|
|
114
149
|
} else {
|
|
115
150
|
const val = get(operation.newProperties, keyName)
|
|
116
|
-
patches.push(
|
|
151
|
+
patches.push(
|
|
152
|
+
set(val, [
|
|
153
|
+
{_key: blockKey},
|
|
154
|
+
'children',
|
|
155
|
+
{_key: childKey},
|
|
156
|
+
keyName,
|
|
157
|
+
]),
|
|
158
|
+
)
|
|
117
159
|
}
|
|
118
160
|
})
|
|
119
161
|
return patches
|
|
@@ -122,7 +164,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
122
164
|
}
|
|
123
165
|
throw new Error('Could not find a valid block')
|
|
124
166
|
} else {
|
|
125
|
-
throw new Error(
|
|
167
|
+
throw new Error(
|
|
168
|
+
`Unexpected path encountered: ${JSON.stringify(operation.path)}`,
|
|
169
|
+
)
|
|
126
170
|
}
|
|
127
171
|
}
|
|
128
172
|
|
|
@@ -136,23 +180,34 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
136
180
|
if (operation.path.length === 1) {
|
|
137
181
|
const position = operation.path[0] === 0 ? 'before' : 'after'
|
|
138
182
|
const beforeBlock = beforeValue[operation.path[0] - 1]
|
|
139
|
-
const targetKey =
|
|
183
|
+
const targetKey =
|
|
184
|
+
operation.path[0] === 0 ? block?._key : beforeBlock?._key
|
|
140
185
|
if (targetKey) {
|
|
141
186
|
return [
|
|
142
|
-
insert(
|
|
143
|
-
|
|
144
|
-
|
|
187
|
+
insert(
|
|
188
|
+
[fromSlateValue([operation.node as Descendant], textBlockName)[0]],
|
|
189
|
+
position,
|
|
190
|
+
[{_key: targetKey}],
|
|
191
|
+
),
|
|
145
192
|
]
|
|
146
193
|
}
|
|
147
194
|
return [
|
|
148
195
|
setIfMissing(beforeValue, []),
|
|
149
|
-
insert(
|
|
150
|
-
operation.
|
|
151
|
-
|
|
196
|
+
insert(
|
|
197
|
+
[fromSlateValue([operation.node as Descendant], textBlockName)[0]],
|
|
198
|
+
'before',
|
|
199
|
+
[operation.path[0]],
|
|
200
|
+
),
|
|
152
201
|
]
|
|
153
|
-
} else if (
|
|
202
|
+
} else if (
|
|
203
|
+
isTextBlock &&
|
|
204
|
+
operation.path.length === 2 &&
|
|
205
|
+
editor.children[operation.path[0]]
|
|
206
|
+
) {
|
|
154
207
|
const position =
|
|
155
|
-
block.children.length === 0 || !block.children[operation.path[1] - 1]
|
|
208
|
+
block.children.length === 0 || !block.children[operation.path[1] - 1]
|
|
209
|
+
? 'before'
|
|
210
|
+
: 'after'
|
|
156
211
|
const node = {...operation.node} as Descendant
|
|
157
212
|
if (!node._type && Text.isText(node)) {
|
|
158
213
|
node._type = 'span'
|
|
@@ -179,7 +234,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
179
234
|
]),
|
|
180
235
|
]
|
|
181
236
|
}
|
|
182
|
-
debug(
|
|
237
|
+
debug(
|
|
238
|
+
'Something was inserted into a void block. Not producing editor patches.',
|
|
239
|
+
)
|
|
183
240
|
return []
|
|
184
241
|
}
|
|
185
242
|
|
|
@@ -205,7 +262,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
205
262
|
textBlockName,
|
|
206
263
|
)[0]
|
|
207
264
|
if (targetValue) {
|
|
208
|
-
patches.push(
|
|
265
|
+
patches.push(
|
|
266
|
+
insert([targetValue], 'after', [{_key: splitBlock._key}]),
|
|
267
|
+
)
|
|
209
268
|
const spansToUnset = oldBlock.children.slice(operation.position)
|
|
210
269
|
spansToUnset.forEach((span) => {
|
|
211
270
|
const path = [{_key: oldBlock._key}, 'children', {_key: span._key}]
|
|
@@ -223,7 +282,10 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
223
282
|
[
|
|
224
283
|
{
|
|
225
284
|
...splitBlock,
|
|
226
|
-
children: splitBlock.children.slice(
|
|
285
|
+
children: splitBlock.children.slice(
|
|
286
|
+
operation.path[1] + 1,
|
|
287
|
+
operation.path[1] + 2,
|
|
288
|
+
),
|
|
227
289
|
} as Descendant,
|
|
228
290
|
],
|
|
229
291
|
textBlockName,
|
|
@@ -267,7 +329,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
267
329
|
const spanToRemove = block.children[operation.path[1]]
|
|
268
330
|
|
|
269
331
|
if (spanToRemove) {
|
|
270
|
-
const spansMatchingKey = block.children.filter(
|
|
332
|
+
const spansMatchingKey = block.children.filter(
|
|
333
|
+
(span) => span._key === operation.node._key,
|
|
334
|
+
)
|
|
271
335
|
|
|
272
336
|
if (spansMatchingKey.length > 1) {
|
|
273
337
|
console.warn(
|
|
@@ -277,7 +341,9 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
277
341
|
return []
|
|
278
342
|
}
|
|
279
343
|
|
|
280
|
-
return [
|
|
344
|
+
return [
|
|
345
|
+
unset([{_key: block._key}, 'children', {_key: spanToRemove._key}]),
|
|
346
|
+
]
|
|
281
347
|
}
|
|
282
348
|
debug('Span not found in editor trying to remove node')
|
|
283
349
|
return []
|
|
@@ -299,7 +365,10 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
299
365
|
|
|
300
366
|
if (operation.path.length === 1) {
|
|
301
367
|
if (block?._key) {
|
|
302
|
-
const newBlock = fromSlateValue(
|
|
368
|
+
const newBlock = fromSlateValue(
|
|
369
|
+
[editor.children[operation.path[0] - 1]],
|
|
370
|
+
textBlockName,
|
|
371
|
+
)[0]
|
|
303
372
|
patches.push(set(newBlock, [{_key: newBlock._key}]))
|
|
304
373
|
patches.push(unset([{_key: block._key}]))
|
|
305
374
|
} else {
|
|
@@ -316,12 +385,15 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
316
385
|
? updatedBlock.children[operation.path[1] - 1]
|
|
317
386
|
: undefined
|
|
318
387
|
const removedSpan =
|
|
319
|
-
block.children[operation.path[1]] &&
|
|
388
|
+
block.children[operation.path[1]] &&
|
|
389
|
+
editor.isTextSpan(block.children[operation.path[1]])
|
|
320
390
|
? block.children[operation.path[1]]
|
|
321
391
|
: undefined
|
|
322
392
|
|
|
323
393
|
if (updatedSpan) {
|
|
324
|
-
const spansMatchingKey = block.children.filter(
|
|
394
|
+
const spansMatchingKey = block.children.filter(
|
|
395
|
+
(span) => span._key === updatedSpan._key,
|
|
396
|
+
)
|
|
325
397
|
|
|
326
398
|
if (spansMatchingKey.length === 1) {
|
|
327
399
|
patches.push(
|
|
@@ -341,10 +413,14 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
341
413
|
}
|
|
342
414
|
|
|
343
415
|
if (removedSpan) {
|
|
344
|
-
const spansMatchingKey = block.children.filter(
|
|
416
|
+
const spansMatchingKey = block.children.filter(
|
|
417
|
+
(span) => span._key === removedSpan._key,
|
|
418
|
+
)
|
|
345
419
|
|
|
346
420
|
if (spansMatchingKey.length === 1) {
|
|
347
|
-
patches.push(
|
|
421
|
+
patches.push(
|
|
422
|
+
unset([{_key: block._key}, 'children', {_key: removedSpan._key}]),
|
|
423
|
+
)
|
|
348
424
|
} else {
|
|
349
425
|
console.warn(
|
|
350
426
|
`Multiple spans have \`_key\` ${removedSpan._key}. It's ambiguous which one to remove.`,
|
|
@@ -367,10 +443,13 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
367
443
|
const block = beforeValue[operation.path[0]]
|
|
368
444
|
const targetBlock = beforeValue[operation.newPath[0]]
|
|
369
445
|
if (operation.path.length === 1) {
|
|
370
|
-
const position: InsertPosition =
|
|
446
|
+
const position: InsertPosition =
|
|
447
|
+
operation.path[0] > operation.newPath[0] ? 'before' : 'after'
|
|
371
448
|
patches.push(unset([{_key: block._key}]))
|
|
372
449
|
patches.push(
|
|
373
|
-
insert([fromSlateValue([block], textBlockName)[0]], position, [
|
|
450
|
+
insert([fromSlateValue([block], textBlockName)[0]], position, [
|
|
451
|
+
{_key: targetBlock._key},
|
|
452
|
+
]),
|
|
374
453
|
)
|
|
375
454
|
} else if (
|
|
376
455
|
operation.path.length === 2 &&
|
|
@@ -379,9 +458,13 @@ export function createOperationToPatches(types: PortableTextMemberSchemaTypes):
|
|
|
379
458
|
) {
|
|
380
459
|
const child = block.children[operation.path[1]]
|
|
381
460
|
const targetChild = targetBlock.children[operation.newPath[1]]
|
|
382
|
-
const position =
|
|
383
|
-
|
|
384
|
-
|
|
461
|
+
const position =
|
|
462
|
+
operation.newPath[1] === targetBlock.children.length
|
|
463
|
+
? 'after'
|
|
464
|
+
: 'before'
|
|
465
|
+
const childToInsert = (
|
|
466
|
+
fromSlateValue([block], textBlockName)[0] as PortableTextTextBlock
|
|
467
|
+
).children[operation.path[1]]
|
|
385
468
|
patches.push(unset([{_key: block._key}, 'children', {_key: child._key}]))
|
|
386
469
|
patches.push(
|
|
387
470
|
insert([childToInsert], position, [
|
package/src/utils/paths.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import {isKeySegment, type Path} from '@sanity/types'
|
|
2
2
|
import {isEqual} from 'lodash'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
Editor,
|
|
5
|
+
Element,
|
|
6
|
+
type Descendant,
|
|
7
|
+
type Point,
|
|
8
|
+
type Path as SlatePath,
|
|
9
|
+
} from 'slate'
|
|
10
|
+
import {
|
|
11
|
+
type EditorSelectionPoint,
|
|
12
|
+
type PortableTextMemberSchemaTypes,
|
|
13
|
+
} from '../types/editor'
|
|
6
14
|
import {type ObjectWithKeyAndType} from './ranges'
|
|
7
15
|
|
|
8
16
|
export function createKeyedPath(
|
|
@@ -28,17 +36,24 @@ export function createKeyedPath(
|
|
|
28
36
|
if (child) {
|
|
29
37
|
keyedChildPath = ['children', {_key: child._key}]
|
|
30
38
|
}
|
|
31
|
-
return (
|
|
39
|
+
return (
|
|
40
|
+
keyedChildPath ? [...keyedBlockPath, ...keyedChildPath] : keyedBlockPath
|
|
41
|
+
) as Path
|
|
32
42
|
}
|
|
33
43
|
|
|
34
|
-
export function createArrayedPath(
|
|
44
|
+
export function createArrayedPath(
|
|
45
|
+
point: EditorSelectionPoint,
|
|
46
|
+
editor: Editor,
|
|
47
|
+
): SlatePath {
|
|
35
48
|
if (!editor) {
|
|
36
49
|
return []
|
|
37
50
|
}
|
|
38
51
|
const [block, blockPath] = Array.from(
|
|
39
52
|
Editor.nodes(editor, {
|
|
40
53
|
at: [],
|
|
41
|
-
match: (n) =>
|
|
54
|
+
match: (n) =>
|
|
55
|
+
isKeySegment(point.path[0]) &&
|
|
56
|
+
(n as Descendant)._key === point.path[0]._key,
|
|
42
57
|
}),
|
|
43
58
|
)[0] || [undefined, undefined]
|
|
44
59
|
if (!block || !Element.isElement(block)) {
|
|
@@ -48,7 +63,9 @@ export function createArrayedPath(point: EditorSelectionPoint, editor: Editor):
|
|
|
48
63
|
return [blockPath[0], 0]
|
|
49
64
|
}
|
|
50
65
|
const childPath = [point.path[2]]
|
|
51
|
-
const childIndex = block.children.findIndex((child) =>
|
|
66
|
+
const childIndex = block.children.findIndex((child) =>
|
|
67
|
+
isEqual([{_key: child._key}], childPath),
|
|
68
|
+
)
|
|
52
69
|
if (childIndex >= 0 && block.children[childIndex]) {
|
|
53
70
|
const child = block.children[childIndex]
|
|
54
71
|
if (Element.isElement(child) && editor.isVoid(child)) {
|
package/src/utils/ranges.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* eslint-disable complexity */
|
|
2
|
-
import {type BaseRange, type Editor, type Operation
|
|
3
|
-
|
|
2
|
+
import {Point, Range, type BaseRange, type Editor, type Operation} from 'slate'
|
|
4
3
|
import {
|
|
5
4
|
type EditorSelection,
|
|
6
5
|
type EditorSelectionPoint,
|
|
@@ -38,11 +37,16 @@ export function toPortableTextRange(
|
|
|
38
37
|
offset: range.focus.offset,
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
|
-
const backward = Boolean(
|
|
40
|
+
const backward = Boolean(
|
|
41
|
+
Range.isRange(range) ? Range.isBackward(range) : undefined,
|
|
42
|
+
)
|
|
42
43
|
return anchor && focus ? {anchor, focus, backward} : null
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
export function toSlateRange(
|
|
46
|
+
export function toSlateRange(
|
|
47
|
+
selection: EditorSelection,
|
|
48
|
+
editor: Editor,
|
|
49
|
+
): Range | null {
|
|
46
50
|
if (!selection || !editor) {
|
|
47
51
|
return null
|
|
48
52
|
}
|
|
@@ -61,7 +65,10 @@ export function toSlateRange(selection: EditorSelection, editor: Editor): Range
|
|
|
61
65
|
return range
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
export function moveRangeByOperation(
|
|
68
|
+
export function moveRangeByOperation(
|
|
69
|
+
range: Range,
|
|
70
|
+
operation: Operation,
|
|
71
|
+
): Range | null {
|
|
65
72
|
const anchor = Point.transform(range.anchor, operation)
|
|
66
73
|
const focus = Point.transform(range.focus, operation)
|
|
67
74
|
|
package/src/utils/selection.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {type Path, type PortableTextBlock} from '@sanity/types'
|
|
2
2
|
import {isEqual} from 'lodash'
|
|
3
|
-
|
|
4
3
|
import {type EditorSelection, type EditorSelectionPoint} from '../types/editor'
|
|
5
4
|
|
|
6
5
|
export function normalizePoint(
|
|
@@ -13,21 +12,31 @@ export function normalizePoint(
|
|
|
13
12
|
const newPath: Path = []
|
|
14
13
|
let newOffset: number = point.offset || 0
|
|
15
14
|
const blockKey =
|
|
16
|
-
typeof point.path[0] === 'object' &&
|
|
15
|
+
typeof point.path[0] === 'object' &&
|
|
16
|
+
'_key' in point.path[0] &&
|
|
17
|
+
point.path[0]._key
|
|
17
18
|
const childKey =
|
|
18
|
-
typeof point.path[2] === 'object' &&
|
|
19
|
-
|
|
19
|
+
typeof point.path[2] === 'object' &&
|
|
20
|
+
'_key' in point.path[2] &&
|
|
21
|
+
point.path[2]._key
|
|
22
|
+
const block: PortableTextBlock | undefined = value.find(
|
|
23
|
+
(blk) => blk._key === blockKey,
|
|
24
|
+
)
|
|
20
25
|
if (block) {
|
|
21
26
|
newPath.push({_key: block._key})
|
|
22
27
|
} else {
|
|
23
28
|
return null
|
|
24
29
|
}
|
|
25
30
|
if (block && point.path[1] === 'children') {
|
|
26
|
-
if (
|
|
31
|
+
if (
|
|
32
|
+
!block.children ||
|
|
33
|
+
(Array.isArray(block.children) && block.children.length === 0)
|
|
34
|
+
) {
|
|
27
35
|
return null
|
|
28
36
|
}
|
|
29
37
|
const child =
|
|
30
|
-
Array.isArray(block.children) &&
|
|
38
|
+
Array.isArray(block.children) &&
|
|
39
|
+
block.children.find((cld) => cld._key === childKey)
|
|
31
40
|
if (child) {
|
|
32
41
|
newPath.push('children')
|
|
33
42
|
newPath.push({_key: child._key})
|
|
@@ -52,7 +61,10 @@ export function normalizeSelection(
|
|
|
52
61
|
let newAnchor: EditorSelectionPoint | null = null
|
|
53
62
|
let newFocus: EditorSelectionPoint | null = null
|
|
54
63
|
const {anchor, focus} = selection
|
|
55
|
-
if (
|
|
64
|
+
if (
|
|
65
|
+
anchor &&
|
|
66
|
+
value.find((blk) => isEqual({_key: blk._key}, anchor.path[0]))
|
|
67
|
+
) {
|
|
56
68
|
newAnchor = normalizePoint(anchor, value)
|
|
57
69
|
}
|
|
58
70
|
if (focus && value.find((blk) => isEqual({_key: blk._key}, focus.path[0]))) {
|