@portabletext/editor 8.0.2 → 8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1179,13 +1179,14 @@ function mapPointThroughStep(step, point, options = {}) {
1179
1179
  };
1180
1180
  }
1181
1181
  case "rekey": {
1182
- let path;
1183
- for (let i = 0; i < point.path.length; i++) {
1184
- let segment = point.path[i];
1185
- isKeyedSegment(segment) && segment._key === step.oldKey && (path === void 0 && (path = [...point.path]), path[i] = { _key: step.newKey });
1186
- }
1187
- return path === void 0 ? point : {
1188
- path,
1182
+ if (point.path.length <= step.path.length || !pathEquals(point.path.slice(0, step.path.length), step.path)) return point;
1183
+ let segment = point.path[step.path.length];
1184
+ return !isKeyedSegment(segment) || segment._key !== step.oldKey ? point : {
1185
+ path: [
1186
+ ...step.path,
1187
+ { _key: step.newKey },
1188
+ ...point.path.slice(step.path.length + 1)
1189
+ ],
1189
1190
  offset: point.offset
1190
1191
  };
1191
1192
  }
@@ -1303,6 +1304,7 @@ function operationToSteps(op) {
1303
1304
  let oldKey = op.inverse?.type === "set" && typeof op.inverse.value == "string" ? op.inverse.value : void 0;
1304
1305
  return oldKey ? [{
1305
1306
  type: "rekey",
1307
+ path: nodePath.slice(0, -1),
1306
1308
  oldKey,
1307
1309
  newKey: op.value
1308
1310
  }] : [];
@@ -6892,13 +6894,17 @@ function applyOperation(editor, op) {
6892
6894
  case "set": {
6893
6895
  let { path, value } = op;
6894
6896
  if (!op.inverse && !editor.isProcessingRemoteChanges) {
6895
- let previousValue = getValue(editor.snapshot.context.value, path);
6897
+ let previousValue = getValue(editor.snapshot.context.value, path), inversePath = path[path.length - 1] === "_key" && typeof value == "string" && isKeyedSegment(path[path.length - 2]) ? [
6898
+ ...path.slice(0, -2),
6899
+ { _key: value },
6900
+ "_key"
6901
+ ] : path;
6896
6902
  op.inverse = previousValue === void 0 ? {
6897
6903
  type: "unset",
6898
- path
6904
+ path: inversePath
6899
6905
  } : {
6900
6906
  type: "set",
6901
- path,
6907
+ path: inversePath,
6902
6908
  value: previousValue
6903
6909
  };
6904
6910
  }
@@ -7675,23 +7681,20 @@ function setNodeProperties(editor, props, path) {
7675
7681
  keyIndex !== -1 && (keys.splice(keyIndex, 1), keys.unshift("_key"));
7676
7682
  let currentPath = path;
7677
7683
  for (let key of keys) if (propsRecord[key] !== nodeRecord[key]) if (propsRecord[key] != null) {
7678
- let hadProperty = nodeRecord.hasOwnProperty(key);
7679
- if (editor.apply({
7684
+ let hadProperty = nodeRecord.hasOwnProperty(key), lastSegment = currentPath[currentPath.length - 1], renamedPath = key === "_key" && typeof propsRecord[key] == "string" && isKeyedSegment(lastSegment) ? [...currentPath.slice(0, -1), { _key: propsRecord[key] }] : void 0, inversePath = renamedPath ? [...renamedPath, key] : [...currentPath, key];
7685
+ editor.apply({
7680
7686
  type: "set",
7681
7687
  path: [...currentPath, key],
7682
7688
  value: propsRecord[key],
7683
7689
  inverse: hadProperty ? {
7684
7690
  type: "set",
7685
- path: [...currentPath, key],
7691
+ path: inversePath,
7686
7692
  value: nodeRecord[key]
7687
7693
  } : {
7688
7694
  type: "unset",
7689
- path: [...currentPath, key]
7695
+ path: inversePath
7690
7696
  }
7691
- }), key === "_key" && typeof propsRecord[key] == "string") {
7692
- let lastSegment = currentPath[currentPath.length - 1];
7693
- isKeyedSegment(lastSegment) && (currentPath = [...currentPath.slice(0, -1), { _key: propsRecord[key] }]);
7694
- }
7697
+ }), renamedPath && (currentPath = renamedPath);
7695
7698
  } else nodeRecord.hasOwnProperty(key) && editor.apply({
7696
7699
  type: "unset",
7697
7700
  path: [...currentPath, key],
@@ -13132,16 +13135,24 @@ const abstractAnnotationBehaviors = [
13132
13135
  let previousBlock = {
13133
13136
  node: previousSibling.node,
13134
13137
  path: previousSibling.path
13135
- };
13138
+ }, previousBlockEndPoint = getBlockEndPoint({
13139
+ context: snapshot.context,
13140
+ block: previousBlock
13141
+ }), { renamedBlock, renameActions } = planMergeKeyRenames({
13142
+ context: snapshot.context,
13143
+ mergingBlockPath: focusTextBlock.path,
13144
+ mergingBlock: focusTextBlock.node,
13145
+ destinationBlock: previousBlock.node
13146
+ });
13136
13147
  return {
13137
- previousBlockEndPoint: getBlockEndPoint({
13138
- context: snapshot.context,
13139
- block: previousBlock
13140
- }),
13141
- focusTextBlock
13148
+ previousBlockEndPoint,
13149
+ focusTextBlock,
13150
+ renamedBlock,
13151
+ renameActions
13142
13152
  };
13143
13153
  },
13144
- actions: [(_, { previousBlockEndPoint, focusTextBlock }) => [
13154
+ actions: [(_, { previousBlockEndPoint, focusTextBlock, renamedBlock, renameActions }) => [
13155
+ ...renameActions,
13145
13156
  raise$1({
13146
13157
  type: "delete.block",
13147
13158
  at: focusTextBlock.path
@@ -13155,7 +13166,7 @@ const abstractAnnotationBehaviors = [
13155
13166
  }),
13156
13167
  raise$1({
13157
13168
  type: "insert.block",
13158
- block: focusTextBlock.node,
13169
+ block: renamedBlock,
13159
13170
  placement: "auto",
13160
13171
  select: "start"
13161
13172
  })
@@ -13224,20 +13235,32 @@ const abstractAnnotationBehaviors = [
13224
13235
  }, focusTextBlock = getFocusTextBlock(adjustedSnapshot);
13225
13236
  if (!focusTextBlock) return !1;
13226
13237
  let nextSibling = getSibling(adjustedSnapshot, focusTextBlock.path, { direction: "next" });
13227
- return !nextSibling || !isAtTheEndOfBlock(focusTextBlock)(adjustedSnapshot) || !isTextBlockNode(snapshot.context, nextSibling.node) ? !1 : { nextBlock: {
13228
- node: nextSibling.node,
13229
- path: nextSibling.path
13230
- } };
13238
+ if (!nextSibling || !isAtTheEndOfBlock(focusTextBlock)(adjustedSnapshot) || !isTextBlock(snapshot.context, nextSibling.node)) return !1;
13239
+ let { renamedBlock, renameActions } = planMergeKeyRenames({
13240
+ context: snapshot.context,
13241
+ mergingBlockPath: nextSibling.path,
13242
+ mergingBlock: nextSibling.node,
13243
+ destinationBlock: focusTextBlock.node
13244
+ });
13245
+ return {
13246
+ nextBlockPath: nextSibling.path,
13247
+ renamedBlock,
13248
+ renameActions
13249
+ };
13231
13250
  },
13232
- actions: [(_, { nextBlock }) => [raise$1({
13233
- type: "delete.block",
13234
- at: nextBlock.path
13235
- }), raise$1({
13236
- type: "insert.block",
13237
- block: nextBlock.node,
13238
- placement: "auto",
13239
- select: "none"
13240
- })]]
13251
+ actions: [(_, { nextBlockPath, renamedBlock, renameActions }) => [
13252
+ ...renameActions,
13253
+ raise$1({
13254
+ type: "delete.block",
13255
+ at: nextBlockPath
13256
+ }),
13257
+ raise$1({
13258
+ type: "insert.block",
13259
+ block: renamedBlock,
13260
+ placement: "auto",
13261
+ select: "none"
13262
+ })
13263
+ ]]
13241
13264
  }),
13242
13265
  defineBehavior({
13243
13266
  on: "delete.block",
@@ -13307,7 +13330,71 @@ const abstractAnnotationBehaviors = [
13307
13330
  type: "delete"
13308
13331
  })]]
13309
13332
  })
13310
- ], mimeTypePriority = [
13333
+ ];
13334
+ /**
13335
+ * A block merge folds `mergingBlock`'s children (and markDefs) into
13336
+ * `destinationBlock` by key. Any key the merging block shares with the
13337
+ * destination has to be renamed before the merge, or `insert.block`'s own
13338
+ * collision handling mints a fresh key for it, which reads on the wire as
13339
+ * that node being destroyed and a new one created instead of moved.
13340
+ *
13341
+ * Renames are raised as `set`/`child.set` events against the still-living
13342
+ * `mergingBlock`, so they land on the wire before the merge's `unset`.
13343
+ * `renamedBlock` mirrors the same renames applied to the value the caller
13344
+ * already captured, since raising the rename events now doesn't change
13345
+ * that captured value.
13346
+ */
13347
+ function planMergeKeyRenames(args) {
13348
+ let { context, mergingBlockPath, mergingBlock, destinationBlock } = args, destinationChildKeys = new Set(destinationBlock.children.map((child) => child._key)), destinationMarkDefKeys = new Set((destinationBlock.markDefs ?? []).map((markDef) => markDef._key)), markDefKeyMap = /* @__PURE__ */ new Map(), renamedMarkDefs = mergingBlock.markDefs?.map((markDef) => {
13349
+ if (!destinationMarkDefKeys.has(markDef._key)) return markDef;
13350
+ let newKey = context.keyGenerator();
13351
+ return markDefKeyMap.set(markDef._key, newKey), {
13352
+ ...markDef,
13353
+ _key: newKey
13354
+ };
13355
+ }), renameActions = [];
13356
+ for (let markDef of mergingBlock.markDefs ?? []) {
13357
+ let newKey = markDefKeyMap.get(markDef._key);
13358
+ newKey && renameActions.push(raise$1({
13359
+ type: "set",
13360
+ at: [
13361
+ ...mergingBlockPath,
13362
+ "markDefs",
13363
+ { _key: markDef._key },
13364
+ "_key"
13365
+ ],
13366
+ value: newKey
13367
+ }));
13368
+ }
13369
+ let renamedChildren = mergingBlock.children.map((child) => {
13370
+ let currentMarks = isSpan(context, child) ? child.marks : void 0, remappedMarks = currentMarks?.map((mark) => markDefKeyMap.get(mark) ?? mark), marksChanged = !!(remappedMarks && !isEqualMarks(remappedMarks, currentMarks)), newKey = destinationChildKeys.has(child._key) ? context.keyGenerator() : child._key, props = {};
13371
+ return newKey !== child._key && (props._key = newKey), marksChanged && (props.marks = remappedMarks), Object.keys(props).length > 0 && renameActions.push(raise$1({
13372
+ type: "child.set",
13373
+ at: [
13374
+ ...mergingBlockPath,
13375
+ "children",
13376
+ { _key: child._key }
13377
+ ],
13378
+ props
13379
+ })), marksChanged ? {
13380
+ ...child,
13381
+ _key: newKey,
13382
+ marks: remappedMarks
13383
+ } : {
13384
+ ...child,
13385
+ _key: newKey
13386
+ };
13387
+ });
13388
+ return {
13389
+ renamedBlock: {
13390
+ ...mergingBlock,
13391
+ children: renamedChildren,
13392
+ ...mergingBlock.markDefs ? { markDefs: renamedMarkDefs } : {}
13393
+ },
13394
+ renameActions
13395
+ };
13396
+ }
13397
+ const mimeTypePriority = [
13311
13398
  "application/x-portable-text",
13312
13399
  "application/json",
13313
13400
  "text/markdown",