@codemirror/view 6.43.1 → 6.43.2

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,15 @@
1
+ ## 6.43.2 (2026-06-23)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix using select-all from the native context menu on Chrome Android.
6
+
7
+ On iOS when autocapitalize is enabled, ignore the shift modifier on virtual keyboard Enter or Backspace presses.
8
+
9
+ Work around an issue where Chrome Android scrolled the editor up when tapping an empty line to focus it.
10
+
11
+ Create undirectional selection ranges for double and triple clicks.
12
+
1
13
  ## 6.43.1 (2026-06-09)
2
14
 
3
15
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -3611,7 +3611,7 @@ function groupAt(state$1, pos, bias = 1) {
3611
3611
  break;
3612
3612
  to = next;
3613
3613
  }
3614
- return state.EditorSelection.range(from + line.from, to + line.from);
3614
+ return state.EditorSelection.undirectionalRange(from + line.from, to + line.from);
3615
3615
  }
3616
3616
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
3617
3617
  let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
@@ -3748,8 +3748,12 @@ function skipAtomsForSelection(atoms, sel) {
3748
3748
  else {
3749
3749
  let from = skipAtomicRanges(atoms, range.from, -1);
3750
3750
  let to = skipAtomicRanges(atoms, range.to, 1);
3751
- if (from != range.from || to != range.to)
3752
- updated = state.EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3751
+ if (from != range.from || to != range.to) {
3752
+ if (range.undirectional)
3753
+ updated = state.EditorSelection.undirectionalRange(range.from, range.to);
3754
+ else
3755
+ updated = state.EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3756
+ }
3753
3757
  }
3754
3758
  if (updated) {
3755
3759
  if (!ranges)
@@ -4155,7 +4159,8 @@ class DOMChange {
4155
4159
  // Chrome will put the selection *inside* them, confusing
4156
4160
  // posFromDOM
4157
4161
  let vp = view.viewport;
4158
- if ((browser.ios || browser.chrome) && curSel.main.empty && head != anchor &&
4162
+ if ((browser.ios || browser.chrome) && head != anchor &&
4163
+ Math.min(head, anchor) <= curSel.main.from && Math.max(head, anchor) >= curSel.main.to &&
4159
4164
  (vp.from > 0 || vp.to < view.state.doc.length)) {
4160
4165
  let from = Math.min(head, anchor), to = Math.max(head, anchor);
4161
4166
  let offFrom = vp.from - from, offTo = vp.to - to;
@@ -4476,13 +4481,11 @@ class InputState {
4476
4481
  // (after which we retroactively handle them and reset the DOM) to
4477
4482
  // avoid messing up the virtual keyboard state.
4478
4483
  this.pendingIOSKey = undefined;
4479
- /**
4480
- When enabled (>-1), tab presses are not given to key handlers,
4481
- leaving the browser's default behavior. If >0, the mode expires
4482
- at that timestamp, and any other keypress clears it.
4483
- Esc enables temporary tab focus mode for two seconds when not
4484
- otherwise handled.
4485
- */
4484
+ // When enabled (>-1), tab presses are not given to key handlers,
4485
+ // leaving the browser's default behavior. If >0, the mode expires
4486
+ // at that timestamp, and any other keypress clears it.
4487
+ // Esc enables temporary tab focus mode for two seconds when not
4488
+ // otherwise handled.
4486
4489
  this.tabFocusMode = -1;
4487
4490
  this.lastSelectionOrigin = null;
4488
4491
  this.lastSelectionTime = 0;
@@ -4590,11 +4593,16 @@ class InputState {
4590
4593
  // state. So we let it go through, and then, in
4591
4594
  // applyDOMChange, notify key handlers of it and reset to
4592
4595
  // the state they produce.
4593
- let pending;
4594
- if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey &&
4595
- ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
4596
+ if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
4597
+ (PendingKeys.some(key => key.keyCode == event.keyCode) && !event.ctrlKey ||
4596
4598
  EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
4597
- this.pendingIOSKey = pending || event;
4599
+ let mods = { ctrlKey: event.ctrlKey, altKey: event.altKey, metaKey: event.metaKey, shiftKey: event.shiftKey };
4600
+ // On iOS with autocapitalize, drop the shift modifier for these
4601
+ // keys, since it will be set at the start of every sentence.
4602
+ if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
4603
+ iosVirtualKeyboardOpen(this.view.win))
4604
+ mods.shiftKey = false;
4605
+ this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4598
4606
  setTimeout(() => this.flushIOSKey(), 250);
4599
4607
  return true;
4600
4608
  }
@@ -4610,7 +4618,7 @@ class InputState {
4610
4618
  if (key.key == "Enter" && change && change.from < change.to && /^\S+$/.test(change.insert.toString()))
4611
4619
  return false;
4612
4620
  this.pendingIOSKey = undefined;
4613
- return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
4621
+ return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key.mods);
4614
4622
  }
4615
4623
  ignoreDuringComposition(event) {
4616
4624
  if (!/^key/.test(event.type) || event.synthetic)
@@ -4648,6 +4656,11 @@ class InputState {
4648
4656
  this.mouseSelection.destroy();
4649
4657
  }
4650
4658
  }
4659
+ function iosVirtualKeyboardOpen(win) {
4660
+ if (!win.visualViewport)
4661
+ return false;
4662
+ return win.visualViewport.height * win.visualViewport.scale / win.document.documentElement.clientHeight < 0.85;
4663
+ }
4651
4664
  function bindHandler(plugin, handler) {
4652
4665
  return (view, event) => {
4653
4666
  try {
@@ -4967,7 +4980,7 @@ function rangeForClick(view, pos, bias, type) {
4967
4980
  let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
4968
4981
  if (to < view.state.doc.length && to == line.to)
4969
4982
  to++;
4970
- return state.EditorSelection.range(from, to);
4983
+ return state.EditorSelection.undirectionalRange(from, to);
4971
4984
  }
4972
4985
  }
4973
4986
  const BadMouseDetail = browser.ie && browser.ie_version <= 11;
@@ -5025,7 +5038,7 @@ handlers.dragstart = (view, event) => {
5025
5038
  if (tile && tile.isWidget()) {
5026
5039
  let from = tile.posAtStart, to = from + tile.length;
5027
5040
  if (from >= range.to || to <= range.from)
5028
- range = state.EditorSelection.range(from, to);
5041
+ range = state.EditorSelection.undirectionalRange(from, to);
5029
5042
  }
5030
5043
  }
5031
5044
  let { inputState } = view;
@@ -7651,7 +7664,6 @@ class EditContextManager {
7651
7664
  for (let event in this.handlers)
7652
7665
  context.addEventListener(event, this.handlers[event]);
7653
7666
  this.measureReq = { read: view => {
7654
- this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
7655
7667
  let sel = getSelection(view.root);
7656
7668
  if (sel && sel.rangeCount)
7657
7669
  this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
package/dist/index.js CHANGED
@@ -3607,7 +3607,7 @@ function groupAt(state, pos, bias = 1) {
3607
3607
  break;
3608
3608
  to = next;
3609
3609
  }
3610
- return EditorSelection.range(from + line.from, to + line.from);
3610
+ return EditorSelection.undirectionalRange(from + line.from, to + line.from);
3611
3611
  }
3612
3612
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
3613
3613
  let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
@@ -3744,8 +3744,12 @@ function skipAtomsForSelection(atoms, sel) {
3744
3744
  else {
3745
3745
  let from = skipAtomicRanges(atoms, range.from, -1);
3746
3746
  let to = skipAtomicRanges(atoms, range.to, 1);
3747
- if (from != range.from || to != range.to)
3748
- updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3747
+ if (from != range.from || to != range.to) {
3748
+ if (range.undirectional)
3749
+ updated = EditorSelection.undirectionalRange(range.from, range.to);
3750
+ else
3751
+ updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3752
+ }
3749
3753
  }
3750
3754
  if (updated) {
3751
3755
  if (!ranges)
@@ -4151,7 +4155,8 @@ class DOMChange {
4151
4155
  // Chrome will put the selection *inside* them, confusing
4152
4156
  // posFromDOM
4153
4157
  let vp = view.viewport;
4154
- if ((browser.ios || browser.chrome) && curSel.main.empty && head != anchor &&
4158
+ if ((browser.ios || browser.chrome) && head != anchor &&
4159
+ Math.min(head, anchor) <= curSel.main.from && Math.max(head, anchor) >= curSel.main.to &&
4155
4160
  (vp.from > 0 || vp.to < view.state.doc.length)) {
4156
4161
  let from = Math.min(head, anchor), to = Math.max(head, anchor);
4157
4162
  let offFrom = vp.from - from, offTo = vp.to - to;
@@ -4472,13 +4477,11 @@ class InputState {
4472
4477
  // (after which we retroactively handle them and reset the DOM) to
4473
4478
  // avoid messing up the virtual keyboard state.
4474
4479
  this.pendingIOSKey = undefined;
4475
- /**
4476
- When enabled (>-1), tab presses are not given to key handlers,
4477
- leaving the browser's default behavior. If >0, the mode expires
4478
- at that timestamp, and any other keypress clears it.
4479
- Esc enables temporary tab focus mode for two seconds when not
4480
- otherwise handled.
4481
- */
4480
+ // When enabled (>-1), tab presses are not given to key handlers,
4481
+ // leaving the browser's default behavior. If >0, the mode expires
4482
+ // at that timestamp, and any other keypress clears it.
4483
+ // Esc enables temporary tab focus mode for two seconds when not
4484
+ // otherwise handled.
4482
4485
  this.tabFocusMode = -1;
4483
4486
  this.lastSelectionOrigin = null;
4484
4487
  this.lastSelectionTime = 0;
@@ -4586,11 +4589,16 @@ class InputState {
4586
4589
  // state. So we let it go through, and then, in
4587
4590
  // applyDOMChange, notify key handlers of it and reset to
4588
4591
  // the state they produce.
4589
- let pending;
4590
- if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey &&
4591
- ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
4592
+ if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
4593
+ (PendingKeys.some(key => key.keyCode == event.keyCode) && !event.ctrlKey ||
4592
4594
  EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
4593
- this.pendingIOSKey = pending || event;
4595
+ let mods = { ctrlKey: event.ctrlKey, altKey: event.altKey, metaKey: event.metaKey, shiftKey: event.shiftKey };
4596
+ // On iOS with autocapitalize, drop the shift modifier for these
4597
+ // keys, since it will be set at the start of every sentence.
4598
+ if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
4599
+ iosVirtualKeyboardOpen(this.view.win))
4600
+ mods.shiftKey = false;
4601
+ this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
4594
4602
  setTimeout(() => this.flushIOSKey(), 250);
4595
4603
  return true;
4596
4604
  }
@@ -4606,7 +4614,7 @@ class InputState {
4606
4614
  if (key.key == "Enter" && change && change.from < change.to && /^\S+$/.test(change.insert.toString()))
4607
4615
  return false;
4608
4616
  this.pendingIOSKey = undefined;
4609
- return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
4617
+ return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key.mods);
4610
4618
  }
4611
4619
  ignoreDuringComposition(event) {
4612
4620
  if (!/^key/.test(event.type) || event.synthetic)
@@ -4644,6 +4652,11 @@ class InputState {
4644
4652
  this.mouseSelection.destroy();
4645
4653
  }
4646
4654
  }
4655
+ function iosVirtualKeyboardOpen(win) {
4656
+ if (!win.visualViewport)
4657
+ return false;
4658
+ return win.visualViewport.height * win.visualViewport.scale / win.document.documentElement.clientHeight < 0.85;
4659
+ }
4647
4660
  function bindHandler(plugin, handler) {
4648
4661
  return (view, event) => {
4649
4662
  try {
@@ -4963,7 +4976,7 @@ function rangeForClick(view, pos, bias, type) {
4963
4976
  let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
4964
4977
  if (to < view.state.doc.length && to == line.to)
4965
4978
  to++;
4966
- return EditorSelection.range(from, to);
4979
+ return EditorSelection.undirectionalRange(from, to);
4967
4980
  }
4968
4981
  }
4969
4982
  const BadMouseDetail = browser.ie && browser.ie_version <= 11;
@@ -5021,7 +5034,7 @@ handlers.dragstart = (view, event) => {
5021
5034
  if (tile && tile.isWidget()) {
5022
5035
  let from = tile.posAtStart, to = from + tile.length;
5023
5036
  if (from >= range.to || to <= range.from)
5024
- range = EditorSelection.range(from, to);
5037
+ range = EditorSelection.undirectionalRange(from, to);
5025
5038
  }
5026
5039
  }
5027
5040
  let { inputState } = view;
@@ -7646,7 +7659,6 @@ class EditContextManager {
7646
7659
  for (let event in this.handlers)
7647
7660
  context.addEventListener(event, this.handlers[event]);
7648
7661
  this.measureReq = { read: view => {
7649
- this.editContext.updateControlBounds(view.contentDOM.getBoundingClientRect());
7650
7662
  let sel = getSelection(view.root);
7651
7663
  if (sel && sel.rangeCount)
7652
7664
  this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.43.1",
3
+ "version": "6.43.2",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -26,7 +26,7 @@
26
26
  "sideEffects": false,
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "@codemirror/state": "^6.6.0",
29
+ "@codemirror/state": "^6.7.0",
30
30
  "crelt": "^1.0.6",
31
31
  "style-mod": "^4.1.0",
32
32
  "w3c-keyname": "^2.2.4"