@portabletext/editor 1.1.12 → 1.2.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.esm.js +155 -27
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +149 -21
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +155 -27
- package/lib/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/editor/behavior/behavior.core.block-objects.ts +106 -0
- package/src/editor/behavior/behavior.core.lists.ts +76 -0
- package/src/editor/behavior/behavior.core.ts +4 -102
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +161 -7
package/lib/index.js
CHANGED
|
@@ -812,6 +812,17 @@ function getFocusBlockObject(context) {
|
|
|
812
812
|
const focusBlock = getFocusBlock(context);
|
|
813
813
|
return focusBlock && !types.isPortableTextTextBlock(focusBlock.node) ? { node: focusBlock.node, path: focusBlock.path } : void 0;
|
|
814
814
|
}
|
|
815
|
+
function getFocusChild(context) {
|
|
816
|
+
const focusBlock = getFocusTextBlock(context);
|
|
817
|
+
if (!focusBlock)
|
|
818
|
+
return;
|
|
819
|
+
const key = context.selection && types.isKeySegment(context.selection.focus.path[2]) ? context.selection.focus.path[2]._key : void 0, node = key ? focusBlock.node.children.find((span) => span._key === key) : void 0;
|
|
820
|
+
return node && key ? { node, path: [...focusBlock.path, "children", { _key: key }] } : void 0;
|
|
821
|
+
}
|
|
822
|
+
function getFocusSpan(context) {
|
|
823
|
+
const focusChild = getFocusChild(context);
|
|
824
|
+
return focusChild && types.isPortableTextSpan(focusChild.node) ? { node: focusChild.node, path: focusChild.path } : void 0;
|
|
825
|
+
}
|
|
815
826
|
function getSelectionStartBlock(context) {
|
|
816
827
|
const key = context.selection.backward ? types.isKeySegment(context.selection.focus.path[0]) ? context.selection.focus.path[0]._key : void 0 : types.isKeySegment(context.selection.anchor.path[0]) ? context.selection.anchor.path[0]._key : void 0, node = key ? context.value.find((block) => block._key === key) : void 0;
|
|
817
828
|
return node && key ? { node, path: [{ _key: key }] } : void 0;
|
|
@@ -858,11 +869,7 @@ function getNextBlock(context) {
|
|
|
858
869
|
function isEmptyTextBlock(block) {
|
|
859
870
|
return block.children.length === 1 && block.children[0].text === "";
|
|
860
871
|
}
|
|
861
|
-
const
|
|
862
|
-
on: "insert soft break",
|
|
863
|
-
actions: [() => [{ type: "insert text", text: `
|
|
864
|
-
` }]]
|
|
865
|
-
}, breakingVoidBlock = {
|
|
872
|
+
const breakingVoidBlock = {
|
|
866
873
|
on: "insert break",
|
|
867
874
|
guard: ({ context }) => !!getFocusBlockObject(context),
|
|
868
875
|
actions: [() => [{ type: "insert text block", decorators: [] }]]
|
|
@@ -914,11 +921,48 @@ const softReturn = {
|
|
|
914
921
|
}
|
|
915
922
|
]
|
|
916
923
|
]
|
|
917
|
-
},
|
|
918
|
-
softReturn,
|
|
924
|
+
}, coreBlockObjectBehaviors = [
|
|
919
925
|
breakingVoidBlock,
|
|
920
926
|
deletingEmptyTextBlockAfterBlockObject,
|
|
921
927
|
deletingEmptyTextBlockBeforeBlockObject
|
|
928
|
+
], clearListOnBackspace = {
|
|
929
|
+
on: "delete backward",
|
|
930
|
+
guard: ({ context }) => {
|
|
931
|
+
const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
|
|
932
|
+
return !selectionCollapsed || !focusTextBlock || !focusSpan ? !1 : focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0 && focusTextBlock.node.level === 1 ? { focusTextBlock } : !1;
|
|
933
|
+
},
|
|
934
|
+
actions: [
|
|
935
|
+
(_, { focusTextBlock }) => [
|
|
936
|
+
{
|
|
937
|
+
type: "unset block",
|
|
938
|
+
props: ["listItem", "level"],
|
|
939
|
+
paths: [focusTextBlock.path]
|
|
940
|
+
}
|
|
941
|
+
]
|
|
942
|
+
]
|
|
943
|
+
}, unindentListOnBackspace = {
|
|
944
|
+
on: "delete backward",
|
|
945
|
+
guard: ({ context }) => {
|
|
946
|
+
const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
|
|
947
|
+
return !selectionCollapsed || !focusTextBlock || !focusSpan ? !1 : focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0 && focusTextBlock.node.level !== void 0 && focusTextBlock.node.level > 1 ? { focusTextBlock, level: focusTextBlock.node.level - 1 } : !1;
|
|
948
|
+
},
|
|
949
|
+
actions: [
|
|
950
|
+
(_, { focusTextBlock, level }) => [
|
|
951
|
+
{
|
|
952
|
+
type: "set block",
|
|
953
|
+
level,
|
|
954
|
+
paths: [focusTextBlock.path]
|
|
955
|
+
}
|
|
956
|
+
]
|
|
957
|
+
]
|
|
958
|
+
}, coreListBehaviors = [clearListOnBackspace, unindentListOnBackspace], softReturn = {
|
|
959
|
+
on: "insert soft break",
|
|
960
|
+
actions: [() => [{ type: "insert text", text: `
|
|
961
|
+
` }]]
|
|
962
|
+
}, coreBehaviors = [
|
|
963
|
+
softReturn,
|
|
964
|
+
...coreBlockObjectBehaviors,
|
|
965
|
+
...coreListBehaviors
|
|
922
966
|
], debug$k = debugWithName("operationToPatches");
|
|
923
967
|
function createOperationToPatches(types2) {
|
|
924
968
|
const textBlockName = types2.block.name;
|
|
@@ -3303,6 +3347,9 @@ function createWithPortableTextLists(types2) {
|
|
|
3303
3347
|
}, editor;
|
|
3304
3348
|
};
|
|
3305
3349
|
}
|
|
3350
|
+
function isPortableTextSpan(node) {
|
|
3351
|
+
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"));
|
|
3352
|
+
}
|
|
3306
3353
|
function isPortableTextBlock(node) {
|
|
3307
3354
|
return (
|
|
3308
3355
|
// A block doesn't _have_ to be named 'block' - to differentiate between
|
|
@@ -3468,6 +3515,71 @@ function createWithPortableTextMarkModel(editorActor, types2) {
|
|
|
3468
3515
|
apply2(op);
|
|
3469
3516
|
return;
|
|
3470
3517
|
}
|
|
3518
|
+
if (op.type === "set_selection" && slate.Editor.marks(editor) && op.properties && op.newProperties && op.properties.anchor && op.properties.focus && op.newProperties.anchor && op.newProperties.focus) {
|
|
3519
|
+
const previousSelectionIsCollapsed = slate.Range.isCollapsed({
|
|
3520
|
+
anchor: op.properties.anchor,
|
|
3521
|
+
focus: op.properties.focus
|
|
3522
|
+
}), newSelectionIsCollapsed = slate.Range.isCollapsed({
|
|
3523
|
+
anchor: op.newProperties.anchor,
|
|
3524
|
+
focus: op.newProperties.focus
|
|
3525
|
+
});
|
|
3526
|
+
if (previousSelectionIsCollapsed && newSelectionIsCollapsed) {
|
|
3527
|
+
const focusSpan = Array.from(
|
|
3528
|
+
slate.Editor.nodes(editor, {
|
|
3529
|
+
mode: "lowest",
|
|
3530
|
+
at: op.properties.focus,
|
|
3531
|
+
match: (n) => editor.isTextSpan(n),
|
|
3532
|
+
voids: !1
|
|
3533
|
+
})
|
|
3534
|
+
)[0]?.[0], newFocusSpan = Array.from(
|
|
3535
|
+
slate.Editor.nodes(editor, {
|
|
3536
|
+
mode: "lowest",
|
|
3537
|
+
at: op.newProperties.focus,
|
|
3538
|
+
match: (n) => editor.isTextSpan(n),
|
|
3539
|
+
voids: !1
|
|
3540
|
+
})
|
|
3541
|
+
)[0]?.[0], movedToNextSpan = focusSpan && newFocusSpan && op.newProperties.focus.path[0] === op.properties.focus.path[0] && op.newProperties.focus.path[1] === op.properties.focus.path[1] + 1 && focusSpan.text.length === op.properties.focus.offset && op.newProperties.focus.offset === 0, movedToPreviousSpan = focusSpan && newFocusSpan && op.newProperties.focus.path[0] === op.properties.focus.path[0] && op.newProperties.focus.path[1] === op.properties.focus.path[1] - 1 && op.properties.focus.offset === 0 && newFocusSpan.text.length === op.newProperties.focus.offset;
|
|
3542
|
+
if (movedToNextSpan || movedToPreviousSpan)
|
|
3543
|
+
return;
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
if (op.type === "insert_node") {
|
|
3547
|
+
const { selection } = editor;
|
|
3548
|
+
if (selection) {
|
|
3549
|
+
const [_block, blockPath] = slate.Editor.node(editor, selection, { depth: 1 }), previousSpan = getPreviousSpan({
|
|
3550
|
+
editor,
|
|
3551
|
+
blockPath,
|
|
3552
|
+
spanPath: op.path
|
|
3553
|
+
}), previousSpanAnnotations = previousSpan ? previousSpan.marks?.filter((mark) => !decorators.includes(mark)) : [], nextSpan = getNextSpan({
|
|
3554
|
+
editor,
|
|
3555
|
+
blockPath,
|
|
3556
|
+
spanPath: [op.path[0], op.path[1] - 1]
|
|
3557
|
+
}), nextSpanAnnotations = nextSpan ? nextSpan.marks?.filter((mark) => !decorators.includes(mark)) : [], annotationsEnding = previousSpanAnnotations?.filter(
|
|
3558
|
+
(annotation) => !nextSpanAnnotations?.includes(annotation)
|
|
3559
|
+
) ?? [];
|
|
3560
|
+
if (annotationsEnding.length > 0 && isPortableTextSpan(op.node) && op.node.marks?.some((mark) => annotationsEnding.includes(mark))) {
|
|
3561
|
+
slate.Transforms.insertNodes(editor, {
|
|
3562
|
+
...op.node,
|
|
3563
|
+
marks: op.node.marks?.filter(
|
|
3564
|
+
(mark) => !annotationsEnding.includes(mark)
|
|
3565
|
+
) ?? []
|
|
3566
|
+
});
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
const annotationsStarting = nextSpanAnnotations?.filter(
|
|
3570
|
+
(annotation) => !previousSpanAnnotations?.includes(annotation)
|
|
3571
|
+
) ?? [];
|
|
3572
|
+
if (annotationsStarting.length > 0 && isPortableTextSpan(op.node) && op.node.marks?.some((mark) => annotationsStarting.includes(mark))) {
|
|
3573
|
+
slate.Transforms.insertNodes(editor, {
|
|
3574
|
+
...op.node,
|
|
3575
|
+
marks: op.node.marks?.filter(
|
|
3576
|
+
(mark) => !annotationsStarting.includes(mark)
|
|
3577
|
+
) ?? []
|
|
3578
|
+
});
|
|
3579
|
+
return;
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3471
3583
|
if (op.type === "insert_text") {
|
|
3472
3584
|
const { selection } = editor, collapsedSelection = selection ? slate.Range.isCollapsed(selection) : !1;
|
|
3473
3585
|
if (selection && collapsedSelection) {
|
|
@@ -3484,25 +3596,41 @@ function createWithPortableTextMarkModel(editorActor, types2) {
|
|
|
3484
3596
|
(mark) => decorators.includes(mark)
|
|
3485
3597
|
), spanHasAnnotations = marks.length > marksWithoutAnnotations.length, spanIsEmpty = span.text.length === 0, atTheBeginningOfSpan = selection.anchor.offset === 0, atTheEndOfSpan = selection.anchor.offset === span.text.length, previousSpan = getPreviousSpan({ editor, blockPath, spanPath }), nextSpan = getNextSpan({ editor, blockPath, spanPath }), nextSpanAnnotations = nextSpan?.marks?.filter((mark) => !decorators.includes(mark)) ?? [], spanAnnotations = marks.filter(
|
|
3486
3598
|
(mark) => !decorators.includes(mark)
|
|
3487
|
-
), previousSpanHasSameAnnotation = previousSpan ? previousSpan.marks?.some(
|
|
3599
|
+
), previousSpanHasAnnotations = previousSpan ? previousSpan.marks?.some((mark) => !decorators.includes(mark)) : !1, previousSpanHasSameAnnotations = previousSpan ? previousSpan.marks?.filter((mark) => !decorators.includes(mark)).every((mark) => marks.includes(mark)) : !1, previousSpanHasSameAnnotation = previousSpan ? previousSpan.marks?.some(
|
|
3488
3600
|
(mark) => !decorators.includes(mark) && marks.includes(mark)
|
|
3489
3601
|
) : !1, previousSpanHasSameMarks = previousSpan ? previousSpan.marks?.every((mark) => marks.includes(mark)) : !1, nextSpanSharesSomeAnnotations = spanAnnotations.some(
|
|
3490
3602
|
(mark) => nextSpanAnnotations?.includes(mark)
|
|
3491
3603
|
);
|
|
3492
3604
|
if (spanHasAnnotations && !spanIsEmpty) {
|
|
3493
3605
|
if (atTheBeginningOfSpan) {
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3606
|
+
if (previousSpanHasSameMarks) {
|
|
3607
|
+
slate.Transforms.insertNodes(editor, {
|
|
3608
|
+
_type: "span",
|
|
3609
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
3610
|
+
text: op.text,
|
|
3611
|
+
marks: previousSpan?.marks ?? []
|
|
3612
|
+
});
|
|
3613
|
+
return;
|
|
3614
|
+
} else if (previousSpanHasSameAnnotations) {
|
|
3615
|
+
slate.Transforms.insertNodes(editor, {
|
|
3616
|
+
_type: "span",
|
|
3617
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
3618
|
+
text: op.text,
|
|
3619
|
+
marks: previousSpan?.marks ?? []
|
|
3620
|
+
});
|
|
3621
|
+
return;
|
|
3622
|
+
} else if (previousSpanHasSameAnnotation) {
|
|
3623
|
+
apply2(op);
|
|
3624
|
+
return;
|
|
3625
|
+
} else if (!previousSpan) {
|
|
3626
|
+
slate.Transforms.insertNodes(editor, {
|
|
3627
|
+
_type: "span",
|
|
3628
|
+
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
3629
|
+
text: op.text,
|
|
3630
|
+
marks: []
|
|
3631
|
+
});
|
|
3632
|
+
return;
|
|
3633
|
+
}
|
|
3506
3634
|
}
|
|
3507
3635
|
if (atTheEndOfSpan) {
|
|
3508
3636
|
if (nextSpan && nextSpanSharesSomeAnnotations && nextSpanAnnotations.length < spanAnnotations.length || !nextSpanSharesSomeAnnotations) {
|
|
@@ -3530,7 +3658,7 @@ function createWithPortableTextMarkModel(editorActor, types2) {
|
|
|
3530
3658
|
_type: "span",
|
|
3531
3659
|
_key: editorActor.getSnapshot().context.keyGenerator(),
|
|
3532
3660
|
text: op.text,
|
|
3533
|
-
marks: (previousSpan.marks ?? []).filter(
|
|
3661
|
+
marks: previousSpanHasAnnotations ? [] : (previousSpan.marks ?? []).filter(
|
|
3534
3662
|
(mark) => decorators.includes(mark)
|
|
3535
3663
|
)
|
|
3536
3664
|
});
|