@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.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 = [],
|
|
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 =
|
|
874
|
-
return spanToRemove ?
|
|
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]],
|
|
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
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
set(
|
|
890
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
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
|
-
{
|
|
2831
|
-
{ at:
|
|
2828
|
+
{ marks: marks.filter((mark) => !orphanedAnnotations.includes(mark)) },
|
|
2829
|
+
{ at: childPath }
|
|
2832
2830
|
);
|
|
2833
2831
|
return;
|
|
2834
2832
|
}
|
|
2835
2833
|
}
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
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) {
|