@portabletext/editor 3.3.2 → 3.3.4
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 +7 -1
- package/package.json +16 -19
- package/src/behaviors/_exports/index.ts +0 -1
- package/src/behaviors/behavior.abstract.annotation.ts +0 -77
- package/src/behaviors/behavior.abstract.decorator.ts +0 -39
- package/src/behaviors/behavior.abstract.delete.ts +0 -273
- package/src/behaviors/behavior.abstract.deserialize.ts +0 -232
- package/src/behaviors/behavior.abstract.insert.ts +0 -525
- package/src/behaviors/behavior.abstract.keyboard.ts +0 -189
- package/src/behaviors/behavior.abstract.list-item.ts +0 -70
- package/src/behaviors/behavior.abstract.move.ts +0 -79
- package/src/behaviors/behavior.abstract.select.ts +0 -118
- package/src/behaviors/behavior.abstract.serialize.ts +0 -96
- package/src/behaviors/behavior.abstract.split.ts +0 -170
- package/src/behaviors/behavior.abstract.style.ts +0 -55
- package/src/behaviors/behavior.abstract.ts +0 -139
- package/src/behaviors/behavior.config.ts +0 -7
- package/src/behaviors/behavior.core.annotations.ts +0 -62
- package/src/behaviors/behavior.core.block-element.ts +0 -116
- package/src/behaviors/behavior.core.block-objects.ts +0 -285
- package/src/behaviors/behavior.core.decorators.ts +0 -44
- package/src/behaviors/behavior.core.dnd.ts +0 -356
- package/src/behaviors/behavior.core.insert-break.ts +0 -266
- package/src/behaviors/behavior.core.insert.ts +0 -52
- package/src/behaviors/behavior.core.lists.ts +0 -691
- package/src/behaviors/behavior.core.ts +0 -44
- package/src/behaviors/behavior.perform-event.ts +0 -354
- package/src/behaviors/behavior.types.action.ts +0 -102
- package/src/behaviors/behavior.types.behavior.ts +0 -83
- package/src/behaviors/behavior.types.event.ts +0 -667
- package/src/behaviors/behavior.types.guard.ts +0 -11
- package/src/behaviors/index.ts +0 -17
- package/src/converters/converter.json.ts +0 -53
- package/src/converters/converter.portable-text.deserialize.test.ts +0 -680
- package/src/converters/converter.portable-text.ts +0 -75
- package/src/converters/converter.text-html.deserialize.test.ts +0 -406
- package/src/converters/converter.text-html.serialize.test.ts +0 -246
- package/src/converters/converter.text-html.ts +0 -87
- package/src/converters/converter.text-markdown.ts +0 -67
- package/src/converters/converter.text-plain.test.ts +0 -245
- package/src/converters/converter.text-plain.ts +0 -126
- package/src/converters/converter.types.ts +0 -72
- package/src/converters/converters.core.ts +0 -18
- package/src/editor/Editable.tsx +0 -1012
- package/src/editor/PortableTextEditor.tsx +0 -791
- package/src/editor/components/drop-indicator.tsx +0 -17
- package/src/editor/components/render-block-object.tsx +0 -121
- package/src/editor/components/render-default-object.tsx +0 -21
- package/src/editor/components/render-element.tsx +0 -88
- package/src/editor/components/render-inline-object.tsx +0 -129
- package/src/editor/components/render-leaf.tsx +0 -64
- package/src/editor/components/render-span.tsx +0 -303
- package/src/editor/components/render-text-block.tsx +0 -265
- package/src/editor/components/render-text.tsx +0 -18
- package/src/editor/components/use-core-block-element-behaviors.ts +0 -39
- package/src/editor/create-editor.ts +0 -323
- package/src/editor/create-slate-editor.tsx +0 -64
- package/src/editor/editor-actor-context.ts +0 -4
- package/src/editor/editor-context.tsx +0 -7
- package/src/editor/editor-dom.ts +0 -220
- package/src/editor/editor-machine.ts +0 -751
- package/src/editor/editor-provider.tsx +0 -111
- package/src/editor/editor-schema.ts +0 -6
- package/src/editor/editor-selector.ts +0 -89
- package/src/editor/editor-snapshot.ts +0 -68
- package/src/editor/event-to-change.tsx +0 -49
- package/src/editor/hooks/usePortableTextEditor.ts +0 -25
- package/src/editor/hooks/usePortableTextEditorSelection.tsx +0 -28
- package/src/editor/mutation-machine.ts +0 -322
- package/src/editor/plugins/create-with-event-listeners.ts +0 -271
- package/src/editor/plugins/createWithEditableAPI.ts +0 -529
- package/src/editor/plugins/createWithHotKeys.ts +0 -68
- package/src/editor/plugins/createWithObjectKeys.ts +0 -289
- package/src/editor/plugins/createWithPatches.ts +0 -272
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +0 -559
- package/src/editor/plugins/createWithSchemaTypes.ts +0 -121
- package/src/editor/plugins/slate-plugin.update-selection.ts +0 -51
- package/src/editor/plugins/slate-plugin.update-value.ts +0 -46
- package/src/editor/plugins/with-plugins.ts +0 -69
- package/src/editor/range-decorations-machine.ts +0 -421
- package/src/editor/relay-actor-context.ts +0 -4
- package/src/editor/relay-machine.ts +0 -152
- package/src/editor/sync-machine.ts +0 -961
- package/src/editor/use-editor.ts +0 -27
- package/src/editor/validate-selection-machine.test.ts +0 -47
- package/src/editor/validate-selection-machine.ts +0 -149
- package/src/editor/weakMaps.ts +0 -15
- package/src/editor/with-normalizing-node.ts +0 -14
- package/src/editor/with-performing-behavior-operation.ts +0 -21
- package/src/editor/withChanges.ts +0 -13
- package/src/editor/without-normalizing-conditional.ts +0 -13
- package/src/editor/withoutPatching.ts +0 -14
- package/src/editor.ts +0 -59
- package/src/history/behavior.operation.history.redo.ts +0 -67
- package/src/history/behavior.operation.history.undo.ts +0 -71
- package/src/history/event.history.undo.test.tsx +0 -672
- package/src/history/history.preserving-keys.test.tsx +0 -112
- package/src/history/remote-patches.ts +0 -20
- package/src/history/slate-plugin.history.ts +0 -142
- package/src/history/slate-plugin.redoing.ts +0 -21
- package/src/history/slate-plugin.undoing.ts +0 -21
- package/src/history/slate-plugin.without-history.ts +0 -23
- package/src/history/transform-operation.ts +0 -245
- package/src/history/undo-redo-collaboration.test.tsx +0 -541
- package/src/history/undo-redo.feature +0 -125
- package/src/history/undo-redo.test.tsx +0 -195
- package/src/history/undo-step.ts +0 -148
- package/src/index.ts +0 -98
- package/src/internal-utils/__tests__/ranges.test.ts +0 -23
- package/src/internal-utils/__tests__/values.test.ts +0 -110
- package/src/internal-utils/apply-operation-to-portable-text.test.ts +0 -1861
- package/src/internal-utils/apply-operation-to-portable-text.ts +0 -615
- package/src/internal-utils/applyPatch.ts +0 -644
- package/src/internal-utils/block-keys.ts +0 -9
- package/src/internal-utils/build-index-maps.test.ts +0 -464
- package/src/internal-utils/build-index-maps.ts +0 -131
- package/src/internal-utils/collapse-selection.ts +0 -36
- package/src/internal-utils/compound-client-rect.ts +0 -28
- package/src/internal-utils/create-placeholder-block.ts +0 -21
- package/src/internal-utils/create-test-snapshot.ts +0 -28
- package/src/internal-utils/debug.ts +0 -12
- package/src/internal-utils/editor-selection.test.ts +0 -44
- package/src/internal-utils/editor-selection.ts +0 -56
- package/src/internal-utils/event-position.ts +0 -318
- package/src/internal-utils/global-scope.ts +0 -27
- package/src/internal-utils/globally-scoped-context.ts +0 -39
- package/src/internal-utils/is-hotkey.test.ts +0 -114
- package/src/internal-utils/is-hotkey.ts +0 -209
- package/src/internal-utils/mime-type.ts +0 -1
- package/src/internal-utils/move-range-by-operation.ts +0 -19
- package/src/internal-utils/operation-to-patches.test.ts +0 -522
- package/src/internal-utils/operation-to-patches.ts +0 -571
- package/src/internal-utils/portable-text-node.ts +0 -209
- package/src/internal-utils/schema.ts +0 -8
- package/src/internal-utils/selection-block-keys.ts +0 -20
- package/src/internal-utils/selection-focus-text.ts +0 -40
- package/src/internal-utils/selection-text.test.ts +0 -32
- package/src/internal-utils/selection-text.ts +0 -21
- package/src/internal-utils/selection.ts +0 -77
- package/src/internal-utils/sibling-utils.ts +0 -55
- package/src/internal-utils/slate-utils.test.tsx +0 -121
- package/src/internal-utils/slate-utils.ts +0 -417
- package/src/internal-utils/split-string.ts +0 -12
- package/src/internal-utils/stop-actor.ts +0 -43
- package/src/internal-utils/string-overlap.test.ts +0 -14
- package/src/internal-utils/string-overlap.ts +0 -28
- package/src/internal-utils/string-utils.ts +0 -7
- package/src/internal-utils/text-block-key.test.ts +0 -41
- package/src/internal-utils/text-block-key.ts +0 -26
- package/src/internal-utils/text-marks.test.ts +0 -41
- package/src/internal-utils/text-marks.ts +0 -22
- package/src/internal-utils/text-selection.test.ts +0 -211
- package/src/internal-utils/text-selection.ts +0 -121
- package/src/internal-utils/to-slate-range.test.ts +0 -278
- package/src/internal-utils/to-slate-range.ts +0 -171
- package/src/internal-utils/validateValue.ts +0 -443
- package/src/internal-utils/value-annotations.ts +0 -33
- package/src/internal-utils/values.test.ts +0 -282
- package/src/internal-utils/values.ts +0 -266
- package/src/keyboard-shortcuts/default-keyboard-shortcuts.ts +0 -146
- package/src/operations/behavior.operation.annotation.add.ts +0 -99
- package/src/operations/behavior.operation.annotation.remove.ts +0 -150
- package/src/operations/behavior.operation.block.set.ts +0 -104
- package/src/operations/behavior.operation.block.unset.ts +0 -54
- package/src/operations/behavior.operation.child.set.ts +0 -107
- package/src/operations/behavior.operation.child.unset.ts +0 -116
- package/src/operations/behavior.operation.decorator.add.ts +0 -131
- package/src/operations/behavior.operation.delete.ts +0 -294
- package/src/operations/behavior.operation.insert.block.ts +0 -495
- package/src/operations/behavior.operation.insert.child.ts +0 -129
- package/src/operations/behavior.operation.insert.text.ts +0 -8
- package/src/operations/behavior.operation.move.backward.ts +0 -12
- package/src/operations/behavior.operation.move.block.ts +0 -44
- package/src/operations/behavior.operation.move.forward.ts +0 -11
- package/src/operations/behavior.operation.select.ts +0 -27
- package/src/operations/behavior.operations.ts +0 -221
- package/src/plugins/_exports/index.ts +0 -1
- package/src/plugins/index.ts +0 -3
- package/src/plugins/plugin.behavior.tsx +0 -24
- package/src/plugins/plugin.editor-ref.tsx +0 -17
- package/src/plugins/plugin.event-listener.tsx +0 -68
- package/src/plugins/plugin.internal.auto-close-brackets.test.tsx +0 -71
- package/src/plugins/plugin.internal.auto-close-brackets.ts +0 -62
- package/src/plugins/plugin.internal.change-ref.tsx +0 -19
- package/src/plugins/plugin.internal.portable-text-editor-ref.tsx +0 -16
- package/src/plugins/plugin.internal.slate-editor-ref.tsx +0 -15
- package/src/priority/priority.core.ts +0 -3
- package/src/priority/priority.sort.test.ts +0 -319
- package/src/priority/priority.sort.ts +0 -123
- package/src/priority/priority.types.ts +0 -24
- package/src/selectors/_exports/index.ts +0 -1
- package/src/selectors/drag-selection.test.ts +0 -578
- package/src/selectors/drag-selection.ts +0 -118
- package/src/selectors/index.ts +0 -54
- package/src/selectors/selector.get-active-annotation-marks.ts +0 -12
- package/src/selectors/selector.get-active-annotations.ts +0 -36
- package/src/selectors/selector.get-active-decorators.ts +0 -29
- package/src/selectors/selector.get-active-list-item.ts +0 -38
- package/src/selectors/selector.get-active-style.ts +0 -38
- package/src/selectors/selector.get-anchor-block.ts +0 -22
- package/src/selectors/selector.get-anchor-child.ts +0 -36
- package/src/selectors/selector.get-anchor-span.ts +0 -17
- package/src/selectors/selector.get-anchor-text-block.ts +0 -18
- package/src/selectors/selector.get-block-offsets.ts +0 -34
- package/src/selectors/selector.get-caret-word-selection.test.ts +0 -284
- package/src/selectors/selector.get-caret-word-selection.ts +0 -134
- package/src/selectors/selector.get-first-block.ts +0 -14
- package/src/selectors/selector.get-focus-block-object.ts +0 -18
- package/src/selectors/selector.get-focus-block.ts +0 -23
- package/src/selectors/selector.get-focus-child.ts +0 -36
- package/src/selectors/selector.get-focus-inline-object.ts +0 -17
- package/src/selectors/selector.get-focus-list-block.ts +0 -18
- package/src/selectors/selector.get-focus-span.ts +0 -18
- package/src/selectors/selector.get-focus-text-block.ts +0 -18
- package/src/selectors/selector.get-last-block.ts +0 -16
- package/src/selectors/selector.get-mark-state.test.ts +0 -325
- package/src/selectors/selector.get-mark-state.ts +0 -263
- package/src/selectors/selector.get-next-block.ts +0 -29
- package/src/selectors/selector.get-next-inline-object.ts +0 -53
- package/src/selectors/selector.get-next-inline-objects.ts +0 -50
- package/src/selectors/selector.get-next-span.ts +0 -56
- package/src/selectors/selector.get-previous-block.ts +0 -29
- package/src/selectors/selector.get-previous-inline-object.ts +0 -50
- package/src/selectors/selector.get-previous-inline-objects.ts +0 -47
- package/src/selectors/selector.get-previous-span.ts +0 -53
- package/src/selectors/selector.get-selected-blocks.ts +0 -61
- package/src/selectors/selector.get-selected-spans.test.ts +0 -347
- package/src/selectors/selector.get-selected-spans.ts +0 -155
- package/src/selectors/selector.get-selected-text-blocks.ts +0 -73
- package/src/selectors/selector.get-selected-value.test.ts +0 -834
- package/src/selectors/selector.get-selected-value.ts +0 -66
- package/src/selectors/selector.get-selection-end-block.ts +0 -33
- package/src/selectors/selector.get-selection-end-child.ts +0 -33
- package/src/selectors/selector.get-selection-end-point.ts +0 -17
- package/src/selectors/selector.get-selection-start-block.ts +0 -33
- package/src/selectors/selector.get-selection-start-child.ts +0 -33
- package/src/selectors/selector.get-selection-start-point.ts +0 -17
- package/src/selectors/selector.get-selection-text.test.ts +0 -421
- package/src/selectors/selector.get-selection-text.ts +0 -27
- package/src/selectors/selector.get-selection.ts +0 -9
- package/src/selectors/selector.get-text-after.ts +0 -46
- package/src/selectors/selector.get-text-before.ts +0 -46
- package/src/selectors/selector.get-value.ts +0 -11
- package/src/selectors/selector.is-active-annotation.test.ts +0 -320
- package/src/selectors/selector.is-active-annotation.ts +0 -52
- package/src/selectors/selector.is-active-decorator.test.ts +0 -136
- package/src/selectors/selector.is-active-decorator.ts +0 -24
- package/src/selectors/selector.is-active-list-item.ts +0 -13
- package/src/selectors/selector.is-active-style.ts +0 -13
- package/src/selectors/selector.is-at-the-end-of-block.ts +0 -30
- package/src/selectors/selector.is-at-the-start-of-block.ts +0 -30
- package/src/selectors/selector.is-overlapping-selection.test.ts +0 -304
- package/src/selectors/selector.is-overlapping-selection.ts +0 -181
- package/src/selectors/selector.is-point-after-selection.ts +0 -97
- package/src/selectors/selector.is-point-before-selection.ts +0 -97
- package/src/selectors/selector.is-selecting-entire-blocks.ts +0 -43
- package/src/selectors/selector.is-selection-collapsed.ts +0 -17
- package/src/selectors/selector.is-selection-expanded.test.ts +0 -63
- package/src/selectors/selector.is-selection-expanded.ts +0 -9
- package/src/test/_exports/index.ts +0 -1
- package/src/test/gherkin-parameter-types.ts +0 -112
- package/src/test/index.ts +0 -1
- package/src/test/vitest/_exports/index.ts +0 -1
- package/src/test/vitest/index.ts +0 -3
- package/src/test/vitest/step-context.ts +0 -13
- package/src/test/vitest/step-definitions.tsx +0 -960
- package/src/test/vitest/test-editor.tsx +0 -198
- package/src/type-utils.ts +0 -29
- package/src/types/block-offset.ts +0 -9
- package/src/types/block-with-optional-key.ts +0 -25
- package/src/types/editor.ts +0 -509
- package/src/types/options.ts +0 -13
- package/src/types/paths.ts +0 -35
- package/src/types/slate-editor.ts +0 -50
- package/src/types/slate.ts +0 -27
- package/src/utils/_exports/index.ts +0 -1
- package/src/utils/asserters.ts +0 -9
- package/src/utils/index.ts +0 -24
- package/src/utils/key-generator.ts +0 -33
- package/src/utils/parse-blocks.test.ts +0 -836
- package/src/utils/parse-blocks.ts +0 -504
- package/src/utils/util.at-the-beginning-of-block.ts +0 -32
- package/src/utils/util.block-offset-to-block-selection-point.ts +0 -28
- package/src/utils/util.block-offset-to-selection-point.ts +0 -33
- package/src/utils/util.block-offset.test.ts +0 -375
- package/src/utils/util.block-offset.ts +0 -136
- package/src/utils/util.block-offsets-to-selection.ts +0 -38
- package/src/utils/util.child-selection-point-to-block-offset.ts +0 -51
- package/src/utils/util.get-block-end-point.ts +0 -35
- package/src/utils/util.get-block-start-point.ts +0 -31
- package/src/utils/util.get-selection-end-point.ts +0 -20
- package/src/utils/util.get-selection-start-point.ts +0 -20
- package/src/utils/util.get-text-block-text.ts +0 -8
- package/src/utils/util.is-empty-text-block.ts +0 -21
- package/src/utils/util.is-equal-selection-points.ts +0 -13
- package/src/utils/util.is-equal-selections.ts +0 -20
- package/src/utils/util.is-keyed-segment.ts +0 -8
- package/src/utils/util.is-selection-collapsed.ts +0 -16
- package/src/utils/util.is-selection-expanded.ts +0 -13
- package/src/utils/util.merge-text-blocks.ts +0 -40
- package/src/utils/util.reverse-selection.ts +0 -26
- package/src/utils/util.selection-point-to-block-offset.ts +0 -30
- package/src/utils/util.selection-point.ts +0 -22
- package/src/utils/util.slice-blocks.ts +0 -221
- package/src/utils/util.slice-text-block.test.ts +0 -190
- package/src/utils/util.slice-text-block.ts +0 -89
- package/src/utils/util.split-text-block.ts +0 -54
|
@@ -1,961 +0,0 @@
|
|
|
1
|
-
import type {Patch} from '@portabletext/patches'
|
|
2
|
-
import {isSpan} from '@portabletext/schema'
|
|
3
|
-
import type {PortableTextBlock} from '@sanity/types'
|
|
4
|
-
import {isEqual} from 'lodash'
|
|
5
|
-
import {deleteText, Editor, Transforms, type Descendant, type Node} from 'slate'
|
|
6
|
-
import type {ActorRefFrom} from 'xstate'
|
|
7
|
-
import {
|
|
8
|
-
and,
|
|
9
|
-
assertEvent,
|
|
10
|
-
assign,
|
|
11
|
-
emit,
|
|
12
|
-
fromCallback,
|
|
13
|
-
not,
|
|
14
|
-
raise,
|
|
15
|
-
setup,
|
|
16
|
-
type AnyEventObject,
|
|
17
|
-
type CallbackLogicFunction,
|
|
18
|
-
} from 'xstate'
|
|
19
|
-
import {pluginWithoutHistory} from '../history/slate-plugin.without-history'
|
|
20
|
-
import {debugWithName} from '../internal-utils/debug'
|
|
21
|
-
import {validateValue} from '../internal-utils/validateValue'
|
|
22
|
-
import {toSlateBlock, VOID_CHILD_KEY} from '../internal-utils/values'
|
|
23
|
-
import type {PickFromUnion} from '../type-utils'
|
|
24
|
-
import type {InvalidValueResolution} from '../types/editor'
|
|
25
|
-
import type {PortableTextSlateEditor} from '../types/slate-editor'
|
|
26
|
-
import type {EditorSchema} from './editor-schema'
|
|
27
|
-
import {isChangingRemotely, withRemoteChanges} from './withChanges'
|
|
28
|
-
import {withoutPatching} from './withoutPatching'
|
|
29
|
-
|
|
30
|
-
const debug = debugWithName('sync machine')
|
|
31
|
-
|
|
32
|
-
type SyncValueEvent =
|
|
33
|
-
| {
|
|
34
|
-
type: 'patch'
|
|
35
|
-
patch: Patch
|
|
36
|
-
}
|
|
37
|
-
| {
|
|
38
|
-
type: 'invalid value'
|
|
39
|
-
resolution: InvalidValueResolution | null
|
|
40
|
-
value: Array<PortableTextBlock> | undefined
|
|
41
|
-
}
|
|
42
|
-
| {
|
|
43
|
-
type: 'value changed'
|
|
44
|
-
value: Array<PortableTextBlock> | undefined
|
|
45
|
-
}
|
|
46
|
-
| {
|
|
47
|
-
type: 'done syncing'
|
|
48
|
-
value: Array<PortableTextBlock> | undefined
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const syncValueCallback: CallbackLogicFunction<
|
|
52
|
-
AnyEventObject,
|
|
53
|
-
SyncValueEvent,
|
|
54
|
-
{
|
|
55
|
-
context: {
|
|
56
|
-
keyGenerator: () => string
|
|
57
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
58
|
-
readOnly: boolean
|
|
59
|
-
schema: EditorSchema
|
|
60
|
-
}
|
|
61
|
-
slateEditor: PortableTextSlateEditor
|
|
62
|
-
streamBlocks: boolean
|
|
63
|
-
value: Array<PortableTextBlock> | undefined
|
|
64
|
-
}
|
|
65
|
-
> = ({sendBack, input}) => {
|
|
66
|
-
updateValue({
|
|
67
|
-
context: input.context,
|
|
68
|
-
sendBack,
|
|
69
|
-
slateEditor: input.slateEditor,
|
|
70
|
-
value: input.value,
|
|
71
|
-
streamBlocks: input.streamBlocks,
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const syncValueLogic = fromCallback(syncValueCallback)
|
|
76
|
-
|
|
77
|
-
export type SyncActor = ActorRefFrom<typeof syncMachine>
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Sync value with the editor state
|
|
81
|
-
*
|
|
82
|
-
* Normally nothing here should apply, and the editor and the real world are perfectly aligned.
|
|
83
|
-
*
|
|
84
|
-
* Inconsistencies could happen though, so we need to check the editor state when the value changes.
|
|
85
|
-
*
|
|
86
|
-
* For performance reasons, it makes sense to also do the content validation here, as we already
|
|
87
|
-
* iterate over the value and can validate only the new content that is actually changed.
|
|
88
|
-
*
|
|
89
|
-
* @internal
|
|
90
|
-
*/
|
|
91
|
-
export const syncMachine = setup({
|
|
92
|
-
types: {
|
|
93
|
-
context: {} as {
|
|
94
|
-
initialValue: Array<PortableTextBlock> | undefined
|
|
95
|
-
initialValueSynced: boolean
|
|
96
|
-
isProcessingLocalChanges: boolean
|
|
97
|
-
keyGenerator: () => string
|
|
98
|
-
schema: EditorSchema
|
|
99
|
-
readOnly: boolean
|
|
100
|
-
slateEditor: PortableTextSlateEditor
|
|
101
|
-
pendingValue: Array<PortableTextBlock> | undefined
|
|
102
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
103
|
-
},
|
|
104
|
-
input: {} as {
|
|
105
|
-
initialValue: Array<PortableTextBlock> | undefined
|
|
106
|
-
keyGenerator: () => string
|
|
107
|
-
schema: EditorSchema
|
|
108
|
-
readOnly: boolean
|
|
109
|
-
slateEditor: PortableTextSlateEditor
|
|
110
|
-
},
|
|
111
|
-
events: {} as
|
|
112
|
-
| {
|
|
113
|
-
type: 'has pending mutations'
|
|
114
|
-
}
|
|
115
|
-
| {
|
|
116
|
-
type: 'mutation'
|
|
117
|
-
}
|
|
118
|
-
| {
|
|
119
|
-
type: 'update value'
|
|
120
|
-
value: Array<PortableTextBlock> | undefined
|
|
121
|
-
}
|
|
122
|
-
| {
|
|
123
|
-
type: 'update readOnly'
|
|
124
|
-
readOnly: boolean
|
|
125
|
-
}
|
|
126
|
-
| SyncValueEvent,
|
|
127
|
-
emitted: {} as
|
|
128
|
-
| PickFromUnion<
|
|
129
|
-
SyncValueEvent,
|
|
130
|
-
'type',
|
|
131
|
-
'invalid value' | 'patch' | 'value changed'
|
|
132
|
-
>
|
|
133
|
-
| {type: 'done syncing value'}
|
|
134
|
-
| {type: 'syncing value'},
|
|
135
|
-
},
|
|
136
|
-
actions: {
|
|
137
|
-
'assign initial value synced': assign({
|
|
138
|
-
initialValueSynced: true,
|
|
139
|
-
}),
|
|
140
|
-
'assign readOnly': assign({
|
|
141
|
-
readOnly: ({event}) => {
|
|
142
|
-
assertEvent(event, 'update readOnly')
|
|
143
|
-
return event.readOnly
|
|
144
|
-
},
|
|
145
|
-
}),
|
|
146
|
-
'assign pending value': assign({
|
|
147
|
-
pendingValue: ({event}) => {
|
|
148
|
-
assertEvent(event, 'update value')
|
|
149
|
-
return event.value
|
|
150
|
-
},
|
|
151
|
-
}),
|
|
152
|
-
'clear pending value': assign({
|
|
153
|
-
pendingValue: undefined,
|
|
154
|
-
}),
|
|
155
|
-
'assign previous value': assign({
|
|
156
|
-
previousValue: ({event}) => {
|
|
157
|
-
assertEvent(event, 'done syncing')
|
|
158
|
-
return event.value
|
|
159
|
-
},
|
|
160
|
-
}),
|
|
161
|
-
'emit done syncing value': emit({
|
|
162
|
-
type: 'done syncing value',
|
|
163
|
-
}),
|
|
164
|
-
'emit syncing value': emit({
|
|
165
|
-
type: 'syncing value',
|
|
166
|
-
}),
|
|
167
|
-
},
|
|
168
|
-
guards: {
|
|
169
|
-
'initial value synced': ({context}) => context.initialValueSynced,
|
|
170
|
-
'is busy': ({context}) => {
|
|
171
|
-
const isProcessingLocalChanges = context.isProcessingLocalChanges
|
|
172
|
-
const isChanging = isChangingRemotely(context.slateEditor) ?? false
|
|
173
|
-
const isBusy = isProcessingLocalChanges || isChanging
|
|
174
|
-
|
|
175
|
-
debug('isBusy', {isBusy, isProcessingLocalChanges, isChanging})
|
|
176
|
-
|
|
177
|
-
return isBusy
|
|
178
|
-
},
|
|
179
|
-
'is empty value': ({event}) => {
|
|
180
|
-
return event.type === 'update value' && event.value === undefined
|
|
181
|
-
},
|
|
182
|
-
'is empty array': ({event}) => {
|
|
183
|
-
return (
|
|
184
|
-
event.type === 'update value' &&
|
|
185
|
-
Array.isArray(event.value) &&
|
|
186
|
-
event.value.length === 0
|
|
187
|
-
)
|
|
188
|
-
},
|
|
189
|
-
'is new value': ({context, event}) => {
|
|
190
|
-
return (
|
|
191
|
-
event.type === 'update value' && context.previousValue !== event.value
|
|
192
|
-
)
|
|
193
|
-
},
|
|
194
|
-
'value changed while syncing': ({context, event}) => {
|
|
195
|
-
assertEvent(event, 'done syncing')
|
|
196
|
-
return context.pendingValue !== event.value
|
|
197
|
-
},
|
|
198
|
-
'pending value equals previous value': ({context}) => {
|
|
199
|
-
return isEqual(context.pendingValue, context.previousValue)
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
actors: {
|
|
203
|
-
'sync value': syncValueLogic,
|
|
204
|
-
},
|
|
205
|
-
}).createMachine({
|
|
206
|
-
id: 'sync',
|
|
207
|
-
context: ({input}) => ({
|
|
208
|
-
initialValue: input.initialValue,
|
|
209
|
-
initialValueSynced: false,
|
|
210
|
-
isProcessingLocalChanges: false,
|
|
211
|
-
keyGenerator: input.keyGenerator,
|
|
212
|
-
schema: input.schema,
|
|
213
|
-
readOnly: input.readOnly,
|
|
214
|
-
slateEditor: input.slateEditor,
|
|
215
|
-
pendingValue: undefined,
|
|
216
|
-
previousValue: undefined,
|
|
217
|
-
}),
|
|
218
|
-
entry: [
|
|
219
|
-
raise(({context}) => {
|
|
220
|
-
return {type: 'update value', value: context.initialValue}
|
|
221
|
-
}),
|
|
222
|
-
],
|
|
223
|
-
on: {
|
|
224
|
-
'has pending mutations': {
|
|
225
|
-
actions: assign({
|
|
226
|
-
isProcessingLocalChanges: true,
|
|
227
|
-
}),
|
|
228
|
-
},
|
|
229
|
-
'mutation': {
|
|
230
|
-
actions: assign({
|
|
231
|
-
isProcessingLocalChanges: false,
|
|
232
|
-
}),
|
|
233
|
-
},
|
|
234
|
-
'update readOnly': {
|
|
235
|
-
actions: ['assign readOnly'],
|
|
236
|
-
},
|
|
237
|
-
},
|
|
238
|
-
initial: 'idle',
|
|
239
|
-
states: {
|
|
240
|
-
idle: {
|
|
241
|
-
entry: [
|
|
242
|
-
() => {
|
|
243
|
-
debug('entry: syncing->idle')
|
|
244
|
-
},
|
|
245
|
-
],
|
|
246
|
-
exit: [
|
|
247
|
-
() => {
|
|
248
|
-
debug('exit: syncing->idle')
|
|
249
|
-
},
|
|
250
|
-
],
|
|
251
|
-
on: {
|
|
252
|
-
'update value': [
|
|
253
|
-
{
|
|
254
|
-
guard: and(['is empty value', not('initial value synced')]),
|
|
255
|
-
actions: ['assign initial value synced', 'emit done syncing value'],
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
guard: and(['is empty array', not('initial value synced')]),
|
|
259
|
-
actions: [
|
|
260
|
-
'assign initial value synced',
|
|
261
|
-
emit({type: 'value changed', value: []}),
|
|
262
|
-
'emit done syncing value',
|
|
263
|
-
],
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
guard: and(['is busy', 'is new value']),
|
|
267
|
-
target: 'busy',
|
|
268
|
-
actions: ['assign pending value'],
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
guard: 'is new value',
|
|
272
|
-
target: 'syncing',
|
|
273
|
-
actions: ['assign pending value'],
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
guard: not('initial value synced'),
|
|
277
|
-
actions: [
|
|
278
|
-
() => {
|
|
279
|
-
debug('no new value – setting initial value as synced')
|
|
280
|
-
},
|
|
281
|
-
'assign initial value synced',
|
|
282
|
-
'emit done syncing value',
|
|
283
|
-
],
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
actions: [
|
|
287
|
-
() => {
|
|
288
|
-
debug('no new value and initial value already synced')
|
|
289
|
-
},
|
|
290
|
-
],
|
|
291
|
-
},
|
|
292
|
-
],
|
|
293
|
-
},
|
|
294
|
-
},
|
|
295
|
-
busy: {
|
|
296
|
-
entry: [
|
|
297
|
-
() => {
|
|
298
|
-
debug('entry: syncing->busy')
|
|
299
|
-
},
|
|
300
|
-
],
|
|
301
|
-
exit: [
|
|
302
|
-
() => {
|
|
303
|
-
debug('exit: syncing->busy')
|
|
304
|
-
},
|
|
305
|
-
],
|
|
306
|
-
after: {
|
|
307
|
-
1000: [
|
|
308
|
-
{
|
|
309
|
-
guard: 'is busy',
|
|
310
|
-
target: '.',
|
|
311
|
-
reenter: true,
|
|
312
|
-
actions: [
|
|
313
|
-
() => {
|
|
314
|
-
debug('reenter: syncing->busy')
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
target: 'syncing',
|
|
320
|
-
},
|
|
321
|
-
],
|
|
322
|
-
},
|
|
323
|
-
on: {
|
|
324
|
-
'update value': [
|
|
325
|
-
{
|
|
326
|
-
guard: 'is new value',
|
|
327
|
-
actions: ['assign pending value'],
|
|
328
|
-
},
|
|
329
|
-
],
|
|
330
|
-
},
|
|
331
|
-
},
|
|
332
|
-
syncing: {
|
|
333
|
-
entry: [
|
|
334
|
-
() => {
|
|
335
|
-
debug('entry: syncing->syncing')
|
|
336
|
-
},
|
|
337
|
-
'emit syncing value',
|
|
338
|
-
],
|
|
339
|
-
exit: [
|
|
340
|
-
() => {
|
|
341
|
-
debug('exit: syncing->syncing')
|
|
342
|
-
},
|
|
343
|
-
'emit done syncing value',
|
|
344
|
-
],
|
|
345
|
-
invoke: {
|
|
346
|
-
src: 'sync value',
|
|
347
|
-
id: 'sync value',
|
|
348
|
-
input: ({context}) => {
|
|
349
|
-
return {
|
|
350
|
-
context: {
|
|
351
|
-
keyGenerator: context.keyGenerator,
|
|
352
|
-
previousValue: context.previousValue,
|
|
353
|
-
readOnly: context.readOnly,
|
|
354
|
-
schema: context.schema,
|
|
355
|
-
},
|
|
356
|
-
slateEditor: context.slateEditor,
|
|
357
|
-
streamBlocks: !context.initialValueSynced,
|
|
358
|
-
value: context.pendingValue,
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
on: {
|
|
363
|
-
'update value': {
|
|
364
|
-
guard: 'is new value',
|
|
365
|
-
actions: ['assign pending value'],
|
|
366
|
-
},
|
|
367
|
-
'patch': {
|
|
368
|
-
actions: [emit(({event}) => event)],
|
|
369
|
-
},
|
|
370
|
-
'invalid value': {
|
|
371
|
-
actions: [emit(({event}) => event)],
|
|
372
|
-
},
|
|
373
|
-
'value changed': {
|
|
374
|
-
actions: [emit(({event}) => event)],
|
|
375
|
-
},
|
|
376
|
-
'done syncing': [
|
|
377
|
-
{
|
|
378
|
-
guard: 'value changed while syncing',
|
|
379
|
-
actions: ['assign previous value', 'assign initial value synced'],
|
|
380
|
-
target: 'syncing',
|
|
381
|
-
reenter: true,
|
|
382
|
-
},
|
|
383
|
-
{
|
|
384
|
-
target: 'idle',
|
|
385
|
-
actions: [
|
|
386
|
-
'clear pending value',
|
|
387
|
-
'assign previous value',
|
|
388
|
-
'assign initial value synced',
|
|
389
|
-
],
|
|
390
|
-
},
|
|
391
|
-
],
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
})
|
|
396
|
-
|
|
397
|
-
async function updateValue({
|
|
398
|
-
context,
|
|
399
|
-
sendBack,
|
|
400
|
-
slateEditor,
|
|
401
|
-
streamBlocks,
|
|
402
|
-
value,
|
|
403
|
-
}: {
|
|
404
|
-
context: {
|
|
405
|
-
keyGenerator: () => string
|
|
406
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
407
|
-
readOnly: boolean
|
|
408
|
-
schema: EditorSchema
|
|
409
|
-
}
|
|
410
|
-
sendBack: (event: SyncValueEvent) => void
|
|
411
|
-
slateEditor: PortableTextSlateEditor
|
|
412
|
-
streamBlocks: boolean
|
|
413
|
-
value: PortableTextBlock[] | undefined
|
|
414
|
-
}) {
|
|
415
|
-
let doneSyncing = false
|
|
416
|
-
let isChanged = false
|
|
417
|
-
let isValid = true
|
|
418
|
-
|
|
419
|
-
const hadSelection = !!slateEditor.selection
|
|
420
|
-
|
|
421
|
-
if (!value || value.length === 0) {
|
|
422
|
-
debug('Value is empty')
|
|
423
|
-
|
|
424
|
-
clearEditor({
|
|
425
|
-
slateEditor,
|
|
426
|
-
doneSyncing,
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
isChanged = true
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Remove, replace or add nodes according to what is changed.
|
|
433
|
-
if (value && value.length > 0) {
|
|
434
|
-
if (streamBlocks) {
|
|
435
|
-
await new Promise<void>((resolve) => {
|
|
436
|
-
if (doneSyncing) {
|
|
437
|
-
resolve()
|
|
438
|
-
return
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
isChanged = removeExtraBlocks({
|
|
442
|
-
slateEditor,
|
|
443
|
-
value,
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
const processBlocks = async () => {
|
|
447
|
-
for await (const [
|
|
448
|
-
currentBlock,
|
|
449
|
-
currentBlockIndex,
|
|
450
|
-
] of getStreamedBlocks({
|
|
451
|
-
value,
|
|
452
|
-
})) {
|
|
453
|
-
const {blockChanged, blockValid} = syncBlock({
|
|
454
|
-
context,
|
|
455
|
-
sendBack,
|
|
456
|
-
block: currentBlock,
|
|
457
|
-
index: currentBlockIndex,
|
|
458
|
-
slateEditor,
|
|
459
|
-
value,
|
|
460
|
-
})
|
|
461
|
-
|
|
462
|
-
isChanged = blockChanged || isChanged
|
|
463
|
-
isValid = isValid && blockValid
|
|
464
|
-
|
|
465
|
-
if (!isValid) {
|
|
466
|
-
break
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
resolve()
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
processBlocks()
|
|
474
|
-
})
|
|
475
|
-
} else {
|
|
476
|
-
if (doneSyncing) {
|
|
477
|
-
return
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
isChanged = removeExtraBlocks({
|
|
481
|
-
slateEditor,
|
|
482
|
-
value,
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
let index = 0
|
|
486
|
-
|
|
487
|
-
for (const block of value) {
|
|
488
|
-
const {blockChanged, blockValid} = syncBlock({
|
|
489
|
-
context,
|
|
490
|
-
sendBack,
|
|
491
|
-
block,
|
|
492
|
-
index,
|
|
493
|
-
slateEditor,
|
|
494
|
-
value,
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
isChanged = blockChanged || isChanged
|
|
498
|
-
isValid = isValid && blockValid
|
|
499
|
-
|
|
500
|
-
if (!blockValid) {
|
|
501
|
-
break
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
index++
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (!isValid) {
|
|
510
|
-
debug('Invalid value, returning')
|
|
511
|
-
|
|
512
|
-
doneSyncing = true
|
|
513
|
-
|
|
514
|
-
sendBack({type: 'done syncing', value})
|
|
515
|
-
|
|
516
|
-
return
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (isChanged) {
|
|
520
|
-
debug('Server value changed, syncing editor')
|
|
521
|
-
try {
|
|
522
|
-
slateEditor.onChange()
|
|
523
|
-
} catch (err) {
|
|
524
|
-
console.error(err)
|
|
525
|
-
|
|
526
|
-
sendBack({
|
|
527
|
-
type: 'invalid value',
|
|
528
|
-
resolution: null,
|
|
529
|
-
value,
|
|
530
|
-
})
|
|
531
|
-
|
|
532
|
-
doneSyncing = true
|
|
533
|
-
|
|
534
|
-
sendBack({type: 'done syncing', value})
|
|
535
|
-
|
|
536
|
-
return
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
if (hadSelection && !slateEditor.selection) {
|
|
540
|
-
Transforms.select(slateEditor, {
|
|
541
|
-
anchor: {path: [0, 0], offset: 0},
|
|
542
|
-
focus: {path: [0, 0], offset: 0},
|
|
543
|
-
})
|
|
544
|
-
|
|
545
|
-
slateEditor.onChange()
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
sendBack({type: 'value changed', value})
|
|
549
|
-
} else {
|
|
550
|
-
debug('Server value and editor value is equal, no need to sync.')
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
doneSyncing = true
|
|
554
|
-
|
|
555
|
-
sendBack({type: 'done syncing', value})
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
async function* getStreamedBlocks({value}: {value: Array<PortableTextBlock>}) {
|
|
559
|
-
let index = 0
|
|
560
|
-
for await (const block of value) {
|
|
561
|
-
if (index % 10 === 0) {
|
|
562
|
-
await new Promise<void>((resolve) => setTimeout(resolve, 0))
|
|
563
|
-
}
|
|
564
|
-
yield [block, index] as const
|
|
565
|
-
index++
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
/**
|
|
570
|
-
* Remove all blocks and insert a placeholder block
|
|
571
|
-
*/
|
|
572
|
-
function clearEditor({
|
|
573
|
-
slateEditor,
|
|
574
|
-
doneSyncing,
|
|
575
|
-
}: {
|
|
576
|
-
slateEditor: PortableTextSlateEditor
|
|
577
|
-
doneSyncing: boolean
|
|
578
|
-
}) {
|
|
579
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
580
|
-
pluginWithoutHistory(slateEditor, () => {
|
|
581
|
-
withRemoteChanges(slateEditor, () => {
|
|
582
|
-
withoutPatching(slateEditor, () => {
|
|
583
|
-
if (doneSyncing) {
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
const childrenLength = slateEditor.children.length
|
|
588
|
-
|
|
589
|
-
slateEditor.children.forEach((_, index) => {
|
|
590
|
-
Transforms.removeNodes(slateEditor, {
|
|
591
|
-
at: [childrenLength - 1 - index],
|
|
592
|
-
})
|
|
593
|
-
})
|
|
594
|
-
})
|
|
595
|
-
})
|
|
596
|
-
})
|
|
597
|
-
})
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Compare the length of the value and the length of the editor's children, and
|
|
602
|
-
* remove blocks that have become superfluous
|
|
603
|
-
*/
|
|
604
|
-
function removeExtraBlocks({
|
|
605
|
-
slateEditor,
|
|
606
|
-
value,
|
|
607
|
-
}: {
|
|
608
|
-
slateEditor: PortableTextSlateEditor
|
|
609
|
-
value: Array<PortableTextBlock>
|
|
610
|
-
}) {
|
|
611
|
-
let isChanged = false
|
|
612
|
-
|
|
613
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
614
|
-
withRemoteChanges(slateEditor, () => {
|
|
615
|
-
withoutPatching(slateEditor, () => {
|
|
616
|
-
const childrenLength = slateEditor.children.length
|
|
617
|
-
|
|
618
|
-
if (value.length < childrenLength) {
|
|
619
|
-
for (let i = childrenLength - 1; i > value.length - 1; i--) {
|
|
620
|
-
Transforms.removeNodes(slateEditor, {
|
|
621
|
-
at: [i],
|
|
622
|
-
})
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
isChanged = true
|
|
626
|
-
}
|
|
627
|
-
})
|
|
628
|
-
})
|
|
629
|
-
})
|
|
630
|
-
|
|
631
|
-
return isChanged
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
function syncBlock({
|
|
635
|
-
context,
|
|
636
|
-
sendBack,
|
|
637
|
-
block,
|
|
638
|
-
index,
|
|
639
|
-
slateEditor,
|
|
640
|
-
value,
|
|
641
|
-
}: {
|
|
642
|
-
context: {
|
|
643
|
-
keyGenerator: () => string
|
|
644
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
645
|
-
readOnly: boolean
|
|
646
|
-
schema: EditorSchema
|
|
647
|
-
}
|
|
648
|
-
sendBack: (event: SyncValueEvent) => void
|
|
649
|
-
block: PortableTextBlock
|
|
650
|
-
index: number
|
|
651
|
-
slateEditor: PortableTextSlateEditor
|
|
652
|
-
value: Array<PortableTextBlock>
|
|
653
|
-
}) {
|
|
654
|
-
const oldBlock = slateEditor.children.at(index)
|
|
655
|
-
|
|
656
|
-
if (!oldBlock) {
|
|
657
|
-
// Insert the new block
|
|
658
|
-
const validation = validateValue(
|
|
659
|
-
[block],
|
|
660
|
-
context.schema,
|
|
661
|
-
context.keyGenerator,
|
|
662
|
-
)
|
|
663
|
-
|
|
664
|
-
if (debug.enabled) {
|
|
665
|
-
debug('Validating and inserting new block in the end of the value', block)
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
if (validation.valid || validation.resolution?.autoResolve) {
|
|
669
|
-
const slateBlock = toSlateBlock(block, {
|
|
670
|
-
schemaTypes: context.schema,
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
674
|
-
withRemoteChanges(slateEditor, () => {
|
|
675
|
-
withoutPatching(slateEditor, () => {
|
|
676
|
-
Transforms.insertNodes(slateEditor, slateBlock, {
|
|
677
|
-
at: [index],
|
|
678
|
-
})
|
|
679
|
-
})
|
|
680
|
-
})
|
|
681
|
-
})
|
|
682
|
-
|
|
683
|
-
return {
|
|
684
|
-
blockChanged: true,
|
|
685
|
-
blockValid: true,
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
debug('Invalid', validation)
|
|
690
|
-
|
|
691
|
-
sendBack({
|
|
692
|
-
type: 'invalid value',
|
|
693
|
-
resolution: validation.resolution,
|
|
694
|
-
value,
|
|
695
|
-
})
|
|
696
|
-
|
|
697
|
-
return {
|
|
698
|
-
blockChanged: false,
|
|
699
|
-
blockValid: false,
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
if (isEqual(block, oldBlock)) {
|
|
704
|
-
// Nothing to sync, skipping the block
|
|
705
|
-
return {
|
|
706
|
-
blockChanged: false,
|
|
707
|
-
blockValid: true,
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
const validationValue = [value[index]]
|
|
712
|
-
const validation = validateValue(
|
|
713
|
-
validationValue,
|
|
714
|
-
context.schema,
|
|
715
|
-
context.keyGenerator,
|
|
716
|
-
)
|
|
717
|
-
|
|
718
|
-
// Resolve validations that can be resolved automatically, without involving the user (but only if the value was changed)
|
|
719
|
-
if (
|
|
720
|
-
!validation.valid &&
|
|
721
|
-
validation.resolution?.autoResolve &&
|
|
722
|
-
validation.resolution?.patches.length > 0
|
|
723
|
-
) {
|
|
724
|
-
// Only apply auto resolution if the value has been populated before and is different from the last one.
|
|
725
|
-
if (
|
|
726
|
-
!context.readOnly &&
|
|
727
|
-
context.previousValue &&
|
|
728
|
-
context.previousValue !== value
|
|
729
|
-
) {
|
|
730
|
-
// Give a console warning about the fact that it did an auto resolution
|
|
731
|
-
console.warn(
|
|
732
|
-
`${validation.resolution.action} for block with _key '${validationValue[0]._key}'. ${validation.resolution?.description}`,
|
|
733
|
-
)
|
|
734
|
-
validation.resolution.patches.forEach((patch) => {
|
|
735
|
-
sendBack({type: 'patch', patch})
|
|
736
|
-
})
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
if (validation.valid || validation.resolution?.autoResolve) {
|
|
741
|
-
if (oldBlock._key === block._key) {
|
|
742
|
-
if (debug.enabled) {
|
|
743
|
-
debug('Updating block', oldBlock, block)
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
747
|
-
withRemoteChanges(slateEditor, () => {
|
|
748
|
-
withoutPatching(slateEditor, () => {
|
|
749
|
-
updateBlock({
|
|
750
|
-
context,
|
|
751
|
-
slateEditor,
|
|
752
|
-
oldBlock,
|
|
753
|
-
block,
|
|
754
|
-
index,
|
|
755
|
-
})
|
|
756
|
-
})
|
|
757
|
-
})
|
|
758
|
-
})
|
|
759
|
-
} else {
|
|
760
|
-
if (debug.enabled) {
|
|
761
|
-
debug('Replacing block', oldBlock, block)
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
Editor.withoutNormalizing(slateEditor, () => {
|
|
765
|
-
withRemoteChanges(slateEditor, () => {
|
|
766
|
-
withoutPatching(slateEditor, () => {
|
|
767
|
-
replaceBlock({
|
|
768
|
-
context,
|
|
769
|
-
slateEditor,
|
|
770
|
-
block,
|
|
771
|
-
index,
|
|
772
|
-
})
|
|
773
|
-
})
|
|
774
|
-
})
|
|
775
|
-
})
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
return {
|
|
779
|
-
blockChanged: true,
|
|
780
|
-
blockValid: true,
|
|
781
|
-
}
|
|
782
|
-
} else {
|
|
783
|
-
sendBack({
|
|
784
|
-
type: 'invalid value',
|
|
785
|
-
resolution: validation.resolution,
|
|
786
|
-
value,
|
|
787
|
-
})
|
|
788
|
-
|
|
789
|
-
return {
|
|
790
|
-
blockChanged: false,
|
|
791
|
-
blockValid: false,
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
function replaceBlock({
|
|
797
|
-
context,
|
|
798
|
-
slateEditor,
|
|
799
|
-
block,
|
|
800
|
-
index,
|
|
801
|
-
}: {
|
|
802
|
-
context: {
|
|
803
|
-
keyGenerator: () => string
|
|
804
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
805
|
-
readOnly: boolean
|
|
806
|
-
schema: EditorSchema
|
|
807
|
-
}
|
|
808
|
-
slateEditor: PortableTextSlateEditor
|
|
809
|
-
block: PortableTextBlock
|
|
810
|
-
index: number
|
|
811
|
-
}) {
|
|
812
|
-
const slateBlock = toSlateBlock(block, {
|
|
813
|
-
schemaTypes: context.schema,
|
|
814
|
-
})
|
|
815
|
-
|
|
816
|
-
// While replacing the block and the current selection focus is on the replaced block,
|
|
817
|
-
// temporarily deselect the editor then optimistically try to restore the selection afterwards.
|
|
818
|
-
const currentSelection = slateEditor.selection
|
|
819
|
-
const selectionFocusOnBlock =
|
|
820
|
-
currentSelection && currentSelection.focus.path[0] === index
|
|
821
|
-
|
|
822
|
-
if (selectionFocusOnBlock) {
|
|
823
|
-
Transforms.deselect(slateEditor)
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
Transforms.removeNodes(slateEditor, {at: [index]})
|
|
827
|
-
Transforms.insertNodes(slateEditor, slateBlock, {at: [index]})
|
|
828
|
-
|
|
829
|
-
slateEditor.onChange()
|
|
830
|
-
|
|
831
|
-
if (selectionFocusOnBlock) {
|
|
832
|
-
Transforms.select(slateEditor, currentSelection)
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
function updateBlock({
|
|
837
|
-
context,
|
|
838
|
-
slateEditor,
|
|
839
|
-
oldBlock,
|
|
840
|
-
block,
|
|
841
|
-
index,
|
|
842
|
-
}: {
|
|
843
|
-
context: {
|
|
844
|
-
keyGenerator: () => string
|
|
845
|
-
previousValue: Array<PortableTextBlock> | undefined
|
|
846
|
-
readOnly: boolean
|
|
847
|
-
schema: EditorSchema
|
|
848
|
-
}
|
|
849
|
-
slateEditor: PortableTextSlateEditor
|
|
850
|
-
oldBlock: Descendant
|
|
851
|
-
block: PortableTextBlock
|
|
852
|
-
index: number
|
|
853
|
-
}) {
|
|
854
|
-
const slateBlock = toSlateBlock(block, {
|
|
855
|
-
schemaTypes: context.schema,
|
|
856
|
-
})
|
|
857
|
-
|
|
858
|
-
// Update the root props on the block
|
|
859
|
-
Transforms.setNodes(slateEditor, slateBlock as Partial<Node>, {
|
|
860
|
-
at: [index],
|
|
861
|
-
})
|
|
862
|
-
|
|
863
|
-
// Text block's need to have their children updated as well (setNode does not target a node's children)
|
|
864
|
-
if (
|
|
865
|
-
slateEditor.isTextBlock(slateBlock) &&
|
|
866
|
-
slateEditor.isTextBlock(oldBlock)
|
|
867
|
-
) {
|
|
868
|
-
const oldBlockChildrenLength = oldBlock.children.length
|
|
869
|
-
if (slateBlock.children.length < oldBlockChildrenLength) {
|
|
870
|
-
// Remove any children that have become superfluous
|
|
871
|
-
Array.from(
|
|
872
|
-
Array(oldBlockChildrenLength - slateBlock.children.length),
|
|
873
|
-
).forEach((_, index) => {
|
|
874
|
-
const childIndex = oldBlockChildrenLength - 1 - index
|
|
875
|
-
|
|
876
|
-
if (childIndex > 0) {
|
|
877
|
-
debug('Removing child')
|
|
878
|
-
|
|
879
|
-
Transforms.removeNodes(slateEditor, {
|
|
880
|
-
at: [index, childIndex],
|
|
881
|
-
})
|
|
882
|
-
}
|
|
883
|
-
})
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
slateBlock.children.forEach((currentBlockChild, currentBlockChildIndex) => {
|
|
887
|
-
const oldBlockChild = oldBlock.children[currentBlockChildIndex]
|
|
888
|
-
const isChildChanged = !isEqual(currentBlockChild, oldBlockChild)
|
|
889
|
-
const isTextChanged = !isEqual(
|
|
890
|
-
currentBlockChild.text,
|
|
891
|
-
oldBlockChild?.text,
|
|
892
|
-
)
|
|
893
|
-
const path = [index, currentBlockChildIndex]
|
|
894
|
-
|
|
895
|
-
if (isChildChanged) {
|
|
896
|
-
// Update if this is the same child
|
|
897
|
-
if (currentBlockChild._key === oldBlockChild?._key) {
|
|
898
|
-
debug('Updating changed child', currentBlockChild, oldBlockChild)
|
|
899
|
-
|
|
900
|
-
Transforms.setNodes(slateEditor, currentBlockChild as Partial<Node>, {
|
|
901
|
-
at: path,
|
|
902
|
-
})
|
|
903
|
-
|
|
904
|
-
const isSpanNode =
|
|
905
|
-
isSpan({schema: context.schema}, currentBlockChild) &&
|
|
906
|
-
isSpan({schema: context.schema}, oldBlockChild)
|
|
907
|
-
|
|
908
|
-
if (isSpanNode && isTextChanged) {
|
|
909
|
-
if (oldBlockChild.text.length > 0) {
|
|
910
|
-
deleteText(slateEditor, {
|
|
911
|
-
at: {
|
|
912
|
-
focus: {path, offset: 0},
|
|
913
|
-
anchor: {path, offset: oldBlockChild.text.length},
|
|
914
|
-
},
|
|
915
|
-
})
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
Transforms.insertText(slateEditor, currentBlockChild.text, {
|
|
919
|
-
at: path,
|
|
920
|
-
})
|
|
921
|
-
|
|
922
|
-
slateEditor.onChange()
|
|
923
|
-
} else if (!isSpanNode) {
|
|
924
|
-
// If it's a inline block, also update the void text node key
|
|
925
|
-
debug('Updating changed inline object child', currentBlockChild)
|
|
926
|
-
|
|
927
|
-
Transforms.setNodes(
|
|
928
|
-
slateEditor,
|
|
929
|
-
{_key: VOID_CHILD_KEY},
|
|
930
|
-
{
|
|
931
|
-
at: [...path, 0],
|
|
932
|
-
voids: true,
|
|
933
|
-
},
|
|
934
|
-
)
|
|
935
|
-
}
|
|
936
|
-
} else if (oldBlockChild) {
|
|
937
|
-
// Replace the child if _key's are different
|
|
938
|
-
debug('Replacing child', currentBlockChild)
|
|
939
|
-
|
|
940
|
-
Transforms.removeNodes(slateEditor, {
|
|
941
|
-
at: [index, currentBlockChildIndex],
|
|
942
|
-
})
|
|
943
|
-
Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
|
|
944
|
-
at: [index, currentBlockChildIndex],
|
|
945
|
-
})
|
|
946
|
-
|
|
947
|
-
slateEditor.onChange()
|
|
948
|
-
} else if (!oldBlockChild) {
|
|
949
|
-
// Insert it if it didn't exist before
|
|
950
|
-
debug('Inserting new child', currentBlockChild)
|
|
951
|
-
|
|
952
|
-
Transforms.insertNodes(slateEditor, currentBlockChild as Node, {
|
|
953
|
-
at: [index, currentBlockChildIndex],
|
|
954
|
-
})
|
|
955
|
-
|
|
956
|
-
slateEditor.onChange()
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
})
|
|
960
|
-
}
|
|
961
|
-
}
|