prosemirror-transform 1.10.0 → 1.10.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.10.1 (2024-10-10)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where a `deleteRange` heuristic could produce unexpected deletion shapes.
6
+
7
+ Make `Transform.join` convert between newlines and line break replacement nodes when necessary.
8
+
1
9
  ## 1.10.0 (2024-08-13)
2
10
 
3
11
  ### New features
package/dist/index.cjs CHANGED
@@ -1034,8 +1034,21 @@ function canJoin(doc, pos) {
1034
1034
  index = $pos.index();
1035
1035
  return joinable($pos.nodeBefore, $pos.nodeAfter) && $pos.parent.canReplace(index, index + 1);
1036
1036
  }
1037
+ function canAppendWithSubstitutedLinebeaks(a, b) {
1038
+ if (!b.content.size) a.type.compatibleContent(b.type);
1039
+ var match = a.contentMatchAt(a.childCount);
1040
+ var linebreakReplacement = a.type.schema.linebreakReplacement;
1041
+ for (var i = 0; i < b.childCount; i++) {
1042
+ var child = b.child(i);
1043
+ var type = child.type == linebreakReplacement ? a.type.schema.nodes.text : child.type;
1044
+ match = match.matchType(type);
1045
+ if (!match) return false;
1046
+ if (!a.type.allowsMarks(child.marks)) return false;
1047
+ }
1048
+ return match.validEnd;
1049
+ }
1037
1050
  function joinable(a, b) {
1038
- return !!(a && b && !a.isLeaf && a.canAppend(b));
1051
+ return !!(a && b && !a.isLeaf && canAppendWithSubstitutedLinebeaks(a, b));
1039
1052
  }
1040
1053
  function joinPoint(doc, pos) {
1041
1054
  var dir = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -1;
@@ -1061,8 +1074,27 @@ function joinPoint(doc, pos) {
1061
1074
  }
1062
1075
  }
1063
1076
  function _join(tr, pos, depth) {
1064
- var step = new ReplaceStep(pos - depth, pos + depth, prosemirrorModel.Slice.empty, true);
1065
- tr.step(step);
1077
+ var convertNewlines = null;
1078
+ var linebreakReplacement = tr.doc.type.schema.linebreakReplacement;
1079
+ if (linebreakReplacement) {
1080
+ var before = tr.doc.resolve(pos - depth).node().type;
1081
+ var pre = before.whitespace == "pre";
1082
+ var supportLinebreak = !!before.contentMatch.matchType(linebreakReplacement);
1083
+ if (pre && !supportLinebreak) convertNewlines = false;else if (!pre && supportLinebreak) convertNewlines = true;
1084
+ }
1085
+ var mapFrom = tr.steps.length;
1086
+ if (convertNewlines === false) {
1087
+ var $after = tr.doc.resolve(pos + depth);
1088
+ replaceLinebreaks(tr, $after.node(), $after.before(), mapFrom);
1089
+ }
1090
+ var mapping = tr.mapping.slice(mapFrom),
1091
+ start = mapping.map(pos - depth);
1092
+ tr.step(new ReplaceStep(start, mapping.map(pos + depth, -1), prosemirrorModel.Slice.empty, true));
1093
+ if (convertNewlines === true) {
1094
+ var $full = tr.doc.resolve(start);
1095
+ replaceNewlines(tr, $full.node(), $full.before(), tr.steps.length);
1096
+ }
1097
+ return tr;
1066
1098
  }
1067
1099
  function insertPoint(doc, pos, nodeType) {
1068
1100
  var $pos = doc.resolve(pos);
@@ -1475,7 +1507,7 @@ function _deleteRange(tr, from, to) {
1475
1507
  if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1)))) return tr["delete"]($from.before(depth), $to.after(depth));
1476
1508
  }
1477
1509
  for (var d = 1; d <= $from.depth && d <= $to.depth; d++) {
1478
- if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d) return tr["delete"]($from.before(d), to);
1510
+ if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d && $from.start(d - 1) == $to.start(d - 1) && $from.node(d - 1).canReplace($from.index(d - 1), $to.index(d - 1))) return tr["delete"]($from.before(d), to);
1479
1511
  }
1480
1512
  tr["delete"](from, to);
1481
1513
  }
package/dist/index.js CHANGED
@@ -1183,8 +1183,24 @@ function canJoin(doc, pos) {
1183
1183
  return joinable($pos.nodeBefore, $pos.nodeAfter) &&
1184
1184
  $pos.parent.canReplace(index, index + 1);
1185
1185
  }
1186
+ function canAppendWithSubstitutedLinebeaks(a, b) {
1187
+ if (!b.content.size)
1188
+ a.type.compatibleContent(b.type);
1189
+ let match = a.contentMatchAt(a.childCount);
1190
+ let { linebreakReplacement } = a.type.schema;
1191
+ for (let i = 0; i < b.childCount; i++) {
1192
+ let child = b.child(i);
1193
+ let type = child.type == linebreakReplacement ? a.type.schema.nodes.text : child.type;
1194
+ match = match.matchType(type);
1195
+ if (!match)
1196
+ return false;
1197
+ if (!a.type.allowsMarks(child.marks))
1198
+ return false;
1199
+ }
1200
+ return match.validEnd;
1201
+ }
1186
1202
  function joinable(a, b) {
1187
- return !!(a && b && !a.isLeaf && a.canAppend(b));
1203
+ return !!(a && b && !a.isLeaf && canAppendWithSubstitutedLinebeaks(a, b));
1188
1204
  }
1189
1205
  /**
1190
1206
  Find an ancestor of the given position that can be joined to the
@@ -1217,8 +1233,29 @@ function joinPoint(doc, pos, dir = -1) {
1217
1233
  }
1218
1234
  }
1219
1235
  function join(tr, pos, depth) {
1220
- let step = new ReplaceStep(pos - depth, pos + depth, Slice.empty, true);
1221
- tr.step(step);
1236
+ let convertNewlines = null;
1237
+ let { linebreakReplacement } = tr.doc.type.schema;
1238
+ if (linebreakReplacement) {
1239
+ let before = tr.doc.resolve(pos - depth).node().type;
1240
+ let pre = before.whitespace == "pre";
1241
+ let supportLinebreak = !!before.contentMatch.matchType(linebreakReplacement);
1242
+ if (pre && !supportLinebreak)
1243
+ convertNewlines = false;
1244
+ else if (!pre && supportLinebreak)
1245
+ convertNewlines = true;
1246
+ }
1247
+ let mapFrom = tr.steps.length;
1248
+ if (convertNewlines === false) {
1249
+ let $after = tr.doc.resolve(pos + depth);
1250
+ replaceLinebreaks(tr, $after.node(), $after.before(), mapFrom);
1251
+ }
1252
+ let mapping = tr.mapping.slice(mapFrom), start = mapping.map(pos - depth);
1253
+ tr.step(new ReplaceStep(start, mapping.map(pos + depth, -1), Slice.empty, true));
1254
+ if (convertNewlines === true) {
1255
+ let $full = tr.doc.resolve(start);
1256
+ replaceNewlines(tr, $full.node(), $full.before(), tr.steps.length);
1257
+ }
1258
+ return tr;
1222
1259
  }
1223
1260
  /**
1224
1261
  Try to find a point where a node of the given type can be inserted
@@ -1702,7 +1739,8 @@ function deleteRange(tr, from, to) {
1702
1739
  return tr.delete($from.before(depth), $to.after(depth));
1703
1740
  }
1704
1741
  for (let d = 1; d <= $from.depth && d <= $to.depth; d++) {
1705
- if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d)
1742
+ if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d &&
1743
+ $from.start(d - 1) == $to.start(d - 1) && $from.node(d - 1).canReplace($from.index(d - 1), $to.index(d - 1)))
1706
1744
  return tr.delete($from.before(d), to);
1707
1745
  }
1708
1746
  tr.delete(from, to);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-transform",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
4
4
  "description": "ProseMirror document transformations",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/replace.ts CHANGED
@@ -434,7 +434,8 @@ export function deleteRange(tr: Transform, from: number, to: number) {
434
434
  return tr.delete($from.before(depth), $to.after(depth))
435
435
  }
436
436
  for (let d = 1; d <= $from.depth && d <= $to.depth; d++) {
437
- if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d)
437
+ if (from - $from.start(d) == $from.depth - d && to > $from.end(d) && $to.end(d) - to != $to.depth - d &&
438
+ $from.start(d - 1) == $to.start(d - 1) && $from.node(d - 1).canReplace($from.index(d - 1), $to.index(d - 1)))
438
439
  return tr.delete($from.before(d), to)
439
440
  }
440
441
  tr.delete(from, to)
package/src/structure.ts CHANGED
@@ -132,7 +132,7 @@ export function setBlockType(tr: Transform, from: number, to: number,
132
132
  let mapping = tr.mapping.slice(mapFrom)
133
133
  let startM = mapping.map(pos, 1), endM = mapping.map(pos + node.nodeSize, 1)
134
134
  tr.step(new ReplaceAroundStep(startM, endM, startM + 1, endM - 1,
135
- new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true))
135
+ new Slice(Fragment.from(type.create(attrsHere, null, node.marks)), 0, 0), 1, true))
136
136
  if (convertNewlines === true) replaceNewlines(tr, node, pos, mapFrom)
137
137
  return false
138
138
  }
@@ -226,8 +226,22 @@ export function canJoin(doc: Node, pos: number): boolean {
226
226
  $pos.parent.canReplace(index, index + 1)
227
227
  }
228
228
 
229
+ function canAppendWithSubstitutedLinebeaks(a: Node, b: Node) {
230
+ if (!b.content.size) a.type.compatibleContent(b.type)
231
+ let match: ContentMatch | null = a.contentMatchAt(a.childCount)
232
+ let {linebreakReplacement} = a.type.schema
233
+ for (let i = 0; i < b.childCount; i++) {
234
+ let child = b.child(i)
235
+ let type = child.type == linebreakReplacement ? a.type.schema.nodes.text : child.type
236
+ match = match.matchType(type)
237
+ if (!match) return false
238
+ if (!a.type.allowsMarks(child.marks)) return false
239
+ }
240
+ return match.validEnd
241
+ }
242
+
229
243
  function joinable(a: Node | null, b: Node | null) {
230
- return !!(a && b && !a.isLeaf && a.canAppend(b))
244
+ return !!(a && b && !a.isLeaf && canAppendWithSubstitutedLinebeaks(a, b))
231
245
  }
232
246
 
233
247
  /// Find an ancestor of the given position that can be joined to the
@@ -256,8 +270,27 @@ export function joinPoint(doc: Node, pos: number, dir = -1) {
256
270
  }
257
271
 
258
272
  export function join(tr: Transform, pos: number, depth: number) {
259
- let step = new ReplaceStep(pos - depth, pos + depth, Slice.empty, true)
260
- tr.step(step)
273
+ let convertNewlines = null
274
+ let {linebreakReplacement} = tr.doc.type.schema
275
+ if (linebreakReplacement) {
276
+ let before = tr.doc.resolve(pos - depth).node().type
277
+ let pre = before.whitespace == "pre"
278
+ let supportLinebreak = !!before.contentMatch.matchType(linebreakReplacement)
279
+ if (pre && !supportLinebreak) convertNewlines = false
280
+ else if (!pre && supportLinebreak) convertNewlines = true
281
+ }
282
+ let mapFrom = tr.steps.length
283
+ if (convertNewlines === false) {
284
+ let $after = tr.doc.resolve(pos + depth)
285
+ replaceLinebreaks(tr, $after.node(), $after.before(), mapFrom)
286
+ }
287
+ let mapping = tr.mapping.slice(mapFrom), start = mapping.map(pos - depth)
288
+ tr.step(new ReplaceStep(start, mapping.map(pos + depth, - 1), Slice.empty, true))
289
+ if (convertNewlines === true) {
290
+ let $full = tr.doc.resolve(start)
291
+ replaceNewlines(tr, $full.node(), $full.before(), tr.steps.length)
292
+ }
293
+ return tr
261
294
  }
262
295
 
263
296
  /// Try to find a point where a node of the given type can be inserted