@portabletext/editor 2.13.2 → 2.13.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-cjs/{selector.is-selection-expanded.cjs → selector.get-selection-text.cjs} +25 -25
- package/lib/_chunks-cjs/selector.get-selection-text.cjs.map +1 -0
- package/lib/_chunks-cjs/selector.get-text-before.cjs +4 -4
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/{selector.is-selecting-entire-blocks.cjs → selector.is-active-style.cjs} +408 -399
- package/lib/_chunks-cjs/selector.is-active-style.cjs.map +1 -0
- package/lib/_chunks-cjs/util.child-selection-point-to-block-offset.cjs +3 -3
- package/lib/_chunks-cjs/util.child-selection-point-to-block-offset.cjs.map +1 -1
- package/lib/_chunks-cjs/{util.slice-blocks.cjs → util.get-text-block-text.cjs} +25 -26
- package/lib/_chunks-cjs/util.get-text-block-text.cjs.map +1 -0
- package/lib/_chunks-cjs/{util.is-selection-collapsed.cjs → util.is-empty-text-block.cjs} +9 -9
- package/lib/_chunks-cjs/util.is-empty-text-block.cjs.map +1 -0
- package/lib/_chunks-cjs/util.merge-text-blocks.cjs +2 -2
- package/lib/_chunks-cjs/util.merge-text-blocks.cjs.map +1 -1
- package/lib/_chunks-cjs/util.slice-text-block.cjs +5 -5
- package/lib/_chunks-cjs/util.slice-text-block.cjs.map +1 -1
- package/lib/_chunks-dts/behavior.types.action.d.cts +270 -270
- package/lib/_chunks-dts/behavior.types.action.d.ts +273 -273
- package/lib/_chunks-es/{selector.is-selection-expanded.js → selector.get-selection-text.js} +20 -20
- package/lib/_chunks-es/selector.get-selection-text.js.map +1 -0
- package/lib/_chunks-es/selector.get-text-before.js +2 -2
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
- package/lib/_chunks-es/{selector.is-selecting-entire-blocks.js → selector.is-active-style.js} +385 -376
- package/lib/_chunks-es/selector.is-active-style.js.map +1 -0
- package/lib/_chunks-es/util.child-selection-point-to-block-offset.js +1 -1
- package/lib/_chunks-es/util.child-selection-point-to-block-offset.js.map +1 -1
- package/lib/_chunks-es/{util.slice-blocks.js → util.get-text-block-text.js} +25 -26
- package/lib/_chunks-es/util.get-text-block-text.js.map +1 -0
- package/lib/_chunks-es/{util.is-selection-collapsed.js → util.is-empty-text-block.js} +8 -8
- package/lib/_chunks-es/util.is-empty-text-block.js.map +1 -0
- package/lib/_chunks-es/util.merge-text-blocks.js +1 -1
- package/lib/_chunks-es/util.merge-text-blocks.js.map +1 -1
- package/lib/_chunks-es/util.slice-text-block.js +1 -1
- package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
- package/lib/index.cjs +429 -363
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +225 -159
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.cjs +21 -21
- package/lib/plugins/index.cjs.map +1 -1
- package/lib/plugins/index.d.cts +4 -4
- package/lib/plugins/index.d.ts +4 -4
- package/lib/plugins/index.js +3 -3
- package/lib/plugins/index.js.map +1 -1
- package/lib/selectors/index.cjs +52 -52
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +4 -1
- package/lib/selectors/index.d.ts +4 -1
- package/lib/selectors/index.js +5 -5
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.cjs +14 -14
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.ts +2 -2
- package/lib/utils/index.js +3 -3
- package/lib/utils/index.js.map +1 -1
- package/package.json +12 -12
- package/src/behaviors/behavior.abstract.annotation.ts +3 -3
- package/src/behaviors/behavior.abstract.decorator.ts +2 -2
- package/src/behaviors/behavior.abstract.delete.ts +25 -16
- package/src/behaviors/behavior.abstract.deserialize.ts +4 -3
- package/src/behaviors/behavior.abstract.insert.ts +6 -7
- package/src/behaviors/behavior.abstract.keyboard.ts +7 -8
- package/src/behaviors/behavior.abstract.list-item.ts +2 -1
- package/src/behaviors/behavior.abstract.move.ts +2 -1
- package/src/behaviors/behavior.abstract.select.ts +4 -2
- package/src/behaviors/behavior.abstract.split.ts +33 -24
- package/src/behaviors/behavior.abstract.style.ts +2 -1
- package/src/behaviors/behavior.abstract.ts +8 -7
- package/src/behaviors/behavior.core.annotations.ts +8 -7
- package/src/behaviors/behavior.core.block-element.ts +7 -5
- package/src/behaviors/behavior.core.block-objects.ts +25 -27
- package/src/behaviors/behavior.core.dnd.ts +10 -8
- package/src/behaviors/behavior.core.insert-break.ts +45 -36
- package/src/behaviors/behavior.core.lists.ts +31 -25
- package/src/behaviors/behavior.decorator-pair.ts +26 -23
- package/src/behaviors/behavior.markdown.ts +26 -21
- package/src/converters/converter.portable-text.ts +3 -3
- package/src/converters/converter.text-html.serialize.test.ts +1 -1
- package/src/converters/converter.text-html.ts +3 -3
- package/src/converters/converter.text-plain.test.ts +1 -1
- package/src/converters/converter.text-plain.ts +3 -3
- package/src/editor/Editable.tsx +18 -78
- package/src/editor/components/render-span.tsx +3 -5
- package/src/editor/create-editor.ts +2 -2
- package/src/editor/create-slate-editor.tsx +1 -4
- package/src/editor/editor-dom.ts +2 -2
- package/src/editor/plugins/createWithEditableAPI.ts +5 -10
- package/src/editor/plugins/createWithMaxBlocks.ts +2 -2
- package/src/editor/plugins/createWithObjectKeys.ts +2 -2
- package/src/editor/plugins/createWithPatches.ts +3 -10
- package/src/editor/plugins/createWithPlaceholderBlock.ts +2 -2
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +2 -2
- package/src/editor/plugins/createWithSchemaTypes.ts +1 -1
- package/src/editor/plugins/createWithUndoRedo.ts +6 -6
- package/src/editor/plugins/slate-plugin.update-selection.ts +1 -1
- package/src/editor/sync-machine.ts +2 -5
- package/src/editor/validate-selection-machine.test.ts +47 -0
- package/src/editor/validate-selection-machine.ts +149 -0
- package/src/{internal-utils → editor}/weakMaps.ts +1 -1
- package/src/editor/with-undo-step.ts +1 -1
- package/src/index.ts +1 -1
- package/src/internal-utils/applyPatch.ts +2 -2
- package/src/internal-utils/build-index-maps.test.ts +1 -1
- package/src/internal-utils/create-test-snapshot.ts +1 -1
- package/src/internal-utils/event-position.ts +11 -9
- package/src/internal-utils/operation-to-patches.test.ts +1 -1
- package/src/internal-utils/portable-text-node.ts +1 -1
- package/src/internal-utils/selection-block-keys.ts +1 -1
- package/src/internal-utils/selection-focus-text.ts +1 -1
- package/src/internal-utils/to-slate-range.ts +4 -4
- package/src/operations/behavior.operation.annotation.add.ts +1 -1
- package/src/operations/behavior.operation.block.set.ts +1 -1
- package/src/operations/behavior.operation.block.unset.ts +2 -2
- package/src/operations/behavior.operation.decorator.add.ts +11 -9
- package/src/operations/behavior.operation.delete.ts +1 -1
- package/src/operations/behavior.operation.insert.block.ts +2 -2
- package/src/operations/behavior.operation.insert.child.ts +1 -1
- package/src/operations/behavior.operation.move.block.ts +1 -1
- package/src/plugins/plugin.behavior.tsx +1 -1
- package/src/plugins/plugin.decorator-shortcut.ts +3 -3
- package/src/plugins/plugin.internal.auto-close-brackets.ts +2 -1
- package/src/plugins/plugin.one-line.tsx +11 -11
- package/src/priority/priority.types.ts +1 -1
- package/src/{internal-utils → selectors}/drag-selection.test.ts +1 -1
- package/src/{internal-utils → selectors}/drag-selection.ts +26 -19
- package/src/selectors/index.ts +1 -1
- package/src/selectors/selector.get-anchor-block.ts +1 -1
- package/src/selectors/selector.get-anchor-child.ts +1 -1
- package/src/selectors/selector.get-block-offsets.ts +3 -3
- package/src/selectors/selector.get-caret-word-selection.test.ts +1 -1
- package/src/selectors/selector.get-focus-block.ts +1 -1
- package/src/selectors/selector.get-focus-child.ts +1 -1
- package/src/selectors/selector.get-focus-list-block.ts +1 -1
- package/src/selectors/selector.get-list-state.test.ts +1 -1
- package/src/selectors/selector.get-mark-state.ts +4 -1
- package/src/selectors/selector.get-next-inline-object.ts +1 -1
- package/src/selectors/selector.get-next-span.ts +1 -1
- package/src/selectors/selector.get-previous-inline-object.ts +1 -1
- package/src/selectors/selector.get-previous-span.ts +1 -1
- package/src/selectors/selector.get-selected-blocks.ts +1 -1
- package/src/selectors/selector.get-selected-spans.test.ts +1 -1
- package/src/selectors/selector.get-selected-spans.ts +2 -2
- package/src/selectors/selector.get-selected-text-blocks.ts +3 -2
- package/src/selectors/selector.get-selected-value.test.ts +87 -1
- package/src/selectors/selector.get-selected-value.ts +4 -6
- package/src/selectors/selector.get-selection-end-point.ts +1 -1
- package/src/selectors/selector.get-selection-start-point.ts +1 -1
- package/src/selectors/selector.get-selection-text.test.ts +1 -1
- package/src/selectors/selector.get-selection.ts +1 -1
- package/src/selectors/selector.get-text-before.ts +1 -1
- package/src/selectors/selector.get-trimmed-selection.test.ts +1 -1
- package/src/selectors/selector.get-trimmed-selection.ts +5 -7
- package/src/selectors/selector.is-active-decorator.test.ts +2 -1
- package/src/selectors/selector.is-at-the-end-of-block.ts +4 -3
- package/src/selectors/selector.is-at-the-start-of-block.ts +4 -3
- package/src/selectors/selector.is-overlapping-selection.test.ts +1 -1
- package/src/selectors/selector.is-overlapping-selection.ts +1 -1
- package/src/selectors/selector.is-point-after-selection.ts +3 -3
- package/src/selectors/selector.is-point-before-selection.ts +3 -3
- package/src/selectors/selector.is-selecting-entire-blocks.ts +7 -5
- package/src/test/gherkin-parameter-types.ts +1 -1
- package/src/test/vitest/step-definitions.tsx +19 -9
- package/src/types/paths.ts +4 -1
- package/src/utils/util.at-the-beginning-of-block.ts +1 -1
- package/src/utils/util.block-offset.ts +4 -4
- package/src/utils/util.block-offsets-to-selection.ts +1 -1
- package/src/utils/util.child-selection-point-to-block-offset.ts +3 -3
- package/src/utils/util.get-selection-end-point.ts +1 -1
- package/src/utils/util.get-selection-start-point.ts +1 -1
- package/src/utils/util.merge-text-blocks.ts +2 -2
- package/src/utils/util.selection-point-to-block-offset.ts +1 -1
- package/src/{selection/selection-point.ts → utils/util.selection-point.ts} +1 -1
- package/src/utils/util.slice-blocks.ts +6 -6
- package/src/utils/util.slice-text-block.test.ts +3 -1
- package/src/utils/util.slice-text-block.ts +3 -3
- package/src/utils/util.split-text-block.ts +1 -1
- package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +0 -1
- package/lib/_chunks-cjs/selector.is-selection-expanded.cjs.map +0 -1
- package/lib/_chunks-cjs/util.is-selection-collapsed.cjs.map +0 -1
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +0 -1
- package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +0 -1
- package/lib/_chunks-es/selector.is-selection-expanded.js.map +0 -1
- package/lib/_chunks-es/util.is-selection-collapsed.js.map +0 -1
- package/lib/_chunks-es/util.slice-blocks.js.map +0 -1
- /package/src/{internal-utils → editor}/withChanges.ts +0 -0
- /package/src/{internal-utils → editor}/withUndoRedo.ts +0 -0
- /package/src/{internal-utils → editor}/withoutPatching.ts +0 -0
- /package/src/{internal-utils → utils}/asserters.ts +0 -0
- /package/src/{editor → utils}/key-generator.ts +0 -0
- /package/src/{internal-utils → utils}/parse-blocks.test.ts +0 -0
- /package/src/{internal-utils → utils}/parse-blocks.ts +0 -0
|
@@ -26,18 +26,12 @@ import {
|
|
|
26
26
|
} from '../../internal-utils/slate-utils'
|
|
27
27
|
import {toSlateRange} from '../../internal-utils/to-slate-range'
|
|
28
28
|
import {fromSlateValue, toSlateValue} from '../../internal-utils/values'
|
|
29
|
-
import {
|
|
30
|
-
KEY_TO_VALUE_ELEMENT,
|
|
31
|
-
SLATE_TO_PORTABLE_TEXT_RANGE,
|
|
32
|
-
} from '../../internal-utils/weakMaps'
|
|
33
|
-
import {
|
|
34
|
-
getFocusBlock,
|
|
35
|
-
getFocusSpan,
|
|
36
|
-
getSelectedValue,
|
|
37
|
-
isActiveAnnotation,
|
|
38
|
-
} from '../../selectors'
|
|
39
29
|
import {getActiveAnnotationsMarks} from '../../selectors/selector.get-active-annotation-marks'
|
|
40
30
|
import {getActiveDecorators} from '../../selectors/selector.get-active-decorators'
|
|
31
|
+
import {getFocusBlock} from '../../selectors/selector.get-focus-block'
|
|
32
|
+
import {getFocusSpan} from '../../selectors/selector.get-focus-span'
|
|
33
|
+
import {getSelectedValue} from '../../selectors/selector.get-selected-value'
|
|
34
|
+
import {isActiveAnnotation} from '../../selectors/selector.is-active-annotation'
|
|
41
35
|
import type {
|
|
42
36
|
EditableAPI,
|
|
43
37
|
EditableAPIDeleteOptions,
|
|
@@ -46,6 +40,7 @@ import type {
|
|
|
46
40
|
} from '../../types/editor'
|
|
47
41
|
import type {EditorActor} from '../editor-machine'
|
|
48
42
|
import {getEditorSnapshot} from '../editor-selector'
|
|
43
|
+
import {KEY_TO_VALUE_ELEMENT, SLATE_TO_PORTABLE_TEXT_RANGE} from '../weakMaps'
|
|
49
44
|
|
|
50
45
|
const debug = debugWithName('API:editable')
|
|
51
46
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {isChangingRemotely} from '../../internal-utils/withChanges'
|
|
2
|
-
import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
|
|
3
1
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
4
2
|
import type {EditorActor} from '../editor-machine'
|
|
3
|
+
import {isChangingRemotely} from '../withChanges'
|
|
4
|
+
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* This plugin makes sure that the PTE maxBlocks prop is respected
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {isSpan, isTextBlock} from '@portabletext/schema'
|
|
2
2
|
import {isEqual} from 'lodash'
|
|
3
3
|
import {Editor, Element, Node, Path, Transforms} from 'slate'
|
|
4
|
-
import {isChangingRemotely} from '../../internal-utils/withChanges'
|
|
5
|
-
import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
|
|
6
4
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
7
5
|
import type {EditorActor} from '../editor-machine'
|
|
6
|
+
import {isChangingRemotely} from '../withChanges'
|
|
7
|
+
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* This plugin makes sure that every new node in the editor get a new _key prop when created
|
|
@@ -13,20 +13,13 @@ import {
|
|
|
13
13
|
splitNodePatch,
|
|
14
14
|
} from '../../internal-utils/operation-to-patches'
|
|
15
15
|
import {fromSlateValue, isEqualToEmptyEditor} from '../../internal-utils/values'
|
|
16
|
-
import {
|
|
17
|
-
IS_PROCESSING_REMOTE_CHANGES,
|
|
18
|
-
KEY_TO_VALUE_ELEMENT,
|
|
19
|
-
} from '../../internal-utils/weakMaps'
|
|
20
|
-
import {withRemoteChanges} from '../../internal-utils/withChanges'
|
|
21
|
-
import {
|
|
22
|
-
isPatching,
|
|
23
|
-
PATCHING,
|
|
24
|
-
withoutPatching,
|
|
25
|
-
} from '../../internal-utils/withoutPatching'
|
|
26
16
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
27
17
|
import type {EditorActor} from '../editor-machine'
|
|
28
18
|
import type {RelayActor} from '../relay-machine'
|
|
19
|
+
import {IS_PROCESSING_REMOTE_CHANGES, KEY_TO_VALUE_ELEMENT} from '../weakMaps'
|
|
29
20
|
import {getCurrentUndoStepId} from '../with-undo-step'
|
|
21
|
+
import {withRemoteChanges} from '../withChanges'
|
|
22
|
+
import {isPatching, PATCHING, withoutPatching} from '../withoutPatching'
|
|
30
23
|
import {withoutSaving} from './createWithUndoRedo'
|
|
31
24
|
|
|
32
25
|
const debug = debugWithName('plugin:withPatches')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {Editor} from 'slate'
|
|
2
2
|
import {debugWithName} from '../../internal-utils/debug'
|
|
3
|
-
import {isChangingRemotely} from '../../internal-utils/withChanges'
|
|
4
|
-
import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
|
|
5
3
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
6
4
|
import type {EditorActor} from '../editor-machine'
|
|
5
|
+
import {isChangingRemotely} from '../withChanges'
|
|
6
|
+
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
7
7
|
|
|
8
8
|
const debug = debugWithName('plugin:withPlaceholderBlock')
|
|
9
9
|
|
|
@@ -10,14 +10,14 @@ import {isEqual, uniq} from 'lodash'
|
|
|
10
10
|
import {Editor, Element, Node, Path, Range, Text, Transforms} from 'slate'
|
|
11
11
|
import {debugWithName} from '../../internal-utils/debug'
|
|
12
12
|
import {getNextSpan, getPreviousSpan} from '../../internal-utils/sibling-utils'
|
|
13
|
-
import {isChangingRemotely} from '../../internal-utils/withChanges'
|
|
14
|
-
import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
|
|
15
13
|
import type {BehaviorOperationImplementation} from '../../operations/behavior.operations'
|
|
16
14
|
import {getActiveDecorators} from '../../selectors/selector.get-active-decorators'
|
|
17
15
|
import {getMarkState} from '../../selectors/selector.get-mark-state'
|
|
18
16
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
19
17
|
import type {EditorActor} from '../editor-machine'
|
|
20
18
|
import {getEditorSnapshot} from '../editor-selector'
|
|
19
|
+
import {isChangingRemotely} from '../withChanges'
|
|
20
|
+
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
21
21
|
|
|
22
22
|
const debug = debugWithName('plugin:withPortableTextMarkModel')
|
|
23
23
|
|
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
} from '@sanity/types'
|
|
7
7
|
import {Editor, Transforms, type Element} from 'slate'
|
|
8
8
|
import {debugWithName} from '../../internal-utils/debug'
|
|
9
|
-
import {isListBlock} from '../../internal-utils/parse-blocks'
|
|
10
9
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
10
|
+
import {isListBlock} from '../../utils/parse-blocks'
|
|
11
11
|
import type {EditorActor} from '../editor-machine'
|
|
12
12
|
|
|
13
13
|
const debug = debugWithName('plugin:withSchemaTypes')
|
|
@@ -22,7 +22,11 @@ import {
|
|
|
22
22
|
} from 'slate'
|
|
23
23
|
import {debugWithName} from '../../internal-utils/debug'
|
|
24
24
|
import {fromSlateValue} from '../../internal-utils/values'
|
|
25
|
-
import {
|
|
25
|
+
import type {BehaviorOperationImplementation} from '../../operations/behavior.operations'
|
|
26
|
+
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
27
|
+
import type {EditorActor} from '../editor-machine'
|
|
28
|
+
import {getCurrentUndoStepId} from '../with-undo-step'
|
|
29
|
+
import {isChangingRemotely} from '../withChanges'
|
|
26
30
|
import {
|
|
27
31
|
isRedoing,
|
|
28
32
|
isUndoing,
|
|
@@ -30,11 +34,7 @@ import {
|
|
|
30
34
|
setIsUndoing,
|
|
31
35
|
withRedoing,
|
|
32
36
|
withUndoing,
|
|
33
|
-
} from '
|
|
34
|
-
import type {BehaviorOperationImplementation} from '../../operations/behavior.operations'
|
|
35
|
-
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
36
|
-
import type {EditorActor} from '../editor-machine'
|
|
37
|
-
import {getCurrentUndoStepId} from '../with-undo-step'
|
|
37
|
+
} from '../withUndoRedo'
|
|
38
38
|
|
|
39
39
|
const debug = debugWithName('plugin:withUndoRedo')
|
|
40
40
|
const debugVerbose = debug.enabled && false
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {slateRangeToSelection} from '../../internal-utils/slate-utils'
|
|
2
|
-
import {SLATE_TO_PORTABLE_TEXT_RANGE} from '../../internal-utils/weakMaps'
|
|
3
2
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
4
3
|
import type {EditorActor} from '../editor-machine'
|
|
4
|
+
import {SLATE_TO_PORTABLE_TEXT_RANGE} from '../weakMaps'
|
|
5
5
|
|
|
6
6
|
export function pluginUpdateSelection({
|
|
7
7
|
editor,
|
|
@@ -25,11 +25,6 @@ import type {ActorRefFrom} from 'xstate'
|
|
|
25
25
|
import {debugWithName} from '../internal-utils/debug'
|
|
26
26
|
import {validateValue} from '../internal-utils/validateValue'
|
|
27
27
|
import {toSlateValue, VOID_CHILD_KEY} from '../internal-utils/values'
|
|
28
|
-
import {
|
|
29
|
-
isChangingRemotely,
|
|
30
|
-
withRemoteChanges,
|
|
31
|
-
} from '../internal-utils/withChanges'
|
|
32
|
-
import {withoutPatching} from '../internal-utils/withoutPatching'
|
|
33
28
|
import type {PickFromUnion} from '../type-utils'
|
|
34
29
|
import type {
|
|
35
30
|
InvalidValueResolution,
|
|
@@ -37,6 +32,8 @@ import type {
|
|
|
37
32
|
} from '../types/editor'
|
|
38
33
|
import type {EditorSchema} from './editor-schema'
|
|
39
34
|
import {withoutSaving} from './plugins/createWithUndoRedo'
|
|
35
|
+
import {isChangingRemotely, withRemoteChanges} from './withChanges'
|
|
36
|
+
import {withoutPatching} from './withoutPatching'
|
|
40
37
|
|
|
41
38
|
const debug = debugWithName('sync machine')
|
|
42
39
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {getTersePt} from '@portabletext/test'
|
|
2
|
+
import {userEvent} from '@vitest/browser/context'
|
|
3
|
+
import {describe, expect, test, vi} from 'vitest'
|
|
4
|
+
import {getSelectionAfterText} from '../internal-utils/text-selection'
|
|
5
|
+
import {createTestEditor} from '../test/vitest'
|
|
6
|
+
import {validateSelectionMachine} from './validate-selection-machine'
|
|
7
|
+
|
|
8
|
+
describe(validateSelectionMachine.id, () => {
|
|
9
|
+
test('Scenario: Does not validate selection while Slate has pending operations', async () => {
|
|
10
|
+
const {editor, locator} = await createTestEditor()
|
|
11
|
+
|
|
12
|
+
await userEvent.click(locator)
|
|
13
|
+
|
|
14
|
+
editor.send({type: 'insert.text', text: 'foo'})
|
|
15
|
+
|
|
16
|
+
await vi.waitFor(() => {
|
|
17
|
+
expect(getTersePt(editor.getSnapshot().context)).toEqual(['foo'])
|
|
18
|
+
expect(editor.getSnapshot().context.selection).toEqual(
|
|
19
|
+
getSelectionAfterText(editor.getSnapshot().context, 'foo'),
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// This event is being sent in before "foo" has been inserted in the DOM
|
|
24
|
+
// This means that when the MutationObserver is finally triggered for the
|
|
25
|
+
// "foo" insertion, "bar" will be in the Slate state but not in the DOM.
|
|
26
|
+
// This causes the selection to be out of sync and this is why we need to
|
|
27
|
+
// make sure the selection is not validated before Slate has committed all
|
|
28
|
+
// pending operations.
|
|
29
|
+
editor.send({type: 'insert.text', text: 'bar'})
|
|
30
|
+
|
|
31
|
+
await vi.waitFor(() => {
|
|
32
|
+
expect(getTersePt(editor.getSnapshot().context)).toEqual(['foobar'])
|
|
33
|
+
expect(editor.getSnapshot().context.selection).toEqual(
|
|
34
|
+
getSelectionAfterText(editor.getSnapshot().context, 'foobar'),
|
|
35
|
+
)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
editor.send({type: 'delete.backward', unit: 'character'})
|
|
39
|
+
|
|
40
|
+
await vi.waitFor(() => {
|
|
41
|
+
expect(getTersePt(editor.getSnapshot().context)).toEqual(['fooba'])
|
|
42
|
+
expect(editor.getSnapshot().context.selection).toEqual(
|
|
43
|
+
getSelectionAfterText(editor.getSnapshot().context, 'fooba'),
|
|
44
|
+
)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
})
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {Editor, Transforms} from 'slate'
|
|
2
|
+
import {ReactEditor} from 'slate-react'
|
|
3
|
+
import {setup} from 'xstate'
|
|
4
|
+
import {debugWithName} from '../internal-utils/debug'
|
|
5
|
+
import type {PortableTextSlateEditor} from '../types/editor'
|
|
6
|
+
|
|
7
|
+
const debug = debugWithName('validate selection machine')
|
|
8
|
+
|
|
9
|
+
const validateSelectionSetup = setup({
|
|
10
|
+
types: {
|
|
11
|
+
context: {} as {
|
|
12
|
+
slateEditor: PortableTextSlateEditor
|
|
13
|
+
},
|
|
14
|
+
input: {} as {
|
|
15
|
+
slateEditor: PortableTextSlateEditor
|
|
16
|
+
},
|
|
17
|
+
events: {} as {
|
|
18
|
+
type: 'validate selection'
|
|
19
|
+
editorElement: HTMLDivElement
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
guards: {
|
|
23
|
+
'pending operations': ({context}) =>
|
|
24
|
+
context.slateEditor.operations.length > 0,
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const validateSelectionAction = validateSelectionSetup.createAction(
|
|
29
|
+
({context, event}) => {
|
|
30
|
+
validateSelection(context.slateEditor, event.editorElement)
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
export const validateSelectionMachine = validateSelectionSetup.createMachine({
|
|
35
|
+
id: 'validate selection',
|
|
36
|
+
context: ({input}) => ({
|
|
37
|
+
slateEditor: input.slateEditor,
|
|
38
|
+
}),
|
|
39
|
+
initial: 'idle',
|
|
40
|
+
states: {
|
|
41
|
+
idle: {
|
|
42
|
+
on: {
|
|
43
|
+
'validate selection': [
|
|
44
|
+
{
|
|
45
|
+
guard: 'pending operations',
|
|
46
|
+
target: 'waiting',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
actions: [validateSelectionAction],
|
|
50
|
+
target: 'idle',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
waiting: {
|
|
56
|
+
after: {
|
|
57
|
+
0: [
|
|
58
|
+
{
|
|
59
|
+
guard: 'pending operations',
|
|
60
|
+
target: '.',
|
|
61
|
+
reenter: true,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
target: 'idle',
|
|
65
|
+
actions: [validateSelectionAction],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
on: {
|
|
70
|
+
'validate selection': {
|
|
71
|
+
target: '.',
|
|
72
|
+
reenter: true,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// This function will handle unexpected DOM changes inside the Editable rendering,
|
|
80
|
+
// and make sure that we can maintain a stable slateEditor.selection when that happens.
|
|
81
|
+
//
|
|
82
|
+
// For example, if this Editable is rendered inside something that might re-render
|
|
83
|
+
// this component (hidden contexts) while the user is still actively changing the
|
|
84
|
+
// contentEditable, this could interfere with the intermediate DOM selection,
|
|
85
|
+
// which again could be picked up by ReactEditor's event listeners.
|
|
86
|
+
// If that range is invalid at that point, the slate.editorSelection could be
|
|
87
|
+
// set either wrong, or invalid, to which slateEditor will throw exceptions
|
|
88
|
+
// that are impossible to recover properly from or result in a wrong selection.
|
|
89
|
+
//
|
|
90
|
+
// Also the other way around, when the ReactEditor will try to create a DOM Range
|
|
91
|
+
// from the current slateEditor.selection, it may throw unrecoverable errors
|
|
92
|
+
// if the current editor.selection is invalid according to the DOM.
|
|
93
|
+
// If this is the case, default to selecting the top of the document, if the
|
|
94
|
+
// user already had a selection.
|
|
95
|
+
function validateSelection(
|
|
96
|
+
slateEditor: PortableTextSlateEditor,
|
|
97
|
+
editorElement: HTMLDivElement,
|
|
98
|
+
) {
|
|
99
|
+
if (!slateEditor.selection) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let root: Document | ShadowRoot | undefined
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
root = ReactEditor.findDocumentOrShadowRoot(slateEditor)
|
|
107
|
+
} catch {}
|
|
108
|
+
|
|
109
|
+
if (!root) {
|
|
110
|
+
// The editor has most likely been unmounted
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Return if the editor isn't the active element
|
|
115
|
+
if (editorElement !== root.activeElement) {
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
const window = ReactEditor.getWindow(slateEditor)
|
|
119
|
+
const domSelection = window.getSelection()
|
|
120
|
+
if (!domSelection || domSelection.rangeCount === 0) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
const existingDOMRange = domSelection.getRangeAt(0)
|
|
124
|
+
try {
|
|
125
|
+
const newDOMRange = ReactEditor.toDOMRange(
|
|
126
|
+
slateEditor,
|
|
127
|
+
slateEditor.selection,
|
|
128
|
+
)
|
|
129
|
+
if (
|
|
130
|
+
newDOMRange.startOffset !== existingDOMRange.startOffset ||
|
|
131
|
+
newDOMRange.endOffset !== existingDOMRange.endOffset
|
|
132
|
+
) {
|
|
133
|
+
debug('DOM range out of sync, validating selection')
|
|
134
|
+
// Remove all ranges temporary
|
|
135
|
+
domSelection?.removeAllRanges()
|
|
136
|
+
// Set the correct range
|
|
137
|
+
domSelection.addRange(newDOMRange)
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
debug(`Could not resolve selection, selecting top document`)
|
|
141
|
+
// Deselect the editor
|
|
142
|
+
Transforms.deselect(slateEditor)
|
|
143
|
+
// Select top document if there is a top block to select
|
|
144
|
+
if (slateEditor.children.length > 0) {
|
|
145
|
+
Transforms.select(slateEditor, Editor.start(slateEditor, []))
|
|
146
|
+
}
|
|
147
|
+
slateEditor.onChange()
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {Editor, Range} from 'slate'
|
|
2
|
-
import type {EditorSelection} from '
|
|
2
|
+
import type {EditorSelection} from '../types/editor'
|
|
3
3
|
|
|
4
4
|
// Is the editor currently receiving remote changes that are being applied to the content?
|
|
5
5
|
export const IS_PROCESSING_REMOTE_CHANGES: WeakMap<Editor, boolean> =
|
package/src/index.ts
CHANGED
|
@@ -40,7 +40,7 @@ export {useEditorSelector, type EditorSelector} from './editor/editor-selector'
|
|
|
40
40
|
export type {EditorContext, EditorSnapshot} from './editor/editor-snapshot'
|
|
41
41
|
export {usePortableTextEditor} from './editor/hooks/usePortableTextEditor'
|
|
42
42
|
export {usePortableTextEditorSelection} from './editor/hooks/usePortableTextEditorSelection'
|
|
43
|
-
export {defaultKeyGenerator as keyGenerator} from './
|
|
43
|
+
export {defaultKeyGenerator as keyGenerator} from './utils/key-generator'
|
|
44
44
|
export {PortableTextEditor} from './editor/PortableTextEditor'
|
|
45
45
|
export type {PortableTextEditorProps} from './editor/PortableTextEditor'
|
|
46
46
|
export type {EditorEmittedEvent, MutationEvent} from './editor/relay-machine'
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
import type {Path, PortableTextBlock, PortableTextChild} from '@sanity/types'
|
|
19
19
|
import {Element, Node, Text, Transforms, type Descendant} from 'slate'
|
|
20
20
|
import type {EditorSchema} from '../editor/editor-schema'
|
|
21
|
+
import {KEY_TO_SLATE_ELEMENT} from '../editor/weakMaps'
|
|
21
22
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
22
|
-
import {isKeyedSegment} from '../utils'
|
|
23
|
+
import {isKeyedSegment} from '../utils/util.is-keyed-segment'
|
|
23
24
|
import {isEqualToEmptyEditor, toSlateValue} from './values'
|
|
24
|
-
import {KEY_TO_SLATE_ELEMENT} from './weakMaps'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Creates a function that can apply a patch onto a PortableTextSlateEditor.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {compileSchema, defineSchema} from '@portabletext/schema'
|
|
2
2
|
import type {PortableTextBlock} from '@sanity/types'
|
|
3
3
|
import {describe, expect, test} from 'vitest'
|
|
4
|
-
import {defaultKeyGenerator} from '../
|
|
4
|
+
import {defaultKeyGenerator} from '../utils/key-generator'
|
|
5
5
|
import {buildIndexMaps} from './build-index-maps'
|
|
6
6
|
|
|
7
7
|
function blockObject(_key: string, name: string) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {compileSchema, defineSchema} from '@portabletext/schema'
|
|
2
2
|
import {createTestKeyGenerator} from '@portabletext/test'
|
|
3
|
-
import type {EditorSnapshot} from '
|
|
3
|
+
import type {EditorSnapshot} from '../editor/editor-snapshot'
|
|
4
4
|
|
|
5
5
|
export function createTestSnapshot(snapshot: {
|
|
6
6
|
context?: Partial<EditorSnapshot['context']>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {Editor, type BaseRange, type Node} from 'slate'
|
|
2
2
|
import {DOMEditor, isDOMNode} from 'slate-dom'
|
|
3
|
-
import type {EditorSchema, EditorSelection} from '..'
|
|
4
3
|
import type {EditorActor} from '../editor/editor-machine'
|
|
5
|
-
import {
|
|
6
|
-
import type {PortableTextSlateEditor} from '../types/editor'
|
|
7
|
-
import
|
|
4
|
+
import type {EditorSchema} from '../editor/editor-schema'
|
|
5
|
+
import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
|
|
6
|
+
import {getBlockEndPoint} from '../utils/util.get-block-end-point'
|
|
7
|
+
import {getBlockStartPoint} from '../utils/util.get-block-start-point'
|
|
8
|
+
import {isSelectionCollapsed} from '../utils/util.is-selection-collapsed'
|
|
9
|
+
import {getBlockKeyFromSelectionPoint} from '../utils/util.selection-point'
|
|
8
10
|
import {
|
|
9
11
|
getFirstBlock,
|
|
10
12
|
getLastBlock,
|
|
@@ -69,14 +71,14 @@ export function getEventPosition({
|
|
|
69
71
|
block: eventPositionBlock,
|
|
70
72
|
isEditor: false,
|
|
71
73
|
selection: {
|
|
72
|
-
anchor:
|
|
74
|
+
anchor: getBlockStartPoint({
|
|
73
75
|
context: editorActor.getSnapshot().context,
|
|
74
76
|
block: {
|
|
75
77
|
node: eventBlock,
|
|
76
78
|
path: [{_key: eventBlock._key}],
|
|
77
79
|
},
|
|
78
80
|
}),
|
|
79
|
-
focus:
|
|
81
|
+
focus: getBlockEndPoint({
|
|
80
82
|
context: editorActor.getSnapshot().context,
|
|
81
83
|
block: {
|
|
82
84
|
node: eventBlock,
|
|
@@ -100,7 +102,7 @@ export function getEventPosition({
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
if (
|
|
103
|
-
|
|
105
|
+
isSelectionCollapsed(eventSelection) &&
|
|
104
106
|
eventBlock &&
|
|
105
107
|
eventSelectionFocusBlockKey !== eventBlock._key
|
|
106
108
|
) {
|
|
@@ -110,14 +112,14 @@ export function getEventPosition({
|
|
|
110
112
|
block: eventPositionBlock,
|
|
111
113
|
isEditor: false,
|
|
112
114
|
selection: {
|
|
113
|
-
anchor:
|
|
115
|
+
anchor: getBlockStartPoint({
|
|
114
116
|
context: editorActor.getSnapshot().context,
|
|
115
117
|
block: {
|
|
116
118
|
node: eventBlock,
|
|
117
119
|
path: [{_key: eventBlock._key}],
|
|
118
120
|
},
|
|
119
121
|
}),
|
|
120
|
-
focus:
|
|
122
|
+
focus: getBlockEndPoint({
|
|
121
123
|
context: editorActor.getSnapshot().context,
|
|
122
124
|
block: {
|
|
123
125
|
node: eventBlock,
|
|
@@ -5,9 +5,9 @@ import {createEditor, type Descendant} from 'slate'
|
|
|
5
5
|
import {beforeEach, describe, expect, it} from 'vitest'
|
|
6
6
|
import {createActor} from 'xstate'
|
|
7
7
|
import {editorMachine} from '../editor/editor-machine'
|
|
8
|
-
import {defaultKeyGenerator} from '../editor/key-generator'
|
|
9
8
|
import {withPlugins} from '../editor/plugins/with-plugins'
|
|
10
9
|
import {relayMachine} from '../editor/relay-machine'
|
|
10
|
+
import {defaultKeyGenerator} from '../utils/key-generator'
|
|
11
11
|
import {
|
|
12
12
|
insertNodePatch,
|
|
13
13
|
insertTextPatch,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {getBlockKeyFromSelectionPoint} from '../selection/selection-point'
|
|
2
1
|
import type {EditorSelection} from '../types/editor'
|
|
2
|
+
import {getBlockKeyFromSelectionPoint} from '../utils/util.selection-point'
|
|
3
3
|
|
|
4
4
|
export function getSelectionBlockKeys(selection: EditorSelection) {
|
|
5
5
|
if (!selection) {
|
|
@@ -3,7 +3,7 @@ import type {EditorContext} from '../editor/editor-snapshot'
|
|
|
3
3
|
import {
|
|
4
4
|
getBlockKeyFromSelectionPoint,
|
|
5
5
|
getChildKeyFromSelectionPoint,
|
|
6
|
-
} from '../
|
|
6
|
+
} from '../utils/util.selection-point'
|
|
7
7
|
|
|
8
8
|
export function getSelectionFocusText(
|
|
9
9
|
context: Pick<EditorContext, 'schema' | 'value' | 'selection'>,
|
|
@@ -2,13 +2,13 @@ import {isSpan, isTextBlock} from '@portabletext/schema'
|
|
|
2
2
|
import type {PortableTextObject, PortableTextSpan} from '@sanity/types'
|
|
3
3
|
import type {Path, Range} from 'slate'
|
|
4
4
|
import type {EditorContext, EditorSnapshot} from '../editor/editor-snapshot'
|
|
5
|
+
import type {EditorSelectionPoint} from '../types/editor'
|
|
6
|
+
import {blockOffsetToSpanSelectionPoint} from '../utils/util.block-offset'
|
|
7
|
+
import {isEqualSelectionPoints} from '../utils/util.is-equal-selection-points'
|
|
5
8
|
import {
|
|
6
9
|
getBlockKeyFromSelectionPoint,
|
|
7
10
|
getChildKeyFromSelectionPoint,
|
|
8
|
-
} from '../
|
|
9
|
-
import type {EditorSelectionPoint} from '../types/editor'
|
|
10
|
-
import {isEqualSelectionPoints} from '../utils'
|
|
11
|
-
import {blockOffsetToSpanSelectionPoint} from '../utils/util.block-offset'
|
|
11
|
+
} from '../utils/util.selection-point'
|
|
12
12
|
|
|
13
13
|
export function toSlateRange(
|
|
14
14
|
snapshot: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {Editor, Node, Range, Text, Transforms} from 'slate'
|
|
2
|
-
import {parseAnnotation} from '../
|
|
2
|
+
import {parseAnnotation} from '../utils/parse-blocks'
|
|
3
3
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
4
4
|
|
|
5
5
|
export const addAnnotationOperationImplementation: BehaviorOperationImplementation<
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Transforms, type Element as SlateElement} from 'slate'
|
|
2
|
-
import {parseBlock} from '../internal-utils/parse-blocks'
|
|
3
2
|
import {toSlateValue} from '../internal-utils/values'
|
|
3
|
+
import {parseBlock} from '../utils/parse-blocks'
|
|
4
4
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
5
5
|
|
|
6
6
|
export const blockSetOperationImplementation: BehaviorOperationImplementation<
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {isTextBlock} from '@portabletext/schema'
|
|
2
2
|
import {omit} from 'lodash'
|
|
3
3
|
import {Editor, Transforms} from 'slate'
|
|
4
|
-
import {
|
|
4
|
+
import {KEY_TO_VALUE_ELEMENT} from '../editor/weakMaps'
|
|
5
5
|
import {toSlateRange} from '../internal-utils/to-slate-range'
|
|
6
6
|
import {fromSlateValue} from '../internal-utils/values'
|
|
7
|
-
import {
|
|
7
|
+
import {parseBlock} from '../utils/parse-blocks'
|
|
8
8
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
9
9
|
|
|
10
10
|
export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
|