@portabletext/editor 2.16.0 → 2.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_chunks-cjs/selector.get-selection-text.cjs +1 -1
- package/lib/_chunks-cjs/selector.get-selection-text.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs +1 -0
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -1
- package/lib/_chunks-dts/behavior.types.action.d.cts +2 -2
- package/lib/_chunks-dts/behavior.types.action.d.ts +5 -5
- package/lib/_chunks-es/selector.get-selection-text.js +1 -1
- package/lib/_chunks-es/selector.get-selection-text.js.map +1 -1
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js +1 -0
- package/lib/index.cjs +485 -511
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +488 -514
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +1 -0
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +8 -1
- package/lib/selectors/index.d.ts +8 -1
- package/lib/selectors/index.js +2 -1
- package/lib/utils/index.d.ts +2 -2
- package/package.json +2 -2
- package/src/behaviors/behavior.abstract.delete.ts +12 -16
- package/src/behaviors/behavior.abstract.insert.ts +37 -6
- package/src/behaviors/behavior.abstract.split.ts +24 -89
- package/src/behaviors/behavior.core.lists.ts +9 -3
- package/src/behaviors/behavior.types.event.ts +1 -1
- package/src/editor/plugins/create-with-event-listeners.ts +30 -31
- package/src/operations/behavior.operation.delete.ts +76 -80
- package/src/selectors/index.ts +1 -0
- package/src/selectors/selector.is-selection-expanded.test.ts +63 -0
- package/src/selectors/selector.is-selection-expanded.ts +1 -1
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import {isTextBlock} from '@portabletext/schema'
|
|
2
|
-
import {
|
|
3
|
-
deleteText,
|
|
4
|
-
Editor,
|
|
5
|
-
Element,
|
|
6
|
-
Range,
|
|
7
|
-
setSelection,
|
|
8
|
-
Transforms,
|
|
9
|
-
} from 'slate'
|
|
2
|
+
import {deleteText, Editor, Element, Range, Transforms} from 'slate'
|
|
10
3
|
import {DOMEditor} from 'slate-dom'
|
|
11
4
|
import {createPlaceholderBlock} from '../internal-utils/create-placeholder-block'
|
|
5
|
+
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
12
6
|
import {toSlateRange} from '../internal-utils/to-slate-range'
|
|
13
7
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
14
8
|
import {getBlockKeyFromSelectionPoint} from '../utils/util.selection-point'
|
|
@@ -17,48 +11,54 @@ import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
|
17
11
|
export const deleteOperationImplementation: BehaviorOperationImplementation<
|
|
18
12
|
'delete'
|
|
19
13
|
> = ({context, operation}) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
14
|
+
const at = operation.at
|
|
15
|
+
? toSlateRange({
|
|
16
|
+
context: {
|
|
17
|
+
schema: context.schema,
|
|
18
|
+
value: operation.editor.value,
|
|
19
|
+
selection: operation.at,
|
|
20
|
+
},
|
|
21
|
+
blockIndexMap: operation.editor.blockIndexMap,
|
|
22
|
+
})
|
|
23
|
+
: undefined
|
|
24
|
+
|
|
25
|
+
const selection = operation.editor.selection
|
|
26
|
+
? slateRangeToSelection({
|
|
27
|
+
schema: context.schema,
|
|
28
|
+
editor: operation.editor,
|
|
29
|
+
range: operation.editor.selection,
|
|
30
|
+
})
|
|
31
|
+
: undefined
|
|
32
|
+
|
|
33
|
+
const reverse = operation.direction === 'backward'
|
|
34
|
+
const anchorPoint = operation.at?.anchor ?? selection?.anchor
|
|
35
|
+
const focusPoint = operation.at?.focus ?? selection?.focus
|
|
36
|
+
const startPoint = reverse ? focusPoint : anchorPoint
|
|
37
|
+
const endPoint = reverse ? anchorPoint : focusPoint
|
|
38
|
+
const startBlockKey = startPoint
|
|
39
|
+
? getBlockKeyFromSelectionPoint(startPoint)
|
|
40
|
+
: undefined
|
|
41
|
+
const endBlockKey = endPoint
|
|
42
|
+
? getBlockKeyFromSelectionPoint(endPoint)
|
|
43
|
+
: undefined
|
|
44
|
+
const startBlockIndex = startBlockKey
|
|
45
|
+
? operation.editor.blockIndexMap.get(startBlockKey)
|
|
46
|
+
: undefined
|
|
47
|
+
const endBlockIndex = endBlockKey
|
|
48
|
+
? operation.editor.blockIndexMap.get(endBlockKey)
|
|
49
|
+
: undefined
|
|
50
|
+
const startBlock = startBlockIndex
|
|
51
|
+
? operation.editor.value.at(startBlockIndex)
|
|
52
|
+
: undefined
|
|
53
|
+
const endBlock = endBlockIndex
|
|
54
|
+
? operation.editor.value.at(endBlockIndex)
|
|
55
|
+
: undefined
|
|
60
56
|
|
|
61
57
|
if (operation.unit === 'block') {
|
|
58
|
+
if (startBlockIndex === undefined || endBlockIndex === undefined) {
|
|
59
|
+
throw new Error('Failed to get start or end block index')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
62
|
Transforms.removeNodes(operation.editor, {
|
|
63
63
|
at: {
|
|
64
64
|
anchor: {path: [startBlockIndex], offset: 0},
|
|
@@ -74,22 +74,13 @@ export const deleteOperationImplementation: BehaviorOperationImplementation<
|
|
|
74
74
|
return
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const range = toSlateRange({
|
|
78
|
-
context: {
|
|
79
|
-
schema: context.schema,
|
|
80
|
-
value: operation.editor.value,
|
|
81
|
-
selection: operation.at,
|
|
82
|
-
},
|
|
83
|
-
blockIndexMap: operation.editor.blockIndexMap,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
if (!range) {
|
|
87
|
-
throw new Error(
|
|
88
|
-
`Failed to get Slate Range for selection ${JSON.stringify(operation.at)}`,
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
77
|
if (operation.direction === 'backward' && operation.unit === 'line') {
|
|
78
|
+
const range = at ?? operation.editor.selection ?? undefined
|
|
79
|
+
|
|
80
|
+
if (!range) {
|
|
81
|
+
throw new Error('Unable to delete line without a selection')
|
|
82
|
+
}
|
|
83
|
+
|
|
93
84
|
const parentBlockEntry = Editor.above(operation.editor, {
|
|
94
85
|
match: (n) => Element.isElement(n) && Editor.isBlock(operation.editor, n),
|
|
95
86
|
at: range,
|
|
@@ -115,23 +106,28 @@ export const deleteOperationImplementation: BehaviorOperationImplementation<
|
|
|
115
106
|
}
|
|
116
107
|
}
|
|
117
108
|
|
|
118
|
-
const hanging =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
109
|
+
const hanging = reverse
|
|
110
|
+
? endPoint
|
|
111
|
+
? isTextBlock(context, endBlock)
|
|
112
|
+
? endPoint.offset === 0
|
|
113
|
+
: true
|
|
114
|
+
: false
|
|
115
|
+
: startPoint
|
|
116
|
+
? isTextBlock(context, startBlock)
|
|
117
|
+
? startPoint.offset === 0
|
|
118
|
+
: true
|
|
119
|
+
: false
|
|
120
|
+
|
|
121
|
+
if (at) {
|
|
122
|
+
deleteText(operation.editor, {
|
|
123
|
+
at,
|
|
124
|
+
hanging,
|
|
125
|
+
reverse,
|
|
126
|
+
})
|
|
127
|
+
} else {
|
|
128
|
+
deleteText(operation.editor, {
|
|
129
|
+
hanging,
|
|
130
|
+
reverse,
|
|
135
131
|
})
|
|
136
132
|
}
|
|
137
133
|
}
|
package/src/selectors/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {getNextSpan} from './selector.get-next-span'
|
|
|
25
25
|
export {getPreviousBlock} from './selector.get-previous-block'
|
|
26
26
|
export {getPreviousInlineObject} from './selector.get-previous-inline-object'
|
|
27
27
|
export {getPreviousInlineObjects} from './selector.get-previous-inline-objects'
|
|
28
|
+
export {getPreviousSpan} from './selector.get-previous-span'
|
|
28
29
|
export {getSelectedBlocks} from './selector.get-selected-blocks'
|
|
29
30
|
export {getSelectedSlice} from './selector.get-selected-slice'
|
|
30
31
|
export {getSelectedSpans} from './selector.get-selected-spans'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {describe, expect, test} from 'vitest'
|
|
2
|
+
import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
|
|
3
|
+
import {isSelectionExpanded} from './selector.is-selection-expanded'
|
|
4
|
+
|
|
5
|
+
describe(isSelectionExpanded.name, () => {
|
|
6
|
+
test('no selection', () => {
|
|
7
|
+
const snapshot = createTestSnapshot({})
|
|
8
|
+
|
|
9
|
+
expect(isSelectionExpanded(snapshot)).toBe(false)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
test('collapsed selection', () => {
|
|
13
|
+
const snapshot = createTestSnapshot({
|
|
14
|
+
context: {
|
|
15
|
+
value: [
|
|
16
|
+
{
|
|
17
|
+
_key: 'k0',
|
|
18
|
+
_type: 'block',
|
|
19
|
+
children: [
|
|
20
|
+
{
|
|
21
|
+
_key: 'k1',
|
|
22
|
+
_type: 'span',
|
|
23
|
+
text: 'foo',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
selection: {
|
|
29
|
+
anchor: {path: [{_key: 'k0'}, 'children', {_key: 'k1'}], offset: 0},
|
|
30
|
+
focus: {path: [{_key: 'k0'}, 'children', {_key: 'k1'}], offset: 0},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
expect(isSelectionExpanded(snapshot)).toBe(false)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('expanded selection', () => {
|
|
39
|
+
const snapshot = createTestSnapshot({
|
|
40
|
+
context: {
|
|
41
|
+
value: [
|
|
42
|
+
{
|
|
43
|
+
_key: 'k0',
|
|
44
|
+
_type: 'block',
|
|
45
|
+
children: [
|
|
46
|
+
{
|
|
47
|
+
_key: 'k1',
|
|
48
|
+
_type: 'span',
|
|
49
|
+
text: 'foo',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
selection: {
|
|
55
|
+
anchor: {path: [{_key: 'k0'}, 'children', {_key: 'k1'}], offset: 0},
|
|
56
|
+
focus: {path: [{_key: 'k0'}, 'children', {_key: 'k1'}], offset: 3},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
expect(isSelectionExpanded(snapshot)).toBe(true)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
@@ -5,5 +5,5 @@ import {isSelectionCollapsed} from './selector.is-selection-collapsed'
|
|
|
5
5
|
* @public
|
|
6
6
|
*/
|
|
7
7
|
export const isSelectionExpanded: EditorSelector<boolean> = (snapshot) => {
|
|
8
|
-
return !isSelectionCollapsed(snapshot)
|
|
8
|
+
return snapshot.context.selection !== null && !isSelectionCollapsed(snapshot)
|
|
9
9
|
}
|