@portabletext/editor 3.2.4 → 3.2.6

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
@@ -22,7 +22,6 @@ import { toHTML } from "@portabletext/to-html";
22
22
  import { Schema } from "@sanity/schema";
23
23
  import flatten from "lodash/flatten.js";
24
24
  import { set, applyAll, unset, insert, setIfMissing, diffMatchPatch as diffMatchPatch$1 } from "@portabletext/patches";
25
- import { createDraft, finishDraft } from "immer";
26
25
  import { createKeyboardShortcut, code, underline, italic, bold, undo, redo } from "@portabletext/keyboard-shortcuts";
27
26
  import isPlainObject from "lodash/isPlainObject.js";
28
27
  import { EditorContext } from "./_chunks-es/use-editor.js";
@@ -6509,17 +6508,16 @@ function getParent(context, root, path) {
6509
6508
  return block;
6510
6509
  }
6511
6510
  function applyOperationToPortableText(context, value, operation) {
6512
- const draft = createDraft({
6511
+ const root = {
6513
6512
  children: value
6514
- });
6513
+ };
6515
6514
  try {
6516
- applyOperationToPortableTextDraft(context, draft, operation);
6515
+ return applyOperationToPortableTextImmutable(context, root, operation).children;
6517
6516
  } catch (e) {
6518
- console.error(e);
6517
+ return console.error(e), value;
6519
6518
  }
6520
- return finishDraft(draft).children;
6521
6519
  }
6522
- function applyOperationToPortableTextDraft(context, root, operation) {
6520
+ function applyOperationToPortableTextImmutable(context, root, operation) {
6523
6521
  switch (operation.type) {
6524
6522
  case "insert_node": {
6525
6523
  const {
@@ -6527,45 +6525,55 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6527
6525
  node: insertedNode
6528
6526
  } = operation, parent = getParent(context, root, path), index = path[path.length - 1];
6529
6527
  if (!parent || index > parent.children.length)
6530
- break;
6528
+ return root;
6531
6529
  if (path.length === 1) {
6532
6530
  if (isTextBlockNode(context, insertedNode)) {
6533
- parent.children.splice(index, 0, {
6531
+ const newBlock = {
6534
6532
  ...insertedNode,
6535
6533
  children: insertedNode.children.map((child) => "__inline" in child ? {
6536
6534
  _key: child._key,
6537
6535
  _type: child._type,
6538
6536
  ..."value" in child && typeof child.value == "object" ? child.value : {}
6539
6537
  } : child)
6540
- });
6541
- break;
6538
+ };
6539
+ return {
6540
+ ...root,
6541
+ children: insertChildren(root.children, index, newBlock)
6542
+ };
6542
6543
  }
6543
6544
  if (Element$1.isElement(insertedNode) && !("__inline" in insertedNode)) {
6544
- parent.children.splice(index, 0, {
6545
+ const newBlock = {
6545
6546
  _key: insertedNode._key,
6546
6547
  _type: insertedNode._type,
6547
6548
  ..."value" in insertedNode && typeof insertedNode.value == "object" ? insertedNode.value : {}
6548
- });
6549
- break;
6549
+ };
6550
+ return {
6551
+ ...root,
6552
+ children: insertChildren(root.children, index, newBlock)
6553
+ };
6550
6554
  }
6551
6555
  }
6552
6556
  if (path.length === 2) {
6557
+ const blockIndex = path[0];
6553
6558
  if (!isTextBlockNode(context, parent))
6554
- break;
6555
- if (isPartialSpanNode(insertedNode)) {
6556
- parent.children.splice(index, 0, insertedNode);
6557
- break;
6558
- }
6559
- if ("__inline" in insertedNode) {
6560
- parent.children.splice(index, 0, {
6559
+ return root;
6560
+ let newChild;
6561
+ if (isPartialSpanNode(insertedNode))
6562
+ newChild = insertedNode;
6563
+ else if ("__inline" in insertedNode)
6564
+ newChild = {
6561
6565
  _key: insertedNode._key,
6562
6566
  _type: insertedNode._type,
6563
6567
  ..."value" in insertedNode && typeof insertedNode.value == "object" ? insertedNode.value : {}
6564
- });
6565
- break;
6566
- }
6568
+ };
6569
+ else
6570
+ return root;
6571
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6572
+ ...block,
6573
+ children: insertChildren(block.children, index, newChild)
6574
+ }));
6567
6575
  }
6568
- break;
6576
+ return root;
6569
6577
  }
6570
6578
  case "insert_text": {
6571
6579
  const {
@@ -6573,29 +6581,50 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6573
6581
  offset,
6574
6582
  text
6575
6583
  } = operation;
6576
- if (text.length === 0) break;
6584
+ if (text.length === 0) return root;
6577
6585
  const span = getSpan(context, root, path);
6578
6586
  if (!span)
6579
- break;
6580
- const before = span.text.slice(0, offset), after = span.text.slice(offset);
6581
- span.text = before + text + after;
6582
- break;
6587
+ return root;
6588
+ const blockIndex = path[0], childIndex = path[1], before = span.text.slice(0, offset), after = span.text.slice(offset), newSpan = {
6589
+ ...span,
6590
+ text: before + text + after
6591
+ };
6592
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6593
+ ...block,
6594
+ children: replaceChild(block.children, childIndex, newSpan)
6595
+ }));
6583
6596
  }
6584
6597
  case "merge_node": {
6585
6598
  const {
6586
6599
  path
6587
6600
  } = operation, node = getNode(context, root, path), prevPath = Path.previous(path), prev = getNode(context, root, prevPath), parent = getParent(context, root, path);
6588
6601
  if (!node || !prev || !parent)
6589
- break;
6602
+ return root;
6590
6603
  const index = path[path.length - 1];
6591
- if (isPartialSpanNode(node) && isPartialSpanNode(prev))
6592
- prev.text += node.text;
6593
- else if (isTextBlockNode(context, node) && isTextBlockNode(context, prev))
6594
- prev.children.push(...node.children);
6595
- else
6596
- break;
6597
- parent.children.splice(index, 1);
6598
- break;
6604
+ if (isPartialSpanNode(node) && isPartialSpanNode(prev)) {
6605
+ const blockIndex = path[0], newPrev = {
6606
+ ...prev,
6607
+ text: prev.text + node.text
6608
+ };
6609
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => {
6610
+ const newChildren = replaceChild(block.children, index - 1, newPrev);
6611
+ return {
6612
+ ...block,
6613
+ children: removeChildren(newChildren, index)
6614
+ };
6615
+ });
6616
+ }
6617
+ if (isTextBlockNode(context, node) && isTextBlockNode(context, prev)) {
6618
+ const newPrev = {
6619
+ ...prev,
6620
+ children: [...prev.children, ...node.children]
6621
+ }, newChildren = replaceChild(root.children, index - 1, newPrev);
6622
+ return {
6623
+ ...root,
6624
+ children: removeChildren(newChildren, index)
6625
+ };
6626
+ }
6627
+ return root;
6599
6628
  }
6600
6629
  case "move_node": {
6601
6630
  const {
@@ -6603,23 +6632,58 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6603
6632
  newPath
6604
6633
  } = operation;
6605
6634
  if (Path.isAncestor(path, newPath))
6606
- break;
6635
+ return root;
6607
6636
  const node = getNode(context, root, path), parent = getParent(context, root, path), index = path[path.length - 1];
6608
6637
  if (!node || !parent)
6609
- break;
6610
- parent.children.splice(index, 1);
6611
- const truePath = Path.transform(path, operation), newParent = getNode(context, root, Path.parent(truePath)), newIndex = truePath[truePath.length - 1];
6612
- if (!newParent || !("children" in newParent) || !Array.isArray(newParent.children))
6613
- break;
6614
- newParent.children.splice(newIndex, 0, node);
6615
- break;
6638
+ return root;
6639
+ let newRoot;
6640
+ if (path.length === 1)
6641
+ newRoot = {
6642
+ ...root,
6643
+ children: removeChildren(root.children, index)
6644
+ };
6645
+ else if (path.length === 2) {
6646
+ const blockIndex = path[0];
6647
+ newRoot = updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6648
+ ...block,
6649
+ children: removeChildren(block.children, index)
6650
+ }));
6651
+ } else
6652
+ return root;
6653
+ const truePath = Path.transform(path, operation), newIndex = truePath[truePath.length - 1];
6654
+ if (truePath.length === 1)
6655
+ return {
6656
+ ...newRoot,
6657
+ children: insertChildren(newRoot.children, newIndex, node)
6658
+ };
6659
+ if (truePath.length === 2) {
6660
+ const newBlockIndex = truePath[0], newParent = newRoot.children[newBlockIndex];
6661
+ return !newParent || !isTextBlockNode(context, newParent) ? root : updateTextBlockAtIndex(context, newRoot, newBlockIndex, (block) => ({
6662
+ ...block,
6663
+ children: insertChildren(block.children, newIndex, node)
6664
+ }));
6665
+ }
6666
+ return root;
6616
6667
  }
6617
6668
  case "remove_node": {
6618
6669
  const {
6619
6670
  path
6620
6671
  } = operation, index = path[path.length - 1];
6621
- getParent(context, root, path)?.children.splice(index, 1);
6622
- break;
6672
+ if (!getParent(context, root, path))
6673
+ return root;
6674
+ if (path.length === 1)
6675
+ return {
6676
+ ...root,
6677
+ children: removeChildren(root.children, index)
6678
+ };
6679
+ if (path.length === 2) {
6680
+ const blockIndex = path[0];
6681
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6682
+ ...block,
6683
+ children: removeChildren(block.children, index)
6684
+ }));
6685
+ }
6686
+ return root;
6623
6687
  }
6624
6688
  case "remove_text": {
6625
6689
  const {
@@ -6628,13 +6692,18 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6628
6692
  text
6629
6693
  } = operation;
6630
6694
  if (text.length === 0)
6631
- break;
6695
+ return root;
6632
6696
  const span = getSpan(context, root, path);
6633
6697
  if (!span)
6634
- break;
6635
- const before = span.text.slice(0, offset), after = span.text.slice(offset + text.length);
6636
- span.text = before + after;
6637
- break;
6698
+ return root;
6699
+ const blockIndex = path[0], childIndex = path[1], before = span.text.slice(0, offset), after = span.text.slice(offset + text.length), newSpan = {
6700
+ ...span,
6701
+ text: before + after
6702
+ };
6703
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6704
+ ...block,
6705
+ children: replaceChild(block.children, childIndex, newSpan)
6706
+ }));
6638
6707
  }
6639
6708
  case "set_node": {
6640
6709
  const {
@@ -6643,48 +6712,68 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6643
6712
  newProperties
6644
6713
  } = operation, node = getNode(context, root, path);
6645
6714
  if (!node || isEditorNode(node))
6646
- break;
6715
+ return root;
6647
6716
  if (isObjectNode(context, node)) {
6648
- const valueBefore = "value" in properties && typeof properties.value == "object" ? properties.value : {}, valueAfter = "value" in newProperties && typeof newProperties.value == "object" ? newProperties.value : {};
6717
+ const valueBefore = "value" in properties && typeof properties.value == "object" ? properties.value : {}, valueAfter = "value" in newProperties && typeof newProperties.value == "object" ? newProperties.value : {}, newNode = {
6718
+ ...node
6719
+ };
6649
6720
  for (const key in newProperties) {
6650
6721
  if (key === "value")
6651
6722
  continue;
6652
6723
  const value = newProperties[key];
6653
- value == null ? delete node[key] : node[key] = value;
6724
+ value == null ? delete newNode[key] : newNode[key] = value;
6654
6725
  }
6655
6726
  for (const key in properties)
6656
- key !== "value" && (newProperties.hasOwnProperty(key) || delete node[key]);
6727
+ key !== "value" && (newProperties.hasOwnProperty(key) || delete newNode[key]);
6657
6728
  for (const key in valueAfter) {
6658
6729
  const value = valueAfter[key];
6659
- value == null ? delete node[key] : node[key] = value;
6730
+ value == null ? delete newNode[key] : newNode[key] = value;
6660
6731
  }
6661
6732
  for (const key in valueBefore)
6662
- valueAfter.hasOwnProperty(key) || delete node[key];
6663
- break;
6733
+ valueAfter.hasOwnProperty(key) || delete newNode[key];
6734
+ return path.length === 1 ? {
6735
+ ...root,
6736
+ children: replaceChild(root.children, path[0], newNode)
6737
+ } : path.length === 2 ? updateTextBlockAtIndex(context, root, path[0], (block) => ({
6738
+ ...block,
6739
+ children: replaceChild(block.children, path[1], newNode)
6740
+ })) : root;
6664
6741
  }
6665
6742
  if (isTextBlockNode(context, node)) {
6743
+ const newNode = {
6744
+ ...node
6745
+ };
6666
6746
  for (const key in newProperties) {
6667
6747
  if (key === "children" || key === "text")
6668
- break;
6748
+ continue;
6669
6749
  const value = newProperties[key];
6670
- value == null ? delete node[key] : node[key] = value;
6750
+ value == null ? delete newNode[key] : newNode[key] = value;
6671
6751
  }
6672
6752
  for (const key in properties)
6673
- newProperties.hasOwnProperty(key) || delete node[key];
6674
- break;
6753
+ newProperties.hasOwnProperty(key) || delete newNode[key];
6754
+ return {
6755
+ ...root,
6756
+ children: replaceChild(root.children, path[0], newNode)
6757
+ };
6675
6758
  }
6676
6759
  if (isPartialSpanNode(node)) {
6760
+ const newNode = {
6761
+ ...node
6762
+ };
6677
6763
  for (const key in newProperties) {
6678
6764
  if (key === "text")
6679
- break;
6765
+ continue;
6680
6766
  const value = newProperties[key];
6681
- value == null ? delete node[key] : node[key] = value;
6767
+ value == null ? delete newNode[key] : newNode[key] = value;
6682
6768
  }
6683
6769
  for (const key in properties)
6684
- newProperties.hasOwnProperty(key) || delete node[key];
6685
- break;
6770
+ newProperties.hasOwnProperty(key) || delete newNode[key];
6771
+ return updateTextBlockAtIndex(context, root, path[0], (block) => ({
6772
+ ...block,
6773
+ children: replaceChild(block.children, path[1], newNode)
6774
+ }));
6686
6775
  }
6687
- break;
6776
+ return root;
6688
6777
  }
6689
6778
  case "split_node": {
6690
6779
  const {
@@ -6693,40 +6782,65 @@ function applyOperationToPortableTextDraft(context, root, operation) {
6693
6782
  properties
6694
6783
  } = operation;
6695
6784
  if (path.length === 0)
6696
- break;
6785
+ return root;
6697
6786
  const parent = getParent(context, root, path), index = path[path.length - 1];
6698
6787
  if (!parent)
6699
- break;
6788
+ return root;
6700
6789
  if (isEditorNode(parent)) {
6701
6790
  const block = getBlock(root, path);
6702
6791
  if (!block || !isTextBlockNode(context, block))
6703
- break;
6704
- const before = block.children.slice(0, position), after = block.children.slice(position);
6705
- block.children = before;
6706
- const newTextBlockNode = {
6792
+ return root;
6793
+ const before = block.children.slice(0, position), after = block.children.slice(position), updatedTextBlockNode = {
6794
+ ...block,
6795
+ children: before
6796
+ }, newTextBlockNode = {
6707
6797
  ...properties,
6708
6798
  children: after,
6709
6799
  _type: context.schema.block.name
6710
6800
  };
6711
- parent.children.splice(index + 1, 0, newTextBlockNode);
6712
- break;
6801
+ return {
6802
+ ...root,
6803
+ children: insertChildren(replaceChild(root.children, index, updatedTextBlockNode), index + 1, newTextBlockNode)
6804
+ };
6713
6805
  }
6714
6806
  if (isTextBlockNode(context, parent)) {
6715
6807
  const node = getNode(context, root, path);
6716
6808
  if (!node || !isSpanNode(context, node))
6717
- break;
6718
- const before = node.text.slice(0, position), after = node.text.slice(position);
6719
- node.text = before;
6720
- const newSpanNode = {
6809
+ return root;
6810
+ const blockIndex = path[0], before = node.text.slice(0, position), after = node.text.slice(position), updatedSpanNode = {
6811
+ ...node,
6812
+ text: before
6813
+ }, newSpanNode = {
6721
6814
  ...properties,
6722
6815
  text: after
6723
6816
  };
6724
- parent.children.splice(index + 1, 0, newSpanNode);
6817
+ return updateTextBlockAtIndex(context, root, blockIndex, (block) => ({
6818
+ ...block,
6819
+ children: insertChildren(replaceChild(block.children, index, updatedSpanNode), index + 1, newSpanNode)
6820
+ }));
6725
6821
  }
6726
- break;
6822
+ return root;
6727
6823
  }
6728
6824
  }
6729
- return root;
6825
+ }
6826
+ function insertChildren(children, index, ...nodes) {
6827
+ return [...children.slice(0, index), ...nodes, ...children.slice(index)];
6828
+ }
6829
+ function removeChildren(children, index, count = 1) {
6830
+ return [...children.slice(0, index), ...children.slice(index + count)];
6831
+ }
6832
+ function replaceChild(children, index, newChild) {
6833
+ return [...children.slice(0, index), newChild, ...children.slice(index + 1)];
6834
+ }
6835
+ function updateTextBlockAtIndex(context, root, blockIndex, updater) {
6836
+ const block = root.children.at(blockIndex);
6837
+ if (!block || !isTextBlockNode(context, block))
6838
+ return root;
6839
+ const newBlock = updater(block);
6840
+ return {
6841
+ ...root,
6842
+ children: replaceChild(root.children, blockIndex, newBlock)
6843
+ };
6730
6844
  }
6731
6845
  function pluginUpdateValue(context, editor) {
6732
6846
  const {