@portabletext/editor 1.1.3 → 1.1.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/index.esm.js +85 -16
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +85 -16
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +85 -16
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/editor/plugins/createWithInsertBreak.ts +51 -7
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +106 -22
package/package.json
CHANGED
|
@@ -21,6 +21,24 @@ export function createWithInsertBreak(
|
|
|
21
21
|
return
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
const [focusSpan] = Array.from(
|
|
25
|
+
Editor.nodes(editor, {
|
|
26
|
+
mode: 'lowest',
|
|
27
|
+
at: editor.selection.focus,
|
|
28
|
+
match: (n) => editor.isTextSpan(n),
|
|
29
|
+
voids: false,
|
|
30
|
+
}),
|
|
31
|
+
)[0] ?? [undefined]
|
|
32
|
+
const focusDecorators =
|
|
33
|
+
focusSpan.marks?.filter((mark) =>
|
|
34
|
+
types.decorators.some((decorator) => decorator.value === mark),
|
|
35
|
+
) ?? []
|
|
36
|
+
const focusAnnotations =
|
|
37
|
+
focusSpan.marks?.filter(
|
|
38
|
+
(mark) =>
|
|
39
|
+
!types.decorators.some((decorator) => decorator.value === mark),
|
|
40
|
+
) ?? []
|
|
41
|
+
|
|
24
42
|
const focusBlockPath = editor.selection.focus.path.slice(0, 1)
|
|
25
43
|
const focusBlock = Node.descendant(editor, focusBlockPath) as
|
|
26
44
|
| SlateTextBlock
|
|
@@ -34,15 +52,11 @@ export function createWithInsertBreak(
|
|
|
34
52
|
})
|
|
35
53
|
|
|
36
54
|
if (isEndAtStartOfBlock && Range.isCollapsed(editor.selection)) {
|
|
37
|
-
const focusDecorators = editor.isTextSpan(focusBlock.children[0])
|
|
38
|
-
? (focusBlock.children[0].marks ?? []).filter((mark) =>
|
|
39
|
-
types.decorators.some((decorator) => decorator.value === mark),
|
|
40
|
-
)
|
|
41
|
-
: []
|
|
42
|
-
|
|
43
55
|
Editor.insertNode(
|
|
44
56
|
editor,
|
|
45
|
-
editor.pteCreateTextBlock({
|
|
57
|
+
editor.pteCreateTextBlock({
|
|
58
|
+
decorators: focusAnnotations.length === 0 ? focusDecorators : [],
|
|
59
|
+
}),
|
|
46
60
|
)
|
|
47
61
|
|
|
48
62
|
const [nextBlockPath] = Path.next(focusBlockPath)
|
|
@@ -64,6 +78,36 @@ export function createWithInsertBreak(
|
|
|
64
78
|
? lastFocusBlockChild.text.length
|
|
65
79
|
: 0,
|
|
66
80
|
})
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
isStartAtEndOfBlock &&
|
|
84
|
+
Range.isCollapsed(editor.selection) &&
|
|
85
|
+
focusDecorators.length > 0 &&
|
|
86
|
+
focusAnnotations.length > 0
|
|
87
|
+
) {
|
|
88
|
+
Editor.withoutNormalizing(editor, () => {
|
|
89
|
+
if (!editor.selection) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Editor.insertNode(
|
|
94
|
+
editor,
|
|
95
|
+
editor.pteCreateTextBlock({
|
|
96
|
+
decorators: [],
|
|
97
|
+
}),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const [nextBlockPath] = Path.next(focusBlockPath)
|
|
101
|
+
|
|
102
|
+
Transforms.setSelection(editor, {
|
|
103
|
+
anchor: {path: [nextBlockPath, 0], offset: 0},
|
|
104
|
+
focus: {path: [nextBlockPath, 0], offset: 0},
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
editor.onChange()
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
67
111
|
const isInTheMiddleOfNode = !isEndAtStartOfBlock && !isStartAtEndOfBlock
|
|
68
112
|
|
|
69
113
|
if (isInTheMiddleOfNode) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {isPortableTextBlock, isPortableTextSpan} from '@portabletext/toolkit'
|
|
8
|
-
import type {PortableTextObject} from '@sanity/types'
|
|
8
|
+
import type {PortableTextObject, PortableTextSpan} from '@sanity/types'
|
|
9
9
|
import {isEqual, uniq} from 'lodash'
|
|
10
10
|
import {Editor, Element, Node, Path, Range, Text, Transforms} from 'slate'
|
|
11
11
|
import type {
|
|
@@ -288,14 +288,20 @@ export function createWithPortableTextMarkModel(
|
|
|
288
288
|
: false
|
|
289
289
|
|
|
290
290
|
if (selection && collapsedSelection) {
|
|
291
|
-
const [
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
291
|
+
const [_block, blockPath] = Editor.node(editor, selection, {
|
|
292
|
+
depth: 1,
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
const [span, spanPath] =
|
|
296
|
+
Array.from(
|
|
297
|
+
Editor.nodes(editor, {
|
|
298
|
+
mode: 'lowest',
|
|
299
|
+
at: selection.focus,
|
|
300
|
+
match: (n) => editor.isTextSpan(n),
|
|
301
|
+
voids: false,
|
|
302
|
+
}),
|
|
303
|
+
)[0] ?? ([undefined, undefined] as const)
|
|
304
|
+
|
|
299
305
|
const marks = span.marks ?? []
|
|
300
306
|
const marksWithoutAnnotations = marks.filter((mark) =>
|
|
301
307
|
decorators.includes(mark),
|
|
@@ -303,19 +309,97 @@ export function createWithPortableTextMarkModel(
|
|
|
303
309
|
const spanHasAnnotations =
|
|
304
310
|
marks.length > marksWithoutAnnotations.length
|
|
305
311
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
312
|
+
const spanIsEmpty = span.text.length === 0
|
|
313
|
+
|
|
314
|
+
const atTheBeginningOfSpan = selection.anchor.offset === 0
|
|
315
|
+
const atTheEndOfSpan = selection.anchor.offset === span.text.length
|
|
316
|
+
|
|
317
|
+
let previousSpan: PortableTextSpan | undefined
|
|
318
|
+
let nextSpan: PortableTextSpan | undefined
|
|
319
|
+
|
|
320
|
+
for (const [child, childPath] of Node.children(editor, blockPath, {
|
|
321
|
+
reverse: true,
|
|
322
|
+
})) {
|
|
323
|
+
if (!editor.isTextSpan(child)) {
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (Path.isBefore(childPath, spanPath)) {
|
|
328
|
+
previousSpan = child
|
|
329
|
+
break
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
for (const [child, childPath] of Node.children(editor, blockPath)) {
|
|
334
|
+
if (!editor.isTextSpan(child)) {
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (Path.isAfter(childPath, spanPath)) {
|
|
339
|
+
nextSpan = child
|
|
340
|
+
break
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const previousSpanHasSameAnnotation = previousSpan
|
|
345
|
+
? previousSpan.marks?.some(
|
|
346
|
+
(mark) => !decorators.includes(mark) && marks.includes(mark),
|
|
347
|
+
)
|
|
348
|
+
: false
|
|
349
|
+
const previousSpanHasSameMarks = previousSpan
|
|
350
|
+
? previousSpan.marks?.every((mark) => marks.includes(mark))
|
|
351
|
+
: false
|
|
352
|
+
const nextSpanHasSameAnnotation = nextSpan
|
|
353
|
+
? nextSpan.marks?.some(
|
|
354
|
+
(mark) => !decorators.includes(mark) && marks.includes(mark),
|
|
355
|
+
)
|
|
356
|
+
: false
|
|
357
|
+
const nextSpanHasSameMarks = nextSpan
|
|
358
|
+
? nextSpan.marks?.every((mark) => marks.includes(mark))
|
|
359
|
+
: false
|
|
360
|
+
|
|
361
|
+
if (spanHasAnnotations && !spanIsEmpty) {
|
|
362
|
+
if (atTheBeginningOfSpan) {
|
|
363
|
+
if (previousSpanHasSameMarks) {
|
|
364
|
+
Transforms.insertNodes(editor, {
|
|
365
|
+
_type: 'span',
|
|
366
|
+
_key: keyGenerator(),
|
|
367
|
+
text: op.text,
|
|
368
|
+
marks: previousSpan?.marks ?? [],
|
|
369
|
+
})
|
|
370
|
+
} else if (previousSpanHasSameAnnotation) {
|
|
371
|
+
apply(op)
|
|
372
|
+
} else {
|
|
373
|
+
Transforms.insertNodes(editor, {
|
|
374
|
+
_type: 'span',
|
|
375
|
+
_key: keyGenerator(),
|
|
376
|
+
text: op.text,
|
|
377
|
+
marks: [],
|
|
378
|
+
})
|
|
379
|
+
}
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (atTheEndOfSpan) {
|
|
384
|
+
if (nextSpanHasSameMarks) {
|
|
385
|
+
Transforms.insertNodes(editor, {
|
|
386
|
+
_type: 'span',
|
|
387
|
+
_key: keyGenerator(),
|
|
388
|
+
text: op.text,
|
|
389
|
+
marks: nextSpan?.marks ?? [],
|
|
390
|
+
})
|
|
391
|
+
} else if (nextSpanHasSameAnnotation) {
|
|
392
|
+
apply(op)
|
|
393
|
+
} else {
|
|
394
|
+
Transforms.insertNodes(editor, {
|
|
395
|
+
_type: 'span',
|
|
396
|
+
_key: keyGenerator(),
|
|
397
|
+
text: op.text,
|
|
398
|
+
marks: [],
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
return
|
|
402
|
+
}
|
|
319
403
|
}
|
|
320
404
|
}
|
|
321
405
|
}
|