@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.
@@ -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, insertText, deleteBackward, deleteForward } from "slate";
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
- }) => !context.readOnly && (context.isProcessingLocalChanges || (isChangingRemotely(context.slateEditor) ?? !1)),
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
- reenter: !0
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
- }), debug$d = debugWithName("hook:useSyncValue");
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 IS_APPLYING_BEHAVIOR_ACTIONS = /* @__PURE__ */ new WeakMap();
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
- insertSoftBreak();
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) => (debug("Host getting fragment"), editor.editable?.getFragment());
6687
+ static getFragment = (editor) => editor.editable?.getFragment();
6621
6688
  static undo = (editor) => {
6622
6689
  debug("Host undoing"), editor.editable?.undo();
6623
6690
  };