@codemirror/view 6.39.8 → 6.39.9

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.39.9 (2026-01-06)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a bug where `EditorSelection.cursor()` with a non-zero `assoc` value would not be visually respected at soft-wrap boundaries on initial view creation.
6
+
7
+ Fix error caused by hover tooltips running a scheduled timeout after their editor has been destroyed.
8
+
9
+ Fix a bug that caused `EditorView.outerDecorations` to not affect the content height map.
10
+
11
+ Fix an issue where composition near a widget could get unnecessarily interrupted.
12
+
1
13
  ## 6.39.8 (2025-12-30)
2
14
 
3
15
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2502,6 +2502,8 @@ class TileCache {
2502
2502
  }
2503
2503
  // Put a tile in the cache.
2504
2504
  add(tile) {
2505
+ if (tile.demo)
2506
+ console.log("Add widget to cache");
2505
2507
  let i = tile.constructor.bucket, bucket = this.buckets[i];
2506
2508
  if (bucket.length < 6 /* C.Bucket */)
2507
2509
  bucket.push(tile);
@@ -2526,6 +2528,8 @@ class TileCache {
2526
2528
  }
2527
2529
  findWidget(widget, length, flags) {
2528
2530
  let widgets = this.buckets[0];
2531
+ if (widget.demo)
2532
+ console.log("looking for widget", widget, "in cache", widgets.slice());
2529
2533
  if (widgets.length)
2530
2534
  for (let i = 0, pass = 0;; i++) {
2531
2535
  if (i == widgets.length) {
@@ -2562,6 +2566,10 @@ class TileCache {
2562
2566
  this.reused.set(tile, type);
2563
2567
  return tile.dom;
2564
2568
  }
2569
+ clear() {
2570
+ for (let i = 0; i < this.buckets.length; i++)
2571
+ this.buckets[i].length = this.index[i] = 0;
2572
+ }
2565
2573
  }
2566
2574
  // This class organizes a pass over the document, guided by the array
2567
2575
  // of replaced ranges. For ranges that haven't changed, it iterates
@@ -2604,17 +2612,20 @@ class TileUpdate {
2604
2612
  }
2605
2613
  if (!next)
2606
2614
  break;
2607
- this.forward(next.fromA, next.toA);
2608
2615
  // Compositions need to be handled specially, forcing the
2609
2616
  // focused text node and its parent nodes to remain stable at
2610
2617
  // that point in the document.
2611
2618
  if (composition && next.fromA <= composition.range.fromA && next.toA >= composition.range.toA) {
2619
+ this.forward(next.fromA, composition.range.fromA);
2612
2620
  this.emit(posB, composition.range.fromB);
2621
+ this.cache.clear(); // Must not reuse DOM across composition
2613
2622
  this.builder.addComposition(composition, compositionContext);
2614
2623
  this.text.skip(composition.range.toB - composition.range.fromB);
2624
+ this.forward(composition.range.fromA, next.toA);
2615
2625
  this.emit(composition.range.toB, next.toB);
2616
2626
  }
2617
2627
  else {
2628
+ this.forward(next.fromA, next.toA);
2618
2629
  this.emit(posB, next.toB);
2619
2630
  }
2620
2631
  posB = next.toB;
@@ -6027,7 +6038,7 @@ class ViewState {
6027
6038
  this.mustEnforceCursorAssoc = false;
6028
6039
  let guessWrapping = state$1.facet(contentAttributes).some(v => typeof v != "function" && v.class == "cm-lineWrapping");
6029
6040
  this.heightOracle = new HeightOracle(guessWrapping);
6030
- this.stateDeco = state$1.facet(decorations).filter(d => typeof d != "function");
6041
+ this.stateDeco = staticDeco(state$1);
6031
6042
  this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, state.Text.empty, this.heightOracle.setDoc(state$1.doc), [new ChangedRange(0, 0, 0, state$1.doc.length)]);
6032
6043
  for (let i = 0; i < 2; i++) {
6033
6044
  this.viewport = this.getViewport(0, null);
@@ -6066,7 +6077,7 @@ class ViewState {
6066
6077
  update(update, scrollTarget = null) {
6067
6078
  this.state = update.state;
6068
6079
  let prevDeco = this.stateDeco;
6069
- this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
6080
+ this.stateDeco = staticDeco(this.state);
6070
6081
  let contentChanges = update.changedRanges;
6071
6082
  let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length)));
6072
6083
  let prevHeight = this.heightMap.height;
@@ -6097,7 +6108,7 @@ class ViewState {
6097
6108
  update.flags |= this.computeVisibleRanges(update.changes);
6098
6109
  if (scrollTarget)
6099
6110
  this.scrollTarget = scrollTarget;
6100
- if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
6111
+ if (!this.mustEnforceCursorAssoc && (update.selectionSet || update.focusChanged) && update.view.lineWrapping &&
6101
6112
  update.state.selection.main.empty && update.state.selection.main.assoc &&
6102
6113
  !update.state.facet(nativeSelectionHidden))
6103
6114
  this.mustEnforceCursorAssoc = true;
@@ -6495,6 +6506,13 @@ const IdScaler = {
6495
6506
  scale: 1,
6496
6507
  eq(other) { return other == this; }
6497
6508
  };
6509
+ function staticDeco(state$1) {
6510
+ let deco = state$1.facet(decorations).filter(d => typeof d != "function");
6511
+ let outer = state$1.facet(outerDecorations).filter(d => typeof d != "function");
6512
+ if (outer.length)
6513
+ deco.push(state.RangeSet.join(outer));
6514
+ return deco;
6515
+ }
6498
6516
  // When the height is too big (> VP.MaxDOMHeight), scale down the
6499
6517
  // regions outside the viewports so that the total height is
6500
6518
  // VP.MaxDOMHeight.
@@ -10524,6 +10542,7 @@ class HoverPlugin {
10524
10542
  }
10525
10543
  destroy() {
10526
10544
  clearTimeout(this.hoverTimeout);
10545
+ clearTimeout(this.restartTimeout);
10527
10546
  this.view.dom.removeEventListener("mouseleave", this.mouseleave);
10528
10547
  this.view.dom.removeEventListener("mousemove", this.mousemove);
10529
10548
  }
package/dist/index.js CHANGED
@@ -2498,6 +2498,8 @@ class TileCache {
2498
2498
  }
2499
2499
  // Put a tile in the cache.
2500
2500
  add(tile) {
2501
+ if (tile.demo)
2502
+ console.log("Add widget to cache");
2501
2503
  let i = tile.constructor.bucket, bucket = this.buckets[i];
2502
2504
  if (bucket.length < 6 /* C.Bucket */)
2503
2505
  bucket.push(tile);
@@ -2522,6 +2524,8 @@ class TileCache {
2522
2524
  }
2523
2525
  findWidget(widget, length, flags) {
2524
2526
  let widgets = this.buckets[0];
2527
+ if (widget.demo)
2528
+ console.log("looking for widget", widget, "in cache", widgets.slice());
2525
2529
  if (widgets.length)
2526
2530
  for (let i = 0, pass = 0;; i++) {
2527
2531
  if (i == widgets.length) {
@@ -2558,6 +2562,10 @@ class TileCache {
2558
2562
  this.reused.set(tile, type);
2559
2563
  return tile.dom;
2560
2564
  }
2565
+ clear() {
2566
+ for (let i = 0; i < this.buckets.length; i++)
2567
+ this.buckets[i].length = this.index[i] = 0;
2568
+ }
2561
2569
  }
2562
2570
  // This class organizes a pass over the document, guided by the array
2563
2571
  // of replaced ranges. For ranges that haven't changed, it iterates
@@ -2600,17 +2608,20 @@ class TileUpdate {
2600
2608
  }
2601
2609
  if (!next)
2602
2610
  break;
2603
- this.forward(next.fromA, next.toA);
2604
2611
  // Compositions need to be handled specially, forcing the
2605
2612
  // focused text node and its parent nodes to remain stable at
2606
2613
  // that point in the document.
2607
2614
  if (composition && next.fromA <= composition.range.fromA && next.toA >= composition.range.toA) {
2615
+ this.forward(next.fromA, composition.range.fromA);
2608
2616
  this.emit(posB, composition.range.fromB);
2617
+ this.cache.clear(); // Must not reuse DOM across composition
2609
2618
  this.builder.addComposition(composition, compositionContext);
2610
2619
  this.text.skip(composition.range.toB - composition.range.fromB);
2620
+ this.forward(composition.range.fromA, next.toA);
2611
2621
  this.emit(composition.range.toB, next.toB);
2612
2622
  }
2613
2623
  else {
2624
+ this.forward(next.fromA, next.toA);
2614
2625
  this.emit(posB, next.toB);
2615
2626
  }
2616
2627
  posB = next.toB;
@@ -6022,7 +6033,7 @@ class ViewState {
6022
6033
  this.mustEnforceCursorAssoc = false;
6023
6034
  let guessWrapping = state.facet(contentAttributes).some(v => typeof v != "function" && v.class == "cm-lineWrapping");
6024
6035
  this.heightOracle = new HeightOracle(guessWrapping);
6025
- this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
6036
+ this.stateDeco = staticDeco(state);
6026
6037
  this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
6027
6038
  for (let i = 0; i < 2; i++) {
6028
6039
  this.viewport = this.getViewport(0, null);
@@ -6061,7 +6072,7 @@ class ViewState {
6061
6072
  update(update, scrollTarget = null) {
6062
6073
  this.state = update.state;
6063
6074
  let prevDeco = this.stateDeco;
6064
- this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
6075
+ this.stateDeco = staticDeco(this.state);
6065
6076
  let contentChanges = update.changedRanges;
6066
6077
  let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
6067
6078
  let prevHeight = this.heightMap.height;
@@ -6092,7 +6103,7 @@ class ViewState {
6092
6103
  update.flags |= this.computeVisibleRanges(update.changes);
6093
6104
  if (scrollTarget)
6094
6105
  this.scrollTarget = scrollTarget;
6095
- if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
6106
+ if (!this.mustEnforceCursorAssoc && (update.selectionSet || update.focusChanged) && update.view.lineWrapping &&
6096
6107
  update.state.selection.main.empty && update.state.selection.main.assoc &&
6097
6108
  !update.state.facet(nativeSelectionHidden))
6098
6109
  this.mustEnforceCursorAssoc = true;
@@ -6490,6 +6501,13 @@ const IdScaler = {
6490
6501
  scale: 1,
6491
6502
  eq(other) { return other == this; }
6492
6503
  };
6504
+ function staticDeco(state) {
6505
+ let deco = state.facet(decorations).filter(d => typeof d != "function");
6506
+ let outer = state.facet(outerDecorations).filter(d => typeof d != "function");
6507
+ if (outer.length)
6508
+ deco.push(RangeSet.join(outer));
6509
+ return deco;
6510
+ }
6493
6511
  // When the height is too big (> VP.MaxDOMHeight), scale down the
6494
6512
  // regions outside the viewports so that the total height is
6495
6513
  // VP.MaxDOMHeight.
@@ -10519,6 +10537,7 @@ class HoverPlugin {
10519
10537
  }
10520
10538
  destroy() {
10521
10539
  clearTimeout(this.hoverTimeout);
10540
+ clearTimeout(this.restartTimeout);
10522
10541
  this.view.dom.removeEventListener("mouseleave", this.mouseleave);
10523
10542
  this.view.dom.removeEventListener("mousemove", this.mousemove);
10524
10543
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.39.8",
3
+ "version": "6.39.9",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -36,6 +36,6 @@
36
36
  },
37
37
  "repository": {
38
38
  "type": "git",
39
- "url": "https://github.com/codemirror/view.git"
39
+ "url": "git+https://github.com/codemirror/view.git"
40
40
  }
41
41
  }