@portabletext/editor 1.30.1 → 1.30.3
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/_chunks-cjs/behavior.core.cjs +1 -11
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/plugin.event-listener.cjs +145 -78
- package/lib/_chunks-cjs/plugin.event-listener.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +1 -11
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/plugin.event-listener.js +147 -80
- package/lib/_chunks-es/plugin.event-listener.js.map +1 -1
- package/lib/behaviors/index.cjs +0 -1
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +0 -3016
- package/lib/behaviors/index.d.ts +0 -3016
- package/lib/behaviors/index.js +1 -2
- package/lib/index.d.cts +111 -1
- package/lib/index.d.ts +111 -1
- package/lib/plugins/index.d.cts +111 -1
- package/lib/plugins/index.d.ts +111 -1
- package/package.json +11 -11
- package/src/behaviors/behavior.core.ts +0 -14
- package/src/behaviors/behavior.foundational.ts +15 -0
- package/src/behaviors/index.ts +1 -1
- package/src/editor/PortableTextEditor.tsx +0 -1
- package/src/editor/editor-machine.ts +6 -2
- package/src/editor/plugins/create-with-event-listeners.ts +8 -2
- package/src/editor/sync-machine.ts +67 -8
- package/src/internal-utils/key-is.ts +10 -0
|
@@ -5,7 +5,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
|
5
5
|
import { withReact, ReactEditor, Slate } from "slate-react";
|
|
6
6
|
import { useSelector, useActorRef } from "@xstate/react";
|
|
7
7
|
import debug$f from "debug";
|
|
8
|
-
import { Editor, Element, Range, Point, Text, Operation, Transforms, Path, Node, createEditor as createEditor$1, select, deleteFragment,
|
|
8
|
+
import { Editor, Element, Range, Point, Text, Operation, Transforms, Path, Node, insertText, createEditor as createEditor$1, select, deleteFragment, deleteBackward, deleteForward } from "slate";
|
|
9
9
|
import { setup, emit, assign, fromCallback, assertEvent, enqueueActions, createActor } from "xstate";
|
|
10
10
|
import isEqual from "lodash/isEqual.js";
|
|
11
11
|
import { unset, set, setIfMissing, insert, diffMatchPatch as diffMatchPatch$1, applyAll } from "@portabletext/patches";
|
|
@@ -24,7 +24,7 @@ import omitBy from "lodash/omitBy.js";
|
|
|
24
24
|
import startCase from "lodash.startcase";
|
|
25
25
|
import { createGuards } from "./selector.is-at-the-start-of-block.js";
|
|
26
26
|
import { blockOffsetToSpanSelectionPoint } from "./util.is-empty-text-block.js";
|
|
27
|
-
import { coreBehaviors, isCustomBehaviorEvent } from "./behavior.core.js";
|
|
27
|
+
import { defineBehavior, raise, coreBehaviors, isCustomBehaviorEvent } from "./behavior.core.js";
|
|
28
28
|
import getRandomValues from "get-random-values-esm";
|
|
29
29
|
import { Subject } from "rxjs";
|
|
30
30
|
function createEditorSchema(portableTextType) {
|
|
@@ -1678,7 +1678,7 @@ function findOperationTargetBlock(editor, operation) {
|
|
|
1678
1678
|
let block;
|
|
1679
1679
|
return operation.type === "set_selection" && editor.selection ? block = editor.children[editor.selection.focus.path[0]] : "path" in operation && (block = editor.children[operation.path[0]]), block;
|
|
1680
1680
|
}
|
|
1681
|
-
const syncValueCallback = ({
|
|
1681
|
+
const debug$d = debugWithName("sync machine"), syncValueCallback = ({
|
|
1682
1682
|
sendBack,
|
|
1683
1683
|
input
|
|
1684
1684
|
}) => {
|
|
@@ -1728,7 +1728,15 @@ const syncValueCallback = ({
|
|
|
1728
1728
|
}) => context.initialValueSynced,
|
|
1729
1729
|
"is busy": ({
|
|
1730
1730
|
context
|
|
1731
|
-
}) =>
|
|
1731
|
+
}) => {
|
|
1732
|
+
const editable = !context.readOnly, isProcessingLocalChanges = context.isProcessingLocalChanges, isChanging = isChangingRemotely(context.slateEditor) ?? !1, isBusy = editable && (isProcessingLocalChanges || isChanging);
|
|
1733
|
+
return debug$d("isBusy", {
|
|
1734
|
+
isBusy,
|
|
1735
|
+
editable,
|
|
1736
|
+
isProcessingLocalChanges,
|
|
1737
|
+
isChanging
|
|
1738
|
+
}), isBusy;
|
|
1739
|
+
},
|
|
1732
1740
|
"value changed while syncing": ({
|
|
1733
1741
|
context,
|
|
1734
1742
|
event
|
|
@@ -1775,13 +1783,24 @@ const syncValueCallback = ({
|
|
|
1775
1783
|
initial: "syncing initial value",
|
|
1776
1784
|
states: {
|
|
1777
1785
|
"syncing initial value": {
|
|
1786
|
+
entry: [() => {
|
|
1787
|
+
debug$d("entry: syncing initial value");
|
|
1788
|
+
}],
|
|
1789
|
+
exit: [() => {
|
|
1790
|
+
debug$d("exit: syncing initial value");
|
|
1791
|
+
}],
|
|
1778
1792
|
always: {
|
|
1779
1793
|
guard: "initial value synced",
|
|
1780
1794
|
target: "done syncing initial value"
|
|
1781
1795
|
}
|
|
1782
1796
|
},
|
|
1783
1797
|
"done syncing initial value": {
|
|
1784
|
-
entry: ["emit done syncing initial value"
|
|
1798
|
+
entry: ["emit done syncing initial value", () => {
|
|
1799
|
+
debug$d("entry: done syncing initial value");
|
|
1800
|
+
}],
|
|
1801
|
+
exit: [() => {
|
|
1802
|
+
debug$d("exit: done syncing initial value");
|
|
1803
|
+
}],
|
|
1785
1804
|
type: "final"
|
|
1786
1805
|
}
|
|
1787
1806
|
}
|
|
@@ -1790,6 +1809,12 @@ const syncValueCallback = ({
|
|
|
1790
1809
|
initial: "idle",
|
|
1791
1810
|
states: {
|
|
1792
1811
|
idle: {
|
|
1812
|
+
entry: [() => {
|
|
1813
|
+
debug$d("entry: syncing->idle");
|
|
1814
|
+
}],
|
|
1815
|
+
exit: [() => {
|
|
1816
|
+
debug$d("exit: syncing->idle");
|
|
1817
|
+
}],
|
|
1793
1818
|
on: {
|
|
1794
1819
|
"update value": [{
|
|
1795
1820
|
guard: "is busy",
|
|
@@ -1802,10 +1827,20 @@ const syncValueCallback = ({
|
|
|
1802
1827
|
}
|
|
1803
1828
|
},
|
|
1804
1829
|
busy: {
|
|
1830
|
+
entry: [() => {
|
|
1831
|
+
debug$d("entry: syncing->busy");
|
|
1832
|
+
}],
|
|
1833
|
+
exit: [() => {
|
|
1834
|
+
debug$d("exit: syncing->busy");
|
|
1835
|
+
}],
|
|
1805
1836
|
after: {
|
|
1806
1837
|
1e3: [{
|
|
1807
1838
|
guard: "is busy",
|
|
1808
|
-
|
|
1839
|
+
target: ".",
|
|
1840
|
+
reenter: !0,
|
|
1841
|
+
actions: [() => {
|
|
1842
|
+
debug$d("reenter: syncing->busy");
|
|
1843
|
+
}]
|
|
1809
1844
|
}, {
|
|
1810
1845
|
target: "syncing"
|
|
1811
1846
|
}]
|
|
@@ -1817,6 +1852,12 @@ const syncValueCallback = ({
|
|
|
1817
1852
|
}
|
|
1818
1853
|
},
|
|
1819
1854
|
syncing: {
|
|
1855
|
+
entry: [() => {
|
|
1856
|
+
debug$d("entry: syncing->syncing");
|
|
1857
|
+
}],
|
|
1858
|
+
exit: [() => {
|
|
1859
|
+
debug$d("exit: syncing->syncing");
|
|
1860
|
+
}],
|
|
1820
1861
|
always: {
|
|
1821
1862
|
guard: "pending value equals previous value",
|
|
1822
1863
|
target: "idle",
|
|
@@ -1871,7 +1912,7 @@ const syncValueCallback = ({
|
|
|
1871
1912
|
}
|
|
1872
1913
|
}
|
|
1873
1914
|
}
|
|
1874
|
-
})
|
|
1915
|
+
});
|
|
1875
1916
|
async function updateValue({
|
|
1876
1917
|
context,
|
|
1877
1918
|
sendBack,
|
|
@@ -2608,7 +2649,74 @@ function createOperationToPatches(types) {
|
|
|
2608
2649
|
splitNodePatch
|
|
2609
2650
|
};
|
|
2610
2651
|
}
|
|
2611
|
-
const
|
|
2652
|
+
const insertBreakActionImplementation = ({
|
|
2653
|
+
context,
|
|
2654
|
+
action
|
|
2655
|
+
}) => {
|
|
2656
|
+
const keyGenerator = context.keyGenerator, schema = context.schema, editor = action.editor;
|
|
2657
|
+
if (!editor.selection)
|
|
2658
|
+
return;
|
|
2659
|
+
const anchorBlockPath = editor.selection.anchor.path.slice(0, 1), focusBlockPath = editor.selection.focus.path.slice(0, 1), focusBlock = Node.descendant(editor, focusBlockPath);
|
|
2660
|
+
if (editor.isTextBlock(focusBlock) && anchorBlockPath[0] === focusBlockPath[0]) {
|
|
2661
|
+
Transforms.splitNodes(editor, {
|
|
2662
|
+
at: editor.selection
|
|
2663
|
+
});
|
|
2664
|
+
const [nextBlock, nextBlockPath] = Editor.node(editor, Path.next(focusBlockPath), {
|
|
2665
|
+
depth: 1
|
|
2666
|
+
}), nextChild = Node.child(nextBlock, 0);
|
|
2667
|
+
if (!editor.isTextSpan(nextChild) && Transforms.insertNodes(editor, {
|
|
2668
|
+
_key: context.keyGenerator(),
|
|
2669
|
+
_type: "span",
|
|
2670
|
+
text: "",
|
|
2671
|
+
marks: []
|
|
2672
|
+
}, {
|
|
2673
|
+
at: [nextBlockPath[0], 0]
|
|
2674
|
+
}), Transforms.setSelection(editor, {
|
|
2675
|
+
anchor: {
|
|
2676
|
+
path: [...nextBlockPath, 0],
|
|
2677
|
+
offset: 0
|
|
2678
|
+
},
|
|
2679
|
+
focus: {
|
|
2680
|
+
path: [...nextBlockPath, 0],
|
|
2681
|
+
offset: 0
|
|
2682
|
+
}
|
|
2683
|
+
}), editor.isTextBlock(nextBlock) && nextBlock.markDefs && nextBlock.markDefs.length > 0) {
|
|
2684
|
+
const newMarkDefKeys = /* @__PURE__ */ new Map(), prevNodeSpans = Array.from(Node.children(editor, focusBlockPath)).map((entry) => entry[0]).filter((node) => editor.isTextSpan(node)), children = Node.children(editor, nextBlockPath);
|
|
2685
|
+
for (const [child, childPath] of children) {
|
|
2686
|
+
if (!editor.isTextSpan(child))
|
|
2687
|
+
continue;
|
|
2688
|
+
const marks = child.marks ?? [];
|
|
2689
|
+
for (const mark of marks)
|
|
2690
|
+
schema.decorators.some((decorator) => decorator.value === mark) || prevNodeSpans.some((prevNodeSpan) => prevNodeSpan.marks?.includes(mark)) && !newMarkDefKeys.has(mark) && newMarkDefKeys.set(mark, keyGenerator());
|
|
2691
|
+
const newMarks = marks.map((mark) => newMarkDefKeys.get(mark) ?? mark);
|
|
2692
|
+
isEqual(marks, newMarks) || Transforms.setNodes(editor, {
|
|
2693
|
+
marks: newMarks
|
|
2694
|
+
}, {
|
|
2695
|
+
at: childPath
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
const newMarkDefs = nextBlock.markDefs.map((markDef) => ({
|
|
2699
|
+
...markDef,
|
|
2700
|
+
_key: newMarkDefKeys.get(markDef._key) ?? markDef._key
|
|
2701
|
+
}));
|
|
2702
|
+
isEqual(nextBlock.markDefs, newMarkDefs) || Transforms.setNodes(editor, {
|
|
2703
|
+
markDefs: newMarkDefs
|
|
2704
|
+
}, {
|
|
2705
|
+
at: nextBlockPath,
|
|
2706
|
+
match: (node) => editor.isTextBlock(node)
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
return;
|
|
2710
|
+
}
|
|
2711
|
+
Transforms.splitNodes(editor, {
|
|
2712
|
+
always: !0
|
|
2713
|
+
});
|
|
2714
|
+
}, insertSoftBreakActionImplementation = ({
|
|
2715
|
+
action
|
|
2716
|
+
}) => {
|
|
2717
|
+
insertText(action.editor, `
|
|
2718
|
+
`);
|
|
2719
|
+
}, IS_APPLYING_BEHAVIOR_ACTIONS = /* @__PURE__ */ new WeakMap();
|
|
2612
2720
|
function withApplyingBehaviorActions(editor, fn) {
|
|
2613
2721
|
const prev = isApplyingBehaviorActions(editor);
|
|
2614
2722
|
IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, !0), fn(), IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, prev);
|
|
@@ -2665,7 +2773,6 @@ function createWithEventListeners(editorActor, subscriptions) {
|
|
|
2665
2773
|
deleteForward: deleteForward2,
|
|
2666
2774
|
insertBreak,
|
|
2667
2775
|
insertData,
|
|
2668
|
-
insertSoftBreak,
|
|
2669
2776
|
insertText: insertText2,
|
|
2670
2777
|
select: select2,
|
|
2671
2778
|
setFragmentData
|
|
@@ -2723,7 +2830,16 @@ function createWithEventListeners(editorActor, subscriptions) {
|
|
|
2723
2830
|
});
|
|
2724
2831
|
}, editor.insertSoftBreak = () => {
|
|
2725
2832
|
if (isApplyingBehaviorActions(editor)) {
|
|
2726
|
-
|
|
2833
|
+
insertSoftBreakActionImplementation({
|
|
2834
|
+
context: {
|
|
2835
|
+
keyGenerator: editorActor.getSnapshot().context.keyGenerator,
|
|
2836
|
+
schema: editorActor.getSnapshot().context.schema
|
|
2837
|
+
},
|
|
2838
|
+
action: {
|
|
2839
|
+
type: "insert.soft break",
|
|
2840
|
+
editor
|
|
2841
|
+
}
|
|
2842
|
+
});
|
|
2727
2843
|
return;
|
|
2728
2844
|
}
|
|
2729
2845
|
editorActor.send({
|
|
@@ -4798,73 +4914,6 @@ const blockSetBehaviorActionImplementation = ({
|
|
|
4798
4914
|
}), action.editor.insertFragment(fragment), Transforms.removeNodes(action.editor, {
|
|
4799
4915
|
at: [0]
|
|
4800
4916
|
})) : action.editor.insertFragment(fragment);
|
|
4801
|
-
}, insertBreakActionImplementation = ({
|
|
4802
|
-
context,
|
|
4803
|
-
action
|
|
4804
|
-
}) => {
|
|
4805
|
-
const keyGenerator = context.keyGenerator, schema = context.schema, editor = action.editor;
|
|
4806
|
-
if (!editor.selection)
|
|
4807
|
-
return;
|
|
4808
|
-
const anchorBlockPath = editor.selection.anchor.path.slice(0, 1), focusBlockPath = editor.selection.focus.path.slice(0, 1), focusBlock = Node.descendant(editor, focusBlockPath);
|
|
4809
|
-
if (editor.isTextBlock(focusBlock) && anchorBlockPath[0] === focusBlockPath[0]) {
|
|
4810
|
-
Transforms.splitNodes(editor, {
|
|
4811
|
-
at: editor.selection
|
|
4812
|
-
});
|
|
4813
|
-
const [nextBlock, nextBlockPath] = Editor.node(editor, Path.next(focusBlockPath), {
|
|
4814
|
-
depth: 1
|
|
4815
|
-
}), nextChild = Node.child(nextBlock, 0);
|
|
4816
|
-
if (!editor.isTextSpan(nextChild) && Transforms.insertNodes(editor, {
|
|
4817
|
-
_key: context.keyGenerator(),
|
|
4818
|
-
_type: "span",
|
|
4819
|
-
text: "",
|
|
4820
|
-
marks: []
|
|
4821
|
-
}, {
|
|
4822
|
-
at: [nextBlockPath[0], 0]
|
|
4823
|
-
}), Transforms.setSelection(editor, {
|
|
4824
|
-
anchor: {
|
|
4825
|
-
path: [...nextBlockPath, 0],
|
|
4826
|
-
offset: 0
|
|
4827
|
-
},
|
|
4828
|
-
focus: {
|
|
4829
|
-
path: [...nextBlockPath, 0],
|
|
4830
|
-
offset: 0
|
|
4831
|
-
}
|
|
4832
|
-
}), editor.isTextBlock(nextBlock) && nextBlock.markDefs && nextBlock.markDefs.length > 0) {
|
|
4833
|
-
const newMarkDefKeys = /* @__PURE__ */ new Map(), prevNodeSpans = Array.from(Node.children(editor, focusBlockPath)).map((entry) => entry[0]).filter((node) => editor.isTextSpan(node)), children = Node.children(editor, nextBlockPath);
|
|
4834
|
-
for (const [child, childPath] of children) {
|
|
4835
|
-
if (!editor.isTextSpan(child))
|
|
4836
|
-
continue;
|
|
4837
|
-
const marks = child.marks ?? [];
|
|
4838
|
-
for (const mark of marks)
|
|
4839
|
-
schema.decorators.some((decorator) => decorator.value === mark) || prevNodeSpans.some((prevNodeSpan) => prevNodeSpan.marks?.includes(mark)) && !newMarkDefKeys.has(mark) && newMarkDefKeys.set(mark, keyGenerator());
|
|
4840
|
-
const newMarks = marks.map((mark) => newMarkDefKeys.get(mark) ?? mark);
|
|
4841
|
-
isEqual(marks, newMarks) || Transforms.setNodes(editor, {
|
|
4842
|
-
marks: newMarks
|
|
4843
|
-
}, {
|
|
4844
|
-
at: childPath
|
|
4845
|
-
});
|
|
4846
|
-
}
|
|
4847
|
-
const newMarkDefs = nextBlock.markDefs.map((markDef) => ({
|
|
4848
|
-
...markDef,
|
|
4849
|
-
_key: newMarkDefKeys.get(markDef._key) ?? markDef._key
|
|
4850
|
-
}));
|
|
4851
|
-
isEqual(nextBlock.markDefs, newMarkDefs) || Transforms.setNodes(editor, {
|
|
4852
|
-
markDefs: newMarkDefs
|
|
4853
|
-
}, {
|
|
4854
|
-
at: nextBlockPath,
|
|
4855
|
-
match: (node) => editor.isTextBlock(node)
|
|
4856
|
-
});
|
|
4857
|
-
}
|
|
4858
|
-
return;
|
|
4859
|
-
}
|
|
4860
|
-
Transforms.splitNodes(editor, {
|
|
4861
|
-
always: !0
|
|
4862
|
-
});
|
|
4863
|
-
}, insertSoftBreakActionImplementation = ({
|
|
4864
|
-
action
|
|
4865
|
-
}) => {
|
|
4866
|
-
insertText(action.editor, `
|
|
4867
|
-
`);
|
|
4868
4917
|
}, insertInlineObjectActionImplementation = ({
|
|
4869
4918
|
context,
|
|
4870
4919
|
action
|
|
@@ -5556,6 +5605,24 @@ function performDefaultAction({
|
|
|
5556
5605
|
});
|
|
5557
5606
|
}
|
|
5558
5607
|
}
|
|
5608
|
+
const keyIs = {
|
|
5609
|
+
lineBreak: (event) => event.key === "Enter" && event.shiftKey
|
|
5610
|
+
}, foundationalBehaviors = [
|
|
5611
|
+
/**
|
|
5612
|
+
* On WebKit, Shift+Enter results in an `insertParagraph` input event rather
|
|
5613
|
+
* than an `insertLineBreak` input event. This Behavior makes sure we catch
|
|
5614
|
+
* that `key.down` event beforehand and raise an `insert.soft break` manually.
|
|
5615
|
+
*/
|
|
5616
|
+
defineBehavior({
|
|
5617
|
+
on: "key.down",
|
|
5618
|
+
guard: ({
|
|
5619
|
+
event
|
|
5620
|
+
}) => keyIs.lineBreak(event.keyboardEvent),
|
|
5621
|
+
actions: [() => [raise({
|
|
5622
|
+
type: "insert.soft break"
|
|
5623
|
+
})]]
|
|
5624
|
+
})
|
|
5625
|
+
];
|
|
5559
5626
|
function getActiveDecorators({
|
|
5560
5627
|
schema,
|
|
5561
5628
|
slateEditorInstance
|
|
@@ -5609,7 +5676,7 @@ const editorMachine = setup({
|
|
|
5609
5676
|
"assign behaviors": assign({
|
|
5610
5677
|
behaviors: ({
|
|
5611
5678
|
event
|
|
5612
|
-
}) => (assertEvent(event, "update behaviors"), new Set(event.behaviors))
|
|
5679
|
+
}) => (assertEvent(event, "update behaviors"), /* @__PURE__ */ new Set([...foundationalBehaviors, ...event.behaviors]))
|
|
5613
5680
|
}),
|
|
5614
5681
|
"assign schema": assign({
|
|
5615
5682
|
schema: ({
|
|
@@ -5776,7 +5843,7 @@ const editorMachine = setup({
|
|
|
5776
5843
|
context: ({
|
|
5777
5844
|
input
|
|
5778
5845
|
}) => ({
|
|
5779
|
-
behaviors: new Set(input.behaviors ?? coreBehaviors),
|
|
5846
|
+
behaviors: /* @__PURE__ */ new Set([...foundationalBehaviors, ...input.behaviors ?? coreBehaviors]),
|
|
5780
5847
|
converters: new Set(input.converters ?? []),
|
|
5781
5848
|
keyGenerator: input.keyGenerator,
|
|
5782
5849
|
pendingEvents: [],
|
|
@@ -6617,7 +6684,7 @@ class PortableTextEditor extends Component {
|
|
|
6617
6684
|
* const selectedSlice = useEditorSelector(editor, selectors.getSelectedSlice)
|
|
6618
6685
|
* ```
|
|
6619
6686
|
*/
|
|
6620
|
-
static getFragment = (editor) =>
|
|
6687
|
+
static getFragment = (editor) => editor.editable?.getFragment();
|
|
6621
6688
|
static undo = (editor) => {
|
|
6622
6689
|
debug("Host undoing"), editor.editable?.undo();
|
|
6623
6690
|
};
|