@portabletext/editor 1.15.2 → 1.16.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/_chunks-cjs/behavior.core.cjs +30 -28
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +14 -14
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/{selectors.cjs → selector.is-selection-collapsed.cjs} +8 -8
- package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +1 -0
- package/lib/_chunks-es/behavior.core.js +12 -10
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/selector.get-text-before.js +14 -14
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
- package/lib/_chunks-es/{selectors.js → selector.is-selection-collapsed.js} +8 -8
- package/lib/_chunks-es/selector.is-selection-collapsed.js.map +1 -0
- package/lib/behaviors/index.cjs +35 -35
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +40 -45
- package/lib/behaviors/index.d.ts +40 -45
- package/lib/behaviors/index.js +20 -20
- package/lib/behaviors/index.js.map +1 -1
- package/lib/index.cjs +868 -542
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +3791 -4503
- package/lib/index.d.ts +3791 -4503
- package/lib/index.js +865 -541
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +166 -16
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +62 -17
- package/lib/selectors/index.d.ts +62 -17
- package/lib/selectors/index.js +154 -3
- package/lib/selectors/index.js.map +1 -1
- package/package.json +11 -11
- package/src/behavior-actions/behavior.action-utils.insert-block.ts +3 -5
- package/src/behavior-actions/behavior.actions.ts +6 -6
- package/src/behavior-actions/behavior.guards.ts +2 -6
- package/src/behaviors/behavior.code-editor.ts +5 -9
- package/src/behaviors/behavior.core.block-objects.ts +14 -20
- package/src/behaviors/behavior.core.lists.ts +13 -19
- package/src/behaviors/behavior.links.ts +6 -6
- package/src/behaviors/behavior.markdown.ts +27 -40
- package/src/behaviors/behavior.types.ts +7 -7
- package/src/behaviors/index.ts +1 -0
- package/src/editor/Editable.tsx +11 -4
- package/src/editor/PortableTextEditor.tsx +4 -5
- package/src/editor/{hooks/useSyncValue.test.tsx → __tests__/sync-value.test.tsx} +42 -23
- package/src/editor/components/Synchronizer.tsx +53 -80
- package/src/{utils/getPortableTextMemberSchemaTypes.ts → editor/create-editor-schema.ts} +3 -3
- package/src/editor/create-editor.ts +2 -2
- package/src/editor/define-schema.ts +8 -3
- package/src/editor/editor-machine.ts +136 -104
- package/src/editor/editor-provider.tsx +0 -3
- package/src/editor/editor-selector.ts +6 -13
- package/src/editor/editor-snapshot.ts +5 -6
- package/src/editor/get-active-decorators.ts +20 -0
- package/src/editor/mutation-machine.ts +100 -0
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +21 -15
- package/src/editor/plugins/createWithMaxBlocks.ts +1 -1
- package/src/editor/plugins/createWithPatches.ts +0 -4
- package/src/editor/plugins/createWithPlaceholderBlock.ts +1 -1
- package/src/editor/plugins/createWithPortableTextSelections.ts +4 -1
- package/src/editor/plugins/createWithUndoRedo.ts +3 -3
- package/src/editor/sync-machine.ts +657 -0
- package/src/editor/withSyncRangeDecorations.ts +17 -5
- package/src/index.ts +3 -5
- package/src/selectors/_exports/index.ts +1 -0
- package/src/selectors/index.ts +10 -4
- package/src/selectors/selector.get-active-style.ts +37 -0
- package/src/selectors/selector.get-selected-spans.ts +136 -0
- package/src/selectors/selector.is-active-annotation.ts +49 -0
- package/src/selectors/selector.is-active-decorator.ts +21 -0
- package/src/selectors/selector.is-active-list-item.ts +13 -0
- package/src/selectors/selector.is-active-style.ts +13 -0
- package/src/selectors/selector.is-selection-collapsed.ts +12 -0
- package/src/selectors/selector.is-selection-expanded.ts +9 -0
- package/src/selectors/selectors.ts +0 -11
- package/src/utils/__tests__/operationToPatches.test.ts +2 -2
- package/src/utils/__tests__/patchToOperations.test.ts +2 -2
- package/src/utils/__tests__/values.test.ts +2 -2
- package/src/utils/weakMaps.ts +0 -3
- package/src/utils/withChanges.ts +1 -8
- package/lib/_chunks-cjs/selectors.cjs.map +0 -1
- package/lib/_chunks-es/selectors.js.map +0 -1
- package/src/editor/hooks/useSyncValue.ts +0 -426
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
import type {PortableTextBlock} from '@sanity/types'
|
|
2
|
-
import {debounce, isEqual} from 'lodash'
|
|
3
|
-
import {useCallback, useMemo, useRef} from 'react'
|
|
4
|
-
import {Editor, Text, Transforms, type Descendant, type Node} from 'slate'
|
|
5
|
-
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
6
|
-
import {debugWithName} from '../../utils/debug'
|
|
7
|
-
import {validateValue} from '../../utils/validateValue'
|
|
8
|
-
import {toSlateValue, VOID_CHILD_KEY} from '../../utils/values'
|
|
9
|
-
import {
|
|
10
|
-
isChangingLocally,
|
|
11
|
-
isChangingRemotely,
|
|
12
|
-
withRemoteChanges,
|
|
13
|
-
} from '../../utils/withChanges'
|
|
14
|
-
import {withoutPatching} from '../../utils/withoutPatching'
|
|
15
|
-
import type {EditorActor} from '../editor-machine'
|
|
16
|
-
import {withoutSaving} from '../plugins/createWithUndoRedo'
|
|
17
|
-
import type {PortableTextEditor} from '../PortableTextEditor'
|
|
18
|
-
|
|
19
|
-
const debug = debugWithName('hook:useSyncValue')
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @internal
|
|
23
|
-
*/
|
|
24
|
-
export interface UseSyncValueProps {
|
|
25
|
-
editorActor: EditorActor
|
|
26
|
-
portableTextEditor: PortableTextEditor
|
|
27
|
-
readOnly: boolean
|
|
28
|
-
slateEditor: PortableTextSlateEditor
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const CURRENT_VALUE = new WeakMap<
|
|
32
|
-
PortableTextEditor,
|
|
33
|
-
PortableTextBlock[] | undefined
|
|
34
|
-
>()
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Sync value with the editor state
|
|
38
|
-
*
|
|
39
|
-
* Normally nothing here should apply, and the editor and the real world are perfectly aligned.
|
|
40
|
-
*
|
|
41
|
-
* Inconsistencies could happen though, so we need to check the editor state when the value changes.
|
|
42
|
-
*
|
|
43
|
-
* For performance reasons, it makes sense to also do the content validation here, as we already
|
|
44
|
-
* iterate over the value and can validate only the new content that is actually changed.
|
|
45
|
-
*
|
|
46
|
-
* @internal
|
|
47
|
-
*/
|
|
48
|
-
export function useSyncValue(
|
|
49
|
-
props: UseSyncValueProps,
|
|
50
|
-
): (
|
|
51
|
-
value: PortableTextBlock[] | undefined,
|
|
52
|
-
userCallbackFn?: () => void,
|
|
53
|
-
) => void {
|
|
54
|
-
const {editorActor, portableTextEditor, readOnly, slateEditor} = props
|
|
55
|
-
const schemaTypes = editorActor.getSnapshot().context.schema
|
|
56
|
-
const previousValue = useRef<PortableTextBlock[]>(undefined)
|
|
57
|
-
const updateValueFunctionRef =
|
|
58
|
-
useRef<(value: PortableTextBlock[] | undefined) => void>(undefined)
|
|
59
|
-
|
|
60
|
-
const updateFromCurrentValue = useCallback(() => {
|
|
61
|
-
const currentValue = CURRENT_VALUE.get(portableTextEditor)
|
|
62
|
-
if (previousValue.current === currentValue) {
|
|
63
|
-
debug('Value is the same object as previous, not need to sync')
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
if (updateValueFunctionRef.current && currentValue) {
|
|
67
|
-
debug('Updating the value debounced')
|
|
68
|
-
updateValueFunctionRef.current(currentValue)
|
|
69
|
-
}
|
|
70
|
-
}, [portableTextEditor])
|
|
71
|
-
const updateValueDebounced = useMemo(
|
|
72
|
-
() =>
|
|
73
|
-
debounce(updateFromCurrentValue, 1000, {trailing: true, leading: false}),
|
|
74
|
-
[updateFromCurrentValue],
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
return useMemo(() => {
|
|
78
|
-
const updateFunction = (value: PortableTextBlock[] | undefined) => {
|
|
79
|
-
CURRENT_VALUE.set(portableTextEditor, value)
|
|
80
|
-
const isProcessingLocalChanges = isChangingLocally(slateEditor)
|
|
81
|
-
const isProcessingRemoteChanges = isChangingRemotely(slateEditor)
|
|
82
|
-
if (!readOnly) {
|
|
83
|
-
if (isProcessingLocalChanges) {
|
|
84
|
-
debug('Has local changes, not syncing value right now')
|
|
85
|
-
updateValueDebounced()
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
if (isProcessingRemoteChanges) {
|
|
89
|
-
debug('Has remote changes, not syncing value right now')
|
|
90
|
-
updateValueDebounced()
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
let isChanged = false
|
|
96
|
-
let isValid = true
|
|
97
|
-
|
|
98
|
-
const hadSelection = !!slateEditor.selection
|
|
99
|
-
|
|
100
|
-
// If empty value, remove everything in the editor and insert a placeholder block
|
|
101
|
-
if (!value || value.length === 0) {
|
|
102
|
-
debug('Value is empty')
|
|
103
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
104
|
-
withoutSaving(slateEditor, () => {
|
|
105
|
-
withoutPatching(slateEditor, () => {
|
|
106
|
-
if (hadSelection) {
|
|
107
|
-
Transforms.deselect(slateEditor)
|
|
108
|
-
}
|
|
109
|
-
const childrenLength = slateEditor.children.length
|
|
110
|
-
slateEditor.children.forEach((_, index) => {
|
|
111
|
-
Transforms.removeNodes(slateEditor, {
|
|
112
|
-
at: [childrenLength - 1 - index],
|
|
113
|
-
})
|
|
114
|
-
})
|
|
115
|
-
Transforms.insertNodes(
|
|
116
|
-
slateEditor,
|
|
117
|
-
slateEditor.pteCreateTextBlock({decorators: []}),
|
|
118
|
-
{at: [0]},
|
|
119
|
-
)
|
|
120
|
-
// Add a new selection in the top of the document
|
|
121
|
-
if (hadSelection) {
|
|
122
|
-
Transforms.select(slateEditor, [0, 0])
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
isChanged = true
|
|
128
|
-
}
|
|
129
|
-
// Remove, replace or add nodes according to what is changed.
|
|
130
|
-
if (value && value.length > 0) {
|
|
131
|
-
const slateValueFromProps = toSlateValue(value, {
|
|
132
|
-
schemaTypes,
|
|
133
|
-
})
|
|
134
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
135
|
-
withRemoteChanges(slateEditor, () => {
|
|
136
|
-
withoutSaving(slateEditor, () => {
|
|
137
|
-
withoutPatching(slateEditor, () => {
|
|
138
|
-
const childrenLength = slateEditor.children.length
|
|
139
|
-
// Remove blocks that have become superfluous
|
|
140
|
-
if (slateValueFromProps.length < childrenLength) {
|
|
141
|
-
for (
|
|
142
|
-
let i = childrenLength - 1;
|
|
143
|
-
i > slateValueFromProps.length - 1;
|
|
144
|
-
i--
|
|
145
|
-
) {
|
|
146
|
-
Transforms.removeNodes(slateEditor, {
|
|
147
|
-
at: [i],
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
isChanged = true
|
|
151
|
-
}
|
|
152
|
-
// Go through all of the blocks and see if they need to be updated
|
|
153
|
-
slateValueFromProps.forEach(
|
|
154
|
-
(currentBlock, currentBlockIndex) => {
|
|
155
|
-
const oldBlock = slateEditor.children[currentBlockIndex]
|
|
156
|
-
const hasChanges =
|
|
157
|
-
oldBlock && !isEqual(currentBlock, oldBlock)
|
|
158
|
-
if (hasChanges && isValid) {
|
|
159
|
-
const validationValue = [value[currentBlockIndex]]
|
|
160
|
-
const validation = validateValue(
|
|
161
|
-
validationValue,
|
|
162
|
-
schemaTypes,
|
|
163
|
-
editorActor.getSnapshot().context.keyGenerator,
|
|
164
|
-
)
|
|
165
|
-
// Resolve validations that can be resolved automatically, without involving the user (but only if the value was changed)
|
|
166
|
-
if (
|
|
167
|
-
!validation.valid &&
|
|
168
|
-
validation.resolution?.autoResolve &&
|
|
169
|
-
validation.resolution?.patches.length > 0
|
|
170
|
-
) {
|
|
171
|
-
// Only apply auto resolution if the value has been populated before and is different from the last one.
|
|
172
|
-
if (
|
|
173
|
-
!readOnly &&
|
|
174
|
-
previousValue.current &&
|
|
175
|
-
previousValue.current !== value
|
|
176
|
-
) {
|
|
177
|
-
// Give a console warning about the fact that it did an auto resolution
|
|
178
|
-
console.warn(
|
|
179
|
-
`${validation.resolution.action} for block with _key '${validationValue[0]._key}'. ${validation.resolution?.description}`,
|
|
180
|
-
)
|
|
181
|
-
validation.resolution.patches.forEach((patch) => {
|
|
182
|
-
editorActor.send({type: 'patch', patch})
|
|
183
|
-
})
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (
|
|
187
|
-
validation.valid ||
|
|
188
|
-
validation.resolution?.autoResolve
|
|
189
|
-
) {
|
|
190
|
-
if (oldBlock._key === currentBlock._key) {
|
|
191
|
-
if (debug.enabled)
|
|
192
|
-
debug('Updating block', oldBlock, currentBlock)
|
|
193
|
-
_updateBlock(
|
|
194
|
-
slateEditor,
|
|
195
|
-
currentBlock,
|
|
196
|
-
oldBlock,
|
|
197
|
-
currentBlockIndex,
|
|
198
|
-
)
|
|
199
|
-
} else {
|
|
200
|
-
if (debug.enabled)
|
|
201
|
-
debug('Replacing block', oldBlock, currentBlock)
|
|
202
|
-
_replaceBlock(
|
|
203
|
-
slateEditor,
|
|
204
|
-
currentBlock,
|
|
205
|
-
currentBlockIndex,
|
|
206
|
-
)
|
|
207
|
-
}
|
|
208
|
-
isChanged = true
|
|
209
|
-
} else {
|
|
210
|
-
editorActor.send({
|
|
211
|
-
type: 'invalid value',
|
|
212
|
-
resolution: validation.resolution,
|
|
213
|
-
value,
|
|
214
|
-
})
|
|
215
|
-
isValid = false
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
if (!oldBlock && isValid) {
|
|
219
|
-
const validationValue = [value[currentBlockIndex]]
|
|
220
|
-
const validation = validateValue(
|
|
221
|
-
validationValue,
|
|
222
|
-
schemaTypes,
|
|
223
|
-
editorActor.getSnapshot().context.keyGenerator,
|
|
224
|
-
)
|
|
225
|
-
if (debug.enabled)
|
|
226
|
-
debug(
|
|
227
|
-
'Validating and inserting new block in the end of the value',
|
|
228
|
-
currentBlock,
|
|
229
|
-
)
|
|
230
|
-
if (
|
|
231
|
-
validation.valid ||
|
|
232
|
-
validation.resolution?.autoResolve
|
|
233
|
-
) {
|
|
234
|
-
Transforms.insertNodes(slateEditor, currentBlock, {
|
|
235
|
-
at: [currentBlockIndex],
|
|
236
|
-
})
|
|
237
|
-
} else {
|
|
238
|
-
debug('Invalid', validation)
|
|
239
|
-
editorActor.send({
|
|
240
|
-
type: 'invalid value',
|
|
241
|
-
resolution: validation.resolution,
|
|
242
|
-
value,
|
|
243
|
-
})
|
|
244
|
-
isValid = false
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
)
|
|
249
|
-
})
|
|
250
|
-
})
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (!isValid) {
|
|
256
|
-
debug('Invalid value, returning')
|
|
257
|
-
return
|
|
258
|
-
}
|
|
259
|
-
if (isChanged) {
|
|
260
|
-
debug('Server value changed, syncing editor')
|
|
261
|
-
try {
|
|
262
|
-
slateEditor.onChange()
|
|
263
|
-
} catch (err) {
|
|
264
|
-
console.error(err)
|
|
265
|
-
editorActor.send({
|
|
266
|
-
type: 'invalid value',
|
|
267
|
-
resolution: null,
|
|
268
|
-
value,
|
|
269
|
-
})
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
if (hadSelection && !slateEditor.selection) {
|
|
273
|
-
Transforms.select(slateEditor, {
|
|
274
|
-
anchor: {path: [0, 0], offset: 0},
|
|
275
|
-
focus: {path: [0, 0], offset: 0},
|
|
276
|
-
})
|
|
277
|
-
slateEditor.onChange()
|
|
278
|
-
}
|
|
279
|
-
editorActor.send({type: 'value changed', value})
|
|
280
|
-
} else {
|
|
281
|
-
debug('Server value and editor value is equal, no need to sync.')
|
|
282
|
-
}
|
|
283
|
-
previousValue.current = value
|
|
284
|
-
}
|
|
285
|
-
updateValueFunctionRef.current = updateFunction
|
|
286
|
-
return updateFunction
|
|
287
|
-
}, [
|
|
288
|
-
editorActor,
|
|
289
|
-
portableTextEditor,
|
|
290
|
-
readOnly,
|
|
291
|
-
schemaTypes,
|
|
292
|
-
slateEditor,
|
|
293
|
-
updateValueDebounced,
|
|
294
|
-
])
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* This code is moved out of the above algorithm to keep complexity down.
|
|
299
|
-
* @internal
|
|
300
|
-
*/
|
|
301
|
-
function _replaceBlock(
|
|
302
|
-
slateEditor: PortableTextSlateEditor,
|
|
303
|
-
currentBlock: Descendant,
|
|
304
|
-
currentBlockIndex: number,
|
|
305
|
-
) {
|
|
306
|
-
// While replacing the block and the current selection focus is on the replaced block,
|
|
307
|
-
// temporarily deselect the editor then optimistically try to restore the selection afterwards.
|
|
308
|
-
const currentSelection = slateEditor.selection
|
|
309
|
-
const selectionFocusOnBlock =
|
|
310
|
-
currentSelection && currentSelection.focus.path[0] === currentBlockIndex
|
|
311
|
-
if (selectionFocusOnBlock) {
|
|
312
|
-
Transforms.deselect(slateEditor)
|
|
313
|
-
}
|
|
314
|
-
Transforms.removeNodes(slateEditor, {at: [currentBlockIndex]})
|
|
315
|
-
Transforms.insertNodes(slateEditor, currentBlock, {at: [currentBlockIndex]})
|
|
316
|
-
slateEditor.onChange()
|
|
317
|
-
if (selectionFocusOnBlock) {
|
|
318
|
-
Transforms.select(slateEditor, currentSelection)
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* This code is moved out of the above algorithm to keep complexity down.
|
|
324
|
-
* @internal
|
|
325
|
-
*/
|
|
326
|
-
function _updateBlock(
|
|
327
|
-
slateEditor: PortableTextSlateEditor,
|
|
328
|
-
currentBlock: Descendant,
|
|
329
|
-
oldBlock: Descendant,
|
|
330
|
-
currentBlockIndex: number,
|
|
331
|
-
) {
|
|
332
|
-
// Update the root props on the block
|
|
333
|
-
Transforms.setNodes(slateEditor, currentBlock as Partial<Node>, {
|
|
334
|
-
at: [currentBlockIndex],
|
|
335
|
-
})
|
|
336
|
-
// Text block's need to have their children updated as well (setNode does not target a node's children)
|
|
337
|
-
if (
|
|
338
|
-
slateEditor.isTextBlock(currentBlock) &&
|
|
339
|
-
slateEditor.isTextBlock(oldBlock)
|
|
340
|
-
) {
|
|
341
|
-
const oldBlockChildrenLength = oldBlock.children.length
|
|
342
|
-
if (currentBlock.children.length < oldBlockChildrenLength) {
|
|
343
|
-
// Remove any children that have become superfluous
|
|
344
|
-
Array.from(
|
|
345
|
-
Array(oldBlockChildrenLength - currentBlock.children.length),
|
|
346
|
-
).forEach((_, index) => {
|
|
347
|
-
const childIndex = oldBlockChildrenLength - 1 - index
|
|
348
|
-
if (childIndex > 0) {
|
|
349
|
-
debug('Removing child')
|
|
350
|
-
Transforms.removeNodes(slateEditor, {
|
|
351
|
-
at: [currentBlockIndex, childIndex],
|
|
352
|
-
})
|
|
353
|
-
}
|
|
354
|
-
})
|
|
355
|
-
}
|
|
356
|
-
currentBlock.children.forEach(
|
|
357
|
-
(currentBlockChild, currentBlockChildIndex) => {
|
|
358
|
-
const oldBlockChild = oldBlock.children[currentBlockChildIndex]
|
|
359
|
-
const isChildChanged = !isEqual(currentBlockChild, oldBlockChild)
|
|
360
|
-
const isTextChanged = !isEqual(
|
|
361
|
-
currentBlockChild.text,
|
|
362
|
-
oldBlockChild?.text,
|
|
363
|
-
)
|
|
364
|
-
const path = [currentBlockIndex, currentBlockChildIndex]
|
|
365
|
-
if (isChildChanged) {
|
|
366
|
-
// Update if this is the same child
|
|
367
|
-
if (currentBlockChild._key === oldBlockChild?._key) {
|
|
368
|
-
debug('Updating changed child', currentBlockChild, oldBlockChild)
|
|
369
|
-
Transforms.setNodes(
|
|
370
|
-
slateEditor,
|
|
371
|
-
currentBlockChild as Partial<Node>,
|
|
372
|
-
{
|
|
373
|
-
at: path,
|
|
374
|
-
},
|
|
375
|
-
)
|
|
376
|
-
const isSpanNode =
|
|
377
|
-
Text.isText(currentBlockChild) &&
|
|
378
|
-
currentBlockChild._type === 'span' &&
|
|
379
|
-
Text.isText(oldBlockChild) &&
|
|
380
|
-
oldBlockChild._type === 'span'
|
|
381
|
-
if (isSpanNode && isTextChanged) {
|
|
382
|
-
Transforms.delete(slateEditor, {
|
|
383
|
-
at: {
|
|
384
|
-
focus: {path, offset: 0},
|
|
385
|
-
anchor: {path, offset: oldBlockChild.text.length},
|
|
386
|
-
},
|
|
387
|
-
})
|
|
388
|
-
Transforms.insertText(slateEditor, currentBlockChild.text, {
|
|
389
|
-
at: path,
|
|
390
|
-
})
|
|
391
|
-
slateEditor.onChange()
|
|
392
|
-
} else if (!isSpanNode) {
|
|
393
|
-
// If it's a inline block, also update the void text node key
|
|
394
|
-
debug('Updating changed inline object child', currentBlockChild)
|
|
395
|
-
Transforms.setNodes(
|
|
396
|
-
slateEditor,
|
|
397
|
-
{_key: VOID_CHILD_KEY},
|
|
398
|
-
{
|
|
399
|
-
at: [...path, 0],
|
|
400
|
-
voids: true,
|
|
401
|
-
},
|
|
402
|
-
)
|
|
403
|
-
}
|
|
404
|
-
// Replace the child if _key's are different
|
|
405
|
-
} else if (oldBlockChild) {
|
|
406
|
-
debug('Replacing child', currentBlockChild)
|
|
407
|
-
Transforms.removeNodes(slateEditor, {
|
|
408
|
-
at: [currentBlockIndex, currentBlockChildIndex],
|
|
409
|
-
})
|
|
410
|
-
Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
|
|
411
|
-
at: [currentBlockIndex, currentBlockChildIndex],
|
|
412
|
-
})
|
|
413
|
-
slateEditor.onChange()
|
|
414
|
-
// Insert it if it didn't exist before
|
|
415
|
-
} else if (!oldBlockChild) {
|
|
416
|
-
debug('Inserting new child', currentBlockChild)
|
|
417
|
-
Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
|
|
418
|
-
at: [currentBlockIndex, currentBlockChildIndex],
|
|
419
|
-
})
|
|
420
|
-
slateEditor.onChange()
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
},
|
|
424
|
-
)
|
|
425
|
-
}
|
|
426
|
-
}
|