@codemirror/view 6.22.0 → 6.22.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,25 @@
1
+ ## 6.22.2 (2023-12-08)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue in the bidirectional motion that could cause the cursor to get stuck in a loop when a zero-width non-joiner char was placed on a direction boundary.
6
+
7
+ Fix a bug that corrupts the editor's internal view tree data structure on some types of edits, putting the editor in a broken state.
8
+
9
+ ## 6.22.1 (2023-11-27)
10
+
11
+ ### Bug fixes
12
+
13
+ Call widget `destroy` methods when the entire editor is destroyed or reset.
14
+
15
+ Work around an issue on Safari on macOS Sonoma that made the native cursor visible even when `drawSelection` is enabled.
16
+
17
+ Fix an issue where, on some browsers, the screenreader announced text ended up in the printed document.
18
+
19
+ Fix a bug where a hover tooltip could stick around even though the pointer was no longer on the editor when it was moved out over the tooltip.
20
+
21
+ Fix an issue where hover tooltips could close when moving the mouse onto them due to mouse position rounding issues.
22
+
1
23
  ## 6.22.0 (2023-11-03)
2
24
 
3
25
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -96,6 +96,15 @@ function windowRect(win) {
96
96
  return { left: 0, right: win.innerWidth,
97
97
  top: 0, bottom: win.innerHeight };
98
98
  }
99
+ function getScale(elt, rect) {
100
+ let scaleX = rect.width / elt.offsetWidth;
101
+ let scaleY = rect.height / elt.offsetHeight;
102
+ if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1)
103
+ scaleX = 1;
104
+ if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1)
105
+ scaleY = 1;
106
+ return { scaleX, scaleY };
107
+ }
99
108
  function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
100
109
  let doc = dom.ownerDocument, win = doc.defaultView || window;
101
110
  for (let cur = dom, stop = false; cur && !stop;) {
@@ -113,8 +122,7 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
113
122
  continue;
114
123
  }
115
124
  let rect = cur.getBoundingClientRect();
116
- scaleX = rect.width / cur.offsetWidth;
117
- scaleY = rect.height / cur.offsetHeight;
125
+ ({ scaleX, scaleY } = getScale(cur, rect));
118
126
  // Make sure scrollbar width isn't included in the rectangle
119
127
  bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
120
128
  top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
@@ -503,7 +511,7 @@ class ContentView {
503
511
  this.markDirty();
504
512
  for (let i = from; i < to; i++) {
505
513
  let child = this.children[i];
506
- if (child.parent == this)
514
+ if (child.parent == this && children.indexOf(child) < 0)
507
515
  child.destroy();
508
516
  }
509
517
  this.children.splice(from, to - from, ...children);
@@ -540,6 +548,9 @@ class ContentView {
540
548
  // number > 0 when after its position.
541
549
  getSide() { return 0; }
542
550
  destroy() {
551
+ for (let child of this.children)
552
+ if (child.parent == this)
553
+ child.destroy();
543
554
  this.parent = null;
544
555
  }
545
556
  }
@@ -776,7 +787,7 @@ class MarkView extends ContentView {
776
787
  if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
777
788
  (from && openStart <= 0) || (to < this.length && openEnd <= 0)))
778
789
  return false;
779
- mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1);
790
+ mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart - 1, openEnd - 1);
780
791
  this.markDirty();
781
792
  return true;
782
793
  }
@@ -1112,7 +1123,7 @@ class LineView extends ContentView {
1112
1123
  }
1113
1124
  if (hasStart)
1114
1125
  this.setDeco(source ? source.attrs : null);
1115
- mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
1126
+ mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart, openEnd);
1116
1127
  return true;
1117
1128
  }
1118
1129
  split(at) {
@@ -2183,9 +2194,8 @@ function charType(ch) {
2183
2194
  0x590 <= ch && ch <= 0x5f4 ? 2 /* T.R */ :
2184
2195
  0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] :
2185
2196
  0x6ee <= ch && ch <= 0x8ac ? 4 /* T.AL */ :
2186
- 0x2000 <= ch && ch <= 0x200b ? 256 /* T.NI */ :
2187
- 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ :
2188
- ch == 0x200c ? 256 /* T.NI */ : 1 /* T.L */;
2197
+ 0x2000 <= ch && ch <= 0x200c ? 256 /* T.NI */ :
2198
+ 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ : 1 /* T.L */;
2189
2199
  }
2190
2200
  const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/;
2191
2201
  /**
@@ -2606,7 +2616,7 @@ function moveVisually(line, order, dir, start, forward) {
2606
2616
  let indexForward = forward == (span.dir == dir);
2607
2617
  let nextIndex = state.findClusterBreak(line.text, startIndex, indexForward);
2608
2618
  movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
2609
- if (nextIndex != span.side(forward, dir))
2619
+ if (nextIndex > span.from && nextIndex < span.to)
2610
2620
  return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
2611
2621
  let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
2612
2622
  if (!nextSpan && span.level != dir)
@@ -5360,12 +5370,7 @@ class ViewState {
5360
5370
  this.mustMeasureContent = false;
5361
5371
  let result = 0, bias = 0;
5362
5372
  if (domRect.width && domRect.height) {
5363
- let scaleX = domRect.width / dom.offsetWidth;
5364
- let scaleY = domRect.height / dom.offsetHeight;
5365
- if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(domRect.width - dom.offsetWidth) < 1)
5366
- scaleX = 1;
5367
- if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(domRect.height - dom.offsetHeight) < 1)
5368
- scaleY = 1;
5373
+ let { scaleX, scaleY } = getScale(dom, domRect);
5369
5374
  if (this.scaleX != scaleX || this.scaleY != scaleY) {
5370
5375
  this.scaleX = scaleX;
5371
5376
  this.scaleY = scaleY;
@@ -5881,6 +5886,13 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5881
5886
  "&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
5882
5887
  display: "block"
5883
5888
  },
5889
+ ".cm-announced": {
5890
+ position: "fixed",
5891
+ top: "-10000px"
5892
+ },
5893
+ "@media print": {
5894
+ ".cm-announced": { display: "none" }
5895
+ },
5884
5896
  "&light .cm-activeLine": { backgroundColor: "#cceeff44" },
5885
5897
  "&dark .cm-activeLine": { backgroundColor: "#99eeff33" },
5886
5898
  "&light .cm-specialChar": { color: "red" },
@@ -6929,7 +6941,7 @@ class EditorView {
6929
6941
  this.scrollDOM.className = "cm-scroller";
6930
6942
  this.scrollDOM.appendChild(this.contentDOM);
6931
6943
  this.announceDOM = document.createElement("div");
6932
- this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6944
+ this.announceDOM.className = "cm-announced";
6933
6945
  this.announceDOM.setAttribute("aria-live", "polite");
6934
6946
  this.dom = document.createElement("div");
6935
6947
  this.dom.appendChild(this.announceDOM);
@@ -7095,6 +7107,7 @@ class EditorView {
7095
7107
  this.pluginMap.clear();
7096
7108
  for (let plugin of this.plugins)
7097
7109
  plugin.update(this);
7110
+ this.docView.destroy();
7098
7111
  this.docView = new DocView(this);
7099
7112
  this.inputState.ensureHandlers(this.plugins);
7100
7113
  this.mountStyles();
@@ -7227,6 +7240,7 @@ class EditorView {
7227
7240
  if (this.viewState.scrollTarget) {
7228
7241
  this.docView.scrollIntoView(this.viewState.scrollTarget);
7229
7242
  this.viewState.scrollTarget = null;
7243
+ scrollAnchorHeight = -1;
7230
7244
  continue;
7231
7245
  }
7232
7246
  else {
@@ -7627,6 +7641,7 @@ class EditorView {
7627
7641
  plugin.destroy(this);
7628
7642
  this.plugins = [];
7629
7643
  this.inputState.destroy();
7644
+ this.docView.destroy();
7630
7645
  this.dom.remove();
7631
7646
  this.observer.destroy();
7632
7647
  if (this.measureScheduled > -1)
@@ -8487,8 +8502,10 @@ const themeSpec = {
8487
8502
  "&::selection": { backgroundColor: "transparent !important" }
8488
8503
  }
8489
8504
  };
8490
- if (CanHidePrimary)
8505
+ if (CanHidePrimary) {
8491
8506
  themeSpec[".cm-line"].caretColor = "transparent !important";
8507
+ themeSpec[".cm-content"] = { caretColor: "transparent !important" };
8508
+ }
8492
8509
  const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
8493
8510
 
8494
8511
  const setDropCursorPos = state.StateEffect.define({
@@ -9545,7 +9562,7 @@ const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
9545
9562
  return null;
9546
9563
  return {
9547
9564
  pos: Math.min(...tooltips.map(t => t.pos)),
9548
- end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
9565
+ end: Math.max(...tooltips.map(t => { var _a; return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos; })),
9549
9566
  create: HoverTooltipHost.create,
9550
9567
  above: tooltips[0].above,
9551
9568
  arrow: tooltips.some(t => t.arrow),
@@ -9625,14 +9642,19 @@ class HoverPlugin {
9625
9642
  view.dispatch({ effects: this.setHover.of(open) });
9626
9643
  }
9627
9644
  }
9645
+ get tooltip() {
9646
+ let plugin = this.view.plugin(tooltipPlugin);
9647
+ let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
9648
+ return index > -1 ? plugin.manager.tooltipViews[index] : null;
9649
+ }
9628
9650
  mousemove(event) {
9629
9651
  var _a;
9630
9652
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9631
9653
  if (this.hoverTimeout < 0)
9632
9654
  this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
9633
- let tooltip = this.active;
9634
- if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
9635
- let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
9655
+ let { active, tooltip } = this;
9656
+ if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9657
+ let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9636
9658
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9637
9659
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9638
9660
  this.view.dispatch({ effects: this.setHover.of(null) });
@@ -9640,11 +9662,26 @@ class HoverPlugin {
9640
9662
  }
9641
9663
  }
9642
9664
  }
9643
- mouseleave(e) {
9665
+ mouseleave(event) {
9644
9666
  clearTimeout(this.hoverTimeout);
9645
9667
  this.hoverTimeout = -1;
9646
- if (this.active && !isInTooltip(e.relatedTarget))
9647
- this.view.dispatch({ effects: this.setHover.of(null) });
9668
+ let { active } = this;
9669
+ if (active) {
9670
+ let { tooltip } = this;
9671
+ let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9672
+ if (!inTooltip)
9673
+ this.view.dispatch({ effects: this.setHover.of(null) });
9674
+ else
9675
+ this.watchTooltipLeave(tooltip.dom);
9676
+ }
9677
+ }
9678
+ watchTooltipLeave(tooltip) {
9679
+ let watch = (event) => {
9680
+ tooltip.removeEventListener("mouseleave", watch);
9681
+ if (this.active && !this.view.dom.contains(event.relatedTarget))
9682
+ this.view.dispatch({ effects: this.setHover.of(null) });
9683
+ };
9684
+ tooltip.addEventListener("mouseleave", watch);
9648
9685
  }
9649
9686
  destroy() {
9650
9687
  clearTimeout(this.hoverTimeout);
@@ -9652,11 +9689,11 @@ class HoverPlugin {
9652
9689
  this.view.dom.removeEventListener("mousemove", this.mousemove);
9653
9690
  }
9654
9691
  }
9655
- function isInTooltip(elt) {
9656
- for (let cur = elt; cur; cur = cur.parentNode)
9657
- if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
9658
- return true;
9659
- return false;
9692
+ const tooltipMargin = 4;
9693
+ function isInTooltip(tooltip, event) {
9694
+ let rect = tooltip.getBoundingClientRect();
9695
+ return event.clientX >= rect.left - tooltipMargin && event.clientX <= rect.right + tooltipMargin &&
9696
+ event.clientY >= rect.top - tooltipMargin && event.clientY <= rect.bottom + tooltipMargin;
9660
9697
  }
9661
9698
  function isOverRange(view, from, to, x, y, margin) {
9662
9699
  let rect = view.scrollDOM.getBoundingClientRect();
package/dist/index.js CHANGED
@@ -94,6 +94,15 @@ function windowRect(win) {
94
94
  return { left: 0, right: win.innerWidth,
95
95
  top: 0, bottom: win.innerHeight };
96
96
  }
97
+ function getScale(elt, rect) {
98
+ let scaleX = rect.width / elt.offsetWidth;
99
+ let scaleY = rect.height / elt.offsetHeight;
100
+ if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1)
101
+ scaleX = 1;
102
+ if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1)
103
+ scaleY = 1;
104
+ return { scaleX, scaleY };
105
+ }
97
106
  function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
98
107
  let doc = dom.ownerDocument, win = doc.defaultView || window;
99
108
  for (let cur = dom, stop = false; cur && !stop;) {
@@ -111,8 +120,7 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
111
120
  continue;
112
121
  }
113
122
  let rect = cur.getBoundingClientRect();
114
- scaleX = rect.width / cur.offsetWidth;
115
- scaleY = rect.height / cur.offsetHeight;
123
+ ({ scaleX, scaleY } = getScale(cur, rect));
116
124
  // Make sure scrollbar width isn't included in the rectangle
117
125
  bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
118
126
  top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
@@ -501,7 +509,7 @@ class ContentView {
501
509
  this.markDirty();
502
510
  for (let i = from; i < to; i++) {
503
511
  let child = this.children[i];
504
- if (child.parent == this)
512
+ if (child.parent == this && children.indexOf(child) < 0)
505
513
  child.destroy();
506
514
  }
507
515
  this.children.splice(from, to - from, ...children);
@@ -538,6 +546,9 @@ class ContentView {
538
546
  // number > 0 when after its position.
539
547
  getSide() { return 0; }
540
548
  destroy() {
549
+ for (let child of this.children)
550
+ if (child.parent == this)
551
+ child.destroy();
541
552
  this.parent = null;
542
553
  }
543
554
  }
@@ -774,7 +785,7 @@ class MarkView extends ContentView {
774
785
  if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
775
786
  (from && openStart <= 0) || (to < this.length && openEnd <= 0)))
776
787
  return false;
777
- mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1);
788
+ mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart - 1, openEnd - 1);
778
789
  this.markDirty();
779
790
  return true;
780
791
  }
@@ -1110,7 +1121,7 @@ class LineView extends ContentView {
1110
1121
  }
1111
1122
  if (hasStart)
1112
1123
  this.setDeco(source ? source.attrs : null);
1113
- mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
1124
+ mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart, openEnd);
1114
1125
  return true;
1115
1126
  }
1116
1127
  split(at) {
@@ -2179,9 +2190,8 @@ function charType(ch) {
2179
2190
  0x590 <= ch && ch <= 0x5f4 ? 2 /* T.R */ :
2180
2191
  0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] :
2181
2192
  0x6ee <= ch && ch <= 0x8ac ? 4 /* T.AL */ :
2182
- 0x2000 <= ch && ch <= 0x200b ? 256 /* T.NI */ :
2183
- 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ :
2184
- ch == 0x200c ? 256 /* T.NI */ : 1 /* T.L */;
2193
+ 0x2000 <= ch && ch <= 0x200c ? 256 /* T.NI */ :
2194
+ 0xfb50 <= ch && ch <= 0xfdff ? 4 /* T.AL */ : 1 /* T.L */;
2185
2195
  }
2186
2196
  const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/;
2187
2197
  /**
@@ -2602,7 +2612,7 @@ function moveVisually(line, order, dir, start, forward) {
2602
2612
  let indexForward = forward == (span.dir == dir);
2603
2613
  let nextIndex = findClusterBreak(line.text, startIndex, indexForward);
2604
2614
  movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
2605
- if (nextIndex != span.side(forward, dir))
2615
+ if (nextIndex > span.from && nextIndex < span.to)
2606
2616
  return EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
2607
2617
  let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
2608
2618
  if (!nextSpan && span.level != dir)
@@ -5355,12 +5365,7 @@ class ViewState {
5355
5365
  this.mustMeasureContent = false;
5356
5366
  let result = 0, bias = 0;
5357
5367
  if (domRect.width && domRect.height) {
5358
- let scaleX = domRect.width / dom.offsetWidth;
5359
- let scaleY = domRect.height / dom.offsetHeight;
5360
- if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(domRect.width - dom.offsetWidth) < 1)
5361
- scaleX = 1;
5362
- if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(domRect.height - dom.offsetHeight) < 1)
5363
- scaleY = 1;
5368
+ let { scaleX, scaleY } = getScale(dom, domRect);
5364
5369
  if (this.scaleX != scaleX || this.scaleY != scaleY) {
5365
5370
  this.scaleX = scaleX;
5366
5371
  this.scaleY = scaleY;
@@ -5876,6 +5881,13 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5876
5881
  "&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
5877
5882
  display: "block"
5878
5883
  },
5884
+ ".cm-announced": {
5885
+ position: "fixed",
5886
+ top: "-10000px"
5887
+ },
5888
+ "@media print": {
5889
+ ".cm-announced": { display: "none" }
5890
+ },
5879
5891
  "&light .cm-activeLine": { backgroundColor: "#cceeff44" },
5880
5892
  "&dark .cm-activeLine": { backgroundColor: "#99eeff33" },
5881
5893
  "&light .cm-specialChar": { color: "red" },
@@ -6924,7 +6936,7 @@ class EditorView {
6924
6936
  this.scrollDOM.className = "cm-scroller";
6925
6937
  this.scrollDOM.appendChild(this.contentDOM);
6926
6938
  this.announceDOM = document.createElement("div");
6927
- this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6939
+ this.announceDOM.className = "cm-announced";
6928
6940
  this.announceDOM.setAttribute("aria-live", "polite");
6929
6941
  this.dom = document.createElement("div");
6930
6942
  this.dom.appendChild(this.announceDOM);
@@ -7090,6 +7102,7 @@ class EditorView {
7090
7102
  this.pluginMap.clear();
7091
7103
  for (let plugin of this.plugins)
7092
7104
  plugin.update(this);
7105
+ this.docView.destroy();
7093
7106
  this.docView = new DocView(this);
7094
7107
  this.inputState.ensureHandlers(this.plugins);
7095
7108
  this.mountStyles();
@@ -7222,6 +7235,7 @@ class EditorView {
7222
7235
  if (this.viewState.scrollTarget) {
7223
7236
  this.docView.scrollIntoView(this.viewState.scrollTarget);
7224
7237
  this.viewState.scrollTarget = null;
7238
+ scrollAnchorHeight = -1;
7225
7239
  continue;
7226
7240
  }
7227
7241
  else {
@@ -7622,6 +7636,7 @@ class EditorView {
7622
7636
  plugin.destroy(this);
7623
7637
  this.plugins = [];
7624
7638
  this.inputState.destroy();
7639
+ this.docView.destroy();
7625
7640
  this.dom.remove();
7626
7641
  this.observer.destroy();
7627
7642
  if (this.measureScheduled > -1)
@@ -8482,8 +8497,10 @@ const themeSpec = {
8482
8497
  "&::selection": { backgroundColor: "transparent !important" }
8483
8498
  }
8484
8499
  };
8485
- if (CanHidePrimary)
8500
+ if (CanHidePrimary) {
8486
8501
  themeSpec[".cm-line"].caretColor = "transparent !important";
8502
+ themeSpec[".cm-content"] = { caretColor: "transparent !important" };
8503
+ }
8487
8504
  const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
8488
8505
 
8489
8506
  const setDropCursorPos = /*@__PURE__*/StateEffect.define({
@@ -9540,7 +9557,7 @@ const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip]
9540
9557
  return null;
9541
9558
  return {
9542
9559
  pos: Math.min(...tooltips.map(t => t.pos)),
9543
- end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
9560
+ end: Math.max(...tooltips.map(t => { var _a; return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos; })),
9544
9561
  create: HoverTooltipHost.create,
9545
9562
  above: tooltips[0].above,
9546
9563
  arrow: tooltips.some(t => t.arrow),
@@ -9620,14 +9637,19 @@ class HoverPlugin {
9620
9637
  view.dispatch({ effects: this.setHover.of(open) });
9621
9638
  }
9622
9639
  }
9640
+ get tooltip() {
9641
+ let plugin = this.view.plugin(tooltipPlugin);
9642
+ let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
9643
+ return index > -1 ? plugin.manager.tooltipViews[index] : null;
9644
+ }
9623
9645
  mousemove(event) {
9624
9646
  var _a;
9625
9647
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9626
9648
  if (this.hoverTimeout < 0)
9627
9649
  this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
9628
- let tooltip = this.active;
9629
- if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
9630
- let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
9650
+ let { active, tooltip } = this;
9651
+ if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9652
+ let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9631
9653
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9632
9654
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9633
9655
  this.view.dispatch({ effects: this.setHover.of(null) });
@@ -9635,11 +9657,26 @@ class HoverPlugin {
9635
9657
  }
9636
9658
  }
9637
9659
  }
9638
- mouseleave(e) {
9660
+ mouseleave(event) {
9639
9661
  clearTimeout(this.hoverTimeout);
9640
9662
  this.hoverTimeout = -1;
9641
- if (this.active && !isInTooltip(e.relatedTarget))
9642
- this.view.dispatch({ effects: this.setHover.of(null) });
9663
+ let { active } = this;
9664
+ if (active) {
9665
+ let { tooltip } = this;
9666
+ let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9667
+ if (!inTooltip)
9668
+ this.view.dispatch({ effects: this.setHover.of(null) });
9669
+ else
9670
+ this.watchTooltipLeave(tooltip.dom);
9671
+ }
9672
+ }
9673
+ watchTooltipLeave(tooltip) {
9674
+ let watch = (event) => {
9675
+ tooltip.removeEventListener("mouseleave", watch);
9676
+ if (this.active && !this.view.dom.contains(event.relatedTarget))
9677
+ this.view.dispatch({ effects: this.setHover.of(null) });
9678
+ };
9679
+ tooltip.addEventListener("mouseleave", watch);
9643
9680
  }
9644
9681
  destroy() {
9645
9682
  clearTimeout(this.hoverTimeout);
@@ -9647,11 +9684,11 @@ class HoverPlugin {
9647
9684
  this.view.dom.removeEventListener("mousemove", this.mousemove);
9648
9685
  }
9649
9686
  }
9650
- function isInTooltip(elt) {
9651
- for (let cur = elt; cur; cur = cur.parentNode)
9652
- if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
9653
- return true;
9654
- return false;
9687
+ const tooltipMargin = 4;
9688
+ function isInTooltip(tooltip, event) {
9689
+ let rect = tooltip.getBoundingClientRect();
9690
+ return event.clientX >= rect.left - tooltipMargin && event.clientX <= rect.right + tooltipMargin &&
9691
+ event.clientY >= rect.top - tooltipMargin && event.clientY <= rect.bottom + tooltipMargin;
9655
9692
  }
9656
9693
  function isOverRange(view, from, to, x, y, margin) {
9657
9694
  let rect = view.scrollDOM.getBoundingClientRect();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.22.0",
3
+ "version": "6.22.2",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",