@portabletext/editor 1.18.6 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_chunks-cjs/behavior.core.cjs +52 -35
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +52 -35
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/behaviors/index.cjs +1 -0
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +76 -84
- package/lib/behaviors/index.d.ts +76 -84
- package/lib/behaviors/index.js +3 -2
- package/lib/index.cjs +234 -251
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +257 -1106
- package/lib/index.d.ts +257 -1106
- package/lib/index.js +235 -252
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +12 -9
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.js +12 -9
- package/lib/selectors/index.js.map +1 -1
- package/package.json +7 -7
- package/src/behavior-actions/behavior.actions.ts +28 -36
- package/src/behaviors/behavior.core.decorators.ts +36 -42
- package/src/behaviors/behavior.core.ts +4 -3
- package/src/behaviors/behavior.types.ts +38 -24
- package/src/behaviors/index.ts +1 -0
- package/src/editor/PortableTextEditor.tsx +14 -16
- package/src/editor/__tests__/self-solving.test.tsx +4 -11
- package/src/editor/create-editor.ts +1 -3
- package/src/editor/editor-machine.ts +37 -41
- package/src/editor/plugins/create-with-event-listeners.ts +44 -57
- package/src/editor/plugins/createWithHotKeys.ts +1 -11
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +12 -1
- package/src/editor/plugins/createWithPortableTextSelections.ts +1 -5
- package/src/editor/with-applying-behavior-actions.ts +15 -0
- package/src/selectors/selector.get-selected-spans.test.ts +122 -0
- package/src/selectors/selector.get-selected-spans.ts +3 -1
- package/src/selectors/selector.is-active-decorator.test.ts +65 -0
|
@@ -63,15 +63,13 @@ export type EditorEvent = PickFromUnion<
|
|
|
63
63
|
'type',
|
|
64
64
|
| 'annotation.add'
|
|
65
65
|
| 'annotation.remove'
|
|
66
|
-
| 'annotation.toggle'
|
|
67
66
|
| 'blur'
|
|
68
|
-
| 'decorator.add'
|
|
69
|
-
| 'decorator.remove'
|
|
70
67
|
| 'decorator.toggle'
|
|
71
68
|
| 'focus'
|
|
72
69
|
| 'insert.block object'
|
|
73
70
|
| 'insert.inline object'
|
|
74
71
|
| 'list item.toggle'
|
|
72
|
+
| 'select'
|
|
75
73
|
| 'style.toggle'
|
|
76
74
|
| 'patches'
|
|
77
75
|
| 'update behaviors'
|
|
@@ -30,6 +30,7 @@ import {KEY_TO_VALUE_ELEMENT} from '../utils/weakMaps'
|
|
|
30
30
|
import type {EditorSchema} from './define-schema'
|
|
31
31
|
import type {EditorContext} from './editor-snapshot'
|
|
32
32
|
import {getActiveDecorators} from './get-active-decorators'
|
|
33
|
+
import {withApplyingBehaviorActions} from './with-applying-behavior-actions'
|
|
33
34
|
|
|
34
35
|
export * from 'xstate/guards'
|
|
35
36
|
|
|
@@ -152,6 +153,7 @@ export type InternalEditorEmittedEvent =
|
|
|
152
153
|
description: string
|
|
153
154
|
data: unknown
|
|
154
155
|
}
|
|
156
|
+
| {type: 'select'; selection: EditorSelection}
|
|
155
157
|
| {type: 'selection'; selection: EditorSelection}
|
|
156
158
|
| {type: 'blurred'; event: FocusEvent<HTMLDivElement, Element>}
|
|
157
159
|
| {type: 'focused'; event: FocusEvent<HTMLDivElement, Element>}
|
|
@@ -164,10 +166,7 @@ export type InternalEditorEmittedEvent =
|
|
|
164
166
|
'type',
|
|
165
167
|
| 'annotation.add'
|
|
166
168
|
| 'annotation.remove'
|
|
167
|
-
| 'annotation.toggle'
|
|
168
169
|
| 'blur'
|
|
169
|
-
| 'decorator.add'
|
|
170
|
-
| 'decorator.remove'
|
|
171
170
|
| 'decorator.toggle'
|
|
172
171
|
| 'insert.block object'
|
|
173
172
|
| 'insert.inline object'
|
|
@@ -263,10 +262,12 @@ export const editorMachine = setup({
|
|
|
263
262
|
return
|
|
264
263
|
}
|
|
265
264
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
265
|
+
withApplyingBehaviorActions(event.editor, () => {
|
|
266
|
+
Editor.withoutNormalizing(event.editor, () => {
|
|
267
|
+
performAction({
|
|
268
|
+
context,
|
|
269
|
+
action: defaultAction,
|
|
270
|
+
})
|
|
270
271
|
})
|
|
271
272
|
})
|
|
272
273
|
event.editor.onChange()
|
|
@@ -324,32 +325,28 @@ export const editorMachine = setup({
|
|
|
324
325
|
(actionIntend) => actionIntend.type !== 'effect',
|
|
325
326
|
))
|
|
326
327
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
328
|
+
withApplyingBehaviorActions(event.editor, () => {
|
|
329
|
+
Editor.withoutNormalizing(event.editor, () => {
|
|
330
|
+
for (const actionIntend of actionIntends) {
|
|
331
|
+
if (actionIntend.type === 'raise') {
|
|
332
|
+
enqueue.raise({
|
|
333
|
+
type: 'behavior event',
|
|
334
|
+
behaviorEvent: actionIntend.event,
|
|
335
|
+
editor: event.editor,
|
|
336
|
+
})
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
333
339
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
340
|
+
const action = {
|
|
341
|
+
...actionIntend,
|
|
342
|
+
editor: event.editor,
|
|
343
|
+
}
|
|
338
344
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
(actionIntend) => actionIntend.type === 'reselect',
|
|
342
|
-
)
|
|
343
|
-
) {
|
|
344
|
-
enqueue.raise({
|
|
345
|
-
type: 'selection',
|
|
346
|
-
selection: toPortableTextRange(
|
|
347
|
-
event.editor.children,
|
|
348
|
-
event.editor.selection,
|
|
349
|
-
context.schema,
|
|
350
|
-
),
|
|
345
|
+
performAction({context, action})
|
|
346
|
+
}
|
|
351
347
|
})
|
|
352
|
-
}
|
|
348
|
+
})
|
|
349
|
+
event.editor.onChange()
|
|
353
350
|
}
|
|
354
351
|
|
|
355
352
|
if (behaviorOverwritten) {
|
|
@@ -363,10 +360,12 @@ export const editorMachine = setup({
|
|
|
363
360
|
return
|
|
364
361
|
}
|
|
365
362
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
363
|
+
withApplyingBehaviorActions(event.editor, () => {
|
|
364
|
+
Editor.withoutNormalizing(event.editor, () => {
|
|
365
|
+
performAction({
|
|
366
|
+
context,
|
|
367
|
+
action: defaultAction,
|
|
368
|
+
})
|
|
370
369
|
})
|
|
371
370
|
})
|
|
372
371
|
event.editor.onChange()
|
|
@@ -450,13 +449,7 @@ export const editorMachine = setup({
|
|
|
450
449
|
'behavior event': {
|
|
451
450
|
actions: 'handle behavior event',
|
|
452
451
|
},
|
|
453
|
-
'annotation
|
|
454
|
-
actions: emit(({event}) => event),
|
|
455
|
-
},
|
|
456
|
-
'annotation.remove': {
|
|
457
|
-
actions: emit(({event}) => event),
|
|
458
|
-
},
|
|
459
|
-
'annotation.toggle': {
|
|
452
|
+
'annotation.*': {
|
|
460
453
|
actions: emit(({event}) => event),
|
|
461
454
|
},
|
|
462
455
|
'blur': {
|
|
@@ -474,6 +467,9 @@ export const editorMachine = setup({
|
|
|
474
467
|
'list item.*': {
|
|
475
468
|
actions: emit(({event}) => event),
|
|
476
469
|
},
|
|
470
|
+
'select': {
|
|
471
|
+
actions: emit(({event}) => event),
|
|
472
|
+
},
|
|
477
473
|
'style.*': {
|
|
478
474
|
actions: emit(({event}) => event),
|
|
479
475
|
},
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {Editor} from 'slate'
|
|
2
|
+
import {toPortableTextRange} from '../../utils/ranges'
|
|
3
|
+
import {fromSlateValue} from '../../utils/values'
|
|
4
|
+
import {KEY_TO_VALUE_ELEMENT} from '../../utils/weakMaps'
|
|
2
5
|
import type {EditorActor} from '../editor-machine'
|
|
6
|
+
import {isApplyingBehaviorActions} from '../with-applying-behavior-actions'
|
|
3
7
|
|
|
4
8
|
export function createWithEventListeners(
|
|
5
9
|
editorActor: EditorActor,
|
|
@@ -35,17 +39,6 @@ export function createWithEventListeners(
|
|
|
35
39
|
})
|
|
36
40
|
break
|
|
37
41
|
}
|
|
38
|
-
case 'annotation.toggle': {
|
|
39
|
-
editorActor.send({
|
|
40
|
-
type: 'behavior event',
|
|
41
|
-
behaviorEvent: {
|
|
42
|
-
type: 'annotation.toggle',
|
|
43
|
-
annotation: event.annotation,
|
|
44
|
-
},
|
|
45
|
-
editor,
|
|
46
|
-
})
|
|
47
|
-
break
|
|
48
|
-
}
|
|
49
42
|
case 'blur': {
|
|
50
43
|
editorActor.send({
|
|
51
44
|
type: 'behavior event',
|
|
@@ -56,28 +49,6 @@ export function createWithEventListeners(
|
|
|
56
49
|
})
|
|
57
50
|
break
|
|
58
51
|
}
|
|
59
|
-
case 'decorator.add': {
|
|
60
|
-
editorActor.send({
|
|
61
|
-
type: 'behavior event',
|
|
62
|
-
behaviorEvent: {
|
|
63
|
-
type: 'decorator.add',
|
|
64
|
-
decorator: event.decorator,
|
|
65
|
-
},
|
|
66
|
-
editor,
|
|
67
|
-
})
|
|
68
|
-
break
|
|
69
|
-
}
|
|
70
|
-
case 'decorator.remove': {
|
|
71
|
-
editorActor.send({
|
|
72
|
-
type: 'behavior event',
|
|
73
|
-
behaviorEvent: {
|
|
74
|
-
type: 'decorator.remove',
|
|
75
|
-
decorator: event.decorator,
|
|
76
|
-
},
|
|
77
|
-
editor,
|
|
78
|
-
})
|
|
79
|
-
break
|
|
80
|
-
}
|
|
81
52
|
case 'decorator.toggle': {
|
|
82
53
|
editorActor.send({
|
|
83
54
|
type: 'behavior event',
|
|
@@ -133,6 +104,17 @@ export function createWithEventListeners(
|
|
|
133
104
|
})
|
|
134
105
|
break
|
|
135
106
|
}
|
|
107
|
+
case 'select': {
|
|
108
|
+
editorActor.send({
|
|
109
|
+
type: 'behavior event',
|
|
110
|
+
behaviorEvent: {
|
|
111
|
+
type: 'select',
|
|
112
|
+
selection: event.selection,
|
|
113
|
+
},
|
|
114
|
+
editor,
|
|
115
|
+
})
|
|
116
|
+
break
|
|
117
|
+
}
|
|
136
118
|
case 'style.toggle': {
|
|
137
119
|
editorActor.send({
|
|
138
120
|
type: 'behavior event',
|
|
@@ -152,29 +134,7 @@ export function createWithEventListeners(
|
|
|
152
134
|
}
|
|
153
135
|
})
|
|
154
136
|
|
|
155
|
-
|
|
156
|
-
editorActor.send({
|
|
157
|
-
type: 'behavior event',
|
|
158
|
-
behaviorEvent: {
|
|
159
|
-
type: 'decorator.add',
|
|
160
|
-
decorator: mark,
|
|
161
|
-
},
|
|
162
|
-
editor,
|
|
163
|
-
})
|
|
164
|
-
return
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
editor.removeMark = (mark) => {
|
|
168
|
-
editorActor.send({
|
|
169
|
-
type: 'behavior event',
|
|
170
|
-
behaviorEvent: {
|
|
171
|
-
type: 'decorator.remove',
|
|
172
|
-
decorator: mark,
|
|
173
|
-
},
|
|
174
|
-
editor,
|
|
175
|
-
})
|
|
176
|
-
return
|
|
177
|
-
}
|
|
137
|
+
const {select} = editor
|
|
178
138
|
|
|
179
139
|
editor.deleteBackward = (unit) => {
|
|
180
140
|
editorActor.send({
|
|
@@ -235,6 +195,33 @@ export function createWithEventListeners(
|
|
|
235
195
|
return
|
|
236
196
|
}
|
|
237
197
|
|
|
198
|
+
editor.select = (location) => {
|
|
199
|
+
if (isApplyingBehaviorActions(editor)) {
|
|
200
|
+
select(location)
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const range = Editor.range(editor, location)
|
|
205
|
+
|
|
206
|
+
editorActor.send({
|
|
207
|
+
type: 'behavior event',
|
|
208
|
+
behaviorEvent: {
|
|
209
|
+
type: 'select',
|
|
210
|
+
selection: toPortableTextRange(
|
|
211
|
+
fromSlateValue(
|
|
212
|
+
editor.children,
|
|
213
|
+
editorActor.getSnapshot().context.schema.block.name,
|
|
214
|
+
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
215
|
+
),
|
|
216
|
+
range,
|
|
217
|
+
editorActor.getSnapshot().context.schema,
|
|
218
|
+
),
|
|
219
|
+
},
|
|
220
|
+
editor,
|
|
221
|
+
})
|
|
222
|
+
return
|
|
223
|
+
}
|
|
224
|
+
|
|
238
225
|
return editor
|
|
239
226
|
}
|
|
240
227
|
}
|
|
@@ -9,16 +9,6 @@ import type {PortableTextEditor} from '../PortableTextEditor'
|
|
|
9
9
|
|
|
10
10
|
const debug = debugWithName('plugin:withHotKeys')
|
|
11
11
|
|
|
12
|
-
const DEFAULT_HOTKEYS: HotkeyOptions = {
|
|
13
|
-
marks: {
|
|
14
|
-
'mod+b': 'strong',
|
|
15
|
-
'mod+i': 'em',
|
|
16
|
-
'mod+u': 'underline',
|
|
17
|
-
"mod+'": 'code',
|
|
18
|
-
},
|
|
19
|
-
custom: {},
|
|
20
|
-
}
|
|
21
|
-
|
|
22
12
|
/**
|
|
23
13
|
* This plugin takes care of all hotkeys in the editor
|
|
24
14
|
*
|
|
@@ -29,7 +19,7 @@ export function createWithHotkeys(
|
|
|
29
19
|
hotkeysFromOptions?: HotkeyOptions,
|
|
30
20
|
): (editor: PortableTextSlateEditor & ReactEditor) => any {
|
|
31
21
|
const reservedHotkeys = ['enter', 'tab', 'shift', 'delete', 'end']
|
|
32
|
-
const activeHotkeys = hotkeysFromOptions
|
|
22
|
+
const activeHotkeys = hotkeysFromOptions ?? {}
|
|
33
23
|
return function withHotKeys(editor: PortableTextSlateEditor & ReactEditor) {
|
|
34
24
|
editor.pteWithHotKeys = (event: KeyboardEvent<HTMLDivElement>): void => {
|
|
35
25
|
// Wire up custom marks hotkeys
|
|
@@ -741,7 +741,12 @@ export const addDecoratorActionImplementation: BehaviorActionImplementation<
|
|
|
741
741
|
editor.marks = marks as Text
|
|
742
742
|
}
|
|
743
743
|
}
|
|
744
|
-
|
|
744
|
+
|
|
745
|
+
if (editor.selection) {
|
|
746
|
+
// Reselect
|
|
747
|
+
const selection = editor.selection
|
|
748
|
+
editor.selection = {...selection}
|
|
749
|
+
}
|
|
745
750
|
}
|
|
746
751
|
}
|
|
747
752
|
|
|
@@ -823,6 +828,12 @@ export const removeDecoratorActionImplementation: BehaviorActionImplementation<
|
|
|
823
828
|
editor.marks = {marks: marks.marks, _type: 'span'} as Text
|
|
824
829
|
}
|
|
825
830
|
}
|
|
831
|
+
|
|
832
|
+
if (editor.selection) {
|
|
833
|
+
// Reselect
|
|
834
|
+
const selection = editor.selection
|
|
835
|
+
editor.selection = {...selection}
|
|
836
|
+
}
|
|
826
837
|
}
|
|
827
838
|
}
|
|
828
839
|
|
|
@@ -55,12 +55,8 @@ export function createWithPortableTextSelections(
|
|
|
55
55
|
|
|
56
56
|
const {onChange} = editor
|
|
57
57
|
editor.onChange = () => {
|
|
58
|
-
const hasChanges = editor.operations.length > 0
|
|
59
58
|
onChange()
|
|
60
|
-
if (
|
|
61
|
-
hasChanges &&
|
|
62
|
-
!editorActor.getSnapshot().matches({setup: 'setting up'})
|
|
63
|
-
) {
|
|
59
|
+
if (!editorActor.getSnapshot().matches({setup: 'setting up'})) {
|
|
64
60
|
emitPortableTextSelection()
|
|
65
61
|
}
|
|
66
62
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type {Editor} from 'slate'
|
|
2
|
+
|
|
3
|
+
const IS_APPLYING_BEHAVIOR_ACTIONS: WeakMap<Editor, boolean | undefined> =
|
|
4
|
+
new WeakMap()
|
|
5
|
+
|
|
6
|
+
export function withApplyingBehaviorActions(editor: Editor, fn: () => void) {
|
|
7
|
+
const prev = isApplyingBehaviorActions(editor)
|
|
8
|
+
IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, true)
|
|
9
|
+
fn()
|
|
10
|
+
IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, prev)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isApplyingBehaviorActions(editor: Editor) {
|
|
14
|
+
return IS_APPLYING_BEHAVIOR_ACTIONS.get(editor) ?? false
|
|
15
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {expect, test} from 'vitest'
|
|
2
|
+
import {getSelectedSpans, type EditorSchema, type EditorSelection} from '.'
|
|
3
|
+
import type {EditorSnapshot} from '../editor/editor-snapshot'
|
|
4
|
+
|
|
5
|
+
test(getSelectedSpans.name, () => {
|
|
6
|
+
function snapshot(selection: EditorSelection): EditorSnapshot {
|
|
7
|
+
return {
|
|
8
|
+
context: {
|
|
9
|
+
schema: {} as EditorSchema,
|
|
10
|
+
keyGenerator: () => '',
|
|
11
|
+
activeDecorators: [],
|
|
12
|
+
value: [
|
|
13
|
+
{
|
|
14
|
+
_type: 'block',
|
|
15
|
+
_key: 'b1',
|
|
16
|
+
children: [
|
|
17
|
+
{
|
|
18
|
+
_type: 'span',
|
|
19
|
+
_key: 's1',
|
|
20
|
+
text: 'foo',
|
|
21
|
+
marks: ['strong'],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
_type: 'span',
|
|
25
|
+
_key: 's2',
|
|
26
|
+
text: 'bar',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
_type: 'image',
|
|
32
|
+
_key: 'b2',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
_type: 'block',
|
|
36
|
+
_key: 'b3',
|
|
37
|
+
children: [
|
|
38
|
+
{
|
|
39
|
+
_type: 'span',
|
|
40
|
+
_key: 's3',
|
|
41
|
+
text: 'baz',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
selection,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
expect(
|
|
52
|
+
getSelectedSpans(
|
|
53
|
+
snapshot({
|
|
54
|
+
anchor: {
|
|
55
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
56
|
+
offset: 0,
|
|
57
|
+
},
|
|
58
|
+
focus: {
|
|
59
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
60
|
+
offset: 3,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
),
|
|
64
|
+
).toEqual([
|
|
65
|
+
{
|
|
66
|
+
node: {_type: 'span', _key: 's1', text: 'foo', marks: ['strong']},
|
|
67
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
68
|
+
},
|
|
69
|
+
])
|
|
70
|
+
|
|
71
|
+
expect(
|
|
72
|
+
getSelectedSpans(
|
|
73
|
+
snapshot({
|
|
74
|
+
anchor: {
|
|
75
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
76
|
+
offset: 2,
|
|
77
|
+
},
|
|
78
|
+
focus: {
|
|
79
|
+
path: [{_key: 'b1'}, 'children', {_key: 's2'}],
|
|
80
|
+
offset: 3,
|
|
81
|
+
},
|
|
82
|
+
}),
|
|
83
|
+
),
|
|
84
|
+
).toEqual([
|
|
85
|
+
{
|
|
86
|
+
node: {_type: 'span', _key: 's1', text: 'foo', marks: ['strong']},
|
|
87
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
node: {_type: 'span', _key: 's2', text: 'bar'},
|
|
91
|
+
path: [{_key: 'b1'}, 'children', {_key: 's2'}],
|
|
92
|
+
},
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
expect(
|
|
96
|
+
getSelectedSpans(
|
|
97
|
+
snapshot({
|
|
98
|
+
anchor: {
|
|
99
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
100
|
+
offset: 2,
|
|
101
|
+
},
|
|
102
|
+
focus: {
|
|
103
|
+
path: [{_key: 'b3'}, 'children', {_key: 's3'}],
|
|
104
|
+
offset: 2,
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
),
|
|
108
|
+
).toEqual([
|
|
109
|
+
{
|
|
110
|
+
node: {_type: 'span', _key: 's1', text: 'foo', marks: ['strong']},
|
|
111
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
node: {_type: 'span', _key: 's2', text: 'bar'},
|
|
115
|
+
path: [{_key: 'b1'}, 'children', {_key: 's2'}],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
node: {_type: 'span', _key: 's3', text: 'baz'},
|
|
119
|
+
path: [{_key: 'b3'}, 'children', {_key: 's3'}],
|
|
120
|
+
},
|
|
121
|
+
])
|
|
122
|
+
})
|
|
@@ -67,9 +67,11 @@ export const getSelectedSpans: EditorSelector<
|
|
|
67
67
|
path: [{_key: block._key}, 'children', {_key: child._key}],
|
|
68
68
|
})
|
|
69
69
|
|
|
70
|
-
if (
|
|
70
|
+
if (startSpanKey === endSpanKey) {
|
|
71
71
|
break
|
|
72
72
|
}
|
|
73
|
+
|
|
74
|
+
continue
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
if (endSpanKey && child._key === endSpanKey) {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {expect, test} from 'vitest'
|
|
2
|
+
import type {EditorSchema, EditorSelection} from '.'
|
|
3
|
+
import type {EditorSnapshot} from '../editor/editor-snapshot'
|
|
4
|
+
import {isActiveDecorator} from './selector.is-active-decorator'
|
|
5
|
+
|
|
6
|
+
test(isActiveDecorator.name, () => {
|
|
7
|
+
function snapshot(selection: EditorSelection): EditorSnapshot {
|
|
8
|
+
return {
|
|
9
|
+
context: {
|
|
10
|
+
schema: {} as EditorSchema,
|
|
11
|
+
keyGenerator: () => '',
|
|
12
|
+
activeDecorators: [],
|
|
13
|
+
value: [
|
|
14
|
+
{
|
|
15
|
+
_type: '_block',
|
|
16
|
+
_key: 'b1',
|
|
17
|
+
children: [
|
|
18
|
+
{
|
|
19
|
+
_type: 'span',
|
|
20
|
+
_key: 's1',
|
|
21
|
+
text: 'foo',
|
|
22
|
+
marks: ['strong'],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
_type: 'span',
|
|
26
|
+
_key: 's2',
|
|
27
|
+
text: 'bar',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
selection,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
expect(
|
|
38
|
+
isActiveDecorator('strong')(
|
|
39
|
+
snapshot({
|
|
40
|
+
anchor: {
|
|
41
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
42
|
+
offset: 0,
|
|
43
|
+
},
|
|
44
|
+
focus: {
|
|
45
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
46
|
+
offset: 3,
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
),
|
|
50
|
+
).toBe(true)
|
|
51
|
+
expect(
|
|
52
|
+
isActiveDecorator('strong')(
|
|
53
|
+
snapshot({
|
|
54
|
+
anchor: {
|
|
55
|
+
path: [{_key: 'b1'}, 'children', {_key: 's1'}],
|
|
56
|
+
offset: 2,
|
|
57
|
+
},
|
|
58
|
+
focus: {
|
|
59
|
+
path: [{_key: 'b1'}, 'children', {_key: 's2'}],
|
|
60
|
+
offset: 3,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
),
|
|
64
|
+
).toBe(false)
|
|
65
|
+
})
|