@portabletext/editor 1.12.0 → 1.12.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/index.d.mts +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.esm.js +119 -27
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +119 -27
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +119 -27
- package/lib/index.mjs.map +1 -1
- package/package.json +12 -12
- package/src/editor/behavior/behavior.action-utils.insert-block.ts +3 -1
- package/src/editor/behavior/behavior.markdown.ts +21 -15
- package/src/editor/behavior/behavior.types.ts +2 -2
- package/src/editor/behavior/behavior.utils.get-selection-text.ts +92 -0
- package/src/editor/behavior/behavior.utils.get-start-point.ts +26 -0
- package/src/editor/behavior/behavior.utils.is-keyed-segment.ts +5 -0
- package/src/editor/behavior/behavior.utils.reverse-selection.ts +21 -0
- package/src/editor/behavior/behavior.utilts.get-text-before.ts +31 -0
package/lib/index.d.mts
CHANGED
|
@@ -123,7 +123,7 @@ export declare type BehaviorActionIntend =
|
|
|
123
123
|
| BehaviorEvent
|
|
124
124
|
| {
|
|
125
125
|
type: 'insert block object'
|
|
126
|
-
placement: 'auto' | 'after'
|
|
126
|
+
placement: 'auto' | 'after' | 'before'
|
|
127
127
|
blockObject: {
|
|
128
128
|
name: string
|
|
129
129
|
value?: {
|
|
@@ -144,7 +144,7 @@ export declare type BehaviorActionIntend =
|
|
|
144
144
|
}
|
|
145
145
|
| {
|
|
146
146
|
type: 'insert text block'
|
|
147
|
-
placement: 'auto' | 'after'
|
|
147
|
+
placement: 'auto' | 'after' | 'before'
|
|
148
148
|
textBlock?: {
|
|
149
149
|
children?: PortableTextTextBlock['children']
|
|
150
150
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -123,7 +123,7 @@ export declare type BehaviorActionIntend =
|
|
|
123
123
|
| BehaviorEvent
|
|
124
124
|
| {
|
|
125
125
|
type: 'insert block object'
|
|
126
|
-
placement: 'auto' | 'after'
|
|
126
|
+
placement: 'auto' | 'after' | 'before'
|
|
127
127
|
blockObject: {
|
|
128
128
|
name: string
|
|
129
129
|
value?: {
|
|
@@ -144,7 +144,7 @@ export declare type BehaviorActionIntend =
|
|
|
144
144
|
}
|
|
145
145
|
| {
|
|
146
146
|
type: 'insert text block'
|
|
147
|
-
placement: 'auto' | 'after'
|
|
147
|
+
placement: 'auto' | 'after' | 'before'
|
|
148
148
|
textBlock?: {
|
|
149
149
|
children?: PortableTextTextBlock['children']
|
|
150
150
|
}
|
package/lib/index.esm.js
CHANGED
|
@@ -364,21 +364,6 @@ function looksLikeUrl(text) {
|
|
|
364
364
|
}
|
|
365
365
|
return looksLikeUrl2;
|
|
366
366
|
}
|
|
367
|
-
function isPortableTextSpan(node) {
|
|
368
|
-
return node._type === "span" && "text" in node && typeof node.text == "string" && (typeof node.marks > "u" || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
|
|
369
|
-
}
|
|
370
|
-
function isPortableTextBlock(node) {
|
|
371
|
-
return (
|
|
372
|
-
// A block doesn't _have_ to be named 'block' - to differentiate between
|
|
373
|
-
// allowed child types and marks, one might name them differently
|
|
374
|
-
typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
|
|
375
|
-
node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
|
|
376
|
-
(!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
|
|
377
|
-
node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
|
|
378
|
-
"children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
|
|
379
|
-
node.children.every((child) => typeof child == "object" && "_type" in child)
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
367
|
function blockOffsetToSpanSelectionPoint({
|
|
383
368
|
value,
|
|
384
369
|
blockOffset
|
|
@@ -431,6 +416,87 @@ function spanSelectionPointToBlockOffset({
|
|
|
431
416
|
}
|
|
432
417
|
}
|
|
433
418
|
}
|
|
419
|
+
function isKeyedSegment$1(segment) {
|
|
420
|
+
return typeof segment == "object" && segment !== null && "_key" in segment;
|
|
421
|
+
}
|
|
422
|
+
function reverseSelection(selection) {
|
|
423
|
+
return selection && (selection.backward ? {
|
|
424
|
+
anchor: selection.focus,
|
|
425
|
+
focus: selection.anchor,
|
|
426
|
+
backward: !1
|
|
427
|
+
} : {
|
|
428
|
+
anchor: selection.focus,
|
|
429
|
+
focus: selection.anchor,
|
|
430
|
+
backward: !0
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function getSelectionText({
|
|
434
|
+
value,
|
|
435
|
+
selection
|
|
436
|
+
}) {
|
|
437
|
+
let text = "";
|
|
438
|
+
if (!value || !selection)
|
|
439
|
+
return text;
|
|
440
|
+
const forwardSelection = selection.backward ? reverseSelection(selection) : selection;
|
|
441
|
+
if (!forwardSelection)
|
|
442
|
+
return text;
|
|
443
|
+
for (const block of value)
|
|
444
|
+
if (!(isKeyedSegment$1(forwardSelection.anchor.path[0]) && block._key !== forwardSelection.anchor.path[0]._key) && isPortableTextTextBlock(block)) {
|
|
445
|
+
for (const child of block.children)
|
|
446
|
+
if (isPortableTextSpan$1(child)) {
|
|
447
|
+
if (isKeyedSegment$1(forwardSelection.anchor.path[2]) && child._key === forwardSelection.anchor.path[2]._key && isKeyedSegment$1(forwardSelection.focus.path[2]) && child._key === forwardSelection.focus.path[2]._key) {
|
|
448
|
+
text = text + child.text.slice(forwardSelection.anchor.offset, forwardSelection.focus.offset);
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
if (isKeyedSegment$1(forwardSelection.anchor.path[2]) && child._key === forwardSelection.anchor.path[2]._key) {
|
|
452
|
+
text = text + child.text.slice(forwardSelection.anchor.offset);
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (isKeyedSegment$1(forwardSelection.focus.path[2]) && child._key === forwardSelection.focus.path[2]._key) {
|
|
456
|
+
text = text + child.text.slice(0, forwardSelection.focus.offset);
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
if (isKeyedSegment$1(forwardSelection.focus.path[0]) && block._key === forwardSelection.focus.path[0]._key)
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
return text;
|
|
464
|
+
}
|
|
465
|
+
function getStartPoint({
|
|
466
|
+
node,
|
|
467
|
+
path
|
|
468
|
+
}) {
|
|
469
|
+
return isPortableTextTextBlock(node) ? {
|
|
470
|
+
path: [...path, "children", {
|
|
471
|
+
_key: node.children[0]._key
|
|
472
|
+
}],
|
|
473
|
+
offset: 0
|
|
474
|
+
} : {
|
|
475
|
+
path,
|
|
476
|
+
offset: 0
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function getBlockTextBefore({
|
|
480
|
+
value,
|
|
481
|
+
point
|
|
482
|
+
}) {
|
|
483
|
+
const key = isKeyedSegment$1(point.path[0]) ? point.path[0]._key : void 0, block = key ? value.find((block2) => block2._key === key) : void 0;
|
|
484
|
+
if (!block)
|
|
485
|
+
return "";
|
|
486
|
+
const startPoint = getStartPoint({
|
|
487
|
+
node: block,
|
|
488
|
+
path: [{
|
|
489
|
+
_key: block._key
|
|
490
|
+
}]
|
|
491
|
+
});
|
|
492
|
+
return getSelectionText({
|
|
493
|
+
value,
|
|
494
|
+
selection: {
|
|
495
|
+
anchor: startPoint,
|
|
496
|
+
focus: point
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
434
500
|
function createMarkdownBehaviors(config) {
|
|
435
501
|
const automaticBlockquoteOnSpace = {
|
|
436
502
|
on: "insert text",
|
|
@@ -503,11 +569,24 @@ function createMarkdownBehaviors(config) {
|
|
|
503
569
|
}), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
|
|
504
570
|
if (!hrObject || !focusBlock || !selectionCollapsed)
|
|
505
571
|
return !1;
|
|
506
|
-
const
|
|
507
|
-
|
|
572
|
+
const textBefore = getBlockTextBefore({
|
|
573
|
+
value: context.value,
|
|
574
|
+
point: context.selection.focus
|
|
575
|
+
}), hrBlockOffsets = {
|
|
576
|
+
anchor: {
|
|
577
|
+
path: focusBlock.path,
|
|
578
|
+
offset: 0
|
|
579
|
+
},
|
|
580
|
+
focus: {
|
|
581
|
+
path: focusBlock.path,
|
|
582
|
+
offset: 3
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
return textBefore === `${hrCharacter}${hrCharacter}` ? {
|
|
508
586
|
hrObject,
|
|
509
587
|
focusBlock,
|
|
510
|
-
hrCharacter
|
|
588
|
+
hrCharacter,
|
|
589
|
+
hrBlockOffsets
|
|
511
590
|
} : !1;
|
|
512
591
|
},
|
|
513
592
|
actions: [(_, {
|
|
@@ -517,17 +596,14 @@ function createMarkdownBehaviors(config) {
|
|
|
517
596
|
text: hrCharacter
|
|
518
597
|
}], (_, {
|
|
519
598
|
hrObject,
|
|
520
|
-
|
|
599
|
+
hrBlockOffsets
|
|
521
600
|
}) => [{
|
|
522
601
|
type: "insert block object",
|
|
523
|
-
placement: "
|
|
602
|
+
placement: "before",
|
|
524
603
|
blockObject: hrObject
|
|
525
604
|
}, {
|
|
526
|
-
type: "delete
|
|
527
|
-
|
|
528
|
-
}, {
|
|
529
|
-
type: "insert text block",
|
|
530
|
-
placement: "after"
|
|
605
|
+
type: "delete text",
|
|
606
|
+
...hrBlockOffsets
|
|
531
607
|
}]]
|
|
532
608
|
}, automaticHrOnPaste = {
|
|
533
609
|
on: "paste",
|
|
@@ -4127,6 +4203,21 @@ function createWithPortableTextLists(types) {
|
|
|
4127
4203
|
}, editor;
|
|
4128
4204
|
};
|
|
4129
4205
|
}
|
|
4206
|
+
function isPortableTextSpan(node) {
|
|
4207
|
+
return node._type === "span" && "text" in node && typeof node.text == "string" && (typeof node.marks > "u" || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
|
|
4208
|
+
}
|
|
4209
|
+
function isPortableTextBlock(node) {
|
|
4210
|
+
return (
|
|
4211
|
+
// A block doesn't _have_ to be named 'block' - to differentiate between
|
|
4212
|
+
// allowed child types and marks, one might name them differently
|
|
4213
|
+
typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
|
|
4214
|
+
node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
|
|
4215
|
+
(!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
|
|
4216
|
+
node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
|
|
4217
|
+
"children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
|
|
4218
|
+
node.children.every((child) => typeof child == "object" && "_type" in child)
|
|
4219
|
+
);
|
|
4220
|
+
}
|
|
4130
4221
|
function getPreviousSpan({
|
|
4131
4222
|
editor,
|
|
4132
4223
|
blockPath,
|
|
@@ -4852,8 +4943,9 @@ function insertBlock({
|
|
|
4852
4943
|
offset: 0
|
|
4853
4944
|
}
|
|
4854
4945
|
});
|
|
4855
|
-
} else
|
|
4856
|
-
|
|
4946
|
+
} else placement === "before" ? Transforms.insertNodes(editor, block, {
|
|
4947
|
+
at: focusBlockPath
|
|
4948
|
+
}) : Editor.insertNode(editor, block);
|
|
4857
4949
|
focusBlock && isEqualToEmptyEditor([focusBlock], schema) && Transforms.removeNodes(editor, {
|
|
4858
4950
|
at: focusBlockPath
|
|
4859
4951
|
});
|