@portabletext/editor 7.3.4 → 7.5.0

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.js CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import { useSelector, useActorRef } from "@xstate/react";
4
4
  import React, { createContext, useContext, useRef, useEffect, useLayoutEffect, useState, useReducer, useCallback, memo, forwardRef, useMemo, Component, useSyncExternalStore, startTransition } from "react";
5
- import { isKeyedSegment, getNode, getParent, parentPath, getChildren, getNodeChildren } from "./_chunks-es/get-parent.js";
5
+ import { serializePath, isKeyedSegment, getNode, getParent, parentPath, getChildren, getNodeChildren } from "./_chunks-es/get-parent.js";
6
6
  import { isPath, getLeaf, isRange, isPoint, isObject, isLeafObject, getAncestor, pathContains, getSpan, isBeforePoint, getText, rangeIntersects, getTextBlock, getUnionSchema, getFirstChild } from "./_chunks-es/get-first-child.js";
7
7
  import { rangeEdges, isTextBlockNode, isBackwardRange, hasNode, getNodes, isAncestorPath, isEditableContainer, getSibling, isInline, isObject as isObject$1, isSpanNode, isBlock, getEnclosingBlock, getAncestors, getPathSubSchema, getBlock, resolveContainerAt, comparePaths, getEnclosingContainer, comparePoints$1 as comparePoints, isAfterPoint } from "./_chunks-es/get-path-sub-schema.js";
8
8
  import { isSpan, isTextBlock, compileSchema } from "@portabletext/schema";
@@ -21,9 +21,6 @@ import { markdownToPortableText, portableTextToMarkdown } from "@portabletext/ma
21
21
  import { applyAll, unset, set, insert, setIfMissing, diffMatchPatch as diffMatchPatch$1 } from "@portabletext/patches";
22
22
  import { EditorContext as EditorContext$1 } from "./_chunks-es/use-editor.js";
23
23
  import { useEditor } from "./_chunks-es/use-editor.js";
24
- function serializePath(path2) {
25
- return path2.reduce((result, segment, index) => isKeyedSegment(segment) ? `${result}[_key=="${segment._key}"]` : `${result}${index === 0 ? "" : "."}${segment}`, "");
26
- }
27
24
  function getDomNode(editor, path2) {
28
25
  const editorElement = editor.domElement;
29
26
  if (!editorElement)
@@ -32,7 +29,7 @@ function getDomNode(editor, path2) {
32
29
  return editorElement;
33
30
  const serializedPath = serializePath(path2), selector = `[data-pt-path="${CSS.escape(serializedPath)}"]`, blockSegment = path2[0];
34
31
  if (isKeyedSegment(blockSegment)) {
35
- const blockIndex = editor.blockIndexMap.get(blockSegment._key);
32
+ const blockIndex = editor.blockIndexMap.get(serializePath([blockSegment]));
36
33
  if (blockIndex !== void 0) {
37
34
  const blockNode = editorElement.children[blockIndex];
38
35
  if (blockNode instanceof HTMLElement) {
@@ -7642,8 +7639,8 @@ const modifyDescendant = (editor, path2, f) => {
7642
7639
  if (rootNumericIndex !== void 0)
7643
7640
  rootIndex = rootNumericIndex;
7644
7641
  else if (keyedSegments.length > 0) {
7645
- const rootKey = keyedSegments[0]._key;
7646
- editor.blockIndexMap.has(rootKey) ? rootIndex = editor.blockIndexMap.get(rootKey) : rootIndex = findIndexByKey(editor.snapshot.context.value, rootKey);
7642
+ const rootSegment = keyedSegments[0], mapIndex = editor.blockIndexMap.get(serializePath([rootSegment]));
7643
+ rootIndex = mapIndex !== void 0 ? mapIndex : findIndexByKey(editor.snapshot.context.value, rootSegment._key);
7647
7644
  } else {
7648
7645
  const firstSegment = path2[0];
7649
7646
  rootIndex = typeof firstSegment == "number" ? firstSegment : -1;
@@ -7682,9 +7679,7 @@ function applyOperation(editor, op) {
7682
7679
  let {
7683
7680
  node
7684
7681
  } = op;
7685
- const isRootInsert = parentPath(path2).length === 0;
7686
- let insertIndex = -1;
7687
- if (modifyChildren(editor, parentPath(path2), (children) => {
7682
+ modifyChildren(editor, parentPath(path2), (children) => {
7688
7683
  !editor.isProcessingRemoteChanges && !editor.isUndoing && !editor.isRedoing && node._key !== void 0 && children.some((sibling) => sibling._key === node._key) && (node = {
7689
7684
  ...node,
7690
7685
  _key: editor.snapshot.context.keyGenerator()
@@ -7692,7 +7687,7 @@ function applyOperation(editor, op) {
7692
7687
  const lastSegment = path2[path2.length - 1];
7693
7688
  let index;
7694
7689
  if (isKeyedSegment(lastSegment)) {
7695
- const siblingIndex = resolveChildIndex$1(children, lastSegment._key, isRootInsert ? editor.blockIndexMap : void 0);
7690
+ const siblingIndex = resolveChildIndex$1(editor.blockIndexMap, path2.slice(0, -1), lastSegment, children);
7696
7691
  if (siblingIndex === -1)
7697
7692
  throw new Error(`Cannot apply an "insert" operation at path [${path2}] because the sibling was not found.`);
7698
7693
  index = op.position === "after" ? siblingIndex + 1 : siblingIndex;
@@ -7707,14 +7702,8 @@ function applyOperation(editor, op) {
7707
7702
  path: node._key !== void 0 ? replaceLastSegment(path2, {
7708
7703
  _key: node._key
7709
7704
  }) : path2
7710
- }), insertIndex = index, insertChildren(children, index, node);
7711
- }), isRootInsert && insertIndex !== -1) {
7712
- if (insertIndex < editor.blockIndexMap.size)
7713
- for (const [key, idx] of editor.blockIndexMap)
7714
- idx >= insertIndex && editor.blockIndexMap.set(key, idx + 1);
7715
- editor.blockIndexMap.set(node._key, insertIndex);
7716
- }
7717
- transformSelection = !0;
7705
+ }), insertChildren(children, index, node);
7706
+ }), transformSelection = !0;
7718
7707
  break;
7719
7708
  }
7720
7709
  case "insert.text": {
@@ -7768,14 +7757,7 @@ function applyOperation(editor, op) {
7768
7757
  };
7769
7758
  }
7770
7759
  if (path2.length === 0) {
7771
- if (Array.isArray(value)) {
7772
- editor.snapshot.context.value = value, editor.blockIndexMap.clear();
7773
- for (let i = 0; i < editor.snapshot.context.value.length; i++) {
7774
- const child = editor.snapshot.context.value[i];
7775
- child && editor.blockIndexMap.set(child._key, i);
7776
- }
7777
- }
7778
- transformSelection = !0;
7760
+ Array.isArray(value) && (editor.snapshot.context.value = value), transformSelection = !0;
7779
7761
  break;
7780
7762
  }
7781
7763
  const {
@@ -7791,20 +7773,17 @@ function applyOperation(editor, op) {
7791
7773
  if (getNode(editor.snapshot, setNodePath))
7792
7774
  if (setPropertyPath.length === 1) {
7793
7775
  const propertyName = setPropertyPath[0];
7794
- if (modifyDescendant(editor, setNodePath, (node) => ({
7776
+ modifyDescendant(editor, setNodePath, (node) => ({
7795
7777
  ...node,
7796
7778
  [propertyName]: value
7797
- })), propertyName === "_key" && setNodePath.length === 1 && op.inverse?.type === "set" && typeof op.inverse.value == "string" && typeof value == "string") {
7798
- const blockIndex = editor.blockIndexMap.get(op.inverse.value);
7799
- blockIndex !== void 0 && (editor.blockIndexMap.delete(op.inverse.value), editor.blockIndexMap.set(value, blockIndex));
7800
- }
7779
+ }));
7801
7780
  } else
7802
7781
  modifyDescendant(editor, setNodePath, (node) => deepSet(node, setPropertyPath, value));
7803
7782
  else {
7804
- const blockKey = findBlockKey(path2);
7805
- if (!blockKey)
7783
+ const blockSegment = findBlockSegment(path2);
7784
+ if (!blockSegment)
7806
7785
  break;
7807
- const blockIndex = resolveBlockIndex(editor, blockKey);
7786
+ const blockIndex = resolveBlockIndex(editor, blockSegment);
7808
7787
  if (blockIndex === -1)
7809
7788
  break;
7810
7789
  const block = editor.snapshot.context.value[blockIndex];
@@ -7825,7 +7804,7 @@ function applyOperation(editor, op) {
7825
7804
  type: "set",
7826
7805
  path: path2,
7827
7806
  value: editor.snapshot.context.value
7828
- }), editor.snapshot.context.value = [], editor.blockIndexMap.clear(), transformSelection = !0;
7807
+ }), editor.snapshot.context.value = [], transformSelection = !0;
7829
7808
  break;
7830
7809
  }
7831
7810
  const lastSegment = path2[path2.length - 1];
@@ -7868,11 +7847,9 @@ function applyOperation(editor, op) {
7868
7847
  backward: isBackwardRange(selection, editor.snapshot.context)
7869
7848
  } : null;
7870
7849
  }
7871
- const isRootRemove = parentPath(path2).length === 0;
7872
- let removeIndex = -1, removedKey;
7873
- if (modifyChildren(editor, parentPath(path2), (children) => {
7850
+ modifyChildren(editor, parentPath(path2), (children) => {
7874
7851
  let index;
7875
- if (isKeyedSegment(lastSegment) ? index = resolveChildIndex$1(children, lastSegment._key, isRootRemove ? editor.blockIndexMap : void 0) : index = lastSegment, index === -1 || index >= children.length)
7852
+ if (isKeyedSegment(lastSegment) ? index = resolveChildIndex$1(editor.blockIndexMap, path2.slice(0, -1), lastSegment, children) : index = lastSegment, index === -1 || index >= children.length)
7876
7853
  throw new Error(`Cannot apply an "unset" (node removal) operation at path [${path2}] because the node was not found.`);
7877
7854
  if (!op.inverse && !editor.isProcessingRemoteChanges) {
7878
7855
  const previousSibling = index > 0 ? children[index - 1] : void 0;
@@ -7890,12 +7867,8 @@ function applyOperation(editor, op) {
7890
7867
  position: "before"
7891
7868
  };
7892
7869
  }
7893
- return removedKey = children[index]?._key, removeIndex = index, removeChildren(children, index, 1);
7894
- }), isRootRemove && removeIndex !== -1 && removedKey) {
7895
- editor.blockIndexMap.delete(removedKey);
7896
- for (const [key, idx] of editor.blockIndexMap)
7897
- idx > removeIndex && editor.blockIndexMap.set(key, idx - 1);
7898
- }
7870
+ return removeChildren(children, index, 1);
7871
+ });
7899
7872
  break;
7900
7873
  }
7901
7874
  const {
@@ -7926,10 +7899,10 @@ function applyOperation(editor, op) {
7926
7899
  } else
7927
7900
  modifyDescendant(editor, unsetNodePath, (node) => deepUnset(node, unsetPropertyPath));
7928
7901
  else {
7929
- const blockKey = findBlockKey(path2);
7930
- if (!blockKey)
7902
+ const blockSegment = findBlockSegment(path2);
7903
+ if (!blockSegment)
7931
7904
  break;
7932
- const blockIndex = resolveBlockIndex(editor, blockKey);
7905
+ const blockIndex = resolveBlockIndex(editor, blockSegment);
7933
7906
  if (blockIndex === -1)
7934
7907
  break;
7935
7908
  const block = editor.snapshot.context.value[blockIndex];
@@ -7995,25 +7968,18 @@ function replaceLastSegment(path2, segment) {
7995
7968
  const result = [...path2];
7996
7969
  return result[result.length - 1] = segment, result;
7997
7970
  }
7998
- function resolveChildIndex$1(children, key, blockIndexMap) {
7999
- if (blockIndexMap) {
8000
- const index = blockIndexMap.get(key);
8001
- if (index !== void 0) {
8002
- const candidate = children[index];
8003
- if (candidate && candidate._key === key)
8004
- return index;
8005
- }
8006
- }
8007
- return children.findIndex((child) => child._key === key);
7971
+ function resolveChildIndex$1(blockIndexMap, parentSegments, segment, children) {
7972
+ const index = blockIndexMap.get(serializePath([...parentSegments, segment]));
7973
+ return index !== void 0 && children[index]?._key === segment._key ? index : children.findIndex((child) => child._key === segment._key);
8008
7974
  }
8009
- function findBlockKey(path2) {
7975
+ function findBlockSegment(path2) {
8010
7976
  const firstSegment = path2[0];
8011
7977
  if (isKeyedSegment(firstSegment))
8012
- return firstSegment._key;
7978
+ return firstSegment;
8013
7979
  }
8014
- function resolveBlockIndex(editor, blockKey) {
8015
- const mapIndex = editor.blockIndexMap.get(blockKey);
8016
- return mapIndex !== void 0 ? mapIndex : editor.snapshot.context.value.findIndex((child) => child._key === blockKey);
7980
+ function resolveBlockIndex(editor, segment) {
7981
+ const value = editor.snapshot.context.value, index = editor.blockIndexMap.get(serializePath([segment]));
7982
+ return index !== void 0 && value[index]?._key === segment._key ? index : value.findIndex((block) => block._key === segment._key);
8017
7983
  }
8018
7984
  function splitNodeAndPropertyPath(path2) {
8019
7985
  let lastKeyedOrNumericIndex = -1;
@@ -9202,18 +9168,47 @@ const shouldNormalize = (_editor, {
9202
9168
  const onContextChange = e.onContextChange;
9203
9169
  onContextChange && onContextChange(options), onChange(options);
9204
9170
  }, e;
9205
- }, levelIndexMaps = /* @__PURE__ */ new Map();
9171
+ };
9172
+ class BlockIndexMap extends Map {
9173
+ get(key) {
9174
+ return key.startsWith("[_key==") ? super.get(key) : super.get(serializePath([{
9175
+ _key: key
9176
+ }]));
9177
+ }
9178
+ has(key) {
9179
+ return key.startsWith("[_key==") ? super.has(key) : super.has(serializePath([{
9180
+ _key: key
9181
+ }]));
9182
+ }
9183
+ }
9184
+ const levelIndexMaps = /* @__PURE__ */ new Map();
9206
9185
  function buildIndexMaps(context, {
9207
9186
  blockIndexMap,
9208
9187
  listIndexMap
9209
9188
  }) {
9210
- blockIndexMap.clear(), listIndexMap.clear(), levelIndexMaps.clear();
9189
+ blockIndexMap.clear();
9190
+ for (let blockIndex = 0; blockIndex < context.value.length; blockIndex++) {
9191
+ const block = context.value.at(blockIndex);
9192
+ if (block === void 0 || block._key === void 0)
9193
+ continue;
9194
+ const blockPath = [{
9195
+ _key: block._key
9196
+ }], blockKey = serializePath(blockPath);
9197
+ blockIndexMap.has(blockKey) || blockIndexMap.set(blockKey, blockIndex), collectDescendantIndexes(context, block, blockPath, void 0, blockIndexMap);
9198
+ }
9199
+ buildListIndexMap(context, listIndexMap);
9200
+ }
9201
+ function buildListIndexMap(context, listIndexMap) {
9202
+ listIndexMap.clear(), levelIndexMaps.clear();
9211
9203
  let previousListItem;
9212
9204
  for (let blockIndex = 0; blockIndex < context.value.length; blockIndex++) {
9213
9205
  const block = context.value.at(blockIndex);
9214
9206
  if (block === void 0)
9215
9207
  continue;
9216
- if (blockIndexMap.set(block._key, blockIndex), !isTextBlockNode(context, block)) {
9208
+ const blockPath = [{
9209
+ _key: block._key
9210
+ }];
9211
+ if (!isTextBlockNode(context, block)) {
9217
9212
  levelIndexMaps.clear(), previousListItem = void 0;
9218
9213
  continue;
9219
9214
  }
@@ -9223,9 +9218,7 @@ function buildIndexMaps(context, {
9223
9218
  }
9224
9219
  if (!previousListItem) {
9225
9220
  const levelIndexMap2 = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map();
9226
- levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(serializePath([{
9227
- _key: block._key
9228
- }]), 1), previousListItem = {
9221
+ levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(serializePath(blockPath), 1), previousListItem = {
9229
9222
  listItem: block.listItem,
9230
9223
  level: block.level
9231
9224
  };
@@ -9233,9 +9226,7 @@ function buildIndexMaps(context, {
9233
9226
  }
9234
9227
  if (previousListItem.listItem === block.listItem && previousListItem.level < block.level) {
9235
9228
  const levelIndexMap2 = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map();
9236
- levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(serializePath([{
9237
- _key: block._key
9238
- }]), 1), previousListItem = {
9229
+ levelIndexMap2.set(block.level, 1), levelIndexMaps.set(block.listItem, levelIndexMap2), listIndexMap.set(serializePath(blockPath), 1), previousListItem = {
9239
9230
  listItem: block.listItem,
9240
9231
  level: block.level
9241
9232
  };
@@ -9252,14 +9243,25 @@ function buildIndexMaps(context, {
9252
9243
  });
9253
9244
  });
9254
9245
  const levelIndexMap = levelIndexMaps.get(block.listItem) ?? /* @__PURE__ */ new Map(), levelCounter = levelIndexMap.get(block.level) ?? 0;
9255
- levelIndexMap.set(block.level, levelCounter + 1), levelIndexMaps.set(block.listItem, levelIndexMap), listIndexMap.set(serializePath([{
9256
- _key: block._key
9257
- }]), levelCounter + 1), previousListItem = {
9246
+ levelIndexMap.set(block.level, levelCounter + 1), levelIndexMaps.set(block.listItem, levelIndexMap), listIndexMap.set(serializePath(blockPath), levelCounter + 1), previousListItem = {
9258
9247
  listItem: block.listItem,
9259
9248
  level: block.level
9260
9249
  };
9261
9250
  }
9262
9251
  }
9252
+ function collectDescendantIndexes(context, node, nodePath, parent, blockIndexMap) {
9253
+ const result = getNodeChildren(context, node, parent);
9254
+ if (result)
9255
+ for (let i = 0; i < result.children.length; i++) {
9256
+ const child = result.children[i];
9257
+ if (!child._key)
9258
+ continue;
9259
+ const childSegment = {
9260
+ _key: child._key
9261
+ }, childPath = [...nodePath, result.fieldName, childSegment], childKey = serializePath(childPath);
9262
+ blockIndexMap.has(childKey) || blockIndexMap.set(childKey, i), collectDescendantIndexes(context, child, childPath, result.parent, blockIndexMap);
9263
+ }
9264
+ }
9263
9265
  function withRemoteChanges(editor, fn) {
9264
9266
  const prev = editor.isProcessingRemoteChanges;
9265
9267
  editor.isProcessingRemoteChanges = !0, fn(), editor.isProcessingRemoteChanges = prev;
@@ -10243,7 +10245,7 @@ function textPatch(snapshot, operation, beforeValue) {
10243
10245
  containers: snapshot.context.containers,
10244
10246
  value: beforeValue
10245
10247
  },
10246
- blockIndexMap: /* @__PURE__ */ new Map()
10248
+ blockIndexMap: snapshot.blockIndexMap
10247
10249
  }, prevSpan = getSpan(beforeSnapshot, operation.path), patch = diffMatchPatch$1(prevSpan?.node.text ?? "", span.node.text, [...operation.path, "text"]);
10248
10250
  return patch.value.length ? [patch] : [];
10249
10251
  }
@@ -10294,6 +10296,279 @@ function subscribePatchGeneration({
10294
10296
  });
10295
10297
  });
10296
10298
  }
10299
+ function transformBlockIndexMap(map, op, beforeValue, afterValue, context) {
10300
+ switch (op.type) {
10301
+ case "insert.text":
10302
+ case "remove.text":
10303
+ case "set.selection":
10304
+ return;
10305
+ case "insert": {
10306
+ const lastSegment = op.path[op.path.length - 1], anchorIndex = typeof lastSegment == "number" ? lastSegment : resolveChildIndexInValue(beforeValue, op.path);
10307
+ if (anchorIndex < 0)
10308
+ return;
10309
+ const siblingContext = resolveSiblingContext(context, afterValue, op.path);
10310
+ if (!siblingContext)
10311
+ return;
10312
+ const insertIndex = Math.min(op.position === "after" ? anchorIndex + 1 : anchorIndex, siblingContext.children.length - 1);
10313
+ reindexSiblings(map, siblingContext, insertIndex);
10314
+ const insertedNumericPath = [...op.path.slice(0, -1), insertIndex];
10315
+ addSubtree(map, context, afterValue, insertedNumericPath);
10316
+ return;
10317
+ }
10318
+ case "unset": {
10319
+ if (op.path.length === 0) {
10320
+ map.clear();
10321
+ return;
10322
+ }
10323
+ const lastSegment = op.path[op.path.length - 1];
10324
+ if (typeof lastSegment == "string") {
10325
+ hasKeyedEntries(resolveValueAtPath(beforeValue, op.path)) && reconcileOwnerSubtree(map, context, beforeValue, afterValue, op.path);
10326
+ return;
10327
+ }
10328
+ const removeIndex = typeof lastSegment == "number" ? lastSegment : resolveChildIndexInValue(beforeValue, op.path);
10329
+ if (pruneSubtreeAtPath(map, beforeValue, op.path), removeIndex >= 0) {
10330
+ const siblingContext = resolveSiblingContext(context, afterValue, op.path);
10331
+ siblingContext && reindexSiblings(map, siblingContext, removeIndex);
10332
+ }
10333
+ return;
10334
+ }
10335
+ case "set": {
10336
+ if (op.path.length === 0) {
10337
+ map.clear(), buildIndexMaps({
10338
+ schema: context.schema,
10339
+ value: afterValue,
10340
+ containers: context.containers
10341
+ }, {
10342
+ blockIndexMap: map,
10343
+ listIndexMap: /* @__PURE__ */ new Map()
10344
+ });
10345
+ return;
10346
+ }
10347
+ const lastSegment = op.path[op.path.length - 1];
10348
+ if (typeof lastSegment == "string") {
10349
+ if (lastSegment === "_key") {
10350
+ handleKeyChange(map, beforeValue, afterValue, op.path.slice(0, -1), context);
10351
+ return;
10352
+ }
10353
+ (op.value !== null && typeof op.value == "object" || hasKeyedEntries(resolveValueAtPath(beforeValue, op.path))) && reconcileOwnerSubtree(map, context, beforeValue, afterValue, op.path);
10354
+ return;
10355
+ }
10356
+ const childIndex = resolveChildIndexInValue(beforeValue, op.path);
10357
+ pruneSubtreeAtPath(map, beforeValue, op.path), childIndex >= 0 && addSubtree(map, context, afterValue, [...op.path.slice(0, -1), childIndex]);
10358
+ return;
10359
+ }
10360
+ }
10361
+ }
10362
+ function resolveChildIndexInValue(value, path2) {
10363
+ let currentChildren = value;
10364
+ for (let i = 0; i < path2.length - 1; i++) {
10365
+ const segment = path2[i];
10366
+ if (typeof segment == "string")
10367
+ continue;
10368
+ let node;
10369
+ if (isKeyedSegment(segment) ? node = currentChildren.find((c2) => c2._key === segment._key) : typeof segment == "number" && (node = currentChildren.at(segment)), !node)
10370
+ return -1;
10371
+ const next = path2[i + 1];
10372
+ if (typeof next == "string") {
10373
+ const field = node[next];
10374
+ if (!Array.isArray(field))
10375
+ return -1;
10376
+ currentChildren = field, i++;
10377
+ }
10378
+ }
10379
+ const last = path2[path2.length - 1];
10380
+ return typeof last == "number" ? last : isKeyedSegment(last) ? currentChildren.findIndex((c2) => c2._key === last._key) : -1;
10381
+ }
10382
+ function resolveSiblingContext(context, value, opPath) {
10383
+ if (opPath.length === 1)
10384
+ return {
10385
+ children: value,
10386
+ serializedPrefix: ""
10387
+ };
10388
+ const fieldSegment = opPath[opPath.length - 2];
10389
+ if (typeof fieldSegment != "string")
10390
+ return;
10391
+ const keyedParentPath = toKeyedPath(value, parentPath(opPath));
10392
+ if (keyedParentPath === void 0)
10393
+ return;
10394
+ const resolvedParent = resolveIndexableNode(context, value, keyedParentPath);
10395
+ if (!resolvedParent)
10396
+ return;
10397
+ const childrenResult = getNodeChildren(context, resolvedParent.node, resolvedParent.containerOfParent);
10398
+ if (!(!childrenResult || childrenResult.fieldName !== fieldSegment))
10399
+ return {
10400
+ children: childrenResult.children,
10401
+ serializedPrefix: serializePath([...keyedParentPath, fieldSegment])
10402
+ };
10403
+ }
10404
+ function reindexSiblings(map, siblingContext, startIndex) {
10405
+ for (let childIndex = Math.max(0, startIndex); childIndex < siblingContext.children.length; childIndex++) {
10406
+ const child = siblingContext.children[childIndex];
10407
+ !child || child._key === void 0 || map.set(`${siblingContext.serializedPrefix}[_key=="${child._key}"]`, childIndex);
10408
+ }
10409
+ }
10410
+ function pruneSubtreeAtPath(map, beforeValue, nodePath, keepSelf = !1) {
10411
+ const node = resolveNodeAtPath(beforeValue, nodePath);
10412
+ if (!node)
10413
+ return;
10414
+ const keyedPath = toKeyedPath(beforeValue, nodePath);
10415
+ keyedPath !== void 0 && (keepSelf || map.delete(serializePath(keyedPath)), walkKeyedChildrenInValue(node, keyedPath, (childPath) => {
10416
+ map.delete(serializePath(childPath));
10417
+ }));
10418
+ }
10419
+ function walkKeyedChildrenInValue(node, nodePath, visit) {
10420
+ for (const key of Object.keys(node)) {
10421
+ const field = node[key];
10422
+ if (Array.isArray(field))
10423
+ for (const child of field) {
10424
+ if (!child || child._key === void 0)
10425
+ continue;
10426
+ const childPath = [...nodePath, key, {
10427
+ _key: child._key
10428
+ }];
10429
+ visit(childPath), walkKeyedChildrenInValue(child, childPath, visit);
10430
+ }
10431
+ }
10432
+ }
10433
+ function addSubtree(map, context, afterValue, opPath) {
10434
+ const keyedPath = toKeyedPath(afterValue, opPath);
10435
+ if (keyedPath === void 0)
10436
+ return;
10437
+ const resolved = resolveIndexableNode(context, afterValue, keyedPath);
10438
+ if (!resolved)
10439
+ return;
10440
+ const childIndex = resolveChildIndexInValue(afterValue, opPath);
10441
+ childIndex >= 0 && map.set(serializePath(keyedPath), childIndex), collectDescendantIndexes(context, resolved.node, keyedPath, resolved.containerOfParent, map);
10442
+ }
10443
+ function resolveIndexableNode(context, value, keyedPath) {
10444
+ if (keyedPath.length === 0)
10445
+ return;
10446
+ let current = {
10447
+ value
10448
+ }, containerOfParent, index = 0;
10449
+ for (; index < keyedPath.length; ) {
10450
+ const childrenResult = getNodeChildren(context, current, containerOfParent);
10451
+ if (!childrenResult)
10452
+ return;
10453
+ if (index > 0) {
10454
+ const fieldSegment = keyedPath[index];
10455
+ if (typeof fieldSegment != "string" || fieldSegment !== childrenResult.fieldName)
10456
+ return;
10457
+ index++;
10458
+ }
10459
+ const childSegment = keyedPath[index];
10460
+ let child;
10461
+ if (isKeyedSegment(childSegment) ? child = childrenResult.children.find((candidate) => candidate._key === childSegment._key) : typeof childSegment == "number" && (child = childrenResult.children.at(childSegment)), !child)
10462
+ return;
10463
+ current = child, containerOfParent = childrenResult.parent, index++;
10464
+ }
10465
+ return {
10466
+ node: current,
10467
+ containerOfParent
10468
+ };
10469
+ }
10470
+ function reconcileOwnerSubtree(map, context, beforeValue, afterValue, propertyPath) {
10471
+ let ownerPathEnd = propertyPath.length;
10472
+ for (; ownerPathEnd > 0 && typeof propertyPath[ownerPathEnd - 1] == "string"; )
10473
+ ownerPathEnd--;
10474
+ if (ownerPathEnd === 0)
10475
+ return;
10476
+ const ownerPath = propertyPath.slice(0, ownerPathEnd);
10477
+ pruneSubtreeAtPath(
10478
+ map,
10479
+ beforeValue,
10480
+ ownerPath,
10481
+ /*keepSelf*/
10482
+ !0
10483
+ ), addSubtree(map, context, afterValue, ownerPath);
10484
+ }
10485
+ function resolveValueAtPath(value, path2) {
10486
+ let nodePathEnd = path2.length;
10487
+ for (; nodePathEnd > 0 && typeof path2[nodePathEnd - 1] == "string"; )
10488
+ nodePathEnd--;
10489
+ if (nodePathEnd === 0)
10490
+ return;
10491
+ let current = resolveNodeAtPath(value, path2.slice(0, nodePathEnd));
10492
+ for (let i = nodePathEnd; i < path2.length; i++) {
10493
+ if (current === null || typeof current != "object")
10494
+ return;
10495
+ current = current[path2[i]];
10496
+ }
10497
+ return current;
10498
+ }
10499
+ function hasKeyedEntries(value) {
10500
+ return Array.isArray(value) && value.some((entry) => entry !== null && typeof entry == "object" && entry._key !== void 0);
10501
+ }
10502
+ function toKeyedPath(value, path2) {
10503
+ const result = [];
10504
+ let currentChildren = value, currentNode;
10505
+ for (let i = 0; i < path2.length; i++) {
10506
+ const segment = path2[i];
10507
+ if (typeof segment == "string") {
10508
+ if (result.push(segment), !currentNode)
10509
+ return;
10510
+ const field = currentNode[segment];
10511
+ if (!Array.isArray(field))
10512
+ return;
10513
+ currentChildren = field;
10514
+ continue;
10515
+ }
10516
+ if (typeof segment == "number") {
10517
+ if (currentNode = currentChildren.at(segment), !currentNode || currentNode._key === void 0)
10518
+ return;
10519
+ result.push({
10520
+ _key: currentNode._key
10521
+ });
10522
+ continue;
10523
+ }
10524
+ if (isKeyedSegment(segment)) {
10525
+ if (currentNode = currentChildren.find((c2) => c2._key === segment._key), !currentNode)
10526
+ return;
10527
+ result.push(segment);
10528
+ continue;
10529
+ }
10530
+ return;
10531
+ }
10532
+ return result;
10533
+ }
10534
+ function handleKeyChange(map, beforeValue, afterValue, nodePath, context) {
10535
+ pruneSubtreeAtPath(
10536
+ map,
10537
+ beforeValue,
10538
+ nodePath,
10539
+ /*keepSelf*/
10540
+ !1
10541
+ );
10542
+ const childIndex = resolveChildIndexInValue(beforeValue, nodePath);
10543
+ if (childIndex < 0)
10544
+ return;
10545
+ const newKeyedNodePath = [...nodePath.slice(0, -1), childIndex];
10546
+ addSubtree(map, context, afterValue, newKeyedNodePath);
10547
+ }
10548
+ function resolveNodeAtPath(value, path2) {
10549
+ let currentChildren = value, currentNode;
10550
+ for (let i = 0; i < path2.length; i++) {
10551
+ const segment = path2[i];
10552
+ if (typeof segment == "string") {
10553
+ if (!currentNode)
10554
+ return;
10555
+ const field = currentNode[segment];
10556
+ if (!Array.isArray(field))
10557
+ return;
10558
+ currentChildren = field;
10559
+ continue;
10560
+ }
10561
+ if (isKeyedSegment(segment))
10562
+ currentNode = currentChildren.find((c2) => c2._key === segment._key);
10563
+ else if (typeof segment == "number")
10564
+ currentNode = currentChildren.at(segment);
10565
+ else
10566
+ return;
10567
+ if (!currentNode)
10568
+ return;
10569
+ }
10570
+ return currentNode;
10571
+ }
10297
10572
  function subscribeUpdateValue(context, editor) {
10298
10573
  const unsubscribeNormalizationLog = debug.normalization.enabled ? subscribeToOperations(editor, (event) => {
10299
10574
  event.isNormalizingNode && debug.normalization(`((engine operation))
@@ -10302,13 +10577,13 @@ ${safeStringify(event.operation, 2)}`);
10302
10577
  phase: "before"
10303
10578
  }) : void 0, unsubscribeIndexMaps = subscribeToOperations(editor, (event) => {
10304
10579
  const operation = event.operation;
10305
- operation.type !== "set.selection" && (operation.type === "insert.text" || operation.type === "remove.text" || operation.path.length <= 2 && buildIndexMaps({
10580
+ operation.type !== "set.selection" && (operation.type === "insert.text" || operation.type === "remove.text" || (transformBlockIndexMap(editor.blockIndexMap, operation, event.beforeValue, editor.snapshot.context.value, {
10581
+ schema: context.schema,
10582
+ containers: editor.snapshot.context.containers
10583
+ }), operation.path.length <= 2 && buildListIndexMap({
10306
10584
  schema: context.schema,
10307
10585
  value: editor.snapshot.context.value
10308
- }, {
10309
- blockIndexMap: editor.blockIndexMap,
10310
- listIndexMap: editor.listIndexMap
10311
- }));
10586
+ }, editor.listIndexMap)));
10312
10587
  });
10313
10588
  return () => {
10314
10589
  unsubscribeNormalizationLog?.(), unsubscribeIndexMaps();
@@ -10316,7 +10591,7 @@ ${safeStringify(event.operation, 2)}`);
10316
10591
  }
10317
10592
  function createEditorEngine(config) {
10318
10593
  debug.setup("creating new editor engine instance");
10319
- const context = config.editorActor.getSnapshot().context, placeholderBlock = createPlaceholderBlock({
10594
+ const context = config.editorActor.getSnapshot().context, blockIndexMap = new BlockIndexMap(), placeholderBlock = createPlaceholderBlock({
10320
10595
  context: {
10321
10596
  schema: context.schema,
10322
10597
  // No containers registered at engine-init time. NodePlugin
@@ -10325,10 +10600,10 @@ function createEditorEngine(config) {
10325
10600
  value: [],
10326
10601
  keyGenerator: context.keyGenerator
10327
10602
  },
10328
- blockIndexMap: /* @__PURE__ */ new Map()
10603
+ blockIndexMap
10329
10604
  }), editor = createEditor();
10330
10605
  editor.snapshot = {
10331
- blockIndexMap: /* @__PURE__ */ new Map(),
10606
+ blockIndexMap,
10332
10607
  context: {
10333
10608
  containers: /* @__PURE__ */ new Map(),
10334
10609
  converters: context.initialConverters,
@@ -10339,7 +10614,7 @@ function createEditorEngine(config) {
10339
10614
  value: [placeholderBlock]
10340
10615
  },
10341
10616
  decoratorState: {}
10342
- }, editor.containers = /* @__PURE__ */ new Map(), editor.blockObjects = /* @__PURE__ */ new Map(), editor.inlineObjects = /* @__PURE__ */ new Map(), editor.spans = /* @__PURE__ */ new Map(), editor.textBlocks = /* @__PURE__ */ new Map(), editor.decoratedRanges = [], editor.blockIndexMap = editor.snapshot.blockIndexMap, editor.history = {
10617
+ }, editor.containers = /* @__PURE__ */ new Map(), editor.blockObjects = /* @__PURE__ */ new Map(), editor.inlineObjects = /* @__PURE__ */ new Map(), editor.spans = /* @__PURE__ */ new Map(), editor.textBlocks = /* @__PURE__ */ new Map(), editor.decoratedRanges = [], editor.blockIndexMap = blockIndexMap, editor.history = {
10343
10618
  undos: [],
10344
10619
  redos: []
10345
10620
  }, editor.listIndexMap = /* @__PURE__ */ new Map(), editor.remotePatches = [], editor.undoStepId = void 0, editor.isDeferringMutations = !1, editor.isNormalizingNode = !1, editor.isPatching = !0, editor.isPerformingBehaviorOperation = !1, editor.isProcessingRemoteChanges = !1, editor.isRedoing = !1, editor.isUndoing = !1, editor.withHistory = !0;
@@ -10359,7 +10634,8 @@ function createEditorEngine(config) {
10359
10634
  editor: editorEngine
10360
10635
  }), buildIndexMaps({
10361
10636
  schema: context.schema,
10362
- value: editorEngine.snapshot.context.value
10637
+ value: editorEngine.snapshot.context.value,
10638
+ containers: editorEngine.snapshot.context.containers
10363
10639
  }, {
10364
10640
  blockIndexMap: editorEngine.blockIndexMap,
10365
10641
  listIndexMap: editorEngine.listIndexMap
@@ -14798,7 +15074,9 @@ const abstractDeserializeBehaviors = [
14798
15074
  })
14799
15075
  ];
14800
15076
  function getUniqueBlockKey(blockKey) {
14801
- return (snapshot) => !blockKey || snapshot.blockIndexMap.has(blockKey) ? snapshot.context.keyGenerator() : blockKey;
15077
+ return (snapshot) => !blockKey || snapshot.blockIndexMap.has(serializePath([{
15078
+ _key: blockKey
15079
+ }])) ? snapshot.context.keyGenerator() : blockKey;
14802
15080
  }
14803
15081
  function selectionAt(path2) {
14804
15082
  return {
@@ -18253,6 +18531,7 @@ function createInternalEditor(config) {
18253
18531
  case "invalid value":
18254
18532
  case "loading":
18255
18533
  case "mutation":
18534
+ case "operation":
18256
18535
  case "patch":
18257
18536
  case "read only":
18258
18537
  case "ready":
@@ -18295,6 +18574,16 @@ function editorConfigToMachineInput(config) {
18295
18574
  initialValue: config.initialValue
18296
18575
  };
18297
18576
  }
18577
+ const publicOperationTypeRecord = {
18578
+ insert: !0,
18579
+ "insert.text": !0,
18580
+ "remove.text": !0,
18581
+ set: !0,
18582
+ unset: !0
18583
+ }, publicOperationTypes = new Set(Object.keys(publicOperationTypeRecord));
18584
+ function isPublicOperation(operation) {
18585
+ return publicOperationTypes.has(operation.type);
18586
+ }
18298
18587
  function createActors(config) {
18299
18588
  debug.setup("creating new actors");
18300
18589
  const mutationBatcher = createMutationBatcher({
@@ -18312,7 +18601,12 @@ function createActors(config) {
18312
18601
  editorEngine: config.editorEngine
18313
18602
  }
18314
18603
  });
18315
- return config.subscriptions.push(mutationBatcher.subscribe), config.subscriptions.push(() => {
18604
+ return config.subscriptions.push(mutationBatcher.subscribe), config.subscriptions.push(() => subscribeToOperations(config.editorEngine, (event) => {
18605
+ isPublicOperation(event.operation) && config.relay.send({
18606
+ type: "operation",
18607
+ operation: event.operation
18608
+ });
18609
+ })), config.subscriptions.push(() => {
18316
18610
  const subscription = syncActor.on("*", (event) => {
18317
18611
  switch (event.type) {
18318
18612
  case "invalid value":