@portabletext/editor 2.17.0 → 2.17.2
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/util.get-text-block-text.cjs +2 -6
- package/lib/_chunks-cjs/util.get-text-block-text.cjs.map +1 -1
- package/lib/_chunks-dts/behavior.types.action.d.cts +12 -12
- package/lib/_chunks-dts/behavior.types.action.d.ts +2 -2
- 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/util.get-text-block-text.js +1 -2
- package/lib/_chunks-es/util.get-text-block-text.js.map +1 -1
- 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/plugins/index.d.cts +3 -3
- package/package.json +9 -10
- 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/selector.is-selection-expanded.test.ts +63 -0
- package/src/selectors/selector.is-selection-expanded.ts +1 -1
- package/src/utils/key-generator.ts +1 -3
package/lib/plugins/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react22 from "react";
|
|
3
3
|
import React from "react";
|
|
4
4
|
/**
|
|
5
5
|
* @beta
|
|
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
|
|
|
181
181
|
*/
|
|
182
182
|
declare function MarkdownPlugin(props: {
|
|
183
183
|
config: MarkdownPluginConfig;
|
|
184
|
-
}):
|
|
184
|
+
}): react22.JSX.Element;
|
|
185
185
|
/**
|
|
186
186
|
* @beta
|
|
187
187
|
* Restrict the editor to one line. The plugin takes care of blocking
|
|
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
|
|
|
192
192
|
*
|
|
193
193
|
* @deprecated Install the plugin from `@portabletext/plugin-one-line`
|
|
194
194
|
*/
|
|
195
|
-
declare function OneLinePlugin():
|
|
195
|
+
declare function OneLinePlugin(): react22.JSX.Element;
|
|
196
196
|
export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, MarkdownPluginConfig, OneLinePlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.2",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -76,7 +76,6 @@
|
|
|
76
76
|
"@portabletext/to-html": "^3.0.0",
|
|
77
77
|
"@xstate/react": "^6.0.0",
|
|
78
78
|
"debug": "^4.4.3",
|
|
79
|
-
"get-random-values-esm": "^1.0.2",
|
|
80
79
|
"immer": "^10.2.0",
|
|
81
80
|
"lodash": "^4.17.21",
|
|
82
81
|
"lodash.startcase": "^4.4.0",
|
|
@@ -85,9 +84,9 @@
|
|
|
85
84
|
"slate-dom": "^0.118.1",
|
|
86
85
|
"slate-react": "0.118.2",
|
|
87
86
|
"xstate": "^5.23.0",
|
|
88
|
-
"@portabletext/block-tools": "^3.5.
|
|
89
|
-
"@portabletext/patches": "^1.1.8",
|
|
87
|
+
"@portabletext/block-tools": "^3.5.14",
|
|
90
88
|
"@portabletext/keyboard-shortcuts": "^1.1.1",
|
|
89
|
+
"@portabletext/patches": "^1.1.8",
|
|
91
90
|
"@portabletext/schema": "^1.2.0"
|
|
92
91
|
},
|
|
93
92
|
"devDependencies": {
|
|
@@ -102,9 +101,9 @@
|
|
|
102
101
|
"@types/react": "^19.2.0",
|
|
103
102
|
"@types/react-dom": "^19.2.0",
|
|
104
103
|
"@vitejs/plugin-react": "^5.0.4",
|
|
105
|
-
"@vitest/browser": "^4.0.
|
|
106
|
-
"@vitest/browser-playwright": "^4.0.
|
|
107
|
-
"@vitest/coverage-istanbul": "^4.0.
|
|
104
|
+
"@vitest/browser": "^4.0.5",
|
|
105
|
+
"@vitest/browser-playwright": "^4.0.5",
|
|
106
|
+
"@vitest/coverage-istanbul": "^4.0.5",
|
|
108
107
|
"babel-plugin-react-compiler": "1.0.0",
|
|
109
108
|
"eslint": "^9.38.0",
|
|
110
109
|
"eslint-formatter-gha": "^1.6.0",
|
|
@@ -116,14 +115,14 @@
|
|
|
116
115
|
"typescript": "5.9.3",
|
|
117
116
|
"typescript-eslint": "^8.46.1",
|
|
118
117
|
"vite": "^7.1.10",
|
|
119
|
-
"vitest": "^4.0.
|
|
118
|
+
"vitest": "^4.0.5",
|
|
120
119
|
"vitest-browser-react": "^2.0.2",
|
|
121
|
-
"@portabletext/sanity-bridge": "1.1.
|
|
120
|
+
"@portabletext/sanity-bridge": "1.1.17",
|
|
122
121
|
"@portabletext/test": "^0.0.0",
|
|
123
122
|
"racejar": "1.3.2"
|
|
124
123
|
},
|
|
125
124
|
"peerDependencies": {
|
|
126
|
-
"@portabletext/sanity-bridge": "^1.1.
|
|
125
|
+
"@portabletext/sanity-bridge": "^1.1.17",
|
|
127
126
|
"@sanity/schema": "^4.12.0",
|
|
128
127
|
"@sanity/types": "^4.12.0",
|
|
129
128
|
"react": "^18.3 || ^19",
|
|
@@ -17,19 +17,14 @@ export const abstractDeleteBehaviors = [
|
|
|
17
17
|
defineBehavior({
|
|
18
18
|
on: 'delete.backward',
|
|
19
19
|
guard: ({snapshot}) => {
|
|
20
|
-
|
|
21
|
-
return false
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return {selection: snapshot.context.selection}
|
|
20
|
+
return snapshot.context.selection
|
|
25
21
|
},
|
|
26
22
|
actions: [
|
|
27
|
-
({event}
|
|
23
|
+
({event}) => [
|
|
28
24
|
raise({
|
|
29
25
|
type: 'delete',
|
|
30
26
|
direction: 'backward',
|
|
31
27
|
unit: event.unit,
|
|
32
|
-
at: selection,
|
|
33
28
|
}),
|
|
34
29
|
],
|
|
35
30
|
],
|
|
@@ -88,19 +83,14 @@ export const abstractDeleteBehaviors = [
|
|
|
88
83
|
defineBehavior({
|
|
89
84
|
on: 'delete.forward',
|
|
90
85
|
guard: ({snapshot}) => {
|
|
91
|
-
|
|
92
|
-
return false
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return {selection: snapshot.context.selection}
|
|
86
|
+
return snapshot.context.selection
|
|
96
87
|
},
|
|
97
88
|
actions: [
|
|
98
|
-
({event}
|
|
89
|
+
({event}) => [
|
|
99
90
|
raise({
|
|
100
91
|
type: 'delete',
|
|
101
92
|
direction: 'forward',
|
|
102
93
|
unit: event.unit,
|
|
103
|
-
at: selection,
|
|
104
94
|
}),
|
|
105
95
|
],
|
|
106
96
|
],
|
|
@@ -112,18 +102,24 @@ export const abstractDeleteBehaviors = [
|
|
|
112
102
|
return false
|
|
113
103
|
}
|
|
114
104
|
|
|
105
|
+
const at = event.at ?? snapshot.context.selection
|
|
106
|
+
|
|
107
|
+
if (!at) {
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
115
111
|
const nextBlock = getNextBlock({
|
|
116
112
|
...snapshot,
|
|
117
113
|
context: {
|
|
118
114
|
...snapshot.context,
|
|
119
|
-
selection:
|
|
115
|
+
selection: at,
|
|
120
116
|
},
|
|
121
117
|
})
|
|
122
118
|
const focusTextBlock = getFocusTextBlock({
|
|
123
119
|
...snapshot,
|
|
124
120
|
context: {
|
|
125
121
|
...snapshot.context,
|
|
126
|
-
selection:
|
|
122
|
+
selection: at,
|
|
127
123
|
},
|
|
128
124
|
})
|
|
129
125
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import {isSelectionExpanded} from '../selectors'
|
|
1
2
|
import {getFocusTextBlock} from '../selectors/selector.get-focus-text-block'
|
|
2
3
|
import {getLastBlock} from '../selectors/selector.get-last-block'
|
|
3
|
-
import {isSelectionCollapsed} from '../utils'
|
|
4
4
|
import {getBlockEndPoint} from '../utils/util.get-block-end-point'
|
|
5
5
|
import {getBlockStartPoint} from '../utils/util.get-block-start-point'
|
|
6
6
|
import {isEmptyTextBlock} from '../utils/util.is-empty-text-block'
|
|
@@ -473,20 +473,51 @@ export const abstractInsertBehaviors = [
|
|
|
473
473
|
],
|
|
474
474
|
],
|
|
475
475
|
}),
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* If there's an expanded selection, then we delete the selection before we
|
|
479
|
+
* insert the text.
|
|
480
|
+
*/
|
|
476
481
|
defineBehavior({
|
|
477
482
|
on: 'insert.text',
|
|
478
483
|
guard: ({snapshot}) => {
|
|
479
|
-
|
|
484
|
+
return isSelectionExpanded(snapshot)
|
|
485
|
+
},
|
|
486
|
+
actions: [({event}) => [raise({type: 'delete'}), raise(event)]],
|
|
487
|
+
}),
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* If there's no selection, then we select the end of the editor before we
|
|
491
|
+
* we insert the text.
|
|
492
|
+
*/
|
|
493
|
+
defineBehavior({
|
|
494
|
+
on: 'insert.text',
|
|
495
|
+
guard: ({snapshot}) => {
|
|
496
|
+
if (snapshot.context.selection) {
|
|
497
|
+
return false
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const lastBlok = getLastBlock(snapshot)
|
|
480
501
|
|
|
481
|
-
if (!
|
|
502
|
+
if (!lastBlok) {
|
|
482
503
|
return false
|
|
483
504
|
}
|
|
484
505
|
|
|
485
|
-
|
|
506
|
+
const endPoint = getBlockEndPoint({
|
|
507
|
+
context: snapshot.context,
|
|
508
|
+
block: lastBlok,
|
|
509
|
+
})
|
|
510
|
+
return {endPoint}
|
|
486
511
|
},
|
|
487
512
|
actions: [
|
|
488
|
-
({event}, {
|
|
489
|
-
raise({
|
|
513
|
+
({event}, {endPoint}) => [
|
|
514
|
+
raise({
|
|
515
|
+
type: 'select',
|
|
516
|
+
at: {
|
|
517
|
+
anchor: endPoint,
|
|
518
|
+
focus: endPoint,
|
|
519
|
+
},
|
|
520
|
+
}),
|
|
490
521
|
raise(event),
|
|
491
522
|
],
|
|
492
523
|
],
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {isTextBlock} from '@portabletext/schema'
|
|
2
|
+
import {isSelectionExpanded} from '../selectors'
|
|
2
3
|
import {getFocusBlockObject} from '../selectors/selector.get-focus-block-object'
|
|
3
4
|
import {getFocusInlineObject} from '../selectors/selector.get-focus-inline-object'
|
|
4
5
|
import {getFocusTextBlock} from '../selectors/selector.get-focus-text-block'
|
|
5
|
-
import {getSelectedValue} from '../selectors/selector.get-selected-value'
|
|
6
6
|
import {getSelectionEndBlock} from '../selectors/selector.get-selection-end-block'
|
|
7
7
|
import {getSelectionStartBlock} from '../selectors/selector.get-selection-start-block'
|
|
8
|
+
import {isEqualSelectionPoints} from '../utils'
|
|
8
9
|
import {parseBlock} from '../utils/parse-blocks'
|
|
9
10
|
import {getBlockEndPoint} from '../utils/util.get-block-end-point'
|
|
10
11
|
import {getBlockStartPoint} from '../utils/util.get-block-start-point'
|
|
@@ -47,115 +48,49 @@ export const abstractSplitBehaviors = [
|
|
|
47
48
|
return false
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
if (!selectionStartBlock || !selectionEndBlock) {
|
|
54
|
-
return false
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
!isTextBlock(snapshot.context, selectionStartBlock.node) &&
|
|
59
|
-
isTextBlock(snapshot.context, selectionEndBlock.node)
|
|
60
|
-
) {
|
|
61
|
-
return {selection}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return false
|
|
65
|
-
},
|
|
66
|
-
actions: [(_, {selection}) => [raise({type: 'delete', at: selection})]],
|
|
67
|
-
}),
|
|
68
|
-
|
|
69
|
-
defineBehavior({
|
|
70
|
-
on: 'split',
|
|
71
|
-
guard: ({snapshot}) => {
|
|
72
|
-
const selection = snapshot.context.selection
|
|
51
|
+
const startPoint = getSelectionStartPoint(selection)
|
|
52
|
+
const endPoint = getSelectionEndPoint(selection)
|
|
73
53
|
|
|
74
|
-
if (!
|
|
54
|
+
if (!startPoint || !endPoint) {
|
|
75
55
|
return false
|
|
76
56
|
}
|
|
77
57
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
if (!selectionStartBlock || !selectionEndBlock) {
|
|
82
|
-
return false
|
|
83
|
-
}
|
|
58
|
+
const startBlock = getSelectionStartBlock(snapshot)
|
|
59
|
+
const endBlock = getSelectionEndBlock(snapshot)
|
|
84
60
|
|
|
85
|
-
if (
|
|
61
|
+
if (!startBlock || !endBlock) {
|
|
86
62
|
return false
|
|
87
63
|
}
|
|
88
64
|
|
|
89
|
-
const
|
|
90
|
-
const startBlockEndPoint = getBlockEndPoint({
|
|
65
|
+
const startBlockStartPoint = getBlockStartPoint({
|
|
91
66
|
context: snapshot.context,
|
|
92
|
-
block:
|
|
67
|
+
block: startBlock,
|
|
93
68
|
})
|
|
94
|
-
const
|
|
95
|
-
const endBlockStartPoint = getBlockStartPoint({
|
|
69
|
+
const endBlockEndPoint = getBlockEndPoint({
|
|
96
70
|
context: snapshot.context,
|
|
97
|
-
block:
|
|
71
|
+
block: endBlock,
|
|
98
72
|
})
|
|
99
73
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
startPoint,
|
|
110
|
-
startBlockEndPoint,
|
|
111
|
-
endPoint,
|
|
112
|
-
endBlockStartPoint,
|
|
113
|
-
blocksInBetween,
|
|
74
|
+
if (
|
|
75
|
+
isTextBlock(snapshot.context, startBlock.node) &&
|
|
76
|
+
isTextBlock(snapshot.context, endBlock.node) &&
|
|
77
|
+
!isEqualSelectionPoints(startPoint, startBlockStartPoint) &&
|
|
78
|
+
!isEqualSelectionPoints(endPoint, endBlockEndPoint)
|
|
79
|
+
) {
|
|
80
|
+
return true
|
|
114
81
|
}
|
|
82
|
+
|
|
83
|
+
return false
|
|
115
84
|
},
|
|
116
|
-
actions: [
|
|
117
|
-
(
|
|
118
|
-
_,
|
|
119
|
-
{
|
|
120
|
-
startPoint,
|
|
121
|
-
startBlockEndPoint,
|
|
122
|
-
endPoint,
|
|
123
|
-
endBlockStartPoint,
|
|
124
|
-
blocksInBetween,
|
|
125
|
-
},
|
|
126
|
-
) => [
|
|
127
|
-
raise({
|
|
128
|
-
type: 'delete',
|
|
129
|
-
at: {anchor: startPoint, focus: startBlockEndPoint},
|
|
130
|
-
}),
|
|
131
|
-
...blocksInBetween.map((block) =>
|
|
132
|
-
raise({type: 'delete.block', at: [{_key: block._key}]}),
|
|
133
|
-
),
|
|
134
|
-
raise({
|
|
135
|
-
type: 'delete',
|
|
136
|
-
at: {anchor: endBlockStartPoint, focus: endPoint},
|
|
137
|
-
}),
|
|
138
|
-
],
|
|
139
|
-
],
|
|
85
|
+
actions: [() => [raise({type: 'delete'}), raise({type: 'split'})]],
|
|
140
86
|
}),
|
|
141
87
|
|
|
142
88
|
defineBehavior({
|
|
143
89
|
on: 'split',
|
|
144
90
|
guard: ({snapshot}) => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (!selection || isSelectionCollapsed(selection)) {
|
|
148
|
-
return false
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return {selection}
|
|
91
|
+
return isSelectionExpanded(snapshot)
|
|
152
92
|
},
|
|
153
|
-
actions: [
|
|
154
|
-
(_, {selection}) => [
|
|
155
|
-
raise({type: 'delete', at: selection}),
|
|
156
|
-
raise({type: 'split'}),
|
|
157
|
-
],
|
|
158
|
-
],
|
|
93
|
+
actions: [() => [raise({type: 'delete'})]],
|
|
159
94
|
}),
|
|
160
95
|
|
|
161
96
|
defineBehavior({
|
|
@@ -204,11 +204,17 @@ const mergeTextIntoListOnBackspace = defineBehavior({
|
|
|
204
204
|
const deletingListFromStart = defineBehavior({
|
|
205
205
|
on: 'delete',
|
|
206
206
|
guard: ({snapshot, event}) => {
|
|
207
|
+
const at = event.at ?? snapshot.context.selection
|
|
208
|
+
|
|
209
|
+
if (!at) {
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
|
|
207
213
|
const blocksToDelete = getSelectedBlocks({
|
|
208
214
|
...snapshot,
|
|
209
215
|
context: {
|
|
210
216
|
...snapshot.context,
|
|
211
|
-
selection:
|
|
217
|
+
selection: at,
|
|
212
218
|
},
|
|
213
219
|
})
|
|
214
220
|
|
|
@@ -233,14 +239,14 @@ const deletingListFromStart = defineBehavior({
|
|
|
233
239
|
...snapshot,
|
|
234
240
|
context: {
|
|
235
241
|
...snapshot.context,
|
|
236
|
-
selection:
|
|
242
|
+
selection: at,
|
|
237
243
|
},
|
|
238
244
|
})
|
|
239
245
|
const deleteEndPoint = getSelectionEndPoint({
|
|
240
246
|
...snapshot,
|
|
241
247
|
context: {
|
|
242
248
|
...snapshot.context,
|
|
243
|
-
selection:
|
|
249
|
+
selection: at,
|
|
244
250
|
},
|
|
245
251
|
})
|
|
246
252
|
|
|
@@ -18,38 +18,37 @@ export function createWithEventListeners(editorActor: EditorActor) {
|
|
|
18
18
|
return
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
21
|
+
const range = options?.at ? Editor.range(editor, options.at) : undefined
|
|
22
|
+
const selection = range
|
|
23
|
+
? slateRangeToSelection({
|
|
24
|
+
schema: editorActor.getSnapshot().context.schema,
|
|
25
|
+
editor,
|
|
26
|
+
range,
|
|
27
|
+
})
|
|
28
|
+
: undefined
|
|
29
|
+
|
|
30
|
+
if (selection) {
|
|
31
|
+
editorActor.send({
|
|
32
|
+
type: 'behavior event',
|
|
33
|
+
behaviorEvent: {
|
|
34
|
+
type: 'delete',
|
|
35
|
+
at: selection,
|
|
36
|
+
direction: options?.reverse ? 'backward' : 'forward',
|
|
37
|
+
unit: options?.unit,
|
|
38
|
+
},
|
|
39
|
+
editor,
|
|
40
|
+
})
|
|
41
|
+
} else {
|
|
42
|
+
editorActor.send({
|
|
43
|
+
type: 'behavior event',
|
|
44
|
+
behaviorEvent: {
|
|
45
|
+
type: 'delete',
|
|
46
|
+
direction: options?.reverse ? 'backward' : 'forward',
|
|
47
|
+
unit: options?.unit,
|
|
48
|
+
},
|
|
49
|
+
editor,
|
|
50
|
+
})
|
|
41
51
|
}
|
|
42
|
-
|
|
43
|
-
editorActor.send({
|
|
44
|
-
type: 'behavior event',
|
|
45
|
-
behaviorEvent: {
|
|
46
|
-
type: 'delete',
|
|
47
|
-
at: selection,
|
|
48
|
-
direction: options?.reverse ? 'backward' : 'forward',
|
|
49
|
-
unit: options?.unit,
|
|
50
|
-
},
|
|
51
|
-
editor,
|
|
52
|
-
})
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
editor.deleteBackward = (unit) => {
|
|
@@ -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
|
}
|