@portabletext/editor 2.1.11 → 2.3.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/util.merge-text-blocks.cjs +2 -2
- package/lib/_chunks-cjs/util.merge-text-blocks.cjs.map +1 -1
- package/lib/_chunks-dts/behavior.types.action.d.cts +9 -9
- package/lib/_chunks-es/selector.is-selection-expanded.js +1 -1
- package/lib/_chunks-es/util.merge-text-blocks.js +2 -2
- package/lib/_chunks-es/util.merge-text-blocks.js.map +1 -1
- package/lib/index.cjs +227 -24
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +230 -27
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +3 -3
- package/package.json +1 -1
- package/src/behaviors/behavior.abstract.delete.ts +91 -1
- package/src/behaviors/behavior.abstract.split.ts +77 -1
- package/src/converters/converter.portable-text.deserialize.test.ts +3 -3
- package/src/converters/converter.portable-text.ts +1 -1
- package/src/converters/converter.text-html.ts +1 -1
- package/src/converters/converter.text-plain.ts +1 -1
- package/src/editor/Editable.tsx +2 -2
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +29 -35
- package/src/editor/plugins/createWithObjectKeys.ts +110 -1
- package/src/internal-utils/test-editor.tsx +2 -0
- package/src/operations/behavior.operation.delete.ts +31 -2
- package/src/operations/behavior.operation.insert.block.ts +85 -13
- package/src/utils/util.merge-text-blocks.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import {isEqual} from 'lodash'
|
|
1
2
|
import {Editor, Path, Point, Range, Transforms, type Descendant} from 'slate'
|
|
2
3
|
import {DOMEditor} from 'slate-dom'
|
|
3
|
-
import
|
|
4
|
-
import {parseBlock} from '../internal-utils/parse-blocks'
|
|
4
|
+
import {isSpan, parseBlock} from '../internal-utils/parse-blocks'
|
|
5
5
|
import {
|
|
6
6
|
getFocusBlock,
|
|
7
7
|
getFocusChild,
|
|
@@ -12,7 +12,10 @@ import {
|
|
|
12
12
|
import {isEqualToEmptyEditor, toSlateValue} from '../internal-utils/values'
|
|
13
13
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
14
14
|
import {isEmptyTextBlock} from '../utils'
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
BehaviorOperationImplementation,
|
|
17
|
+
BehaviorOperationImplementationContext,
|
|
18
|
+
} from './behavior.operations'
|
|
16
19
|
|
|
17
20
|
export const insertBlockOperationImplementation: BehaviorOperationImplementation<
|
|
18
21
|
'insert.block'
|
|
@@ -36,26 +39,26 @@ export const insertBlockOperationImplementation: BehaviorOperationImplementation
|
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
insertBlock({
|
|
42
|
+
context,
|
|
39
43
|
block: fragment,
|
|
40
44
|
placement: operation.placement,
|
|
41
45
|
select: operation.select ?? 'start',
|
|
42
46
|
editor: operation.editor,
|
|
43
|
-
schema: context.schema,
|
|
44
47
|
})
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export function insertBlock({
|
|
51
|
+
context,
|
|
48
52
|
block,
|
|
49
53
|
placement,
|
|
50
54
|
select,
|
|
51
55
|
editor,
|
|
52
|
-
schema,
|
|
53
56
|
}: {
|
|
57
|
+
context: BehaviorOperationImplementationContext
|
|
54
58
|
block: Descendant
|
|
55
59
|
placement: 'auto' | 'after' | 'before'
|
|
56
60
|
select: 'start' | 'end' | 'none'
|
|
57
61
|
editor: PortableTextSlateEditor
|
|
58
|
-
schema: EditorSchema
|
|
59
62
|
}) {
|
|
60
63
|
const [startBlock, startBlockPath] = getSelectionStartBlock({editor})
|
|
61
64
|
const [endBlock, endBlockPath] = getSelectionEndBlock({editor})
|
|
@@ -93,7 +96,7 @@ export function insertBlock({
|
|
|
93
96
|
} else {
|
|
94
97
|
// placement === 'auto'
|
|
95
98
|
|
|
96
|
-
if (lastBlock && isEqualToEmptyEditor([lastBlock], schema)) {
|
|
99
|
+
if (lastBlock && isEqualToEmptyEditor([lastBlock], context.schema)) {
|
|
97
100
|
// And if the last block was an empty text block, let's remove
|
|
98
101
|
// that too
|
|
99
102
|
Transforms.removeNodes(editor, {at: lastBlockPath})
|
|
@@ -211,7 +214,7 @@ export function insertBlock({
|
|
|
211
214
|
Transforms.select(editor, adjustedSelection)
|
|
212
215
|
}
|
|
213
216
|
|
|
214
|
-
if (focusBlock && isEqualToEmptyEditor([focusBlock], schema)) {
|
|
217
|
+
if (focusBlock && isEqualToEmptyEditor([focusBlock], context.schema)) {
|
|
215
218
|
Transforms.removeNodes(editor, {at: focusBlockPath})
|
|
216
219
|
}
|
|
217
220
|
|
|
@@ -221,7 +224,7 @@ export function insertBlock({
|
|
|
221
224
|
if (editor.isTextBlock(endBlock) && editor.isTextBlock(block)) {
|
|
222
225
|
const selectionStartPoint = Range.start(currentSelection)
|
|
223
226
|
|
|
224
|
-
if (isEqualToEmptyEditor([endBlock], schema)) {
|
|
227
|
+
if (isEqualToEmptyEditor([endBlock], context.schema)) {
|
|
225
228
|
const currentSelection = editor.selection
|
|
226
229
|
|
|
227
230
|
Transforms.insertNodes(editor, [block], {
|
|
@@ -241,25 +244,94 @@ export function insertBlock({
|
|
|
241
244
|
return
|
|
242
245
|
}
|
|
243
246
|
|
|
247
|
+
const endBlockChildKeys = endBlock.children.map((child) => child._key)
|
|
248
|
+
const endBlockMarkDefsKeys =
|
|
249
|
+
endBlock.markDefs?.map((markDef) => markDef._key) ?? []
|
|
250
|
+
|
|
251
|
+
// Assign new keys to markDefs with duplicate keys and keep track of
|
|
252
|
+
// the mapping between the old and new keys
|
|
253
|
+
const markDefKeyMap = new Map<string, string>()
|
|
254
|
+
const adjustedMarkDefs = block.markDefs?.map((markDef) => {
|
|
255
|
+
if (endBlockMarkDefsKeys.includes(markDef._key)) {
|
|
256
|
+
const newKey = context.keyGenerator()
|
|
257
|
+
markDefKeyMap.set(markDef._key, newKey)
|
|
258
|
+
return {
|
|
259
|
+
...markDef,
|
|
260
|
+
_key: newKey,
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return markDef
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
// Assign new keys to spans with duplicate keys and update any markDef
|
|
268
|
+
// key if needed
|
|
269
|
+
const adjustedChildren = block.children.map((child) => {
|
|
270
|
+
if (isSpan(context, child)) {
|
|
271
|
+
const marks =
|
|
272
|
+
child.marks?.map((mark) => {
|
|
273
|
+
const markDefKey = markDefKeyMap.get(mark)
|
|
274
|
+
|
|
275
|
+
if (markDefKey) {
|
|
276
|
+
return markDefKey
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return mark
|
|
280
|
+
}) ?? []
|
|
281
|
+
|
|
282
|
+
if (!isEqual(child.marks, marks)) {
|
|
283
|
+
return {
|
|
284
|
+
...child,
|
|
285
|
+
_key: endBlockChildKeys.includes(child._key)
|
|
286
|
+
? context.keyGenerator()
|
|
287
|
+
: child._key,
|
|
288
|
+
marks,
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (endBlockChildKeys.includes(child._key)) {
|
|
294
|
+
return {
|
|
295
|
+
...child,
|
|
296
|
+
_key: context.keyGenerator(),
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return child
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
// Carry over the markDefs from the incoming block to the end block
|
|
244
304
|
Transforms.setNodes(
|
|
245
305
|
editor,
|
|
246
306
|
{
|
|
247
|
-
markDefs: [
|
|
307
|
+
markDefs: [
|
|
308
|
+
...(endBlock.markDefs ?? []),
|
|
309
|
+
...(adjustedMarkDefs ?? []),
|
|
310
|
+
],
|
|
248
311
|
},
|
|
249
312
|
{
|
|
250
313
|
at: endBlockPath,
|
|
251
314
|
},
|
|
252
315
|
)
|
|
253
316
|
|
|
317
|
+
// If the children have changed, we need to create a new block with
|
|
318
|
+
// the adjusted children
|
|
319
|
+
const adjustedBlock = !isEqual(block.children, adjustedChildren)
|
|
320
|
+
? {
|
|
321
|
+
...block,
|
|
322
|
+
children: adjustedChildren as Descendant[],
|
|
323
|
+
}
|
|
324
|
+
: block
|
|
325
|
+
|
|
254
326
|
if (select === 'end') {
|
|
255
|
-
Transforms.insertFragment(editor, [
|
|
327
|
+
Transforms.insertFragment(editor, [adjustedBlock], {
|
|
256
328
|
voids: true,
|
|
257
329
|
})
|
|
258
330
|
|
|
259
331
|
return
|
|
260
332
|
}
|
|
261
333
|
|
|
262
|
-
Transforms.insertFragment(editor, [
|
|
334
|
+
Transforms.insertFragment(editor, [adjustedBlock], {
|
|
263
335
|
at: currentSelection,
|
|
264
336
|
voids: true,
|
|
265
337
|
})
|
|
@@ -301,7 +373,7 @@ export function insertBlock({
|
|
|
301
373
|
Transforms.select(editor, Editor.start(editor, endBlockPath))
|
|
302
374
|
}
|
|
303
375
|
|
|
304
|
-
if (isEmptyTextBlock(
|
|
376
|
+
if (isEmptyTextBlock(context, endBlock)) {
|
|
305
377
|
Transforms.removeNodes(editor, {at: Path.next(endBlockPath)})
|
|
306
378
|
}
|
|
307
379
|
} else if (
|
|
@@ -18,7 +18,7 @@ export function mergeTextBlocks({
|
|
|
18
18
|
const parsedIncomingBlock = parseBlock({
|
|
19
19
|
context,
|
|
20
20
|
block: incomingBlock,
|
|
21
|
-
options: {refreshKeys:
|
|
21
|
+
options: {refreshKeys: false, validateFields: false},
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
if (!parsedIncomingBlock || !isTextBlock(context, parsedIncomingBlock)) {
|