@codemirror/view 6.22.0 → 6.22.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,17 @@
1
+ ## 6.22.1 (2023-11-27)
2
+
3
+ ### Bug fixes
4
+
5
+ Call widget `destroy` methods when the entire editor is destroyed or reset.
6
+
7
+ Work around an issue on Safari on macOS Sonoma that made the native cursor visible even when `drawSelection` is enabled.
8
+
9
+ Fix an issue where, on some browsers, the screenreader announced text ended up in the printed document.
10
+
11
+ 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.
12
+
13
+ Fix an issue where hover tooltips could close when moving the mouse onto them due to mouse position rounding issues.
14
+
1
15
  ## 6.22.0 (2023-11-03)
2
16
 
3
17
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -503,7 +503,7 @@ class ContentView {
503
503
  this.markDirty();
504
504
  for (let i = from; i < to; i++) {
505
505
  let child = this.children[i];
506
- if (child.parent == this)
506
+ if (child.parent == this && children.indexOf(child) < 0)
507
507
  child.destroy();
508
508
  }
509
509
  this.children.splice(from, to - from, ...children);
@@ -540,6 +540,8 @@ class ContentView {
540
540
  // number > 0 when after its position.
541
541
  getSide() { return 0; }
542
542
  destroy() {
543
+ for (let child of this.children)
544
+ child.destroy();
543
545
  this.parent = null;
544
546
  }
545
547
  }
@@ -5881,6 +5883,13 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5881
5883
  "&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
5882
5884
  display: "block"
5883
5885
  },
5886
+ ".cm-announced": {
5887
+ position: "fixed",
5888
+ top: "-10000px"
5889
+ },
5890
+ "@media print": {
5891
+ ".cm-announced": { display: "none" }
5892
+ },
5884
5893
  "&light .cm-activeLine": { backgroundColor: "#cceeff44" },
5885
5894
  "&dark .cm-activeLine": { backgroundColor: "#99eeff33" },
5886
5895
  "&light .cm-specialChar": { color: "red" },
@@ -6929,7 +6938,7 @@ class EditorView {
6929
6938
  this.scrollDOM.className = "cm-scroller";
6930
6939
  this.scrollDOM.appendChild(this.contentDOM);
6931
6940
  this.announceDOM = document.createElement("div");
6932
- this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6941
+ this.announceDOM.className = "cm-announced";
6933
6942
  this.announceDOM.setAttribute("aria-live", "polite");
6934
6943
  this.dom = document.createElement("div");
6935
6944
  this.dom.appendChild(this.announceDOM);
@@ -7095,6 +7104,7 @@ class EditorView {
7095
7104
  this.pluginMap.clear();
7096
7105
  for (let plugin of this.plugins)
7097
7106
  plugin.update(this);
7107
+ this.docView.destroy();
7098
7108
  this.docView = new DocView(this);
7099
7109
  this.inputState.ensureHandlers(this.plugins);
7100
7110
  this.mountStyles();
@@ -7627,6 +7637,7 @@ class EditorView {
7627
7637
  plugin.destroy(this);
7628
7638
  this.plugins = [];
7629
7639
  this.inputState.destroy();
7640
+ this.docView.destroy();
7630
7641
  this.dom.remove();
7631
7642
  this.observer.destroy();
7632
7643
  if (this.measureScheduled > -1)
@@ -8487,8 +8498,10 @@ const themeSpec = {
8487
8498
  "&::selection": { backgroundColor: "transparent !important" }
8488
8499
  }
8489
8500
  };
8490
- if (CanHidePrimary)
8501
+ if (CanHidePrimary) {
8491
8502
  themeSpec[".cm-line"].caretColor = "transparent !important";
8503
+ themeSpec[".cm-content"] = { caretColor: "transparent !important" };
8504
+ }
8492
8505
  const hideNativeSelection = state.Prec.highest(EditorView.theme(themeSpec));
8493
8506
 
8494
8507
  const setDropCursorPos = state.StateEffect.define({
@@ -9545,7 +9558,7 @@ const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
9545
9558
  return null;
9546
9559
  return {
9547
9560
  pos: Math.min(...tooltips.map(t => t.pos)),
9548
- end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
9561
+ end: Math.max(...tooltips.map(t => { var _a; return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos; })),
9549
9562
  create: HoverTooltipHost.create,
9550
9563
  above: tooltips[0].above,
9551
9564
  arrow: tooltips.some(t => t.arrow),
@@ -9625,14 +9638,19 @@ class HoverPlugin {
9625
9638
  view.dispatch({ effects: this.setHover.of(open) });
9626
9639
  }
9627
9640
  }
9641
+ get tooltip() {
9642
+ let plugin = this.view.plugin(tooltipPlugin);
9643
+ let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
9644
+ return index > -1 ? plugin.manager.tooltipViews[index] : null;
9645
+ }
9628
9646
  mousemove(event) {
9629
9647
  var _a;
9630
9648
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9631
9649
  if (this.hoverTimeout < 0)
9632
9650
  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;
9651
+ let { active, tooltip } = this;
9652
+ if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9653
+ let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9636
9654
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9637
9655
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9638
9656
  this.view.dispatch({ effects: this.setHover.of(null) });
@@ -9640,11 +9658,26 @@ class HoverPlugin {
9640
9658
  }
9641
9659
  }
9642
9660
  }
9643
- mouseleave(e) {
9661
+ mouseleave(event) {
9644
9662
  clearTimeout(this.hoverTimeout);
9645
9663
  this.hoverTimeout = -1;
9646
- if (this.active && !isInTooltip(e.relatedTarget))
9647
- this.view.dispatch({ effects: this.setHover.of(null) });
9664
+ let { active } = this;
9665
+ if (active) {
9666
+ let { tooltip } = this;
9667
+ let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9668
+ if (!inTooltip)
9669
+ this.view.dispatch({ effects: this.setHover.of(null) });
9670
+ else
9671
+ this.watchTooltipLeave(tooltip.dom);
9672
+ }
9673
+ }
9674
+ watchTooltipLeave(tooltip) {
9675
+ let watch = (event) => {
9676
+ tooltip.removeEventListener("mouseleave", watch);
9677
+ if (this.active && !this.view.dom.contains(event.relatedTarget))
9678
+ this.view.dispatch({ effects: this.setHover.of(null) });
9679
+ };
9680
+ tooltip.addEventListener("mouseleave", watch);
9648
9681
  }
9649
9682
  destroy() {
9650
9683
  clearTimeout(this.hoverTimeout);
@@ -9652,11 +9685,11 @@ class HoverPlugin {
9652
9685
  this.view.dom.removeEventListener("mousemove", this.mousemove);
9653
9686
  }
9654
9687
  }
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;
9688
+ const tooltipMargin = 4;
9689
+ function isInTooltip(tooltip, event) {
9690
+ let rect = tooltip.getBoundingClientRect();
9691
+ return event.clientX >= rect.left - tooltipMargin && event.clientX <= rect.right + tooltipMargin &&
9692
+ event.clientY >= rect.top - tooltipMargin && event.clientY <= rect.bottom + tooltipMargin;
9660
9693
  }
9661
9694
  function isOverRange(view, from, to, x, y, margin) {
9662
9695
  let rect = view.scrollDOM.getBoundingClientRect();
package/dist/index.js CHANGED
@@ -501,7 +501,7 @@ class ContentView {
501
501
  this.markDirty();
502
502
  for (let i = from; i < to; i++) {
503
503
  let child = this.children[i];
504
- if (child.parent == this)
504
+ if (child.parent == this && children.indexOf(child) < 0)
505
505
  child.destroy();
506
506
  }
507
507
  this.children.splice(from, to - from, ...children);
@@ -538,6 +538,8 @@ class ContentView {
538
538
  // number > 0 when after its position.
539
539
  getSide() { return 0; }
540
540
  destroy() {
541
+ for (let child of this.children)
542
+ child.destroy();
541
543
  this.parent = null;
542
544
  }
543
545
  }
@@ -5876,6 +5878,13 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5876
5878
  "&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
5877
5879
  display: "block"
5878
5880
  },
5881
+ ".cm-announced": {
5882
+ position: "fixed",
5883
+ top: "-10000px"
5884
+ },
5885
+ "@media print": {
5886
+ ".cm-announced": { display: "none" }
5887
+ },
5879
5888
  "&light .cm-activeLine": { backgroundColor: "#cceeff44" },
5880
5889
  "&dark .cm-activeLine": { backgroundColor: "#99eeff33" },
5881
5890
  "&light .cm-specialChar": { color: "red" },
@@ -6924,7 +6933,7 @@ class EditorView {
6924
6933
  this.scrollDOM.className = "cm-scroller";
6925
6934
  this.scrollDOM.appendChild(this.contentDOM);
6926
6935
  this.announceDOM = document.createElement("div");
6927
- this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6936
+ this.announceDOM.className = "cm-announced";
6928
6937
  this.announceDOM.setAttribute("aria-live", "polite");
6929
6938
  this.dom = document.createElement("div");
6930
6939
  this.dom.appendChild(this.announceDOM);
@@ -7090,6 +7099,7 @@ class EditorView {
7090
7099
  this.pluginMap.clear();
7091
7100
  for (let plugin of this.plugins)
7092
7101
  plugin.update(this);
7102
+ this.docView.destroy();
7093
7103
  this.docView = new DocView(this);
7094
7104
  this.inputState.ensureHandlers(this.plugins);
7095
7105
  this.mountStyles();
@@ -7622,6 +7632,7 @@ class EditorView {
7622
7632
  plugin.destroy(this);
7623
7633
  this.plugins = [];
7624
7634
  this.inputState.destroy();
7635
+ this.docView.destroy();
7625
7636
  this.dom.remove();
7626
7637
  this.observer.destroy();
7627
7638
  if (this.measureScheduled > -1)
@@ -8482,8 +8493,10 @@ const themeSpec = {
8482
8493
  "&::selection": { backgroundColor: "transparent !important" }
8483
8494
  }
8484
8495
  };
8485
- if (CanHidePrimary)
8496
+ if (CanHidePrimary) {
8486
8497
  themeSpec[".cm-line"].caretColor = "transparent !important";
8498
+ themeSpec[".cm-content"] = { caretColor: "transparent !important" };
8499
+ }
8487
8500
  const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
8488
8501
 
8489
8502
  const setDropCursorPos = /*@__PURE__*/StateEffect.define({
@@ -9540,7 +9553,7 @@ const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip]
9540
9553
  return null;
9541
9554
  return {
9542
9555
  pos: Math.min(...tooltips.map(t => t.pos)),
9543
- end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
9556
+ end: Math.max(...tooltips.map(t => { var _a; return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos; })),
9544
9557
  create: HoverTooltipHost.create,
9545
9558
  above: tooltips[0].above,
9546
9559
  arrow: tooltips.some(t => t.arrow),
@@ -9620,14 +9633,19 @@ class HoverPlugin {
9620
9633
  view.dispatch({ effects: this.setHover.of(open) });
9621
9634
  }
9622
9635
  }
9636
+ get tooltip() {
9637
+ let plugin = this.view.plugin(tooltipPlugin);
9638
+ let index = plugin ? plugin.manager.tooltips.findIndex(t => t.create == HoverTooltipHost.create) : -1;
9639
+ return index > -1 ? plugin.manager.tooltipViews[index] : null;
9640
+ }
9623
9641
  mousemove(event) {
9624
9642
  var _a;
9625
9643
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9626
9644
  if (this.hoverTimeout < 0)
9627
9645
  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;
9646
+ let { active, tooltip } = this;
9647
+ if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9648
+ let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9631
9649
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9632
9650
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9633
9651
  this.view.dispatch({ effects: this.setHover.of(null) });
@@ -9635,11 +9653,26 @@ class HoverPlugin {
9635
9653
  }
9636
9654
  }
9637
9655
  }
9638
- mouseleave(e) {
9656
+ mouseleave(event) {
9639
9657
  clearTimeout(this.hoverTimeout);
9640
9658
  this.hoverTimeout = -1;
9641
- if (this.active && !isInTooltip(e.relatedTarget))
9642
- this.view.dispatch({ effects: this.setHover.of(null) });
9659
+ let { active } = this;
9660
+ if (active) {
9661
+ let { tooltip } = this;
9662
+ let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9663
+ if (!inTooltip)
9664
+ this.view.dispatch({ effects: this.setHover.of(null) });
9665
+ else
9666
+ this.watchTooltipLeave(tooltip.dom);
9667
+ }
9668
+ }
9669
+ watchTooltipLeave(tooltip) {
9670
+ let watch = (event) => {
9671
+ tooltip.removeEventListener("mouseleave", watch);
9672
+ if (this.active && !this.view.dom.contains(event.relatedTarget))
9673
+ this.view.dispatch({ effects: this.setHover.of(null) });
9674
+ };
9675
+ tooltip.addEventListener("mouseleave", watch);
9643
9676
  }
9644
9677
  destroy() {
9645
9678
  clearTimeout(this.hoverTimeout);
@@ -9647,11 +9680,11 @@ class HoverPlugin {
9647
9680
  this.view.dom.removeEventListener("mousemove", this.mousemove);
9648
9681
  }
9649
9682
  }
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;
9683
+ const tooltipMargin = 4;
9684
+ function isInTooltip(tooltip, event) {
9685
+ let rect = tooltip.getBoundingClientRect();
9686
+ return event.clientX >= rect.left - tooltipMargin && event.clientX <= rect.right + tooltipMargin &&
9687
+ event.clientY >= rect.top - tooltipMargin && event.clientY <= rect.bottom + tooltipMargin;
9655
9688
  }
9656
9689
  function isOverRange(view, from, to, x, y, margin) {
9657
9690
  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.1",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",