@codemirror/view 6.39.17 → 6.40.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 6.40.0 (2026-03-12)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a bug that caused Shift-Enter/Backspace/Delete on iOS to lose the shift modifier when delivered to key event handlers.
6
+
7
+ Fix an issue where `EditorView.moveVertically` could move to the wrong place in wrapped lines with a large line height.
8
+
9
+ Make sure the selection head associativity is properly set for mouse selections made with shift held down.
10
+
11
+ ### New features
12
+
13
+ `WidgetType.updateDOM` is now called with the previous widget value as third argument.
14
+
1
15
  ## 6.39.17 (2026-03-10)
2
16
 
3
17
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -134,7 +134,7 @@ class WidgetType {
134
134
  couldn't (in which case the widget will be redrawn). The default
135
135
  implementation just returns false.
136
136
  */
137
- updateDOM(dom, view) { return false; }
137
+ updateDOM(dom, view, from) { return false; }
138
138
  /**
139
139
  @internal
140
140
  */
@@ -2539,7 +2539,7 @@ class TileCache {
2539
2539
  let tile = widgets[i];
2540
2540
  if (!this.reused.has(tile) &&
2541
2541
  (pass == 0 ? tile.widget.compare(widget)
2542
- : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view))) {
2542
+ : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view, tile.widget))) {
2543
2543
  widgets.splice(i, 1);
2544
2544
  if (i < this.index[0])
2545
2545
  this.index[0]--;
@@ -3395,6 +3395,7 @@ class DocView {
3395
3395
  this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
3396
3396
  }
3397
3397
  scrollIntoView(target) {
3398
+ var _a;
3398
3399
  if (target.isSnapshot) {
3399
3400
  let ref = this.view.viewState.lineBlockAt(target.range.head);
3400
3401
  this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
@@ -3411,7 +3412,7 @@ class DocView {
3411
3412
  }
3412
3413
  }
3413
3414
  let { range } = target;
3414
- let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
3415
+ let rect = this.coordsAt(range.head, (_a = range.assoc) !== null && _a !== void 0 ? _a : (range.empty ? 0 : range.head > range.anchor ? -1 : 1)), other;
3415
3416
  if (!rect)
3416
3417
  return;
3417
3418
  if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
@@ -3678,7 +3679,8 @@ function moveVertically(view, start, forward, distance) {
3678
3679
  return state.EditorSelection.cursor(startPos, start.assoc);
3679
3680
  let goal = start.goalColumn, startY;
3680
3681
  let rect = view.contentDOM.getBoundingClientRect();
3681
- let startCoords = view.coordsAtPos(startPos, (start.empty ? start.assoc : 0) || (forward ? 1 : -1)), docTop = view.documentTop;
3682
+ let startCoords = view.coordsAtPos(startPos, start.assoc || ((start.empty ? forward : start.head == start.from) ? 1 : -1));
3683
+ let docTop = view.documentTop;
3682
3684
  if (startCoords) {
3683
3685
  if (goal == null)
3684
3686
  goal = startCoords.left - rect.left;
@@ -3691,9 +3693,16 @@ function moveVertically(view, start, forward, distance) {
3691
3693
  startY = (dir < 0 ? line.top : line.bottom) + docTop;
3692
3694
  }
3693
3695
  let resolvedGoal = rect.left + goal;
3694
- let dist = distance !== null && distance !== void 0 ? distance : (view.viewState.heightOracle.textHeight >> 1);
3695
- let pos = posAtCoords(view, { x: resolvedGoal, y: startY + dist * dir }, false, dir);
3696
- return state.EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
3696
+ let halfText = view.viewState.heightOracle.textHeight >> 1, dist = distance !== null && distance !== void 0 ? distance : halfText;
3697
+ for (let scan = 0;; scan += halfText) {
3698
+ let y = startY + (dist + scan) * dir;
3699
+ let pos = posAtCoords(view, { x: resolvedGoal, y }, false, dir);
3700
+ if (forward ? y > rect.bottom : y < rect.top)
3701
+ return state.EditorSelection.cursor(pos.pos, pos.assoc);
3702
+ let posCoords = view.coordsAtPos(pos.pos, pos.assoc), mid = posCoords ? (posCoords.top + posCoords.bottom) / 2 : 0;
3703
+ if (!posCoords || (forward ? mid > startY : mid < startY))
3704
+ return state.EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
3705
+ }
3697
3706
  }
3698
3707
  function skipAtomicRanges(atoms, pos, bias) {
3699
3708
  for (;;) {
@@ -4552,9 +4561,9 @@ class InputState {
4552
4561
  // applyDOMChange, notify key handlers of it and reset to
4553
4562
  // the state they produce.
4554
4563
  let pending;
4555
- if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
4564
+ if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey &&
4556
4565
  ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
4557
- EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
4566
+ EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
4558
4567
  this.pendingIOSKey = pending || event;
4559
4568
  setTimeout(() => this.flushIOSKey(), 250);
4560
4569
  return true;
@@ -4958,10 +4967,10 @@ function basicMouseSelection(view, event) {
4958
4967
  if (start.pos != cur.pos && !extend) {
4959
4968
  let startRange = rangeForClick(view, start.pos, start.assoc, type);
4960
4969
  let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to);
4961
- range = from < range.from ? state.EditorSelection.range(from, to) : state.EditorSelection.range(to, from);
4970
+ range = from < range.from ? state.EditorSelection.range(from, to, range.assoc) : state.EditorSelection.range(to, from, range.assoc);
4962
4971
  }
4963
4972
  if (extend)
4964
- return startSel.replaceRange(startSel.main.extend(range.from, range.to));
4973
+ return startSel.replaceRange(startSel.main.extend(range.from, range.to, range.assoc));
4965
4974
  else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
4966
4975
  return removed;
4967
4976
  else if (multiple)
@@ -9454,7 +9463,7 @@ const cursorLayer = layer({
9454
9463
  let prim = r == state$1.selection.main;
9455
9464
  if (r.empty || conf.drawRangeCursor && !(prim && browser.ios && conf.iosSelectionHandles)) {
9456
9465
  let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
9457
- let cursor = r.empty ? r : state.EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
9466
+ let cursor = r.empty ? r : state.EditorSelection.cursor(r.head, r.assoc);
9458
9467
  for (let piece of RectangleMarker.forRange(view, className, cursor))
9459
9468
  cursors.push(piece);
9460
9469
  }
package/dist/index.d.cts CHANGED
@@ -224,7 +224,7 @@ declare abstract class WidgetType {
224
224
  couldn't (in which case the widget will be redrawn). The default
225
225
  implementation just returns false.
226
226
  */
227
- updateDOM(dom: HTMLElement, view: EditorView): boolean;
227
+ updateDOM(dom: HTMLElement, view: EditorView, from: this): boolean;
228
228
  /**
229
229
  The estimated height this widget will have, to be used when
230
230
  estimating the height of content that hasn't been drawn. May
package/dist/index.d.ts CHANGED
@@ -224,7 +224,7 @@ declare abstract class WidgetType {
224
224
  couldn't (in which case the widget will be redrawn). The default
225
225
  implementation just returns false.
226
226
  */
227
- updateDOM(dom: HTMLElement, view: EditorView): boolean;
227
+ updateDOM(dom: HTMLElement, view: EditorView, from: this): boolean;
228
228
  /**
229
229
  The estimated height this widget will have, to be used when
230
230
  estimating the height of content that hasn't been drawn. May
package/dist/index.js CHANGED
@@ -132,7 +132,7 @@ class WidgetType {
132
132
  couldn't (in which case the widget will be redrawn). The default
133
133
  implementation just returns false.
134
134
  */
135
- updateDOM(dom, view) { return false; }
135
+ updateDOM(dom, view, from) { return false; }
136
136
  /**
137
137
  @internal
138
138
  */
@@ -2535,7 +2535,7 @@ class TileCache {
2535
2535
  let tile = widgets[i];
2536
2536
  if (!this.reused.has(tile) &&
2537
2537
  (pass == 0 ? tile.widget.compare(widget)
2538
- : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view))) {
2538
+ : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view, tile.widget))) {
2539
2539
  widgets.splice(i, 1);
2540
2540
  if (i < this.index[0])
2541
2541
  this.index[0]--;
@@ -3391,6 +3391,7 @@ class DocView {
3391
3391
  this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
3392
3392
  }
3393
3393
  scrollIntoView(target) {
3394
+ var _a;
3394
3395
  if (target.isSnapshot) {
3395
3396
  let ref = this.view.viewState.lineBlockAt(target.range.head);
3396
3397
  this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
@@ -3407,7 +3408,7 @@ class DocView {
3407
3408
  }
3408
3409
  }
3409
3410
  let { range } = target;
3410
- let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
3411
+ let rect = this.coordsAt(range.head, (_a = range.assoc) !== null && _a !== void 0 ? _a : (range.empty ? 0 : range.head > range.anchor ? -1 : 1)), other;
3411
3412
  if (!rect)
3412
3413
  return;
3413
3414
  if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
@@ -3674,7 +3675,8 @@ function moveVertically(view, start, forward, distance) {
3674
3675
  return EditorSelection.cursor(startPos, start.assoc);
3675
3676
  let goal = start.goalColumn, startY;
3676
3677
  let rect = view.contentDOM.getBoundingClientRect();
3677
- let startCoords = view.coordsAtPos(startPos, (start.empty ? start.assoc : 0) || (forward ? 1 : -1)), docTop = view.documentTop;
3678
+ let startCoords = view.coordsAtPos(startPos, start.assoc || ((start.empty ? forward : start.head == start.from) ? 1 : -1));
3679
+ let docTop = view.documentTop;
3678
3680
  if (startCoords) {
3679
3681
  if (goal == null)
3680
3682
  goal = startCoords.left - rect.left;
@@ -3687,9 +3689,16 @@ function moveVertically(view, start, forward, distance) {
3687
3689
  startY = (dir < 0 ? line.top : line.bottom) + docTop;
3688
3690
  }
3689
3691
  let resolvedGoal = rect.left + goal;
3690
- let dist = distance !== null && distance !== void 0 ? distance : (view.viewState.heightOracle.textHeight >> 1);
3691
- let pos = posAtCoords(view, { x: resolvedGoal, y: startY + dist * dir }, false, dir);
3692
- return EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
3692
+ let halfText = view.viewState.heightOracle.textHeight >> 1, dist = distance !== null && distance !== void 0 ? distance : halfText;
3693
+ for (let scan = 0;; scan += halfText) {
3694
+ let y = startY + (dist + scan) * dir;
3695
+ let pos = posAtCoords(view, { x: resolvedGoal, y }, false, dir);
3696
+ if (forward ? y > rect.bottom : y < rect.top)
3697
+ return EditorSelection.cursor(pos.pos, pos.assoc);
3698
+ let posCoords = view.coordsAtPos(pos.pos, pos.assoc), mid = posCoords ? (posCoords.top + posCoords.bottom) / 2 : 0;
3699
+ if (!posCoords || (forward ? mid > startY : mid < startY))
3700
+ return EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
3701
+ }
3693
3702
  }
3694
3703
  function skipAtomicRanges(atoms, pos, bias) {
3695
3704
  for (;;) {
@@ -4548,9 +4557,9 @@ class InputState {
4548
4557
  // applyDOMChange, notify key handlers of it and reset to
4549
4558
  // the state they produce.
4550
4559
  let pending;
4551
- if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey &&
4560
+ if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey &&
4552
4561
  ((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
4553
- EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
4562
+ EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
4554
4563
  this.pendingIOSKey = pending || event;
4555
4564
  setTimeout(() => this.flushIOSKey(), 250);
4556
4565
  return true;
@@ -4954,10 +4963,10 @@ function basicMouseSelection(view, event) {
4954
4963
  if (start.pos != cur.pos && !extend) {
4955
4964
  let startRange = rangeForClick(view, start.pos, start.assoc, type);
4956
4965
  let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to);
4957
- range = from < range.from ? EditorSelection.range(from, to) : EditorSelection.range(to, from);
4966
+ range = from < range.from ? EditorSelection.range(from, to, range.assoc) : EditorSelection.range(to, from, range.assoc);
4958
4967
  }
4959
4968
  if (extend)
4960
- return startSel.replaceRange(startSel.main.extend(range.from, range.to));
4969
+ return startSel.replaceRange(startSel.main.extend(range.from, range.to, range.assoc));
4961
4970
  else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
4962
4971
  return removed;
4963
4972
  else if (multiple)
@@ -9449,7 +9458,7 @@ const cursorLayer = /*@__PURE__*/layer({
9449
9458
  let prim = r == state.selection.main;
9450
9459
  if (r.empty || conf.drawRangeCursor && !(prim && browser.ios && conf.iosSelectionHandles)) {
9451
9460
  let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
9452
- let cursor = r.empty ? r : EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
9461
+ let cursor = r.empty ? r : EditorSelection.cursor(r.head, r.assoc);
9453
9462
  for (let piece of RectangleMarker.forRange(view, className, cursor))
9454
9463
  cursors.push(piece);
9455
9464
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.39.17",
3
+ "version": "6.40.0",
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.5.0",
29
+ "@codemirror/state": "^6.6.0",
30
30
  "crelt": "^1.0.6",
31
31
  "style-mod": "^4.1.0",
32
32
  "w3c-keyname": "^2.2.4"