@codemirror/view 6.3.1 → 6.4.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,31 @@
1
+ ## 6.4.1 (2022-11-07)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where coordinates next to replaced widgets were returned incorrectly, causing the cursor to be drawn in the wrong place.
6
+
7
+ Update the `crosshairCursor` state on every mousemove event.
8
+
9
+ Avoid an issue in the way that the editor enforces cursor associativity that could cause the cursor to get stuck on single-character wrapped lines.
10
+
11
+ ## 6.4.0 (2022-10-18)
12
+
13
+ ### Bug fixes
14
+
15
+ Avoid an issue where `scrollPastEnd` makes a single-line editor have a vertical scrollbar.
16
+
17
+ Work around a Chrome bug where it inserts a newline when you press space at the start of a wrapped line.
18
+
19
+ Align `rectangularSelection`'s behavior with other popular editors by making it create cursors at the end of lines that are too short to touch the rectangle.
20
+
21
+ Fix an issue where coordinates on mark decoration boundaries were sometimes taken from the wrong side of the position.
22
+
23
+ Prevent scrolling artifacts caused by attempts to scroll stuff into view when the editor isn't being displayed.
24
+
25
+ ### New features
26
+
27
+ `TooltipView` objects can now provide a `destroy` method to be called when the tooltip is removed.
28
+
1
29
  ## 6.3.1 (2022-10-10)
2
30
 
3
31
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -875,7 +875,7 @@ class WidgetView extends ContentView {
875
875
  if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
876
876
  break;
877
877
  }
878
- return flattenRect(rect, this.side > 0);
878
+ return this.length ? rect : flattenRect(rect, this.side > 0);
879
879
  }
880
880
  get isEditable() { return false; }
881
881
  destroy() {
@@ -1054,57 +1054,31 @@ function joinInlineInto(parent, view, open) {
1054
1054
  parent.length += view.length;
1055
1055
  }
1056
1056
  function coordsInChildren(view, pos, side) {
1057
- if (!view.children.length)
1058
- return fallbackRect(view);
1059
- return (side <= 0 ? coordsInChildrenBefore : coordsInChildrenAfter)(view, pos);
1060
- }
1061
- function coordsInChildrenBefore(view, pos) {
1062
- // Find the last leaf in the tree that touches pos and doesn't have getSide() > 0
1063
- let found = null, foundPos = -1;
1057
+ let before = null, beforePos = -1, after = null, afterPos = -1;
1064
1058
  function scan(view, pos) {
1065
1059
  for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
1066
1060
  let child = view.children[i], end = off + child.length;
1067
1061
  if (end >= pos) {
1068
1062
  if (child.children.length) {
1069
- if (scan(child, pos - off))
1070
- return true;
1063
+ scan(child, pos - off);
1071
1064
  }
1072
- else if (end >= pos) {
1073
- if (end == pos && child.getSide() > 0)
1074
- return true;
1075
- found = child;
1076
- foundPos = pos - off;
1065
+ else if (!after && (end > pos || off == end && child.getSide() > 0)) {
1066
+ after = child;
1067
+ afterPos = pos - off;
1077
1068
  }
1078
- }
1079
- off = end;
1080
- }
1081
- }
1082
- scan(view, pos);
1083
- return found ? found.coordsAt(Math.max(0, foundPos), -1) : coordsInChildrenAfter(view, pos);
1084
- }
1085
- function coordsInChildrenAfter(view, pos) {
1086
- // Find the first leaf in the tree that touches pos and doesn't have getSide() < 0
1087
- let found = null, foundPos = -1;
1088
- function scan(view, pos) {
1089
- for (let i = view.children.length - 1, off = view.length; i >= 0 && off >= pos; i--) {
1090
- let child = view.children[i];
1091
- off -= child.length;
1092
- if (off <= pos) {
1093
- if (child.children.length) {
1094
- if (scan(child, pos - off))
1095
- return true;
1096
- }
1097
- else if (off <= pos) {
1098
- if (off == pos && child.getSide() < 0)
1099
- return true;
1100
- found = child;
1101
- foundPos = pos - off;
1069
+ else if (off < pos || (off == end && child.getSide() < 0)) {
1070
+ before = child;
1071
+ beforePos = pos - off;
1102
1072
  }
1103
1073
  }
1074
+ off = end;
1104
1075
  }
1105
1076
  }
1106
1077
  scan(view, pos);
1107
- return found ? found.coordsAt(Math.max(0, foundPos), 1) : coordsInChildrenBefore(view, pos);
1078
+ let target = (side < 0 ? before : after) || before || after;
1079
+ if (target)
1080
+ return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side);
1081
+ return fallbackRect(view);
1108
1082
  }
1109
1083
  function fallbackRect(view) {
1110
1084
  let last = view.dom.lastChild;
@@ -1792,6 +1766,9 @@ const inputHandler = state.Facet.define();
1792
1766
  const perLineTextDirection = state.Facet.define({
1793
1767
  combine: values => values.some(x => x)
1794
1768
  });
1769
+ const nativeSelectionHidden = state.Facet.define({
1770
+ combine: values => values.some(x => x)
1771
+ });
1795
1772
  class ScrollTarget {
1796
1773
  constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
1797
1774
  this.range = range;
@@ -2705,8 +2682,9 @@ class DocView extends ContentView {
2705
2682
  enforceCursorAssoc() {
2706
2683
  if (this.compositionDeco.size)
2707
2684
  return;
2708
- let cursor = this.view.state.selection.main;
2709
- let sel = getSelection(this.view.root);
2685
+ let { view } = this, cursor = view.state.selection.main;
2686
+ let sel = getSelection(view.root);
2687
+ let { anchorNode, anchorOffset } = view.observer.selectionRange;
2710
2688
  if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
2711
2689
  return;
2712
2690
  let line = LineView.find(this, cursor.head);
@@ -2721,6 +2699,12 @@ class DocView extends ContentView {
2721
2699
  let dom = this.domAtPos(cursor.head + cursor.assoc);
2722
2700
  sel.collapse(dom.node, dom.offset);
2723
2701
  sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
2702
+ // This can go wrong in corner cases like single-character lines,
2703
+ // so check and reset if necessary.
2704
+ view.observer.readSelectionRange();
2705
+ let newRange = view.observer.selectionRange;
2706
+ if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
2707
+ sel.collapse(anchorNode, anchorOffset);
2724
2708
  }
2725
2709
  mayControlSelection() {
2726
2710
  let active = this.view.root.activeElement;
@@ -4805,7 +4789,7 @@ class ViewState {
4805
4789
  // Flag set when editor content was redrawn, so that the next
4806
4790
  // measure stage knows it must read DOM layout
4807
4791
  this.mustMeasureContent = true;
4808
- this.defaultTextDirection = exports.Direction.RTL;
4792
+ this.defaultTextDirection = exports.Direction.LTR;
4809
4793
  this.visibleRanges = [];
4810
4794
  // Cursor 'assoc' is only significant when the cursor is on a line
4811
4795
  // wrap point, where it must stick to the character that it is
@@ -4870,7 +4854,8 @@ class ViewState {
4870
4854
  if (scrollTarget)
4871
4855
  this.scrollTarget = scrollTarget;
4872
4856
  if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
4873
- update.state.selection.main.empty && update.state.selection.main.assoc)
4857
+ update.state.selection.main.empty && update.state.selection.main.assoc &&
4858
+ !update.state.facet(nativeSelectionHidden))
4874
4859
  this.mustEnforceCursorAssoc = true;
4875
4860
  }
4876
4861
  measure(view) {
@@ -4933,7 +4918,9 @@ class ViewState {
4933
4918
  oracle.heightChanged = false;
4934
4919
  for (let vp of this.viewports) {
4935
4920
  let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
4936
- this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4921
+ this.heightMap = refresh
4922
+ ? HeightMap.empty().applyChanges(this.stateDeco, state.Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)])
4923
+ : this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4937
4924
  }
4938
4925
  if (oracle.heightChanged)
4939
4926
  result |= 2 /* UpdateFlag.Height */;
@@ -5572,6 +5559,15 @@ function applyDOMChange(view, domChange) {
5572
5559
  newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
5573
5560
  change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
5574
5561
  }
5562
+ else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
5563
+ change.insert.toString() == "\n " && view.lineWrapping) {
5564
+ // In Chrome, if you insert a space at the start of a wrapped
5565
+ // line, it will actually insert a newline and a space, causing a
5566
+ // bogus new line to be created in CodeMirror (#968)
5567
+ if (newSel)
5568
+ newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
5569
+ change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
5570
+ }
5575
5571
  if (change) {
5576
5572
  let startState = view.state;
5577
5573
  if (browser.ios && view.inputState.flushIOSKey(view))
@@ -5784,7 +5780,8 @@ class DOMObserver {
5784
5780
  this.onScroll = this.onScroll.bind(this);
5785
5781
  if (typeof ResizeObserver == "function") {
5786
5782
  this.resize = new ResizeObserver(() => {
5787
- if (this.view.docView.lastUpdate < Date.now() - 75)
5783
+ var _a;
5784
+ if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
5788
5785
  this.onResize();
5789
5786
  });
5790
5787
  this.resize.observe(view.scrollDOM);
@@ -6496,17 +6493,19 @@ class EditorView {
6496
6493
  logException(this.state, e);
6497
6494
  }
6498
6495
  }
6499
- if (this.viewState.scrollTarget) {
6500
- this.docView.scrollIntoView(this.viewState.scrollTarget);
6501
- this.viewState.scrollTarget = null;
6502
- scrolled = true;
6503
- }
6504
- else {
6505
- let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
6506
- if (diff > 1 || diff < -1) {
6507
- this.scrollDOM.scrollTop += diff;
6496
+ if (this.viewState.editorHeight) {
6497
+ if (this.viewState.scrollTarget) {
6498
+ this.docView.scrollIntoView(this.viewState.scrollTarget);
6499
+ this.viewState.scrollTarget = null;
6508
6500
  scrolled = true;
6509
6501
  }
6502
+ else {
6503
+ let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
6504
+ if (diff > 1 || diff < -1) {
6505
+ this.scrollDOM.scrollTop += diff;
6506
+ scrolled = true;
6507
+ }
6508
+ }
6510
6509
  }
6511
6510
  if (redrawn)
6512
6511
  this.docView.updateSelection(true);
@@ -7326,7 +7325,8 @@ function drawSelection(config = {}) {
7326
7325
  return [
7327
7326
  selectionConfig.of(config),
7328
7327
  drawSelectionPlugin,
7329
- hideNativeSelection
7328
+ hideNativeSelection,
7329
+ nativeSelectionHidden.of(true)
7330
7330
  ];
7331
7331
  }
7332
7332
  class Piece {
@@ -7912,7 +7912,8 @@ const plugin = ViewPlugin.fromClass(class {
7912
7912
  this.attrs = { style: "padding-bottom: 1000px" };
7913
7913
  }
7914
7914
  update(update) {
7915
- let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
7915
+ let { view } = update;
7916
+ let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
7916
7917
  if (height != this.height) {
7917
7918
  this.height = height;
7918
7919
  this.attrs = { style: `padding-bottom: ${height}px` };
@@ -8014,7 +8015,10 @@ function rectangleFor(state$1, a, b) {
8014
8015
  for (let i = startLine; i <= endLine; i++) {
8015
8016
  let line = state$1.doc.line(i);
8016
8017
  let start = state.findColumn(line.text, startCol, state$1.tabSize, true);
8017
- if (start > -1) {
8018
+ if (start < 0) {
8019
+ ranges.push(state.EditorSelection.cursor(line.to));
8020
+ }
8021
+ else {
8018
8022
  let end = state.findColumn(line.text, endCol, state$1.tabSize);
8019
8023
  ranges.push(state.EditorSelection.range(line.from + start, line.from + end));
8020
8024
  }
@@ -8107,6 +8111,9 @@ function crosshairCursor(options = {}) {
8107
8111
  keyup(e) {
8108
8112
  if (e.keyCode == code || !getter(e))
8109
8113
  this.set(false);
8114
+ },
8115
+ mousemove(e) {
8116
+ this.set(getter(e));
8110
8117
  }
8111
8118
  }
8112
8119
  });
@@ -8126,6 +8133,7 @@ class TooltipViewManager {
8126
8133
  this.tooltipViews = this.tooltips.map(createTooltipView);
8127
8134
  }
8128
8135
  update(update) {
8136
+ var _a;
8129
8137
  let input = update.state.facet(this.facet);
8130
8138
  let tooltips = input.filter(x => x);
8131
8139
  if (input === this.input) {
@@ -8154,8 +8162,10 @@ class TooltipViewManager {
8154
8162
  }
8155
8163
  }
8156
8164
  for (let t of this.tooltipViews)
8157
- if (tooltipViews.indexOf(t) < 0)
8165
+ if (tooltipViews.indexOf(t) < 0) {
8158
8166
  t.dom.remove();
8167
+ (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
8168
+ }
8159
8169
  this.input = input;
8160
8170
  this.tooltips = tooltips;
8161
8171
  this.tooltipViews = tooltipViews;
@@ -8274,11 +8284,13 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8274
8284
  return tooltipView;
8275
8285
  }
8276
8286
  destroy() {
8277
- var _a;
8287
+ var _a, _b;
8278
8288
  this.view.win.removeEventListener("resize", this.measureSoon);
8279
- for (let { dom } of this.manager.tooltipViews)
8280
- dom.remove();
8281
- (_a = this.intersectionObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
8289
+ for (let tooltipView of this.manager.tooltipViews) {
8290
+ tooltipView.dom.remove();
8291
+ (_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
8292
+ }
8293
+ (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
8282
8294
  clearTimeout(this.measureTimeout);
8283
8295
  }
8284
8296
  readMeasure() {
package/dist/index.d.ts CHANGED
@@ -1579,6 +1579,11 @@ interface TooltipView {
1579
1579
  */
1580
1580
  update?(update: ViewUpdate): void;
1581
1581
  /**
1582
+ Called when the tooltip is removed from the editor or the editor
1583
+ is destroyed.
1584
+ */
1585
+ destroy?(): void;
1586
+ /**
1582
1587
  Called when the tooltip has been (re)positioned.
1583
1588
  */
1584
1589
  positioned?(): void;
package/dist/index.js CHANGED
@@ -871,7 +871,7 @@ class WidgetView extends ContentView {
871
871
  if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
872
872
  break;
873
873
  }
874
- return flattenRect(rect, this.side > 0);
874
+ return this.length ? rect : flattenRect(rect, this.side > 0);
875
875
  }
876
876
  get isEditable() { return false; }
877
877
  destroy() {
@@ -1050,57 +1050,31 @@ function joinInlineInto(parent, view, open) {
1050
1050
  parent.length += view.length;
1051
1051
  }
1052
1052
  function coordsInChildren(view, pos, side) {
1053
- if (!view.children.length)
1054
- return fallbackRect(view);
1055
- return (side <= 0 ? coordsInChildrenBefore : coordsInChildrenAfter)(view, pos);
1056
- }
1057
- function coordsInChildrenBefore(view, pos) {
1058
- // Find the last leaf in the tree that touches pos and doesn't have getSide() > 0
1059
- let found = null, foundPos = -1;
1053
+ let before = null, beforePos = -1, after = null, afterPos = -1;
1060
1054
  function scan(view, pos) {
1061
1055
  for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
1062
1056
  let child = view.children[i], end = off + child.length;
1063
1057
  if (end >= pos) {
1064
1058
  if (child.children.length) {
1065
- if (scan(child, pos - off))
1066
- return true;
1059
+ scan(child, pos - off);
1067
1060
  }
1068
- else if (end >= pos) {
1069
- if (end == pos && child.getSide() > 0)
1070
- return true;
1071
- found = child;
1072
- foundPos = pos - off;
1061
+ else if (!after && (end > pos || off == end && child.getSide() > 0)) {
1062
+ after = child;
1063
+ afterPos = pos - off;
1073
1064
  }
1074
- }
1075
- off = end;
1076
- }
1077
- }
1078
- scan(view, pos);
1079
- return found ? found.coordsAt(Math.max(0, foundPos), -1) : coordsInChildrenAfter(view, pos);
1080
- }
1081
- function coordsInChildrenAfter(view, pos) {
1082
- // Find the first leaf in the tree that touches pos and doesn't have getSide() < 0
1083
- let found = null, foundPos = -1;
1084
- function scan(view, pos) {
1085
- for (let i = view.children.length - 1, off = view.length; i >= 0 && off >= pos; i--) {
1086
- let child = view.children[i];
1087
- off -= child.length;
1088
- if (off <= pos) {
1089
- if (child.children.length) {
1090
- if (scan(child, pos - off))
1091
- return true;
1092
- }
1093
- else if (off <= pos) {
1094
- if (off == pos && child.getSide() < 0)
1095
- return true;
1096
- found = child;
1097
- foundPos = pos - off;
1065
+ else if (off < pos || (off == end && child.getSide() < 0)) {
1066
+ before = child;
1067
+ beforePos = pos - off;
1098
1068
  }
1099
1069
  }
1070
+ off = end;
1100
1071
  }
1101
1072
  }
1102
1073
  scan(view, pos);
1103
- return found ? found.coordsAt(Math.max(0, foundPos), 1) : coordsInChildrenBefore(view, pos);
1074
+ let target = (side < 0 ? before : after) || before || after;
1075
+ if (target)
1076
+ return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side);
1077
+ return fallbackRect(view);
1104
1078
  }
1105
1079
  function fallbackRect(view) {
1106
1080
  let last = view.dom.lastChild;
@@ -1787,6 +1761,9 @@ const inputHandler = /*@__PURE__*/Facet.define();
1787
1761
  const perLineTextDirection = /*@__PURE__*/Facet.define({
1788
1762
  combine: values => values.some(x => x)
1789
1763
  });
1764
+ const nativeSelectionHidden = /*@__PURE__*/Facet.define({
1765
+ combine: values => values.some(x => x)
1766
+ });
1790
1767
  class ScrollTarget {
1791
1768
  constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
1792
1769
  this.range = range;
@@ -2699,8 +2676,9 @@ class DocView extends ContentView {
2699
2676
  enforceCursorAssoc() {
2700
2677
  if (this.compositionDeco.size)
2701
2678
  return;
2702
- let cursor = this.view.state.selection.main;
2703
- let sel = getSelection(this.view.root);
2679
+ let { view } = this, cursor = view.state.selection.main;
2680
+ let sel = getSelection(view.root);
2681
+ let { anchorNode, anchorOffset } = view.observer.selectionRange;
2704
2682
  if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
2705
2683
  return;
2706
2684
  let line = LineView.find(this, cursor.head);
@@ -2715,6 +2693,12 @@ class DocView extends ContentView {
2715
2693
  let dom = this.domAtPos(cursor.head + cursor.assoc);
2716
2694
  sel.collapse(dom.node, dom.offset);
2717
2695
  sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
2696
+ // This can go wrong in corner cases like single-character lines,
2697
+ // so check and reset if necessary.
2698
+ view.observer.readSelectionRange();
2699
+ let newRange = view.observer.selectionRange;
2700
+ if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
2701
+ sel.collapse(anchorNode, anchorOffset);
2718
2702
  }
2719
2703
  mayControlSelection() {
2720
2704
  let active = this.view.root.activeElement;
@@ -4798,7 +4782,7 @@ class ViewState {
4798
4782
  // Flag set when editor content was redrawn, so that the next
4799
4783
  // measure stage knows it must read DOM layout
4800
4784
  this.mustMeasureContent = true;
4801
- this.defaultTextDirection = Direction.RTL;
4785
+ this.defaultTextDirection = Direction.LTR;
4802
4786
  this.visibleRanges = [];
4803
4787
  // Cursor 'assoc' is only significant when the cursor is on a line
4804
4788
  // wrap point, where it must stick to the character that it is
@@ -4863,7 +4847,8 @@ class ViewState {
4863
4847
  if (scrollTarget)
4864
4848
  this.scrollTarget = scrollTarget;
4865
4849
  if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
4866
- update.state.selection.main.empty && update.state.selection.main.assoc)
4850
+ update.state.selection.main.empty && update.state.selection.main.assoc &&
4851
+ !update.state.facet(nativeSelectionHidden))
4867
4852
  this.mustEnforceCursorAssoc = true;
4868
4853
  }
4869
4854
  measure(view) {
@@ -4926,7 +4911,9 @@ class ViewState {
4926
4911
  oracle.heightChanged = false;
4927
4912
  for (let vp of this.viewports) {
4928
4913
  let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
4929
- this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4914
+ this.heightMap = refresh
4915
+ ? HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)])
4916
+ : this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4930
4917
  }
4931
4918
  if (oracle.heightChanged)
4932
4919
  result |= 2 /* UpdateFlag.Height */;
@@ -5565,6 +5552,15 @@ function applyDOMChange(view, domChange) {
5565
5552
  newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
5566
5553
  change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
5567
5554
  }
5555
+ else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
5556
+ change.insert.toString() == "\n " && view.lineWrapping) {
5557
+ // In Chrome, if you insert a space at the start of a wrapped
5558
+ // line, it will actually insert a newline and a space, causing a
5559
+ // bogus new line to be created in CodeMirror (#968)
5560
+ if (newSel)
5561
+ newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
5562
+ change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
5563
+ }
5568
5564
  if (change) {
5569
5565
  let startState = view.state;
5570
5566
  if (browser.ios && view.inputState.flushIOSKey(view))
@@ -5777,7 +5773,8 @@ class DOMObserver {
5777
5773
  this.onScroll = this.onScroll.bind(this);
5778
5774
  if (typeof ResizeObserver == "function") {
5779
5775
  this.resize = new ResizeObserver(() => {
5780
- if (this.view.docView.lastUpdate < Date.now() - 75)
5776
+ var _a;
5777
+ if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
5781
5778
  this.onResize();
5782
5779
  });
5783
5780
  this.resize.observe(view.scrollDOM);
@@ -6489,17 +6486,19 @@ class EditorView {
6489
6486
  logException(this.state, e);
6490
6487
  }
6491
6488
  }
6492
- if (this.viewState.scrollTarget) {
6493
- this.docView.scrollIntoView(this.viewState.scrollTarget);
6494
- this.viewState.scrollTarget = null;
6495
- scrolled = true;
6496
- }
6497
- else {
6498
- let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
6499
- if (diff > 1 || diff < -1) {
6500
- this.scrollDOM.scrollTop += diff;
6489
+ if (this.viewState.editorHeight) {
6490
+ if (this.viewState.scrollTarget) {
6491
+ this.docView.scrollIntoView(this.viewState.scrollTarget);
6492
+ this.viewState.scrollTarget = null;
6501
6493
  scrolled = true;
6502
6494
  }
6495
+ else {
6496
+ let diff = this.viewState.lineBlockAt(refBlock.from).top - refBlock.top;
6497
+ if (diff > 1 || diff < -1) {
6498
+ this.scrollDOM.scrollTop += diff;
6499
+ scrolled = true;
6500
+ }
6501
+ }
6503
6502
  }
6504
6503
  if (redrawn)
6505
6504
  this.docView.updateSelection(true);
@@ -7319,7 +7318,8 @@ function drawSelection(config = {}) {
7319
7318
  return [
7320
7319
  selectionConfig.of(config),
7321
7320
  drawSelectionPlugin,
7322
- hideNativeSelection
7321
+ hideNativeSelection,
7322
+ nativeSelectionHidden.of(true)
7323
7323
  ];
7324
7324
  }
7325
7325
  class Piece {
@@ -7905,7 +7905,8 @@ const plugin = /*@__PURE__*/ViewPlugin.fromClass(class {
7905
7905
  this.attrs = { style: "padding-bottom: 1000px" };
7906
7906
  }
7907
7907
  update(update) {
7908
- let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
7908
+ let { view } = update;
7909
+ let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
7909
7910
  if (height != this.height) {
7910
7911
  this.height = height;
7911
7912
  this.attrs = { style: `padding-bottom: ${height}px` };
@@ -8007,7 +8008,10 @@ function rectangleFor(state, a, b) {
8007
8008
  for (let i = startLine; i <= endLine; i++) {
8008
8009
  let line = state.doc.line(i);
8009
8010
  let start = findColumn(line.text, startCol, state.tabSize, true);
8010
- if (start > -1) {
8011
+ if (start < 0) {
8012
+ ranges.push(EditorSelection.cursor(line.to));
8013
+ }
8014
+ else {
8011
8015
  let end = findColumn(line.text, endCol, state.tabSize);
8012
8016
  ranges.push(EditorSelection.range(line.from + start, line.from + end));
8013
8017
  }
@@ -8100,6 +8104,9 @@ function crosshairCursor(options = {}) {
8100
8104
  keyup(e) {
8101
8105
  if (e.keyCode == code || !getter(e))
8102
8106
  this.set(false);
8107
+ },
8108
+ mousemove(e) {
8109
+ this.set(getter(e));
8103
8110
  }
8104
8111
  }
8105
8112
  });
@@ -8119,6 +8126,7 @@ class TooltipViewManager {
8119
8126
  this.tooltipViews = this.tooltips.map(createTooltipView);
8120
8127
  }
8121
8128
  update(update) {
8129
+ var _a;
8122
8130
  let input = update.state.facet(this.facet);
8123
8131
  let tooltips = input.filter(x => x);
8124
8132
  if (input === this.input) {
@@ -8147,8 +8155,10 @@ class TooltipViewManager {
8147
8155
  }
8148
8156
  }
8149
8157
  for (let t of this.tooltipViews)
8150
- if (tooltipViews.indexOf(t) < 0)
8158
+ if (tooltipViews.indexOf(t) < 0) {
8151
8159
  t.dom.remove();
8160
+ (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
8161
+ }
8152
8162
  this.input = input;
8153
8163
  this.tooltips = tooltips;
8154
8164
  this.tooltipViews = tooltipViews;
@@ -8267,11 +8277,13 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8267
8277
  return tooltipView;
8268
8278
  }
8269
8279
  destroy() {
8270
- var _a;
8280
+ var _a, _b;
8271
8281
  this.view.win.removeEventListener("resize", this.measureSoon);
8272
- for (let { dom } of this.manager.tooltipViews)
8273
- dom.remove();
8274
- (_a = this.intersectionObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
8282
+ for (let tooltipView of this.manager.tooltipViews) {
8283
+ tooltipView.dom.remove();
8284
+ (_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
8285
+ }
8286
+ (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
8275
8287
  clearTimeout(this.measureTimeout);
8276
8288
  }
8277
8289
  readMeasure() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.3.1",
3
+ "version": "6.4.1",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",