prosemirror-view 1.42.3 → 1.42.5

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,19 @@
1
+ ## 1.42.5 (2026-09-21)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where some kinds of deletions on Chrome Android were interpreted as Enter presses.
6
+
7
+ Fix a regression where some types of Enter presses on Android would not go through the Enter key handling.
8
+
9
+ ## 1.42.4 (2026-09-18)
10
+
11
+ ### Bug fixes
12
+
13
+ Prevent uneditable elements rendered as part of node or mark view from blocking cursor motion.
14
+
15
+ Fix a bug that could break some types of composition input starting with a non-empty selection.
16
+
1
17
  ## 1.42.3 (2026-08-25)
2
18
 
3
19
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2400,7 +2400,7 @@ function nodeLen(node) {
2400
2400
  }
2401
2401
  function isIgnorable(dom, dir) {
2402
2402
  var desc = dom.pmViewDesc;
2403
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
2403
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR") : dom.nodeType == 1 && dom.contentEditable == "false";
2404
2404
  }
2405
2405
  function skipIgnoredNodes(view, dir) {
2406
2406
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -2913,11 +2913,10 @@ function addContext(slice, context) {
2913
2913
  var type = schema.nodes[array[i]];
2914
2914
  if (!type || type.hasRequiredAttrs()) break;
2915
2915
  try {
2916
- type.checkAttrs(array[i + 1]);
2916
+ content = prosemirrorModel.Fragment.from(type.create(array[i + 1], content));
2917
2917
  } catch (e) {
2918
2918
  break;
2919
2919
  }
2920
- content = prosemirrorModel.Fragment.from(type.create(array[i + 1], content));
2921
2920
  openStart++;
2922
2921
  openEnd++;
2923
2922
  }
@@ -3387,7 +3386,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = function (view)
3387
3386
  view.domObserver.flush();
3388
3387
  var state = view.state,
3389
3388
  $pos = state.selection.$to;
3390
- if (state.selection instanceof prosemirrorState.TextSelection && (state.storedMarks || !$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) {
3389
+ if (state.selection instanceof prosemirrorState.TextSelection && state.selection.empty && (state.storedMarks || !$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(function (m) {
3391
3390
  return m.type.spec.inclusive === false;
3392
3391
  }) || chrome && windows && selectionBeforeUneditable(view))) {
3393
3392
  view.markCursor = view.state.storedMarks || $pos.marks();
@@ -4891,7 +4890,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
4891
4890
  var inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;
4892
4891
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 && (!inlineChange || addedNodes.some(function (n) {
4893
4892
  return n.nodeName == "DIV" || n.nodeName == "P";
4894
- })) || !inlineChange && $from.pos < parse.doc.content.size && (!$from.sameParent($to) || !$from.parent.inlineContent) && $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", ""))) && view.someProp("handleKeyDown", function (f) {
4893
+ })) || !inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos)) && view.someProp("handleKeyDown", function (f) {
4895
4894
  return f(view, keyEvent(13, "Enter"));
4896
4895
  })) {
4897
4896
  view.input.lastIOSEnter = 0;
@@ -5004,6 +5003,14 @@ function looksLikeBackspace(old, start, end, $newStart, $newEnd) {
5004
5003
  if (!$next.parent.isTextblock || $next.pos > end || skipClosingAndOpening($next, true, false) < end) return false;
5005
5004
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
5006
5005
  }
5006
+ function looksLikeEnter(content, from, to) {
5007
+ var newTextlines = 0,
5008
+ newLeaves = 0;
5009
+ content.nodesBetween(from, to, function (node, pos) {
5010
+ if (node.isTextblock && pos >= from && pos < to) newTextlines++;else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf) newLeaves++;
5011
+ });
5012
+ return newLeaves == 0 && newTextlines == 1;
5013
+ }
5007
5014
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
5008
5015
  var depth = $pos.depth,
5009
5016
  end = fromEnd ? $pos.end() : $pos.pos;
package/dist/index.js CHANGED
@@ -2494,7 +2494,8 @@ function nodeLen(node) {
2494
2494
  }
2495
2495
  function isIgnorable(dom, dir) {
2496
2496
  let desc = dom.pmViewDesc;
2497
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
2497
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
2498
+ : dom.nodeType == 1 && dom.contentEditable == "false";
2498
2499
  }
2499
2500
  function skipIgnoredNodes(view, dir) {
2500
2501
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -3083,12 +3084,11 @@ function addContext(slice, context) {
3083
3084
  if (!type || type.hasRequiredAttrs())
3084
3085
  break;
3085
3086
  try {
3086
- type.checkAttrs(array[i + 1]);
3087
+ content = Fragment.from(type.create(array[i + 1], content));
3087
3088
  }
3088
3089
  catch (e) {
3089
3090
  break;
3090
3091
  }
3091
- content = Fragment.from(type.create(array[i + 1], content));
3092
3092
  openStart++;
3093
3093
  openEnd++;
3094
3094
  }
@@ -3569,7 +3569,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
3569
3569
  if (!view.composing) {
3570
3570
  view.domObserver.flush();
3571
3571
  let { state } = view, $pos = state.selection.$to;
3572
- if (state.selection instanceof TextSelection &&
3572
+ if (state.selection instanceof TextSelection && state.selection.empty &&
3573
3573
  (state.storedMarks ||
3574
3574
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
3575
3575
  chrome && windows && selectionBeforeUneditable(view))) { // Issue #1500
@@ -5206,9 +5206,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
5206
5206
  // as being an iOS enter press), just dispatch an Enter key instead.
5207
5207
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
5208
5208
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
5209
- (!inlineChange && $from.pos < parse.doc.content.size &&
5210
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
5211
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
5209
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
5212
5210
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
5213
5211
  view.input.lastIOSEnter = 0;
5214
5212
  return;
@@ -5359,6 +5357,16 @@ function looksLikeBackspace(old, start, end, $newStart, $newEnd) {
5359
5357
  // The fragments after the join point must match
5360
5358
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
5361
5359
  }
5360
+ function looksLikeEnter(content, from, to) {
5361
+ let newTextlines = 0, newLeaves = 0;
5362
+ content.nodesBetween(from, to, (node, pos) => {
5363
+ if (node.isTextblock && pos >= from && pos < to)
5364
+ newTextlines++;
5365
+ else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
5366
+ newLeaves++;
5367
+ });
5368
+ return newLeaves == 0 && newTextlines == 1;
5369
+ }
5362
5370
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
5363
5371
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
5364
5372
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.42.3",
3
+ "version": "1.42.5",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -28,7 +28,7 @@
28
28
  "url": "git+https://code.haverbeke.berlin/prosemirror/prosemirror-view.git"
29
29
  },
30
30
  "dependencies": {
31
- "prosemirror-model": "^1.25.8",
31
+ "prosemirror-model": "^1.25.12",
32
32
  "prosemirror-state": "^1.0.0",
33
33
  "prosemirror-transform": "^1.1.0"
34
34
  },
@@ -61,7 +61,8 @@ function nodeLen(node: Node) {
61
61
 
62
62
  function isIgnorable(dom: Node, dir: number) {
63
63
  let desc = dom.pmViewDesc
64
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
64
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
65
+ : dom.nodeType == 1 && (dom as HTMLElement).contentEditable == "false"
65
66
  }
66
67
 
67
68
  function skipIgnoredNodes(view: EditorView, dir: number) {
package/src/clipboard.ts CHANGED
@@ -270,9 +270,11 @@ function addContext(slice: Slice, context: string) {
270
270
  for (let i = array.length - 2; i >= 0; i -= 2) {
271
271
  let type = schema.nodes[array[i]]
272
272
  if (!type || type.hasRequiredAttrs()) break
273
- try { type.checkAttrs(array[i + 1]) }
274
- catch(e) { break }
275
- content = Fragment.from(type.create(array[i + 1], content))
273
+ try {
274
+ content = Fragment.from(type.create(array[i + 1], content))
275
+ } catch(e) {
276
+ break
277
+ }
276
278
  openStart++; openEnd++
277
279
  }
278
280
  return new Slice(content, openStart, openEnd)
package/src/domchange.ts CHANGED
@@ -180,9 +180,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
180
180
  // as being an iOS enter press), just dispatch an Enter key instead.
181
181
  if (((browser.ios && view.input.lastIOSEnter > Date.now() - 225 &&
182
182
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
183
- (!inlineChange && $from.pos < parse.doc.content.size &&
184
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
185
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
183
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
186
184
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
187
185
  view.input.lastIOSEnter = 0
188
186
  return
@@ -333,6 +331,17 @@ function looksLikeBackspace(old: Node, start: number, end: number, $newStart: Re
333
331
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content)
334
332
  }
335
333
 
334
+ function looksLikeEnter(content: Node, from: number, to: number) {
335
+ let newTextlines = 0, newLeaves = 0
336
+ content.nodesBetween(from, to, (node, pos) => {
337
+ if (node.isTextblock && pos >= from && pos < to)
338
+ newTextlines++
339
+ else if (node.isText ? /\S/.test(node.text!.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
340
+ newLeaves++
341
+ })
342
+ return newLeaves == 0 && newTextlines == 1
343
+ }
344
+
336
345
  function skipClosingAndOpening($pos: ResolvedPos, fromEnd: boolean, mayOpen: boolean) {
337
346
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos
338
347
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
package/src/input.ts CHANGED
@@ -518,7 +518,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
518
518
  if (!view.composing) {
519
519
  view.domObserver.flush()
520
520
  let {state} = view, $pos = state.selection.$to
521
- if (state.selection instanceof TextSelection &&
521
+ if (state.selection instanceof TextSelection && state.selection.empty &&
522
522
  (state.storedMarks ||
523
523
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore!.marks.some(m => m.type.spec.inclusive === false)) ||
524
524
  browser.chrome && browser.windows && selectionBeforeUneditable(view))) { // Issue #1500