@portabletext/editor 1.0.17 → 1.0.19

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 CHANGED
@@ -122,7 +122,7 @@ function normalizeSelection(selection, value) {
122
122
  const { anchor, focus } = selection;
123
123
  return anchor && value.find((blk) => isEqual({ _key: blk._key }, anchor.path[0])) && (newAnchor = normalizePoint(anchor, value)), focus && value.find((blk) => isEqual({ _key: blk._key }, focus.path[0])) && (newFocus = normalizePoint(focus, value)), newAnchor && newFocus ? { anchor: newAnchor, focus: newFocus, backward: selection.backward } : null;
124
124
  }
125
- const EMPTY_MARKDEFS = [], EMPTY_MARKS$1 = [], VOID_CHILD_KEY = "void-child";
125
+ const EMPTY_MARKDEFS = [], VOID_CHILD_KEY = "void-child";
126
126
  function keepObjectEquality(object, keyMap) {
127
127
  const value = keyMap[object._key];
128
128
  return value && isEqual(object, value) ? value : (keyMap[object._key] = object, object);
@@ -870,24 +870,38 @@ function createOperationToPatches(types) {
870
870
  return [unset([{ _key: block._key }])];
871
871
  throw new Error("Block not found");
872
872
  } else if (editor.isTextBlock(block) && operation.path.length === 2) {
873
- const spanToRemove = editor.isTextBlock(block) && block.children && block.children[operation.path[1]];
874
- return spanToRemove ? [unset([{ _key: block._key }, "children", { _key: spanToRemove._key }])] : (debug$k("Span not found in editor trying to remove node"), []);
873
+ const spanToRemove = block.children[operation.path[1]];
874
+ return spanToRemove ? block.children.filter((span) => span._key === operation.node._key).length > 1 ? (console.warn(
875
+ `Multiple spans have \`_key\` ${operation.node._key}. It's ambiguous which one to remove.`,
876
+ JSON.stringify(block, null, 2)
877
+ ), []) : [unset([{ _key: block._key }, "children", { _key: spanToRemove._key }])] : (debug$k("Span not found in editor trying to remove node"), []);
875
878
  } else
876
879
  return debug$k("Not creating patch inside object block"), [];
877
880
  }
878
881
  function mergeNodePatch(editor, operation, beforeValue) {
879
- const patches = [], block = beforeValue[operation.path[0]], targetBlock = editor.children[operation.path[0]];
882
+ const patches = [], block = beforeValue[operation.path[0]], updatedBlock = editor.children[operation.path[0]];
880
883
  if (operation.path.length === 1)
881
884
  if (block?._key) {
882
885
  const newBlock = fromSlateValue([editor.children[operation.path[0] - 1]], textBlockName)[0];
883
886
  patches.push(set(newBlock, [{ _key: newBlock._key }])), patches.push(unset([{ _key: block._key }]));
884
887
  } else
885
888
  throw new Error("Target key not found!");
886
- else if (operation.path.length === 2 && editor.isTextBlock(targetBlock)) {
887
- const mergedSpan = editor.isTextBlock(block) && block.children[operation.path[1]] || void 0, targetSpan = targetBlock.children[operation.path[1] - 1];
888
- editor.isTextSpan(targetSpan) && (patches.push(
889
- set(targetSpan.text, [{ _key: block._key }, "children", { _key: targetSpan._key }, "text"])
890
- ), mergedSpan && patches.push(unset([{ _key: block._key }, "children", { _key: mergedSpan._key }])));
889
+ else if (editor.isTextBlock(block) && editor.isTextBlock(updatedBlock) && operation.path.length === 2) {
890
+ const updatedSpan = updatedBlock.children[operation.path[1] - 1] && editor.isTextSpan(updatedBlock.children[operation.path[1] - 1]) ? updatedBlock.children[operation.path[1] - 1] : void 0, removedSpan = block.children[operation.path[1]] && editor.isTextSpan(block.children[operation.path[1]]) ? block.children[operation.path[1]] : void 0;
891
+ updatedSpan && (block.children.filter((span) => span._key === updatedSpan._key).length === 1 ? patches.push(
892
+ set(updatedSpan.text, [
893
+ { _key: block._key },
894
+ "children",
895
+ { _key: updatedSpan._key },
896
+ "text"
897
+ ])
898
+ ) : console.warn(
899
+ `Multiple spans have \`_key\` ${updatedSpan._key}. It's ambiguous which one to update.`,
900
+ JSON.stringify(block, null, 2)
901
+ )), removedSpan && (block.children.filter((span) => span._key === removedSpan._key).length === 1 ? patches.push(unset([{ _key: block._key }, "children", { _key: removedSpan._key }])) : console.warn(
902
+ `Multiple spans have \`_key\` ${removedSpan._key}. It's ambiguous which one to remove.`,
903
+ JSON.stringify(block, null, 2)
904
+ ));
891
905
  } else
892
906
  debug$k("Void nodes can't be merged, not creating any patches");
893
907
  return patches;
@@ -1154,9 +1168,10 @@ function createWithEditableAPI(portableTextEditor, types, keyGenerator) {
1154
1168
  const [block] = Editor.node(editor, originalSelection.focus, { depth: 1 });
1155
1169
  if (!editor.isTextBlock(block))
1156
1170
  return;
1157
- Range.isCollapsed(originalSelection) && (editor.pteExpandToWord(), editor.onChange());
1158
1171
  const [textNode] = Editor.node(editor, originalSelection.focus, { depth: 2 });
1159
- editor.selection && (Editor.withoutNormalizing(editor, () => {
1172
+ if (!isPortableTextSpan$1(textNode) || textNode.text === "")
1173
+ return;
1174
+ Range.isCollapsed(originalSelection) && (editor.pteExpandToWord(), editor.onChange()), editor.selection && (Editor.withoutNormalizing(editor, () => {
1160
1175
  const annotationKey = keyGenerator();
1161
1176
  Transforms.setNodes(
1162
1177
  editor,
@@ -2772,7 +2787,7 @@ function createWithPortableTextMarkModel(types, change$, keyGenerator) {
2772
2787
  change$.next({ type: "selection", selection: ptRange });
2773
2788
  };
2774
2789
  return editor.normalizeNode = (nodeEntry) => {
2775
- const [node, path] = nodeEntry, isSpan = Text.isText(node) && node._type === types.span.name, isTextBlock = editor.isTextBlock(node);
2790
+ const [node, path] = nodeEntry;
2776
2791
  if (editor.isTextBlock(node)) {
2777
2792
  const children = Node.children(editor, path);
2778
2793
  for (const [child, childPath] of children) {
@@ -2787,65 +2802,47 @@ function createWithPortableTextMarkModel(types, change$, keyGenerator) {
2787
2802
  }
2788
2803
  }
2789
2804
  }
2790
- if (isSpan || isTextBlock) {
2791
- if (isSpan && !Array.isArray(node.marks)) {
2792
- debug$c("Adding .marks to span node"), Transforms.setNodes(editor, { marks: [] }, { at: path });
2793
- return;
2794
- }
2795
- if (isSpan && (node.marks || []).length > 0) {
2796
- const spanMarks = node.marks || EMPTY_MARKS$1, annotationMarks = spanMarks.filter(
2797
- (mark) => !types.decorators.map((dec) => dec.value).includes(mark)
2805
+ if (editor.isTextSpan(node) && !Array.isArray(node.marks)) {
2806
+ debug$c("Adding .marks to span node"), Transforms.setNodes(editor, { marks: [] }, { at: path });
2807
+ return;
2808
+ }
2809
+ if (editor.isTextSpan(node)) {
2810
+ const blockPath = Path.parent(path), [block] = Editor.node(editor, blockPath), decorators2 = types.decorators.map((decorator) => decorator.value), annotations = node.marks?.filter((mark) => !decorators2.includes(mark));
2811
+ if (editor.isTextBlock(block) && node.text === "" && annotations && annotations.length > 0) {
2812
+ debug$c("Removing annotations from empty span node"), Transforms.setNodes(
2813
+ editor,
2814
+ { marks: node.marks?.filter((mark) => decorators2.includes(mark)) },
2815
+ { at: path }
2798
2816
  );
2799
- if (annotationMarks.length > 0) {
2800
- const [block] = Editor.node(editor, Path.parent(path)), orphanedMarks = editor.isTextBlock(block) && annotationMarks.filter(
2801
- (mark) => !block.markDefs?.find((def) => def._key === mark)
2802
- ) || [];
2803
- if (orphanedMarks.length > 0) {
2804
- debug$c("Removing orphaned .marks from span node"), Transforms.setNodes(
2805
- editor,
2806
- { marks: spanMarks.filter((mark) => !orphanedMarks.includes(mark)) },
2807
- { at: path }
2808
- );
2809
- return;
2810
- }
2811
- }
2817
+ return;
2812
2818
  }
2813
- for (const op of editor.operations) {
2814
- if (op.type === "merge_node" && op.path.length === 1 && "markDefs" in op.properties && op.properties._type === types.block.name && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0 && op.path[0] - 1 >= 0) {
2815
- const [targetBlock, targetPath] = Editor.node(editor, [op.path[0] - 1]);
2816
- if (debug$c("Copying markDefs over to merged block", op), editor.isTextBlock(targetBlock)) {
2817
- const oldDefs = Array.isArray(targetBlock.markDefs) && targetBlock.markDefs || [], newMarkDefs = uniq([...oldDefs, ...op.properties.markDefs]);
2818
- if (!isEqual(newMarkDefs, targetBlock.markDefs)) {
2819
- Transforms.setNodes(editor, { markDefs: newMarkDefs }, { at: targetPath, voids: !1 });
2820
- return;
2821
- }
2822
- }
2823
- }
2824
- if (op.type === "split_node" && op.path.length === 1 && Element$1.isElementProps(op.properties) && op.properties._type === types.block.name && "markDefs" in op.properties && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0 && op.path[0] + 1 < editor.children.length) {
2825
- const [targetBlock, targetPath] = Editor.node(editor, [op.path[0] + 1]);
2826
- if (debug$c("Copying markDefs over to split block", op), editor.isTextBlock(targetBlock)) {
2827
- const oldDefs = Array.isArray(targetBlock.markDefs) && targetBlock.markDefs || [];
2828
- Transforms.setNodes(
2819
+ }
2820
+ if (editor.isTextBlock(node)) {
2821
+ const decorators2 = types.decorators.map((decorator) => decorator.value);
2822
+ for (const [child, childPath] of Node.children(editor, path))
2823
+ if (editor.isTextSpan(child)) {
2824
+ const marks = child.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !node.markDefs?.find((def) => def._key === mark));
2825
+ if (orphanedAnnotations.length > 0) {
2826
+ debug$c("Removing orphaned annotations from span node"), Transforms.setNodes(
2829
2827
  editor,
2830
- { markDefs: uniq([...oldDefs, ...op.properties.markDefs]) },
2831
- { at: targetPath, voids: !1 }
2828
+ { marks: marks.filter((mark) => !orphanedAnnotations.includes(mark)) },
2829
+ { at: childPath }
2832
2830
  );
2833
2831
  return;
2834
2832
  }
2835
2833
  }
2836
- if (op.type === "split_node" && op.path.length === 2 && op.properties._type === types.span.name && "marks" in op.properties && Array.isArray(op.properties.marks) && op.properties.marks.length > 0 && op.path[0] + 1 < editor.children.length) {
2837
- const [child, childPath] = Editor.node(editor, [op.path[0] + 1, 0]);
2838
- if (Text.isText(child) && child.text === "" && Array.isArray(child.marks) && child.marks.length > 0) {
2839
- Transforms.setNodes(editor, { marks: [] }, { at: childPath, voids: !1 });
2840
- return;
2841
- }
2842
- }
2843
- if (op.type === "split_node" && op.path.length === 1 && op.properties._type === types.block.name && "markDefs" in op.properties && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0) {
2844
- const [block, blockPath] = Editor.node(editor, [op.path[0]]);
2845
- if (editor.isTextBlock(block) && block.children.length === 1 && block.markDefs && block.markDefs.length > 0 && Text.isText(block.children[0]) && block.children[0].text === "" && (!block.children[0].marks || block.children[0].marks.length === 0)) {
2846
- Transforms.setNodes(editor, { markDefs: [] }, { at: blockPath });
2847
- return;
2848
- }
2834
+ }
2835
+ if (editor.isTextSpan(node)) {
2836
+ const blockPath = Path.parent(path), [block] = Editor.node(editor, blockPath);
2837
+ if (editor.isTextBlock(block)) {
2838
+ const decorators2 = types.decorators.map((decorator) => decorator.value), marks = node.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !block.markDefs?.find((def) => def._key === mark));
2839
+ if (orphanedAnnotations.length > 0) {
2840
+ debug$c("Removing orphaned annotations from span node"), Transforms.setNodes(
2841
+ editor,
2842
+ { marks: marks.filter((mark) => !orphanedAnnotations.includes(mark)) },
2843
+ { at: path }
2844
+ );
2845
+ return;
2849
2846
  }
2850
2847
  }
2851
2848
  }
@@ -2939,6 +2936,14 @@ function createWithPortableTextMarkModel(types, change$, keyGenerator) {
2939
2936
  }
2940
2937
  }
2941
2938
  }
2939
+ if (op.type === "merge_node" && op.path.length === 1 && "markDefs" in op.properties && op.properties._type === types.block.name && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0 && op.path[0] - 1 >= 0) {
2940
+ const [targetBlock, targetPath] = Editor.node(editor, [op.path[0] - 1]);
2941
+ if (editor.isTextBlock(targetBlock)) {
2942
+ const oldDefs = Array.isArray(targetBlock.markDefs) && targetBlock.markDefs || [], newMarkDefs = uniq([...oldDefs, ...op.properties.markDefs]);
2943
+ debug$c("Copying markDefs over to merged block", op), Transforms.setNodes(editor, { markDefs: newMarkDefs }, { at: targetPath, voids: !1 }), apply2(op);
2944
+ return;
2945
+ }
2946
+ }
2942
2947
  apply2(op);
2943
2948
  }, editor.addMark = (mark) => {
2944
2949
  if (editor.selection) {