@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 +69 -64
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +69 -64
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +69 -64
- package/lib/index.mjs.map +1 -1
- package/package.json +7 -3
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +0 -533
- package/src/editor/plugins/createWithEditableAPI.ts +10 -1
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +97 -118
- package/src/utils/operationToPatches.ts +58 -14
- package/src/utils/values.ts +0 -1
- package/src/editor/plugins/__tests__/withHotkeys.test.tsx +0 -212
- package/src/editor/plugins/__tests__/withInsertBreak.test.tsx +0 -220
- package/src/editor/plugins/__tests__/withPlaceholderBlock.test.tsx +0 -133
package/lib/index.js
CHANGED
|
@@ -106,7 +106,7 @@ function normalizeSelection(selection, value) {
|
|
|
106
106
|
const { anchor, focus } = selection;
|
|
107
107
|
return anchor && value.find((blk) => isEqual__default.default({ _key: blk._key }, anchor.path[0])) && (newAnchor = normalizePoint(anchor, value)), focus && value.find((blk) => isEqual__default.default({ _key: blk._key }, focus.path[0])) && (newFocus = normalizePoint(focus, value)), newAnchor && newFocus ? { anchor: newAnchor, focus: newFocus, backward: selection.backward } : null;
|
|
108
108
|
}
|
|
109
|
-
const EMPTY_MARKDEFS = [],
|
|
109
|
+
const EMPTY_MARKDEFS = [], VOID_CHILD_KEY = "void-child";
|
|
110
110
|
function keepObjectEquality(object, keyMap) {
|
|
111
111
|
const value = keyMap[object._key];
|
|
112
112
|
return value && isEqual__default.default(object, value) ? value : (keyMap[object._key] = object, object);
|
|
@@ -854,24 +854,38 @@ function createOperationToPatches(types2) {
|
|
|
854
854
|
return [patches.unset([{ _key: block._key }])];
|
|
855
855
|
throw new Error("Block not found");
|
|
856
856
|
} else if (editor.isTextBlock(block) && operation.path.length === 2) {
|
|
857
|
-
const spanToRemove =
|
|
858
|
-
return spanToRemove ?
|
|
857
|
+
const spanToRemove = block.children[operation.path[1]];
|
|
858
|
+
return spanToRemove ? block.children.filter((span) => span._key === operation.node._key).length > 1 ? (console.warn(
|
|
859
|
+
`Multiple spans have \`_key\` ${operation.node._key}. It's ambiguous which one to remove.`,
|
|
860
|
+
JSON.stringify(block, null, 2)
|
|
861
|
+
), []) : [patches.unset([{ _key: block._key }, "children", { _key: spanToRemove._key }])] : (debug$k("Span not found in editor trying to remove node"), []);
|
|
859
862
|
} else
|
|
860
863
|
return debug$k("Not creating patch inside object block"), [];
|
|
861
864
|
}
|
|
862
865
|
function mergeNodePatch(editor, operation, beforeValue) {
|
|
863
|
-
const patches$1 = [], block = beforeValue[operation.path[0]],
|
|
866
|
+
const patches$1 = [], block = beforeValue[operation.path[0]], updatedBlock = editor.children[operation.path[0]];
|
|
864
867
|
if (operation.path.length === 1)
|
|
865
868
|
if (block?._key) {
|
|
866
869
|
const newBlock = fromSlateValue([editor.children[operation.path[0] - 1]], textBlockName)[0];
|
|
867
870
|
patches$1.push(patches.set(newBlock, [{ _key: newBlock._key }])), patches$1.push(patches.unset([{ _key: block._key }]));
|
|
868
871
|
} else
|
|
869
872
|
throw new Error("Target key not found!");
|
|
870
|
-
else if (operation.path.length === 2
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
patches.set(
|
|
874
|
-
|
|
873
|
+
else if (editor.isTextBlock(block) && editor.isTextBlock(updatedBlock) && operation.path.length === 2) {
|
|
874
|
+
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;
|
|
875
|
+
updatedSpan && (block.children.filter((span) => span._key === updatedSpan._key).length === 1 ? patches$1.push(
|
|
876
|
+
patches.set(updatedSpan.text, [
|
|
877
|
+
{ _key: block._key },
|
|
878
|
+
"children",
|
|
879
|
+
{ _key: updatedSpan._key },
|
|
880
|
+
"text"
|
|
881
|
+
])
|
|
882
|
+
) : console.warn(
|
|
883
|
+
`Multiple spans have \`_key\` ${updatedSpan._key}. It's ambiguous which one to update.`,
|
|
884
|
+
JSON.stringify(block, null, 2)
|
|
885
|
+
)), removedSpan && (block.children.filter((span) => span._key === removedSpan._key).length === 1 ? patches$1.push(patches.unset([{ _key: block._key }, "children", { _key: removedSpan._key }])) : console.warn(
|
|
886
|
+
`Multiple spans have \`_key\` ${removedSpan._key}. It's ambiguous which one to remove.`,
|
|
887
|
+
JSON.stringify(block, null, 2)
|
|
888
|
+
));
|
|
875
889
|
} else
|
|
876
890
|
debug$k("Void nodes can't be merged, not creating any patches");
|
|
877
891
|
return patches$1;
|
|
@@ -1138,9 +1152,10 @@ function createWithEditableAPI(portableTextEditor, types$1, keyGenerator) {
|
|
|
1138
1152
|
const [block] = slate.Editor.node(editor, originalSelection.focus, { depth: 1 });
|
|
1139
1153
|
if (!editor.isTextBlock(block))
|
|
1140
1154
|
return;
|
|
1141
|
-
slate.Range.isCollapsed(originalSelection) && (editor.pteExpandToWord(), editor.onChange());
|
|
1142
1155
|
const [textNode] = slate.Editor.node(editor, originalSelection.focus, { depth: 2 });
|
|
1143
|
-
|
|
1156
|
+
if (!types.isPortableTextSpan(textNode) || textNode.text === "")
|
|
1157
|
+
return;
|
|
1158
|
+
slate.Range.isCollapsed(originalSelection) && (editor.pteExpandToWord(), editor.onChange()), editor.selection && (slate.Editor.withoutNormalizing(editor, () => {
|
|
1144
1159
|
const annotationKey = keyGenerator();
|
|
1145
1160
|
slate.Transforms.setNodes(
|
|
1146
1161
|
editor,
|
|
@@ -2756,7 +2771,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
|
|
|
2756
2771
|
change$.next({ type: "selection", selection: ptRange });
|
|
2757
2772
|
};
|
|
2758
2773
|
return editor.normalizeNode = (nodeEntry) => {
|
|
2759
|
-
const [node, path] = nodeEntry
|
|
2774
|
+
const [node, path] = nodeEntry;
|
|
2760
2775
|
if (editor.isTextBlock(node)) {
|
|
2761
2776
|
const children = slate.Node.children(editor, path);
|
|
2762
2777
|
for (const [child, childPath] of children) {
|
|
@@ -2771,65 +2786,47 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
|
|
|
2771
2786
|
}
|
|
2772
2787
|
}
|
|
2773
2788
|
}
|
|
2774
|
-
if (
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2789
|
+
if (editor.isTextSpan(node) && !Array.isArray(node.marks)) {
|
|
2790
|
+
debug$c("Adding .marks to span node"), slate.Transforms.setNodes(editor, { marks: [] }, { at: path });
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2793
|
+
if (editor.isTextSpan(node)) {
|
|
2794
|
+
const blockPath = slate.Path.parent(path), [block] = slate.Editor.node(editor, blockPath), decorators2 = types2.decorators.map((decorator) => decorator.value), annotations = node.marks?.filter((mark) => !decorators2.includes(mark));
|
|
2795
|
+
if (editor.isTextBlock(block) && node.text === "" && annotations && annotations.length > 0) {
|
|
2796
|
+
debug$c("Removing annotations from empty span node"), slate.Transforms.setNodes(
|
|
2797
|
+
editor,
|
|
2798
|
+
{ marks: node.marks?.filter((mark) => decorators2.includes(mark)) },
|
|
2799
|
+
{ at: path }
|
|
2782
2800
|
);
|
|
2783
|
-
|
|
2784
|
-
const [block] = slate.Editor.node(editor, slate.Path.parent(path)), orphanedMarks = editor.isTextBlock(block) && annotationMarks.filter(
|
|
2785
|
-
(mark) => !block.markDefs?.find((def) => def._key === mark)
|
|
2786
|
-
) || [];
|
|
2787
|
-
if (orphanedMarks.length > 0) {
|
|
2788
|
-
debug$c("Removing orphaned .marks from span node"), slate.Transforms.setNodes(
|
|
2789
|
-
editor,
|
|
2790
|
-
{ marks: spanMarks.filter((mark) => !orphanedMarks.includes(mark)) },
|
|
2791
|
-
{ at: path }
|
|
2792
|
-
);
|
|
2793
|
-
return;
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2801
|
+
return;
|
|
2796
2802
|
}
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
}
|
|
2806
|
-
}
|
|
2807
|
-
}
|
|
2808
|
-
if (op.type === "split_node" && op.path.length === 1 && slate.Element.isElementProps(op.properties) && op.properties._type === types2.block.name && "markDefs" in op.properties && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0 && op.path[0] + 1 < editor.children.length) {
|
|
2809
|
-
const [targetBlock, targetPath] = slate.Editor.node(editor, [op.path[0] + 1]);
|
|
2810
|
-
if (debug$c("Copying markDefs over to split block", op), editor.isTextBlock(targetBlock)) {
|
|
2811
|
-
const oldDefs = Array.isArray(targetBlock.markDefs) && targetBlock.markDefs || [];
|
|
2812
|
-
slate.Transforms.setNodes(
|
|
2803
|
+
}
|
|
2804
|
+
if (editor.isTextBlock(node)) {
|
|
2805
|
+
const decorators2 = types2.decorators.map((decorator) => decorator.value);
|
|
2806
|
+
for (const [child, childPath] of slate.Node.children(editor, path))
|
|
2807
|
+
if (editor.isTextSpan(child)) {
|
|
2808
|
+
const marks = child.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !node.markDefs?.find((def) => def._key === mark));
|
|
2809
|
+
if (orphanedAnnotations.length > 0) {
|
|
2810
|
+
debug$c("Removing orphaned annotations from span node"), slate.Transforms.setNodes(
|
|
2813
2811
|
editor,
|
|
2814
|
-
{
|
|
2815
|
-
{ at:
|
|
2812
|
+
{ marks: marks.filter((mark) => !orphanedAnnotations.includes(mark)) },
|
|
2813
|
+
{ at: childPath }
|
|
2816
2814
|
);
|
|
2817
2815
|
return;
|
|
2818
2816
|
}
|
|
2819
2817
|
}
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
}
|
|
2818
|
+
}
|
|
2819
|
+
if (editor.isTextSpan(node)) {
|
|
2820
|
+
const blockPath = slate.Path.parent(path), [block] = slate.Editor.node(editor, blockPath);
|
|
2821
|
+
if (editor.isTextBlock(block)) {
|
|
2822
|
+
const decorators2 = types2.decorators.map((decorator) => decorator.value), marks = node.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !block.markDefs?.find((def) => def._key === mark));
|
|
2823
|
+
if (orphanedAnnotations.length > 0) {
|
|
2824
|
+
debug$c("Removing orphaned annotations from span node"), slate.Transforms.setNodes(
|
|
2825
|
+
editor,
|
|
2826
|
+
{ marks: marks.filter((mark) => !orphanedAnnotations.includes(mark)) },
|
|
2827
|
+
{ at: path }
|
|
2828
|
+
);
|
|
2829
|
+
return;
|
|
2833
2830
|
}
|
|
2834
2831
|
}
|
|
2835
2832
|
}
|
|
@@ -2923,6 +2920,14 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
|
|
|
2923
2920
|
}
|
|
2924
2921
|
}
|
|
2925
2922
|
}
|
|
2923
|
+
if (op.type === "merge_node" && op.path.length === 1 && "markDefs" in op.properties && op.properties._type === types2.block.name && Array.isArray(op.properties.markDefs) && op.properties.markDefs.length > 0 && op.path[0] - 1 >= 0) {
|
|
2924
|
+
const [targetBlock, targetPath] = slate.Editor.node(editor, [op.path[0] - 1]);
|
|
2925
|
+
if (editor.isTextBlock(targetBlock)) {
|
|
2926
|
+
const oldDefs = Array.isArray(targetBlock.markDefs) && targetBlock.markDefs || [], newMarkDefs = uniq__default.default([...oldDefs, ...op.properties.markDefs]);
|
|
2927
|
+
debug$c("Copying markDefs over to merged block", op), slate.Transforms.setNodes(editor, { markDefs: newMarkDefs }, { at: targetPath, voids: !1 }), apply2(op);
|
|
2928
|
+
return;
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2926
2931
|
apply2(op);
|
|
2927
2932
|
}, editor.addMark = (mark) => {
|
|
2928
2933
|
if (editor.selection) {
|