@portabletext/editor 7.8.1 → 7.9.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
@@ -8890,22 +8890,20 @@ const normalizeNode = (editor, entry) => {
8890
8890
  return;
8891
8891
  }
8892
8892
  if (path2.length > 0 && nodeRecord._key !== void 0) {
8893
- const parent = getParent(editor.snapshot, path2), siblingList = [...parent ? getChildren(editor.snapshot, parent.path) : editor.snapshot.context.value.map((child, index) => ({
8894
- node: child,
8895
- path: [{
8896
- _key: child._key
8897
- }],
8898
- index
8899
- }))], key = nodeRecord._key;
8900
- let firstIndex = -1;
8901
- for (let i = 0; i < siblingList.length; i++)
8902
- if (siblingList[i].node._key === key)
8903
- if (firstIndex === -1)
8904
- firstIndex = i;
8905
- else {
8893
+ const parent = getParent(editor.snapshot, path2), key = nodeRecord._key, childFieldName = parent ? path2[parent.path.length] : void 0, rawSiblings = parent && typeof childFieldName == "string" ? parent.node[childFieldName] : void 0, siblingNodes = parent ? Array.isArray(rawSiblings) ? rawSiblings : getChildren(editor.snapshot, parent.path).map((entry2) => entry2.node) : editor.snapshot.context.value;
8894
+ if (siblingNodes.length > 1) {
8895
+ const groupId2 = parent && typeof childFieldName == "string" ? serializePath([...parent.path, childFieldName]) : "";
8896
+ if (!editor.verifiedUniqueChildGroups.has(groupId2)) {
8897
+ const seenKeys = /* @__PURE__ */ new Set();
8898
+ let groupIsUnique = !0, duplicateIndexOfKey = -1;
8899
+ for (let index = 0; index < siblingNodes.length; index++) {
8900
+ const siblingKey = siblingNodes[index]?._key;
8901
+ siblingKey !== void 0 && (seenKeys.has(siblingKey) ? (groupIsUnique = !1, siblingKey === key && duplicateIndexOfKey === -1 && (duplicateIndexOfKey = index)) : seenKeys.add(siblingKey));
8902
+ }
8903
+ if (duplicateIndexOfKey !== -1) {
8906
8904
  const newKey = editor.snapshot.context.keyGenerator();
8907
8905
  debug.normalization("Fixing duplicate key on node");
8908
- const dupParentPath = parent ? parent.path : [], numericPath = dupParentPath.length === 0 ? [i] : [...dupParentPath, getChildFieldName(editor.snapshot.context, parent.path) ?? "children", i];
8906
+ const numericPath = parent && typeof childFieldName == "string" ? [...parent.path, childFieldName, duplicateIndexOfKey] : [duplicateIndexOfKey];
8909
8907
  editor.apply({
8910
8908
  type: "set",
8911
8909
  path: [...numericPath, "_key"],
@@ -8918,6 +8916,9 @@ const normalizeNode = (editor, entry) => {
8918
8916
  });
8919
8917
  return;
8920
8918
  }
8919
+ groupIsUnique && editor.verifiedUniqueChildGroups.add(groupId2);
8920
+ }
8921
+ }
8921
8922
  }
8922
8923
  if (isTextBlockNode({
8923
8924
  schema: editor.snapshot.context.schema
@@ -10374,7 +10375,7 @@ function transformBlockIndexMap(map, op, beforeValue, afterValue, context) {
10374
10375
  case "set.selection":
10375
10376
  return;
10376
10377
  case "insert": {
10377
- const lastSegment = op.path[op.path.length - 1], anchorIndex = typeof lastSegment == "number" ? lastSegment : resolveChildIndexInValue(beforeValue, op.path);
10378
+ const anchorIndex = childIndexFromMap(map, beforeValue, op.path);
10378
10379
  if (anchorIndex < 0)
10379
10380
  return;
10380
10381
  const siblingContext = resolveSiblingContext(context, afterValue, op.path);
@@ -10391,12 +10392,11 @@ function transformBlockIndexMap(map, op, beforeValue, afterValue, context) {
10391
10392
  map.clear();
10392
10393
  return;
10393
10394
  }
10394
- const lastSegment = op.path[op.path.length - 1];
10395
- if (typeof lastSegment == "string") {
10395
+ if (typeof op.path[op.path.length - 1] == "string") {
10396
10396
  hasKeyedEntries(resolveValueAtPath(beforeValue, op.path)) && reconcileOwnerSubtree(map, context, beforeValue, afterValue, op.path);
10397
10397
  return;
10398
10398
  }
10399
- const removeIndex = typeof lastSegment == "number" ? lastSegment : resolveChildIndexInValue(beforeValue, op.path);
10399
+ const removeIndex = childIndexFromMap(map, beforeValue, op.path);
10400
10400
  if (pruneSubtreeAtPath(map, beforeValue, op.path), removeIndex >= 0) {
10401
10401
  const siblingContext = resolveSiblingContext(context, afterValue, op.path);
10402
10402
  siblingContext && reindexSiblings(map, siblingContext, removeIndex);
@@ -10424,12 +10424,31 @@ function transformBlockIndexMap(map, op, beforeValue, afterValue, context) {
10424
10424
  (op.value !== null && typeof op.value == "object" || hasKeyedEntries(resolveValueAtPath(beforeValue, op.path))) && reconcileOwnerSubtree(map, context, beforeValue, afterValue, op.path);
10425
10425
  return;
10426
10426
  }
10427
- const childIndex = resolveChildIndexInValue(beforeValue, op.path);
10427
+ const childIndex = childIndexFromMap(map, beforeValue, op.path);
10428
10428
  pruneSubtreeAtPath(map, beforeValue, op.path), childIndex >= 0 && addSubtree(map, context, afterValue, [...op.path.slice(0, -1), childIndex]);
10429
10429
  return;
10430
10430
  }
10431
10431
  }
10432
10432
  }
10433
+ function childIndexFromMap(map, beforeValue, path2) {
10434
+ const last = path2[path2.length - 1];
10435
+ if (typeof last == "number")
10436
+ return last;
10437
+ if (isKeyedSegment(last)) {
10438
+ let keyed = !0;
10439
+ for (let i = 0; i < path2.length - 1; i++)
10440
+ if (typeof path2[i] == "number") {
10441
+ keyed = !1;
10442
+ break;
10443
+ }
10444
+ if (keyed) {
10445
+ const index = map.get(serializePath(path2));
10446
+ if (index !== void 0)
10447
+ return index;
10448
+ }
10449
+ }
10450
+ return resolveChildIndexInValue(beforeValue, path2);
10451
+ }
10433
10452
  function resolveChildIndexInValue(value, path2) {
10434
10453
  let currentChildren = value;
10435
10454
  for (let i = 0; i < path2.length - 1; i++) {
@@ -10640,6 +10659,69 @@ function resolveNodeAtPath(value, path2) {
10640
10659
  }
10641
10660
  return currentNode;
10642
10661
  }
10662
+ function groupId(prefix) {
10663
+ for (const segment of prefix)
10664
+ if (typeof segment == "number")
10665
+ return null;
10666
+ return serializePath(prefix);
10667
+ }
10668
+ function invalidateVerifiedGroups(groups, operation) {
10669
+ if (groups.size === 0)
10670
+ return;
10671
+ if (operation.path.length === 0) {
10672
+ groups.clear();
10673
+ return;
10674
+ }
10675
+ const drop = (prefix) => {
10676
+ const id = groupId(prefix);
10677
+ return id === null ? (groups.clear(), !1) : (groups.delete(id), !0);
10678
+ }, dropSubtreeGroups = (node, nodePath) => {
10679
+ walkKeyedChildrenInValue(node, nodePath, (childPath) => {
10680
+ const id = groupId(childPath.slice(0, -1));
10681
+ id !== null && groups.delete(id);
10682
+ });
10683
+ }, path2 = operation.path, lastSegment = path2[path2.length - 1];
10684
+ if (operation.type === "insert") {
10685
+ const groupPath = path2.slice(0, -1);
10686
+ drop(groupPath) && operation.node._key !== void 0 && dropSubtreeGroups(operation.node, [...groupPath, {
10687
+ _key: operation.node._key
10688
+ }]);
10689
+ return;
10690
+ }
10691
+ if (operation.type === "unset") {
10692
+ if (typeof lastSegment == "string" && lastSegment !== "_key") {
10693
+ drop(path2);
10694
+ return;
10695
+ }
10696
+ const nodePath = lastSegment === "_key" ? path2.slice(0, -1) : path2;
10697
+ drop(nodePath.slice(0, -1));
10698
+ return;
10699
+ }
10700
+ if (typeof lastSegment == "number" || isKeyedSegment(lastSegment) || lastSegment === "_key") {
10701
+ const nodePath = lastSegment === "_key" ? path2.slice(0, -1) : path2;
10702
+ if (drop(nodePath.slice(0, -1)) && lastSegment !== "_key") {
10703
+ const replacement = operation.value;
10704
+ if (replacement !== null && typeof replacement == "object" && !Array.isArray(replacement)) {
10705
+ const replacementKey = replacement._key;
10706
+ replacementKey !== void 0 && dropSubtreeGroups(replacement, [...nodePath.slice(0, -1), {
10707
+ _key: replacementKey
10708
+ }]);
10709
+ }
10710
+ }
10711
+ return;
10712
+ }
10713
+ if (typeof lastSegment == "string") {
10714
+ if (Array.isArray(operation.value)) {
10715
+ if (drop(path2))
10716
+ for (const child of operation.value)
10717
+ child && child._key !== void 0 && dropSubtreeGroups(child, [...path2, {
10718
+ _key: child._key
10719
+ }]);
10720
+ return;
10721
+ }
10722
+ operation.value !== null && typeof operation.value == "object" && groups.clear();
10723
+ }
10724
+ }
10643
10725
  function subscribeUpdateValue(context, editor) {
10644
10726
  const unsubscribeNormalizationLog = debug.normalization.enabled ? subscribeToOperations(editor, (event) => {
10645
10727
  event.isNormalizingNode && debug.normalization(`((engine operation))
@@ -10651,7 +10733,7 @@ ${safeStringify(event.operation, 2)}`);
10651
10733
  operation.type !== "set.selection" && (operation.type === "insert.text" || operation.type === "remove.text" || (transformBlockIndexMap(editor.blockIndexMap, operation, event.beforeValue, editor.snapshot.context.value, {
10652
10734
  schema: context.schema,
10653
10735
  containers: editor.snapshot.context.containers
10654
- }), editor.listIndexMapDirty = !0));
10736
+ }), editor.listIndexMapDirty = !0, invalidateVerifiedGroups(editor.verifiedUniqueChildGroups, operation)));
10655
10737
  });
10656
10738
  return () => {
10657
10739
  unsubscribeNormalizationLog?.(), unsubscribeIndexMaps();
@@ -10685,7 +10767,7 @@ function createEditorEngine(config) {
10685
10767
  }, 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 = {
10686
10768
  undos: [],
10687
10769
  redos: []
10688
- }, editor.listIndexMap = /* @__PURE__ */ new Map(), editor.listIndexMapDirty = !1, 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;
10770
+ }, editor.listIndexMap = /* @__PURE__ */ new Map(), editor.listIndexMapDirty = !1, editor.verifiedUniqueChildGroups = /* @__PURE__ */ new Set(), 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;
10689
10771
  const editorEngine = plugins(withDOM(editor), {
10690
10772
  editorActor: config.editorActor
10691
10773
  });
@@ -11640,7 +11722,7 @@ const coreDndBehaviors = [
11640
11722
  ...snapshot.context,
11641
11723
  selection: dragSelection
11642
11724
  }
11643
- }, draggingEntireBlocks = isSelectingEntireBlocks(dragSnapshot), draggedNodes = getFragment(dragSnapshot), fittedBlocks = fitBlocksToDestination({
11725
+ }, draggingEntireBlocks = isSelectingEntireBlocks(dragSnapshot), movedInlineObjectKey = !draggingEntireBlocks && isCollapsedRange(dragSelection) ? getFocusInlineObject(dragSnapshot)?.node._key : void 0, draggedNodes = getFragment(dragSnapshot), fittedBlocks = fitBlocksToDestination({
11644
11726
  ...snapshot,
11645
11727
  context: {
11646
11728
  ...snapshot.context,
@@ -11653,7 +11735,8 @@ const coreDndBehaviors = [
11653
11735
  draggedNodes,
11654
11736
  dragOrigin,
11655
11737
  originEvent: event.originEvent,
11656
- fittedBlocks
11738
+ fittedBlocks,
11739
+ movedInlineObjectKey
11657
11740
  };
11658
11741
  },
11659
11742
  actions: [(_, {
@@ -11662,9 +11745,21 @@ const coreDndBehaviors = [
11662
11745
  dragOrigin,
11663
11746
  dropPosition,
11664
11747
  originEvent,
11665
- fittedBlocks
11748
+ fittedBlocks,
11749
+ movedInlineObjectKey
11666
11750
  }) => {
11667
- const deleteEvents = draggingEntireBlocks ? draggedNodes.map((entry) => raise({
11751
+ const movedInlineObjectPath = movedInlineObjectKey ? [...dropPosition.anchor.path.slice(0, -2), "children", {
11752
+ _key: movedInlineObjectKey
11753
+ }] : void 0, movedInlineObjectSelection = movedInlineObjectPath ? {
11754
+ anchor: {
11755
+ path: movedInlineObjectPath,
11756
+ offset: 0
11757
+ },
11758
+ focus: {
11759
+ path: movedInlineObjectPath,
11760
+ offset: 0
11761
+ }
11762
+ } : void 0, deleteEvents = draggingEntireBlocks ? draggedNodes.map((entry) => raise({
11668
11763
  type: "unset",
11669
11764
  at: entry.path
11670
11765
  })) : [raise({
@@ -11677,8 +11772,12 @@ const coreDndBehaviors = [
11677
11772
  }), ...deleteEvents, raise({
11678
11773
  type: "insert.blocks",
11679
11774
  blocks: fittedBlocks,
11680
- placement: draggingEntireBlocks ? originEvent.position.block === "start" ? "before" : originEvent.position.block === "end" ? "after" : "auto" : "auto"
11681
- })];
11775
+ placement: draggingEntireBlocks ? originEvent.position.block === "start" ? "before" : originEvent.position.block === "end" ? "after" : "auto" : "auto",
11776
+ select: movedInlineObjectSelection ? "none" : void 0
11777
+ }), ...movedInlineObjectSelection ? [raise({
11778
+ type: "select",
11779
+ at: movedInlineObjectSelection
11780
+ })] : []];
11682
11781
  }]
11683
11782
  })
11684
11783
  ], coreInsertBehaviors = [defineBehavior({
@@ -12957,19 +13056,17 @@ const childSetOperationImplementation = ({
12957
13056
  function unhangRange(snapshot, range2) {
12958
13057
  const {
12959
13058
  context
12960
- } = snapshot;
12961
- let [start2, end2] = rangeEdges(range2, {
13059
+ } = snapshot, [start2, end2] = rangeEdges(range2, {
12962
13060
  value: context.value
12963
13061
  });
12964
13062
  if (start2.offset !== 0 || end2.offset !== 0 || isCollapsedRange(range2) || getSibling(snapshot, end2.path, {
12965
13063
  direction: "previous"
12966
- }) !== void 0)
12967
- return range2;
12968
- const endBlock = getParent(snapshot, end2.path, {
13064
+ }) !== void 0 || !getParent(snapshot, end2.path, {
12969
13065
  match: (node) => isTextBlock({
12970
13066
  schema: snapshot.context.schema
12971
13067
  }, node)
12972
- }), blockPath = endBlock ? endBlock.path : [];
13068
+ }))
13069
+ return range2;
12973
13070
  for (const {
12974
13071
  path: path2
12975
13072
  } of getNodes(snapshot, {
@@ -12979,7 +13076,7 @@ function unhangRange(snapshot, range2) {
12979
13076
  }))
12980
13077
  if (!isAncestorPath(path2, start2.path) && !isAncestorPath(path2, end2.path))
12981
13078
  return range2;
12982
- let skip = !0;
13079
+ let skip = !0, sawEmpty = !1;
12983
13080
  for (const {
12984
13081
  node,
12985
13082
  path: nodePath
@@ -12997,20 +13094,21 @@ function unhangRange(snapshot, range2) {
12997
13094
  }
12998
13095
  if (isSpan({
12999
13096
  schema: context.schema
13000
- }, node) && (node.text !== "" || isBeforePath(nodePath, blockPath, {
13001
- value: context.value
13002
- }))) {
13003
- end2 = {
13004
- path: nodePath,
13005
- offset: node.text.length
13097
+ }, node)) {
13098
+ if (node.text === "") {
13099
+ sawEmpty = !0;
13100
+ continue;
13101
+ }
13102
+ return sawEmpty ? range2 : {
13103
+ anchor: start2,
13104
+ focus: {
13105
+ path: nodePath,
13106
+ offset: node.text.length
13107
+ }
13006
13108
  };
13007
- break;
13008
13109
  }
13009
13110
  }
13010
- return {
13011
- anchor: start2,
13012
- focus: end2
13013
- };
13111
+ return range2;
13014
13112
  }
13015
13113
  function pointRef(editor, point2, options = {}) {
13016
13114
  const {
@@ -18469,17 +18567,14 @@ function updateBlock({
18469
18567
  if (isChildChanged) {
18470
18568
  if (currentBlockChild._key === oldBlockChild?._key && currentBlockChild._type === oldBlockChild?._type) {
18471
18569
  debug.syncValue("Updating changed child", currentBlockChild, oldBlockChild);
18472
- const {
18473
- text: _text,
18474
- ...childProps
18475
- } = currentBlockChild;
18476
- setNodeProperties(editorEngine, childProps, path2);
18477
18570
  const isSpanNode2 = isSpan({
18478
18571
  schema: context.schema
18479
18572
  }, currentBlockChild) && isSpan({
18480
18573
  schema: context.schema
18481
- }, oldBlockChild);
18482
- isSpanNode2 && isTextChanged ? (oldBlockChild.text.length > 0 && deleteRange(editorEngine, {
18574
+ }, oldBlockChild), childProps = {
18575
+ ...currentBlockChild
18576
+ };
18577
+ isSpanNode2 && delete childProps.text, setNodeProperties(editorEngine, childProps, path2), isSpanNode2 && isTextChanged ? (oldBlockChild.text.length > 0 && deleteRange(editorEngine, {
18483
18578
  focus: {
18484
18579
  path: path2,
18485
18580
  offset: 0