@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.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 softReturn = {
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
- }, coreBehaviors = [
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
- previousSpanHasSameMarks ? slate.Transforms.insertNodes(editor, {
3495
- _type: "span",
3496
- _key: editorActor.getSnapshot().context.keyGenerator(),
3497
- text: op.text,
3498
- marks: previousSpan?.marks ?? []
3499
- }) : previousSpanHasSameAnnotation ? apply2(op) : slate.Transforms.insertNodes(editor, {
3500
- _type: "span",
3501
- _key: editorActor.getSnapshot().context.keyGenerator(),
3502
- text: op.text,
3503
- marks: []
3504
- });
3505
- return;
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
  });