@portabletext/editor 1.1.1 → 1.1.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.
Files changed (53) hide show
  1. package/README.md +3 -0
  2. package/lib/index.d.mts +1668 -1
  3. package/lib/index.d.ts +1668 -1
  4. package/lib/index.esm.js +320 -172
  5. package/lib/index.esm.js.map +1 -1
  6. package/lib/index.js +320 -173
  7. package/lib/index.js.map +1 -1
  8. package/lib/index.mjs +320 -172
  9. package/lib/index.mjs.map +1 -1
  10. package/package.json +23 -23
  11. package/src/editor/Editable.tsx +32 -34
  12. package/src/editor/PortableTextEditor.tsx +23 -7
  13. package/src/editor/__tests__/PortableTextEditor.test.tsx +9 -9
  14. package/src/editor/__tests__/PortableTextEditorTester.tsx +2 -5
  15. package/src/editor/__tests__/RangeDecorations.test.tsx +2 -2
  16. package/src/editor/__tests__/handleClick.test.tsx +27 -7
  17. package/src/editor/__tests__/insert-block.test.tsx +4 -4
  18. package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +7 -7
  19. package/src/editor/__tests__/self-solving.test.tsx +176 -0
  20. package/src/editor/components/Leaf.tsx +28 -23
  21. package/src/editor/components/Synchronizer.tsx +60 -32
  22. package/src/editor/editor-machine.ts +195 -0
  23. package/src/editor/hooks/usePortableTextEditorSelection.tsx +12 -14
  24. package/src/editor/hooks/useSyncValue.test.tsx +9 -9
  25. package/src/editor/hooks/useSyncValue.ts +14 -13
  26. package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +1 -1
  27. package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +28 -28
  28. package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +17 -17
  29. package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +8 -8
  30. package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +5 -5
  31. package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +2 -2
  32. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +46 -46
  33. package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +22 -11
  34. package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +9 -9
  35. package/src/editor/plugins/createWithEditableAPI.ts +5 -7
  36. package/src/editor/plugins/createWithInsertData.ts +4 -9
  37. package/src/editor/plugins/createWithObjectKeys.ts +7 -0
  38. package/src/editor/plugins/createWithPatches.ts +5 -6
  39. package/src/editor/plugins/createWithPortableTextBlockStyle.ts +10 -2
  40. package/src/editor/plugins/createWithPortableTextMarkModel.ts +40 -36
  41. package/src/editor/plugins/createWithPortableTextSelections.ts +4 -5
  42. package/src/editor/plugins/createWithSchemaTypes.ts +9 -0
  43. package/src/editor/plugins/index.ts +18 -8
  44. package/src/index.ts +9 -3
  45. package/src/utils/__tests__/dmpToOperations.test.ts +1 -1
  46. package/src/utils/__tests__/operationToPatches.test.ts +61 -61
  47. package/src/utils/__tests__/patchToOperations.test.ts +39 -39
  48. package/src/utils/__tests__/ranges.test.ts +1 -1
  49. package/src/utils/__tests__/valueNormalization.test.tsx +13 -2
  50. package/src/utils/__tests__/values.test.ts +17 -17
  51. package/src/utils/applyPatch.ts +4 -10
  52. package/src/utils/validateValue.ts +0 -22
  53. package/src/editor/__tests__/utils.ts +0 -44
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var jsxRuntime = require("react/jsx-runtime"), isEqual = require("lodash/isEqual.js"), noop = require("lodash/noop.js"), react = require("react"), slate = require("slate"), slateReact = require("slate-react"), debug$m = require("debug"), types = require("@sanity/types"), styledComponents = require("styled-components"), uniq = require("lodash/uniq.js"), rxjs = require("rxjs"), schema = require("@sanity/schema"), patches = require("@portabletext/patches"), get = require("lodash/get.js"), isUndefined = require("lodash/isUndefined.js"), omitBy = require("lodash/omitBy.js"), flatten = require("lodash/flatten.js"), isHotkeyEsm = require("is-hotkey-esm"), blockTools = require("@sanity/block-tools"), isPlainObject = require("lodash/isPlainObject.js"), throttle = require("lodash/throttle.js"), content = require("@sanity/util/content"), debounce = require("lodash/debounce.js");
3
+ var jsxRuntime = require("react/jsx-runtime"), isEqual = require("lodash/isEqual.js"), noop = require("lodash/noop.js"), react = require("react"), slate = require("slate"), slateReact = require("slate-react"), debug$m = require("debug"), types = require("@sanity/types"), styledComponents = require("styled-components"), uniq = require("lodash/uniq.js"), rxjs = require("rxjs"), xstate = require("xstate"), schema = require("@sanity/schema"), patches = require("@portabletext/patches"), get = require("lodash/get.js"), isUndefined = require("lodash/isUndefined.js"), omitBy = require("lodash/omitBy.js"), flatten = require("lodash/flatten.js"), isHotkeyEsm = require("is-hotkey-esm"), blockTools = require("@sanity/block-tools"), isPlainObject = require("lodash/isPlainObject.js"), throttle = require("lodash/throttle.js"), content = require("@sanity/util/content"), debounce = require("lodash/debounce.js");
4
4
  function _interopDefaultCompat(e) {
5
5
  return e && typeof e == "object" && "default" in e ? e : { default: e };
6
6
  }
@@ -110,7 +110,7 @@ function normalizeSelection(selection, value) {
110
110
  const { anchor, focus } = selection;
111
111
  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;
112
112
  }
113
- const EMPTY_MARKDEFS = [], VOID_CHILD_KEY = "void-child";
113
+ const VOID_CHILD_KEY = "void-child";
114
114
  function keepObjectEquality(object, keyMap) {
115
115
  const value = keyMap[object._key];
116
116
  return value && isEqual__default.default(object, value) ? value : (keyMap[object._key] = object, object);
@@ -1694,7 +1694,7 @@ function createWithMaxBlocks(maxBlocks) {
1694
1694
  }, editor;
1695
1695
  };
1696
1696
  }
1697
- function createWithObjectKeys(schemaTypes, keyGenerator) {
1697
+ function createWithObjectKeys(editorActor, schemaTypes, keyGenerator) {
1698
1698
  return function(editor) {
1699
1699
  const { apply: apply2, normalizeNode } = editor;
1700
1700
  return editor.apply = (operation) => {
@@ -1730,10 +1730,13 @@ function createWithObjectKeys(schemaTypes, keyGenerator) {
1730
1730
  }, editor.normalizeNode = (entry) => {
1731
1731
  const [node, path] = entry;
1732
1732
  if (slate.Element.isElement(node) && node._type === schemaTypes.block.name) {
1733
- node._key || slate.Transforms.setNodes(editor, { _key: keyGenerator() }, { at: path });
1733
+ if (!node._key) {
1734
+ editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { _key: keyGenerator() }, { at: path }), editorActor.send({ type: "done normalizing" });
1735
+ return;
1736
+ }
1734
1737
  for (const [child, childPath] of slate.Node.children(editor, path))
1735
1738
  if (!child._key) {
1736
- slate.Transforms.setNodes(editor, { _key: keyGenerator() }, { at: childPath });
1739
+ editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { _key: keyGenerator() }, { at: childPath }), editorActor.send({ type: "done normalizing" });
1737
1740
  return;
1738
1741
  }
1739
1742
  }
@@ -2438,7 +2441,6 @@ function toInt(num) {
2438
2441
  }
2439
2442
  const debug$i = debugWithName("applyPatches"), debugVerbose$4 = debug$i.enabled && !0;
2440
2443
  function createApplyPatch(schemaTypes) {
2441
- let previousPatch;
2442
2444
  return (editor, patch) => {
2443
2445
  let changed = !1;
2444
2446
  debugVerbose$4 && (debug$i(
@@ -2452,7 +2454,7 @@ NEW PATCH =============================================================`
2452
2454
  changed = insertPatch(editor, patch, schemaTypes);
2453
2455
  break;
2454
2456
  case "unset":
2455
- changed = unsetPatch(editor, patch, previousPatch);
2457
+ changed = unsetPatch(editor, patch);
2456
2458
  break;
2457
2459
  case "set":
2458
2460
  changed = setPatch(editor, patch);
@@ -2466,7 +2468,7 @@ NEW PATCH =============================================================`
2466
2468
  } catch (err) {
2467
2469
  console.error(err);
2468
2470
  }
2469
- return previousPatch = patch, changed;
2471
+ return changed;
2470
2472
  };
2471
2473
  }
2472
2474
  function diffMatchPatch(editor, patch) {
@@ -2581,11 +2583,11 @@ function setPatch(editor, patch) {
2581
2583
  }
2582
2584
  return debugState(editor, "after"), !0;
2583
2585
  }
2584
- function unsetPatch(editor, patch, previousPatch) {
2586
+ function unsetPatch(editor, patch) {
2585
2587
  if (patch.path.length === 0) {
2586
2588
  debug$i("Removing everything"), debugState(editor, "before");
2587
2589
  const previousSelection = editor.selection;
2588
- return slate.Transforms.deselect(editor), editor.children.forEach((c, i) => {
2590
+ return slate.Transforms.deselect(editor), editor.children.forEach((_child, i) => {
2589
2591
  slate.Transforms.removeNodes(editor, { at: [i] });
2590
2592
  }), slate.Transforms.insertNodes(editor, editor.pteCreateTextBlock({ decorators: [] })), previousSelection && slate.Transforms.select(editor, {
2591
2593
  anchor: { path: [0, 0], offset: 0 },
@@ -2890,7 +2892,7 @@ function findOperationTargetBlock(editor, operation) {
2890
2892
  }
2891
2893
  const debug$g = debugWithName("plugin:withPatches");
2892
2894
  function createWithPatches({
2893
- change$,
2895
+ editorActor,
2894
2896
  patches$,
2895
2897
  patchFunctions,
2896
2898
  readOnly,
@@ -3019,7 +3021,7 @@ function createWithPatches({
3019
3021
  }
3020
3022
  return !editorWasEmpty && editorIsEmpty && ["merge_node", "set_node", "remove_text", "remove_node"].includes(
3021
3023
  operation.type
3022
- ) && (patches$1 = [...patches$1, patches.unset([])], change$.next({
3024
+ ) && (patches$1 = [...patches$1, patches.unset([])], editorActor.send({
3023
3025
  type: "unset",
3024
3026
  previousValue: fromSlateValue(
3025
3027
  previousChildren,
@@ -3027,7 +3029,7 @@ function createWithPatches({
3027
3029
  KEY_TO_VALUE_ELEMENT.get(editor)
3028
3030
  )
3029
3031
  })), editorWasEmpty && patches$1.length > 0 && (patches$1 = [patches.setIfMissing([], []), ...patches$1]), patches$1.length > 0 && patches$1.forEach((patch) => {
3030
- change$.next({
3032
+ editorActor.send({
3031
3033
  type: "patch",
3032
3034
  patch: { ...patch, origin: "local" }
3033
3035
  });
@@ -3063,25 +3065,25 @@ function createWithPlaceholderBlock() {
3063
3065
  };
3064
3066
  }
3065
3067
  const debug$e = debugWithName("plugin:withPortableTextBlockStyle");
3066
- function createWithPortableTextBlockStyle(types2) {
3068
+ function createWithPortableTextBlockStyle(editorActor, types2) {
3067
3069
  const defaultStyle = types2.styles[0].value;
3068
3070
  return function(editor) {
3069
3071
  const { normalizeNode } = editor;
3070
3072
  return editor.normalizeNode = (nodeEntry) => {
3071
- normalizeNode(nodeEntry);
3072
3073
  const [, path] = nodeEntry;
3073
3074
  for (const op of editor.operations)
3074
3075
  if (op.type === "split_node" && op.path.length === 1 && editor.isTextBlock(op.properties) && op.properties.style !== defaultStyle && op.path[0] === path[0] && !slate.Path.equals(path, op.path)) {
3075
3076
  const [child] = slate.Editor.node(editor, [op.path[0] + 1, 0]);
3076
3077
  if (slate.Text.isText(child) && child.text === "") {
3077
- debug$e(`Normalizing split node to ${defaultStyle} style`, op), slate.Transforms.setNodes(
3078
+ debug$e(`Normalizing split node to ${defaultStyle} style`, op), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3078
3079
  editor,
3079
3080
  { style: defaultStyle },
3080
3081
  { at: [op.path[0] + 1], voids: !1 }
3081
- );
3082
- break;
3082
+ ), editorActor.send({ type: "done normalizing" });
3083
+ return;
3083
3084
  }
3084
3085
  }
3086
+ normalizeNode(nodeEntry);
3085
3087
  }, editor.pteHasBlockStyle = (style) => editor.selection ? [
3086
3088
  ...slate.Editor.nodes(editor, {
3087
3089
  at: editor.selection,
@@ -3226,7 +3228,7 @@ function isPortableTextBlock(node) {
3226
3228
  );
3227
3229
  }
3228
3230
  const debug$c = debugWithName("plugin:withPortableTextMarkModel");
3229
- function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3231
+ function createWithPortableTextMarkModel(editorActor, types2, keyGenerator) {
3230
3232
  return function(editor) {
3231
3233
  const { apply: apply2, normalizeNode } = editor, decorators = types2.decorators.map((t) => t.value), forceNewSelection = () => {
3232
3234
  editor.selection && (slate.Transforms.select(editor, { ...editor.selection }), editor.selection = { ...editor.selection });
@@ -3235,7 +3237,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3235
3237
  editor.selection,
3236
3238
  types2
3237
3239
  );
3238
- change$.next({ type: "selection", selection: ptRange });
3240
+ editorActor.send({ type: "selection", selection: ptRange });
3239
3241
  };
3240
3242
  return editor.normalizeNode = (nodeEntry) => {
3241
3243
  const [node, path] = nodeEntry;
@@ -3248,20 +3250,20 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3248
3250
  "Merging spans",
3249
3251
  JSON.stringify(child, null, 2),
3250
3252
  JSON.stringify(nextNode, null, 2)
3251
- ), slate.Transforms.mergeNodes(editor, {
3253
+ ), editorActor.send({ type: "normalizing" }), slate.Transforms.mergeNodes(editor, {
3252
3254
  at: [childPath[0], childPath[1] + 1],
3253
3255
  voids: !0
3254
- });
3256
+ }), editorActor.send({ type: "done normalizing" });
3255
3257
  return;
3256
3258
  }
3257
3259
  }
3258
3260
  }
3259
3261
  if (editor.isTextBlock(node) && !Array.isArray(node.markDefs)) {
3260
- debug$c("Adding .markDefs to block node"), slate.Transforms.setNodes(editor, { markDefs: [] }, { at: path });
3262
+ debug$c("Adding .markDefs to block node"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { markDefs: [] }, { at: path }), editorActor.send({ type: "done normalizing" });
3261
3263
  return;
3262
3264
  }
3263
3265
  if (editor.isTextSpan(node) && !Array.isArray(node.marks)) {
3264
- debug$c("Adding .marks to span node"), slate.Transforms.setNodes(editor, { marks: [] }, { at: path });
3266
+ debug$c("Adding .marks to span node"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { marks: [] }, { at: path }), editorActor.send({ type: "done normalizing" });
3265
3267
  return;
3266
3268
  }
3267
3269
  if (editor.isTextSpan(node)) {
@@ -3269,11 +3271,11 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3269
3271
  (mark) => !decorators2.includes(mark)
3270
3272
  );
3271
3273
  if (editor.isTextBlock(block) && node.text === "" && annotations && annotations.length > 0) {
3272
- debug$c("Removing annotations from empty span node"), slate.Transforms.setNodes(
3274
+ debug$c("Removing annotations from empty span node"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3273
3275
  editor,
3274
3276
  { marks: node.marks?.filter((mark) => decorators2.includes(mark)) },
3275
3277
  { at: path }
3276
- );
3278
+ ), editorActor.send({ type: "done normalizing" });
3277
3279
  return;
3278
3280
  }
3279
3281
  }
@@ -3283,7 +3285,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3283
3285
  if (editor.isTextSpan(child)) {
3284
3286
  const marks = child.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !node.markDefs?.find((def) => def._key === mark));
3285
3287
  if (orphanedAnnotations.length > 0) {
3286
- debug$c("Removing orphaned annotations from span node"), slate.Transforms.setNodes(
3288
+ debug$c("Removing orphaned annotations from span node"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3287
3289
  editor,
3288
3290
  {
3289
3291
  marks: marks.filter(
@@ -3291,7 +3293,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3291
3293
  )
3292
3294
  },
3293
3295
  { at: childPath }
3294
- );
3296
+ ), editorActor.send({ type: "done normalizing" });
3295
3297
  return;
3296
3298
  }
3297
3299
  }
@@ -3303,7 +3305,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3303
3305
  (decorator) => decorator.value
3304
3306
  ), marks = node.marks ?? [], orphanedAnnotations = marks.filter((mark) => !decorators2.includes(mark) && !block.markDefs?.find((def) => def._key === mark));
3305
3307
  if (orphanedAnnotations.length > 0) {
3306
- debug$c("Removing orphaned annotations from span node"), slate.Transforms.setNodes(
3308
+ debug$c("Removing orphaned annotations from span node"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3307
3309
  editor,
3308
3310
  {
3309
3311
  marks: marks.filter(
@@ -3311,7 +3313,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3311
3313
  )
3312
3314
  },
3313
3315
  { at: path }
3314
- );
3316
+ ), editorActor.send({ type: "done normalizing" });
3315
3317
  return;
3316
3318
  }
3317
3319
  }
@@ -3320,20 +3322,23 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3320
3322
  const markDefs = node.markDefs ?? [], markDefKeys = /* @__PURE__ */ new Set(), newMarkDefs = [];
3321
3323
  for (const markDef of markDefs)
3322
3324
  markDefKeys.has(markDef._key) || (markDefKeys.add(markDef._key), newMarkDefs.push(markDef));
3323
- markDefs.length !== newMarkDefs.length && (debug$c("Removing duplicate markDefs"), slate.Transforms.setNodes(editor, { markDefs: newMarkDefs }, { at: path }));
3325
+ if (markDefs.length !== newMarkDefs.length) {
3326
+ debug$c("Removing duplicate markDefs"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { markDefs: newMarkDefs }, { at: path }), editorActor.send({ type: "done normalizing" });
3327
+ return;
3328
+ }
3324
3329
  }
3325
3330
  if (editor.isTextBlock(node) && !editor.operations.some(
3326
3331
  (op) => op.type === "merge_node" && "markDefs" in op.properties && op.path.length === 1
3327
3332
  )) {
3328
3333
  const newMarkDefs = (node.markDefs || []).filter((def) => node.children.find((child) => slate.Text.isText(child) && Array.isArray(child.marks) && child.marks.includes(def._key)));
3329
3334
  if (node.markDefs && !isEqual__default.default(newMarkDefs, node.markDefs)) {
3330
- debug$c("Removing markDef not in use"), slate.Transforms.setNodes(
3335
+ debug$c("Removing markDef not in use"), editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3331
3336
  editor,
3332
3337
  {
3333
3338
  markDefs: newMarkDefs
3334
3339
  },
3335
3340
  { at: path }
3336
- );
3341
+ ), editorActor.send({ type: "done normalizing" });
3337
3342
  return;
3338
3343
  }
3339
3344
  }
@@ -3348,27 +3353,24 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3348
3353
  return;
3349
3354
  }
3350
3355
  if (op.type === "insert_text") {
3351
- const { selection } = editor;
3352
- if (selection && slate.Range.isCollapsed(selection) && slate.Editor.marks(editor)?.marks?.some(
3353
- (mark) => !decorators.includes(mark)
3354
- )) {
3355
- const [node] = Array.from(
3356
+ const { selection } = editor, collapsedSelection = selection ? slate.Range.isCollapsed(selection) : !1;
3357
+ if (selection && collapsedSelection) {
3358
+ const [span] = Array.from(
3356
3359
  slate.Editor.nodes(editor, {
3357
3360
  mode: "lowest",
3358
3361
  at: selection.focus,
3359
- match: (n) => n._type === types2.span.name,
3362
+ match: (n) => editor.isTextSpan(n),
3360
3363
  voids: !1
3361
3364
  })
3362
- )[0] || [void 0];
3363
- if (slate.Text.isText(node) && node.text.length === selection.focus.offset && Array.isArray(node.marks) && node.marks.length > 0) {
3364
- const marksWithoutAnnotationMarks = ({
3365
- ...slate.Editor.marks(editor) || {}
3366
- }.marks || []).filter((mark) => decorators.includes(mark));
3365
+ )[0], marks = span.marks ?? [], marksWithoutAnnotations = marks.filter(
3366
+ (mark) => decorators.includes(mark)
3367
+ );
3368
+ if (marks.length > marksWithoutAnnotations.length && (selection.anchor.offset === 0 || span.text.length === selection.focus.offset)) {
3367
3369
  slate.Transforms.insertNodes(editor, {
3368
3370
  _type: "span",
3369
3371
  _key: keyGenerator(),
3370
3372
  text: op.text,
3371
- marks: marksWithoutAnnotationMarks
3373
+ marks: marksWithoutAnnotations
3372
3374
  }), debug$c("Inserting text at end of annotation");
3373
3375
  return;
3374
3376
  }
@@ -3566,7 +3568,7 @@ function createWithPortableTextMarkModel(types2, change$, keyGenerator) {
3566
3568
  };
3567
3569
  }
3568
3570
  const debug$b = debugWithName("plugin:withPortableTextSelections"), debugVerbose$2 = debug$b.enabled && !1;
3569
- function createWithPortableTextSelections(change$, types2) {
3571
+ function createWithPortableTextSelections(editorActor, types2) {
3570
3572
  let prevSelection = null;
3571
3573
  return function(editor) {
3572
3574
  const emitPortableTextSelection = () => {
@@ -3585,7 +3587,7 @@ function createWithPortableTextSelections(change$, types2) {
3585
3587
  `Emitting selection ${JSON.stringify(ptRange || null)} (${JSON.stringify(
3586
3588
  editor.selection
3587
3589
  )})`
3588
- ), ptRange ? change$.next({ type: "selection", selection: ptRange }) : change$.next({ type: "selection", selection: null });
3590
+ ), ptRange ? editorActor.send({ type: "selection", selection: ptRange }) : editorActor.send({ type: "selection", selection: null });
3589
3591
  }
3590
3592
  prevSelection = editor.selection;
3591
3593
  }, { onChange } = editor;
@@ -3597,6 +3599,7 @@ function createWithPortableTextSelections(change$, types2) {
3597
3599
  }
3598
3600
  const debug$a = debugWithName("plugin:withSchemaTypes");
3599
3601
  function createWithSchemaTypes({
3602
+ editorActor,
3600
3603
  schemaTypes,
3601
3604
  keyGenerator
3602
3605
  }) {
@@ -3608,16 +3611,18 @@ function createWithSchemaTypes({
3608
3611
  if (node._type === void 0 && path.length === 2) {
3609
3612
  debug$a("Setting span type on text node without a type");
3610
3613
  const span = node, key = span._key || keyGenerator();
3611
- slate.Transforms.setNodes(
3614
+ editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(
3612
3615
  editor,
3613
3616
  { ...span, _type: schemaTypes.span.name, _key: key },
3614
3617
  { at: path }
3615
- );
3618
+ ), editorActor.send({ type: "done normalizing" });
3619
+ return;
3616
3620
  }
3617
3621
  if (node._key === void 0 && (path.length === 1 || path.length === 2)) {
3618
3622
  debug$a("Setting missing key on child node without a key");
3619
3623
  const key = keyGenerator();
3620
- slate.Transforms.setNodes(editor, { _key: key }, { at: path });
3624
+ editorActor.send({ type: "normalizing" }), slate.Transforms.setNodes(editor, { _key: key }, { at: path }), editorActor.send({ type: "done normalizing" });
3625
+ return;
3621
3626
  }
3622
3627
  normalizeNode(entry);
3623
3628
  }, editor;
@@ -3925,22 +3930,6 @@ function validateValue(value, types$1, keyGenerator) {
3925
3930
  }
3926
3931
  }, !0;
3927
3932
  }
3928
- if (blk.markDefs && !Array.isArray(blk.markDefs))
3929
- return resolution = {
3930
- patches: [
3931
- patches.set({ ...textBlock, markDefs: EMPTY_MARKDEFS }, [
3932
- { _key: textBlock._key }
3933
- ])
3934
- ],
3935
- description: "Block has invalid required property 'markDefs'.",
3936
- action: "Add empty markDefs array",
3937
- item: textBlock,
3938
- i18n: {
3939
- description: "inputs.portable-text.invalid-value.missing-or-invalid-markdefs.description",
3940
- action: "inputs.portable-text.invalid-value.missing-or-invalid-markdefs.action",
3941
- values: { key: textBlock._key }
3942
- }
3943
- }, !0;
3944
3933
  const allUsedMarks = uniq__default.default(
3945
3934
  flatten__default.default(
3946
3935
  textBlock.children.filter((cld) => cld._type === types$1.span.name).map((cld) => cld.marks || [])
@@ -4085,7 +4074,7 @@ function validateValue(value, types$1, keyGenerator) {
4085
4074
  }) && (valid = !1), { valid, resolution, value });
4086
4075
  }
4087
4076
  const debug$7 = debugWithName("plugin:withInsertData");
4088
- function createWithInsertData(change$, schemaTypes, keyGenerator) {
4077
+ function createWithInsertData(editorActor, schemaTypes, keyGenerator) {
4089
4078
  return function(editor) {
4090
4079
  const blockTypeName = schemaTypes.block.name, spanTypeName = schemaTypes.span.name, whitespaceOnPasteMode = schemaTypes.block.options.unstable_whitespaceOnPasteMode, toPlainText = (blocks) => blocks.map((block) => editor.isTextBlock(block) ? block.children.map((child) => child._type === spanTypeName ? child.text : `[${schemaTypes.inlineObjects.find((t) => t.name === child._type)?.title || "Object"}]`).join("") : `[${schemaTypes.blockObjects.find((t) => t.name === block._type)?.title || "Object"}]`).join(`
4091
4080
 
@@ -4139,9 +4128,8 @@ function createWithInsertData(change$, schemaTypes, keyGenerator) {
4139
4128
  ), validation = validateValue(parsed, schemaTypes, keyGenerator);
4140
4129
  if (!validation.valid && !validation.resolution?.autoResolve) {
4141
4130
  const errorDescription = `${validation.resolution?.description}`;
4142
- return change$.next({
4131
+ return editorActor.send({
4143
4132
  type: "error",
4144
- level: "warning",
4145
4133
  name: "pasteError",
4146
4134
  description: errorDescription,
4147
4135
  data: validation
@@ -4154,7 +4142,6 @@ function createWithInsertData(change$, schemaTypes, keyGenerator) {
4154
4142
  }, editor.insertTextOrHTMLData = (data) => {
4155
4143
  if (!editor.selection)
4156
4144
  return debug$7("No selection, not inserting"), !1;
4157
- change$.next({ type: "loading", isLoading: !0 });
4158
4145
  const html = data.getData("text/html"), text = data.getData("text/plain");
4159
4146
  if (html || text) {
4160
4147
  debug$7("Inserting data", data);
@@ -4185,9 +4172,8 @@ function createWithInsertData(change$, schemaTypes, keyGenerator) {
4185
4172
  const errorDescription = `Could not validate the resulting portable text to insert.
4186
4173
  ${validation.resolution?.description}
4187
4174
  Try to insert as plain text (shift-paste) instead.`;
4188
- return change$.next({
4175
+ return editorActor.send({
4189
4176
  type: "error",
4190
- level: "warning",
4191
4177
  name: "pasteError",
4192
4178
  description: errorDescription,
4193
4179
  data: validation
@@ -4195,9 +4181,9 @@ Try to insert as plain text (shift-paste) instead.`;
4195
4181
  }
4196
4182
  return debug$7(
4197
4183
  `Inserting ${insertedType} fragment at ${JSON.stringify(editor.selection)}`
4198
- ), _insertFragment(editor, fragment, schemaTypes), change$.next({ type: "loading", isLoading: !1 }), !0;
4184
+ ), _insertFragment(editor, fragment, schemaTypes), !0;
4199
4185
  }
4200
- return change$.next({ type: "loading", isLoading: !1 }), !1;
4186
+ return !1;
4201
4187
  }, editor.insertData = (data) => {
4202
4188
  editor.insertPortableTextData(data) || editor.insertTextOrHTMLData(data);
4203
4189
  }, editor.insertFragmentData = (data) => {
@@ -4284,18 +4270,26 @@ function _insertFragment(editor, fragment, schemaTypes) {
4284
4270
  }), editor.onChange();
4285
4271
  }
4286
4272
  const originalFnMap = /* @__PURE__ */ new WeakMap(), withPlugins = (editor, options) => {
4287
- const e = editor, { keyGenerator, portableTextEditor, patches$, readOnly, maxBlocks } = options, { schemaTypes, change$ } = portableTextEditor;
4273
+ const e = editor, { keyGenerator, portableTextEditor, patches$, readOnly, maxBlocks } = options, { editorActor, schemaTypes } = portableTextEditor;
4288
4274
  e.subscriptions = [], e.destroy ? e.destroy() : originalFnMap.set(e, {
4289
4275
  apply: e.apply,
4290
4276
  onChange: e.onChange,
4291
4277
  normalizeNode: e.normalizeNode
4292
4278
  });
4293
- const operationToPatches = createOperationToPatches(schemaTypes), withObjectKeys = createWithObjectKeys(schemaTypes, keyGenerator), withSchemaTypes = createWithSchemaTypes({ schemaTypes, keyGenerator }), withEditableAPI = createWithEditableAPI(
4279
+ const operationToPatches = createOperationToPatches(schemaTypes), withObjectKeys = createWithObjectKeys(
4280
+ editorActor,
4281
+ schemaTypes,
4282
+ keyGenerator
4283
+ ), withSchemaTypes = createWithSchemaTypes({
4284
+ editorActor,
4285
+ schemaTypes,
4286
+ keyGenerator
4287
+ }), withEditableAPI = createWithEditableAPI(
4294
4288
  portableTextEditor,
4295
4289
  schemaTypes,
4296
4290
  keyGenerator
4297
4291
  ), withPatches = createWithPatches({
4298
- change$,
4292
+ editorActor,
4299
4293
  keyGenerator,
4300
4294
  patches$,
4301
4295
  patchFunctions: operationToPatches,
@@ -4306,15 +4300,18 @@ const originalFnMap = /* @__PURE__ */ new WeakMap(), withPlugins = (editor, opti
4306
4300
  patches$,
4307
4301
  blockSchemaType: schemaTypes.block
4308
4302
  }), withPortableTextMarkModel = createWithPortableTextMarkModel(
4303
+ editorActor,
4309
4304
  schemaTypes,
4310
- change$,
4311
4305
  keyGenerator
4312
- ), withPortableTextBlockStyle = createWithPortableTextBlockStyle(schemaTypes), withPlaceholderBlock = createWithPlaceholderBlock(), withInsertBreak = createWithInsertBreak(schemaTypes, keyGenerator), withUtils = createWithUtils({
4306
+ ), withPortableTextBlockStyle = createWithPortableTextBlockStyle(
4307
+ editorActor,
4308
+ schemaTypes
4309
+ ), withPlaceholderBlock = createWithPlaceholderBlock(), withInsertBreak = createWithInsertBreak(schemaTypes, keyGenerator), withUtils = createWithUtils({
4313
4310
  keyGenerator,
4314
4311
  schemaTypes,
4315
4312
  portableTextEditor
4316
4313
  }), withPortableTextSelections = createWithPortableTextSelections(
4317
- change$,
4314
+ editorActor,
4318
4315
  schemaTypes
4319
4316
  );
4320
4317
  return e.destroy = () => {
@@ -4431,7 +4428,7 @@ const defaultKeyGenerator = () => content.randomKey(12), PortableTextEditorKeyGe
4431
4428
  return readOnly;
4432
4429
  }, debug$5 = debugWithName("hook:useSyncValue"), CURRENT_VALUE = /* @__PURE__ */ new WeakMap();
4433
4430
  function useSyncValue(props) {
4434
- const { portableTextEditor, readOnly, keyGenerator } = props, { change$, schemaTypes } = portableTextEditor, previousValue = react.useRef(), slateEditor = slateReact.useSlate(), updateValueFunctionRef = react.useRef(), updateFromCurrentValue = react.useCallback(() => {
4431
+ const { editorActor, portableTextEditor, readOnly, keyGenerator } = props, { schemaTypes } = portableTextEditor, previousValue = react.useRef(), slateEditor = slateReact.useSlate(), updateValueFunctionRef = react.useRef(), updateFromCurrentValue = react.useCallback(() => {
4435
4432
  const currentValue = CURRENT_VALUE.get(portableTextEditor);
4436
4433
  if (previousValue.current === currentValue) {
4437
4434
  debug$5("Value is the same object as previous, not need to sync");
@@ -4502,7 +4499,7 @@ function useSyncValue(props) {
4502
4499
  !validation.valid && validation.resolution?.autoResolve && validation.resolution?.patches.length > 0 && !readOnly && previousValue.current && previousValue.current !== value && (console.warn(
4503
4500
  `${validation.resolution.action} for block with _key '${validationValue[0]._key}'. ${validation.resolution?.description}`
4504
4501
  ), validation.resolution.patches.forEach((patch) => {
4505
- change$.next({ type: "patch", patch });
4502
+ editorActor.send({ type: "patch", patch });
4506
4503
  })), validation.valid || validation.resolution?.autoResolve ? (oldBlock._key === currentBlock._key ? (debug$5.enabled && debug$5("Updating block", oldBlock, currentBlock), _updateBlock(
4507
4504
  slateEditor,
4508
4505
  currentBlock,
@@ -4512,8 +4509,8 @@ function useSyncValue(props) {
4512
4509
  slateEditor,
4513
4510
  currentBlock,
4514
4511
  currentBlockIndex
4515
- )), isChanged = !0) : (change$.next({
4516
- type: "invalidValue",
4512
+ )), isChanged = !0) : (editorActor.send({
4513
+ type: "invalid value",
4517
4514
  resolution: validation.resolution,
4518
4515
  value
4519
4516
  }), isValid = !1);
@@ -4529,8 +4526,8 @@ function useSyncValue(props) {
4529
4526
  currentBlock
4530
4527
  ), validation.valid || validation.resolution?.autoResolve ? slate.Transforms.insertNodes(slateEditor, currentBlock, {
4531
4528
  at: [currentBlockIndex]
4532
- }) : (debug$5("Invalid", validation), change$.next({
4533
- type: "invalidValue",
4529
+ }) : (debug$5("Invalid", validation), editorActor.send({
4530
+ type: "invalid value",
4534
4531
  resolution: validation.resolution,
4535
4532
  value
4536
4533
  }), isValid = !1);
@@ -4551,8 +4548,8 @@ function useSyncValue(props) {
4551
4548
  try {
4552
4549
  slateEditor.onChange();
4553
4550
  } catch (err) {
4554
- console.error(err), change$.next({
4555
- type: "invalidValue",
4551
+ console.error(err), editorActor.send({
4552
+ type: "invalid value",
4556
4553
  resolution: null,
4557
4554
  value
4558
4555
  });
@@ -4561,14 +4558,14 @@ function useSyncValue(props) {
4561
4558
  hadSelection && !slateEditor.selection && (slate.Transforms.select(slateEditor, {
4562
4559
  anchor: { path: [0, 0], offset: 0 },
4563
4560
  focus: { path: [0, 0], offset: 0 }
4564
- }), slateEditor.onChange()), change$.next({ type: "value", value });
4561
+ }), slateEditor.onChange()), editorActor.send({ type: "value changed", value });
4565
4562
  } else
4566
4563
  debug$5("Server value and editor value is equal, no need to sync.");
4567
4564
  previousValue.current = value;
4568
4565
  };
4569
4566
  return updateValueFunctionRef.current = updateFunction, updateFunction;
4570
4567
  }, [
4571
- change$,
4568
+ editorActor,
4572
4569
  keyGenerator,
4573
4570
  portableTextEditor,
4574
4571
  readOnly,
@@ -4637,9 +4634,9 @@ function _updateBlock(slateEditor, currentBlock, oldBlock, currentBlockIndex) {
4637
4634
  }
4638
4635
  const debug$4 = debugWithName("component:PortableTextEditor:Synchronizer"), debugVerbose$1 = debug$4.enabled && !1, FLUSH_PATCHES_THROTTLED_MS = process.env.NODE_ENV === "test" ? 500 : 1e3;
4639
4636
  function Synchronizer(props) {
4640
- const portableTextEditor = usePortableTextEditor(), keyGenerator = usePortableTextEditorKeyGenerator(), readOnly = usePortableTextEditorReadOnlyStatus(), { change$, getValue, onChange, value } = props, pendingPatches = react.useRef([]), syncValue = useSyncValue({
4637
+ const portableTextEditor = usePortableTextEditor(), keyGenerator = usePortableTextEditorKeyGenerator(), readOnly = usePortableTextEditorReadOnlyStatus(), { editorActor, getValue, onChange, value } = props, pendingPatches = react.useRef([]), syncValue = useSyncValue({
4638
+ editorActor,
4641
4639
  keyGenerator,
4642
- onChange,
4643
4640
  portableTextEditor,
4644
4641
  readOnly
4645
4642
  }), slateEditor = slateReact.useSlate();
@@ -4651,14 +4648,14 @@ function Synchronizer(props) {
4651
4648
  debug$4("Flushing pending patches"), debugVerbose$1 && debug$4(`Patches:
4652
4649
  ${JSON.stringify(pendingPatches.current, null, 2)}`);
4653
4650
  const snapshot = getValue();
4654
- change$.next({
4651
+ editorActor.send({
4655
4652
  type: "mutation",
4656
4653
  patches: pendingPatches.current,
4657
4654
  snapshot
4658
4655
  }), pendingPatches.current = [];
4659
4656
  }
4660
4657
  IS_PROCESSING_LOCAL_CHANGES.set(slateEditor, !1);
4661
- }, [slateEditor, getValue, change$]), onFlushPendingPatchesThrottled = react.useMemo(() => throttle__default.default(
4658
+ }, [editorActor, slateEditor, getValue]), onFlushPendingPatchesThrottled = react.useMemo(() => throttle__default.default(
4662
4659
  () => {
4663
4660
  if (slate.Editor.isNormalizing(slateEditor)) {
4664
4661
  onFlushPendingPatches();
@@ -4675,34 +4672,174 @@ ${JSON.stringify(pendingPatches.current, null, 2)}`);
4675
4672
  react.useEffect(() => () => {
4676
4673
  onFlushPendingPatches();
4677
4674
  }, [onFlushPendingPatches]), react.useEffect(() => {
4678
- debug$4("Subscribing to editor changes$");
4679
- const sub = change$.subscribe((next) => {
4680
- switch (next.type) {
4675
+ debug$4("Subscribing to editor changes");
4676
+ const sub = editorActor.on("*", (event) => {
4677
+ switch (event.type) {
4681
4678
  case "patch":
4682
- IS_PROCESSING_LOCAL_CHANGES.set(slateEditor, !0), pendingPatches.current.push(next.patch), onFlushPendingPatchesThrottled(), onChange(next);
4679
+ IS_PROCESSING_LOCAL_CHANGES.set(slateEditor, !0), pendingPatches.current.push(event.patch), onFlushPendingPatchesThrottled(), onChange(event);
4680
+ break;
4681
+ case "loading": {
4682
+ onChange({ type: "loading", isLoading: !0 });
4683
+ break;
4684
+ }
4685
+ case "done loading": {
4686
+ onChange({ type: "loading", isLoading: !1 });
4687
+ break;
4688
+ }
4689
+ case "offline": {
4690
+ onChange({ type: "connection", value: "offline" });
4691
+ break;
4692
+ }
4693
+ case "online": {
4694
+ onChange({ type: "connection", value: "online" });
4695
+ break;
4696
+ }
4697
+ case "value changed": {
4698
+ onChange({ type: "value", value: event.value });
4699
+ break;
4700
+ }
4701
+ case "invalid value": {
4702
+ onChange({
4703
+ type: "invalidValue",
4704
+ resolution: event.resolution,
4705
+ value: event.value
4706
+ });
4707
+ break;
4708
+ }
4709
+ case "error": {
4710
+ onChange({
4711
+ ...event,
4712
+ level: "warning"
4713
+ });
4683
4714
  break;
4715
+ }
4684
4716
  default:
4685
- onChange(next);
4717
+ onChange(event);
4686
4718
  }
4687
4719
  });
4688
4720
  return () => {
4689
- debug$4("Unsubscribing to changes$"), sub.unsubscribe();
4721
+ debug$4("Unsubscribing to changes"), sub.unsubscribe();
4690
4722
  };
4691
- }, [change$, onChange, onFlushPendingPatchesThrottled, slateEditor]);
4723
+ }, [editorActor, onFlushPendingPatchesThrottled, slateEditor]);
4692
4724
  const handleOnline = react.useCallback(() => {
4693
- debug$4("Editor is online, syncing from props.value"), change$.next({ type: "connection", value: "online" }), syncValue(value);
4694
- }, [change$, syncValue, value]), handleOffline = react.useCallback(() => {
4695
- debug$4("Editor is offline"), change$.next({ type: "connection", value: "offline" });
4696
- }, [change$]);
4697
- react.useEffect(() => (portableTextEditor.props.patches$ && (window.addEventListener("online", handleOnline), window.addEventListener("offline", handleOffline)), () => {
4698
- portableTextEditor.props.patches$ && (window.removeEventListener("online", handleOnline), window.removeEventListener("offline", handleOffline));
4699
- }));
4725
+ debug$4("Editor is online, syncing from props.value"), syncValue(value);
4726
+ }, [syncValue, value]);
4727
+ react.useEffect(() => {
4728
+ const subscription = editorActor.on("online", () => {
4729
+ portableTextEditor.props.patches$ && handleOnline();
4730
+ });
4731
+ return () => {
4732
+ subscription.unsubscribe();
4733
+ };
4734
+ }, [editorActor]);
4700
4735
  const isInitialValueFromProps = react.useRef(!0);
4701
4736
  return react.useEffect(() => {
4702
- debug$4("Value from props changed, syncing new value"), syncValue(value), isInitialValueFromProps.current && (change$.next({ type: "loading", isLoading: !1 }), change$.next({ type: "ready" }), isInitialValueFromProps.current = !1);
4703
- }, [change$, syncValue, value]), null;
4737
+ debug$4("Value from props changed, syncing new value"), syncValue(value), isInitialValueFromProps.current && (editorActor.send({ type: "ready" }), isInitialValueFromProps.current = !1);
4738
+ }, [editorActor, syncValue, value]), null;
4704
4739
  }
4705
- const PortableTextEditorSelectionContext = react.createContext(null), usePortableTextEditorSelection = () => {
4740
+ const networkLogic = xstate.fromCallback(({ sendBack }) => {
4741
+ const onlineHandler = () => {
4742
+ sendBack({ type: "online" });
4743
+ }, offlineHandler = () => {
4744
+ sendBack({ type: "offline" });
4745
+ };
4746
+ return window.addEventListener("online", onlineHandler), window.addEventListener("offline", offlineHandler), () => {
4747
+ window.removeEventListener("online", onlineHandler), window.removeEventListener("offline", offlineHandler);
4748
+ };
4749
+ }), editorMachine = xstate.setup({
4750
+ types: {
4751
+ context: {},
4752
+ events: {},
4753
+ emitted: {}
4754
+ },
4755
+ actions: {
4756
+ "emit patch event": xstate.emit(({ event }) => (xstate.assertEvent(event, "patch"), event)),
4757
+ "emit mutation event": xstate.emit(({ event }) => (xstate.assertEvent(event, "mutation"), event)),
4758
+ "defer event": xstate.assign({
4759
+ pendingEvents: ({ context, event }) => (xstate.assertEvent(event, ["patch", "mutation"]), [...context.pendingEvents, event])
4760
+ }),
4761
+ "emit pending events": xstate.enqueueActions(({ context, enqueue }) => {
4762
+ for (const event of context.pendingEvents)
4763
+ enqueue(xstate.emit(event));
4764
+ }),
4765
+ "clear pending events": xstate.assign({
4766
+ pendingEvents: []
4767
+ })
4768
+ },
4769
+ actors: {
4770
+ networkLogic
4771
+ }
4772
+ }).createMachine({
4773
+ id: "editor",
4774
+ context: {
4775
+ pendingEvents: []
4776
+ },
4777
+ invoke: {
4778
+ id: "networkLogic",
4779
+ src: "networkLogic"
4780
+ },
4781
+ on: {
4782
+ ready: { actions: xstate.emit(({ event }) => event) },
4783
+ unset: { actions: xstate.emit(({ event }) => event) },
4784
+ "value changed": { actions: xstate.emit(({ event }) => event) },
4785
+ "invalid value": { actions: xstate.emit(({ event }) => event) },
4786
+ error: { actions: xstate.emit(({ event }) => event) },
4787
+ selection: { actions: xstate.emit(({ event }) => event) },
4788
+ blur: { actions: xstate.emit(({ event }) => event) },
4789
+ focus: { actions: xstate.emit(({ event }) => event) },
4790
+ online: { actions: xstate.emit({ type: "online" }) },
4791
+ offline: { actions: xstate.emit({ type: "offline" }) },
4792
+ loading: { actions: xstate.emit({ type: "loading" }) },
4793
+ "done loading": { actions: xstate.emit({ type: "done loading" }) }
4794
+ },
4795
+ initial: "pristine",
4796
+ states: {
4797
+ pristine: {
4798
+ initial: "idle",
4799
+ states: {
4800
+ idle: {
4801
+ on: {
4802
+ normalizing: {
4803
+ target: "normalizing"
4804
+ },
4805
+ patch: {
4806
+ actions: "defer event",
4807
+ target: "#editor.dirty"
4808
+ },
4809
+ mutation: {
4810
+ actions: "defer event",
4811
+ target: "#editor.dirty"
4812
+ }
4813
+ }
4814
+ },
4815
+ normalizing: {
4816
+ on: {
4817
+ "done normalizing": {
4818
+ target: "idle"
4819
+ },
4820
+ patch: {
4821
+ actions: "defer event"
4822
+ },
4823
+ mutation: {
4824
+ actions: "defer event"
4825
+ }
4826
+ }
4827
+ }
4828
+ }
4829
+ },
4830
+ dirty: {
4831
+ entry: ["emit pending events", "clear pending events"],
4832
+ on: {
4833
+ patch: {
4834
+ actions: "emit patch event"
4835
+ },
4836
+ mutation: {
4837
+ actions: "emit mutation event"
4838
+ }
4839
+ }
4840
+ }
4841
+ }
4842
+ }), PortableTextEditorSelectionContext = react.createContext(null), usePortableTextEditorSelection = () => {
4706
4843
  const selection = react.useContext(PortableTextEditorSelectionContext);
4707
4844
  if (selection === void 0)
4708
4845
  throw new Error(
@@ -4711,21 +4848,26 @@ const PortableTextEditorSelectionContext = react.createContext(null), usePortabl
4711
4848
  return selection;
4712
4849
  }, debug$3 = debugWithName("component:PortableTextEditor:SelectionProvider"), debugVerbose = debug$3.enabled && !1;
4713
4850
  function PortableTextEditorSelectionProvider(props) {
4714
- const { change$ } = props, [selection, setSelection] = react.useState(null);
4851
+ const [selection, setSelection] = react.useState(null);
4715
4852
  return react.useEffect(() => {
4716
- debug$3("Subscribing to selection changes$");
4717
- const subscription = change$.subscribe((next) => {
4718
- next.type === "selection" && react.startTransition(() => {
4719
- debugVerbose && debug$3("Setting selection"), setSelection(next.selection);
4853
+ debug$3("Subscribing to selection changes");
4854
+ const subscription = props.editorActor.on("selection", (event) => {
4855
+ react.startTransition(() => {
4856
+ debugVerbose && debug$3("Setting selection"), setSelection(event.selection);
4720
4857
  });
4721
4858
  });
4722
4859
  return () => {
4723
- debug$3("Unsubscribing to selection changes$"), subscription.unsubscribe();
4860
+ debug$3("Unsubscribing to selection changes"), subscription.unsubscribe();
4724
4861
  };
4725
- }, [change$]), /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorSelectionContext.Provider, { value: selection, children: props.children });
4862
+ }, [props.editorActor]), /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorSelectionContext.Provider, { value: selection, children: props.children });
4726
4863
  }
4727
4864
  const debug$2 = debugWithName("component:PortableTextEditor");
4728
4865
  class PortableTextEditor extends react.Component {
4866
+ /**
4867
+ * @internal
4868
+ * Don't use this API directly. It's subject to change.
4869
+ */
4870
+ editorActor;
4729
4871
  /**
4730
4872
  * An observable of all the editor changes.
4731
4873
  */
@@ -4743,7 +4885,7 @@ class PortableTextEditor extends react.Component {
4743
4885
  throw new Error('PortableTextEditor: missing "schemaType" property');
4744
4886
  props.incomingPatches$ && console.warn(
4745
4887
  "The prop 'incomingPatches$' is deprecated and renamed to 'patches$'"
4746
- ), this.change$.next({ type: "loading", isLoading: !0 }), this.schemaTypes = getPortableTextMemberSchemaTypes(
4888
+ ), this.editorActor = xstate.createActor(editorMachine), this.editorActor.start(), this.schemaTypes = getPortableTextMemberSchemaTypes(
4747
4889
  props.schemaType.hasOwnProperty("jsonType") ? props.schemaType : compileType(props.schemaType)
4748
4890
  );
4749
4891
  }
@@ -4760,7 +4902,7 @@ class PortableTextEditor extends react.Component {
4760
4902
  return this.editable.getValue();
4761
4903
  };
4762
4904
  render() {
4763
- const { onChange, value, children, patches$, incomingPatches$ } = this.props, { change$ } = this, _patches$ = incomingPatches$ || patches$, maxBlocks = typeof this.props.maxBlocks > "u" ? void 0 : Number.parseInt(this.props.maxBlocks.toString(), 10) || void 0, readOnly = !!this.props.readOnly, keyGenerator = this.props.keyGenerator || defaultKeyGenerator;
4905
+ const { value, children, patches$, incomingPatches$ } = this.props, _patches$ = incomingPatches$ || patches$, maxBlocks = typeof this.props.maxBlocks > "u" ? void 0 : Number.parseInt(this.props.maxBlocks.toString(), 10) || void 0, readOnly = !!this.props.readOnly, keyGenerator = this.props.keyGenerator || defaultKeyGenerator;
4764
4906
  return /* @__PURE__ */ jsxRuntime.jsx(
4765
4907
  SlateContainer,
4766
4908
  {
@@ -4769,18 +4911,26 @@ class PortableTextEditor extends react.Component {
4769
4911
  patches$: _patches$,
4770
4912
  portableTextEditor: this,
4771
4913
  readOnly,
4772
- children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorKeyGeneratorContext.Provider, { value: keyGenerator, children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorContext.Provider, { value: this, children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorReadOnlyContext.Provider, { value: readOnly, children: /* @__PURE__ */ jsxRuntime.jsxs(PortableTextEditorSelectionProvider, { change$, children: [
4773
- /* @__PURE__ */ jsxRuntime.jsx(
4774
- Synchronizer,
4775
- {
4776
- change$,
4777
- getValue: this.getValue,
4778
- onChange,
4779
- value
4780
- }
4781
- ),
4782
- children
4783
- ] }) }) }) })
4914
+ children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorKeyGeneratorContext.Provider, { value: keyGenerator, children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorContext.Provider, { value: this, children: /* @__PURE__ */ jsxRuntime.jsx(PortableTextEditorReadOnlyContext.Provider, { value: readOnly, children: /* @__PURE__ */ jsxRuntime.jsxs(
4915
+ PortableTextEditorSelectionProvider,
4916
+ {
4917
+ editorActor: this.editorActor,
4918
+ children: [
4919
+ /* @__PURE__ */ jsxRuntime.jsx(
4920
+ Synchronizer,
4921
+ {
4922
+ editorActor: this.editorActor,
4923
+ getValue: this.getValue,
4924
+ onChange: (change) => {
4925
+ this.props.onChange(change), this.change$.next(change);
4926
+ },
4927
+ value
4928
+ }
4929
+ ),
4930
+ children
4931
+ ]
4932
+ }
4933
+ ) }) }) })
4784
4934
  }
4785
4935
  );
4786
4936
  }
@@ -4810,7 +4960,7 @@ class PortableTextEditor extends react.Component {
4810
4960
  static insertBlock = (editor, type, value) => editor.editable?.insertBlock(type, value);
4811
4961
  static insertBreak = (editor) => editor.editable?.insertBreak();
4812
4962
  static isVoid = (editor, element) => editor.editable?.isVoid(element);
4813
- static isObjectPath = (editor, path) => {
4963
+ static isObjectPath = (_editor, path) => {
4814
4964
  if (!path || !Array.isArray(path)) return !1;
4815
4965
  const isChildObjectEditPath = path.length > 3 && path[1] === "children";
4816
4966
  return path.length > 1 && path[1] !== "children" || isChildObjectEditPath;
@@ -4890,20 +5040,19 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
4890
5040
  react.useEffect(() => {
4891
5041
  if (!shouldTrackSelectionAndFocus)
4892
5042
  return;
4893
- const sub = portableTextEditor.change$.subscribe((next) => {
4894
- if (next.type === "blur") {
4895
- setFocused(!1), setSelected(!1);
4896
- return;
5043
+ const onBlur = portableTextEditor.editorActor.on("blur", () => {
5044
+ setFocused(!1), setSelected(!1);
5045
+ }), onFocus = portableTextEditor.editorActor.on("focus", () => {
5046
+ const sel = PortableTextEditor.getSelection(portableTextEditor);
5047
+ sel && isEqual__default.default(sel.focus.path, path) && PortableTextEditor.isCollapsedSelection(portableTextEditor) && setFocused(!0), setSelectedFromRange();
5048
+ }), onSelection = portableTextEditor.editorActor.on(
5049
+ "selection",
5050
+ (event) => {
5051
+ event.selection && isEqual__default.default(event.selection.focus.path, path) && PortableTextEditor.isCollapsedSelection(portableTextEditor) ? setFocused(!0) : setFocused(!1), setSelectedFromRange();
4897
5052
  }
4898
- if (next.type === "focus") {
4899
- const sel = PortableTextEditor.getSelection(portableTextEditor);
4900
- sel && isEqual__default.default(sel.focus.path, path) && PortableTextEditor.isCollapsedSelection(portableTextEditor) && setFocused(!0), setSelectedFromRange();
4901
- return;
4902
- }
4903
- next.type === "selection" && (next.selection && isEqual__default.default(next.selection.focus.path, path) && PortableTextEditor.isCollapsedSelection(portableTextEditor) ? setFocused(!0) : setFocused(!1), setSelectedFromRange());
4904
- });
5053
+ );
4905
5054
  return () => {
4906
- sub.unsubscribe();
5055
+ onBlur.unsubscribe(), onFocus.unsubscribe(), onSelection.unsubscribe();
4907
5056
  };
4908
5057
  }, [
4909
5058
  path,
@@ -5054,9 +5203,9 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5054
5203
  forwardedRef,
5055
5204
  () => ref.current
5056
5205
  );
5057
- const rangeDecorationsRef = react.useRef(rangeDecorations), { change$, schemaTypes } = portableTextEditor, slateEditor = slateReact.useSlate(), blockTypeName = schemaTypes.block.name, withInsertData = react.useMemo(
5058
- () => createWithInsertData(change$, schemaTypes, keyGenerator),
5059
- [change$, keyGenerator, schemaTypes]
5206
+ const rangeDecorationsRef = react.useRef(rangeDecorations), { editorActor, schemaTypes } = portableTextEditor, slateEditor = slateReact.useSlate(), blockTypeName = schemaTypes.block.name, withInsertData = react.useMemo(
5207
+ () => createWithInsertData(editorActor, schemaTypes, keyGenerator),
5208
+ [editorActor, keyGenerator, schemaTypes]
5060
5209
  ), withHotKeys = react.useMemo(
5061
5210
  () => createWithHotkeys(schemaTypes, portableTextEditor, hotkeys),
5062
5211
  [hotkeys, portableTextEditor, schemaTypes]
@@ -5129,10 +5278,13 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5129
5278
  `Normalized selection from props ${JSON.stringify(normalizedSelection)}`
5130
5279
  );
5131
5280
  const slateRange = toSlateRange(normalizedSelection, slateEditor);
5132
- slateRange && (slate.Transforms.select(slateEditor, slateRange), slateEditor.operations.some((o) => o.type === "set_selection") || change$.next({ type: "selection", selection: normalizedSelection }), slateEditor.onChange());
5281
+ slateRange && (slate.Transforms.select(slateEditor, slateRange), slateEditor.operations.some((o) => o.type === "set_selection") || editorActor.send({
5282
+ type: "selection",
5283
+ selection: normalizedSelection
5284
+ }), slateEditor.onChange());
5133
5285
  }
5134
5286
  }
5135
- }, [propsSelection, slateEditor, blockTypeName, change$]), syncRangeDecorations = react.useCallback(
5287
+ }, [editorActor, propsSelection, slateEditor]), syncRangeDecorations = react.useCallback(
5136
5288
  (operation) => {
5137
5289
  if (rangeDecorations && rangeDecorations.length > 0) {
5138
5290
  const newSlateRanges = [];
@@ -5176,23 +5328,17 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5176
5328
  [portableTextEditor, rangeDecorations, schemaTypes, slateEditor]
5177
5329
  );
5178
5330
  react.useEffect(() => {
5179
- const sub = change$.subscribe((next) => {
5180
- switch (next.type) {
5181
- case "ready":
5182
- restoreSelectionFromProps();
5183
- break;
5184
- case "invalidValue":
5185
- setHasInvalidValue(!0);
5186
- break;
5187
- case "value":
5188
- setHasInvalidValue(!1);
5189
- break;
5190
- }
5331
+ const onReady = editorActor.on("ready", () => {
5332
+ restoreSelectionFromProps();
5333
+ }), onInvalidValue = editorActor.on("invalid value", () => {
5334
+ setHasInvalidValue(!0);
5335
+ }), onValueChanged = editorActor.on("value changed", () => {
5336
+ setHasInvalidValue(!1);
5191
5337
  });
5192
5338
  return () => {
5193
- sub.unsubscribe();
5339
+ onReady.unsubscribe(), onInvalidValue.unsubscribe(), onValueChanged.unsubscribe();
5194
5340
  };
5195
- }, [change$, restoreSelectionFromProps]), react.useEffect(() => {
5341
+ }, [editorActor, restoreSelectionFromProps]), react.useEffect(() => {
5196
5342
  propsSelection && !hasInvalidValue && restoreSelectionFromProps();
5197
5343
  }, [hasInvalidValue, propsSelection, restoreSelectionFromProps]);
5198
5344
  const originalApply = react.useMemo(() => slateEditor.apply, [slateEditor]), [syncedRangeDecorations, setSyncedRangeDecorations] = react.useState(!1);
@@ -5223,7 +5369,7 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5223
5369
  slateEditor.selection,
5224
5370
  schemaTypes
5225
5371
  )?.focus.path || [], onPasteResult = onPaste({ event, value, path, schemaTypes });
5226
- onPasteResult === void 0 ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event.clipboardData)) : (change$.next({ type: "loading", isLoading: !0 }), Promise.resolve(onPasteResult).then((result) => {
5372
+ onPasteResult === void 0 ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event.clipboardData)) : (editorActor.send({ type: "loading" }), Promise.resolve(onPasteResult).then((result) => {
5227
5373
  debug("Custom paste function from client resolved", result), !result || !result.insert ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event.clipboardData)) : result.insert ? slateEditor.insertFragment(
5228
5374
  toSlateValue(result.insert, {
5229
5375
  schemaTypes
@@ -5233,23 +5379,23 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5233
5379
  result
5234
5380
  );
5235
5381
  }).catch((error) => (console.error(error), error)).finally(() => {
5236
- change$.next({ type: "loading", isLoading: !1 });
5382
+ editorActor.send({ type: "done loading" });
5237
5383
  }));
5238
5384
  },
5239
- [change$, onPaste, portableTextEditor, schemaTypes, slateEditor]
5385
+ [onPaste, portableTextEditor, schemaTypes, slateEditor]
5240
5386
  ), handleOnFocus = react.useCallback(
5241
5387
  (event) => {
5242
5388
  if (onFocus && onFocus(event), !event.isDefaultPrevented()) {
5243
5389
  const selection = PortableTextEditor.getSelection(portableTextEditor);
5244
- selection === null && (slate.Transforms.select(slateEditor, slate.Editor.start(slateEditor, [])), slateEditor.onChange()), change$.next({ type: "focus", event });
5390
+ selection === null && (slate.Transforms.select(slateEditor, slate.Editor.start(slateEditor, [])), slateEditor.onChange()), editorActor.send({ type: "focus", event });
5245
5391
  const newSelection = PortableTextEditor.getSelection(portableTextEditor);
5246
- selection === newSelection && change$.next({
5392
+ selection === newSelection && editorActor.send({
5247
5393
  type: "selection",
5248
5394
  selection
5249
5395
  });
5250
5396
  }
5251
5397
  },
5252
- [onFocus, portableTextEditor, change$, slateEditor]
5398
+ [editorActor, onFocus, portableTextEditor, slateEditor]
5253
5399
  ), handleClick = react.useCallback(
5254
5400
  (event) => {
5255
5401
  if (onClick && onClick(event), slateEditor.selection && event.target === event.currentTarget) {
@@ -5266,9 +5412,9 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5266
5412
  [onClick, slateEditor]
5267
5413
  ), handleOnBlur = react.useCallback(
5268
5414
  (event) => {
5269
- onBlur && onBlur(event), event.isPropagationStopped() || change$.next({ type: "blur", event });
5415
+ onBlur && onBlur(event), event.isPropagationStopped() || editorActor.send({ type: "blur", event });
5270
5416
  },
5271
- [change$, onBlur]
5417
+ [editorActor, onBlur]
5272
5418
  ), handleOnBeforeInput = react.useCallback(
5273
5419
  (event) => {
5274
5420
  onBeforeInput && onBeforeInput(event);
@@ -5315,7 +5461,7 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5315
5461
  [props, slateEditor]
5316
5462
  ), scrollSelectionIntoViewToSlate = react.useMemo(() => {
5317
5463
  if (scrollSelectionIntoView !== void 0)
5318
- return scrollSelectionIntoView === null ? noop__default.default : (editor, domRange) => {
5464
+ return scrollSelectionIntoView === null ? noop__default.default : (_editor, domRange) => {
5319
5465
  scrollSelectionIntoView(portableTextEditor, domRange);
5320
5466
  };
5321
5467
  }, [portableTextEditor, scrollSelectionIntoView]), decorate = react.useCallback(
@@ -5373,6 +5519,7 @@ const debug$1 = debugWithName("components:Leaf"), EMPTY_MARKS = [], Leaf = (prop
5373
5519
  });
5374
5520
  exports.PortableTextEditable = PortableTextEditable;
5375
5521
  exports.PortableTextEditor = PortableTextEditor;
5522
+ exports.editorMachine = editorMachine;
5376
5523
  exports.keyGenerator = defaultKeyGenerator;
5377
5524
  exports.usePortableTextEditor = usePortableTextEditor;
5378
5525
  exports.usePortableTextEditorSelection = usePortableTextEditorSelection;