@codemirror/view 6.23.0 → 6.24.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,23 @@
1
+ ## 6.24.0 (2024-02-09)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue that broke context-menu select-all on Chrome when the viewport didn't cover the whole document.
6
+
7
+ Make sure tooltips are ordered by extension precedence in the DOM.
8
+
9
+ ### New features
10
+
11
+ Hover tooltip sources may now return multiple tooltips.
12
+
13
+ ## 6.23.1 (2024-01-24)
14
+
15
+ ### Bug fixes
16
+
17
+ Fix a bug that caused `Tooltip.above` to not take effect for tooltips that were already present when the tooltip plugin is initialized.
18
+
19
+ Automatically reposition tooltips when their size changes.
20
+
1
21
  ## 6.23.0 (2023-12-28)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -3193,6 +3193,7 @@ class BlockGapWidget extends WidgetType {
3193
3193
  }
3194
3194
  get editable() { return true; }
3195
3195
  get estimatedHeight() { return this.height; }
3196
+ ignoreEvent() { return false; }
3196
3197
  }
3197
3198
  function findCompositionNode(view, headPos) {
3198
3199
  let sel = view.observer.selectionRange;
@@ -6208,12 +6209,16 @@ class DOMChange {
6208
6209
  !contains(view.contentDOM, domSel.anchorNode)
6209
6210
  ? view.state.selection.main.anchor
6210
6211
  : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
6211
- // iOS will refuse to select the block gaps when doing select-all
6212
+ // iOS will refuse to select the block gaps when doing
6213
+ // select-all.
6214
+ // Chrome will put the selection *inside* them, confusing
6215
+ // posFromDOM
6212
6216
  let vp = view.viewport;
6213
- if (browser.ios && view.state.selection.main.empty && head != anchor &&
6217
+ if ((browser.ios || browser.chrome) && view.state.selection.main.empty && head != anchor &&
6214
6218
  (vp.from > 0 || vp.to < view.state.doc.length)) {
6215
- let offFrom = vp.from - Math.min(head, anchor), offTo = vp.to - Math.max(head, anchor);
6216
- if ((offFrom == 0 || offFrom == 1) && (offTo == 0 || offTo == -1)) {
6219
+ let from = Math.min(head, anchor), to = Math.max(head, anchor);
6220
+ let offFrom = vp.from - from, offTo = vp.to - to;
6221
+ if ((offFrom == 0 || offFrom == 1 || from == 0) && (offTo == 0 || offTo == -1 || to == view.state.doc.length)) {
6217
6222
  head = 0;
6218
6223
  anchor = view.state.doc.length;
6219
6224
  }
@@ -9179,12 +9184,14 @@ function crosshairCursor(options = {}) {
9179
9184
 
9180
9185
  const Outside = "-10000px";
9181
9186
  class TooltipViewManager {
9182
- constructor(view, facet, createTooltipView) {
9187
+ constructor(view, facet, createTooltipView, removeTooltipView) {
9183
9188
  this.facet = facet;
9184
9189
  this.createTooltipView = createTooltipView;
9190
+ this.removeTooltipView = removeTooltipView;
9185
9191
  this.input = view.state.facet(facet);
9186
9192
  this.tooltips = this.input.filter(t => t);
9187
- this.tooltipViews = this.tooltips.map(createTooltipView);
9193
+ let prev = null;
9194
+ this.tooltipViews = this.tooltips.map(t => prev = createTooltipView(t, prev));
9188
9195
  }
9189
9196
  update(update, above) {
9190
9197
  var _a;
@@ -9207,7 +9214,7 @@ class TooltipViewManager {
9207
9214
  known = i;
9208
9215
  }
9209
9216
  if (known < 0) {
9210
- tooltipViews[i] = this.createTooltipView(tip);
9217
+ tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
9211
9218
  if (newAbove)
9212
9219
  newAbove[i] = !!tip.above;
9213
9220
  }
@@ -9221,7 +9228,7 @@ class TooltipViewManager {
9221
9228
  }
9222
9229
  for (let t of this.tooltipViews)
9223
9230
  if (tooltipViews.indexOf(t) < 0) {
9224
- t.dom.remove();
9231
+ this.removeTooltipView(t);
9225
9232
  (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
9226
9233
  }
9227
9234
  if (above) {
@@ -9269,7 +9276,13 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
9269
9276
  this.classes = view.themeClasses;
9270
9277
  this.createContainer();
9271
9278
  this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
9272
- this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
9279
+ this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
9280
+ this.manager = new TooltipViewManager(view, showTooltip, (t, p) => this.createTooltip(t, p), t => {
9281
+ if (this.resizeObserver)
9282
+ this.resizeObserver.unobserve(t.dom);
9283
+ t.dom.remove();
9284
+ });
9285
+ this.above = this.manager.tooltips.map(t => !!t.above);
9273
9286
  this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
9274
9287
  if (Date.now() > this.lastTransaction - 50 &&
9275
9288
  entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
@@ -9333,24 +9346,27 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
9333
9346
  if (shouldMeasure)
9334
9347
  this.maybeMeasure();
9335
9348
  }
9336
- createTooltip(tooltip) {
9349
+ createTooltip(tooltip, prev) {
9337
9350
  let tooltipView = tooltip.create(this.view);
9351
+ let before = prev ? prev.dom : null;
9338
9352
  tooltipView.dom.classList.add("cm-tooltip");
9339
9353
  if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
9340
9354
  let arrow = document.createElement("div");
9341
9355
  arrow.className = "cm-tooltip-arrow";
9342
- tooltipView.dom.appendChild(arrow);
9356
+ tooltipView.dom.insertBefore(arrow, before);
9343
9357
  }
9344
9358
  tooltipView.dom.style.position = this.position;
9345
9359
  tooltipView.dom.style.top = Outside;
9346
9360
  tooltipView.dom.style.left = "0px";
9347
- this.container.appendChild(tooltipView.dom);
9361
+ this.container.insertBefore(tooltipView.dom, before);
9348
9362
  if (tooltipView.mount)
9349
9363
  tooltipView.mount(this.view);
9364
+ if (this.resizeObserver)
9365
+ this.resizeObserver.observe(tooltipView.dom);
9350
9366
  return tooltipView;
9351
9367
  }
9352
9368
  destroy() {
9353
- var _a, _b;
9369
+ var _a, _b, _c;
9354
9370
  this.view.win.removeEventListener("resize", this.measureSoon);
9355
9371
  for (let tooltipView of this.manager.tooltipViews) {
9356
9372
  tooltipView.dom.remove();
@@ -9358,7 +9374,8 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
9358
9374
  }
9359
9375
  if (this.parent)
9360
9376
  this.container.remove();
9361
- (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
9377
+ (_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
9378
+ (_c = this.intersectionObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
9362
9379
  clearTimeout(this.measureTimeout);
9363
9380
  }
9364
9381
  readMeasure() {
@@ -9561,7 +9578,9 @@ Facet to which an extension can add a value to show a tooltip.
9561
9578
  const showTooltip = state.Facet.define({
9562
9579
  enables: [tooltipPlugin, baseTheme]
9563
9580
  });
9564
- const showHoverTooltip = state.Facet.define();
9581
+ const showHoverTooltip = state.Facet.define({
9582
+ combine: inputs => inputs.reduce((a, i) => a.concat(i), [])
9583
+ });
9565
9584
  class HoverTooltipHost {
9566
9585
  // Needs to be static so that host tooltip instances always match
9567
9586
  static create(view) {
@@ -9572,12 +9591,12 @@ class HoverTooltipHost {
9572
9591
  this.mounted = false;
9573
9592
  this.dom = document.createElement("div");
9574
9593
  this.dom.classList.add("cm-tooltip-hover");
9575
- this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
9594
+ this.manager = new TooltipViewManager(view, showHoverTooltip, (t, p) => this.createHostedView(t, p), t => t.dom.remove());
9576
9595
  }
9577
- createHostedView(tooltip) {
9596
+ createHostedView(tooltip, prev) {
9578
9597
  let hostedView = tooltip.create(this.view);
9579
9598
  hostedView.dom.classList.add("cm-tooltip-section");
9580
- this.dom.appendChild(hostedView.dom);
9599
+ this.dom.insertBefore(hostedView.dom, prev ? prev.dom.nextSibling : this.dom.firstChild);
9581
9600
  if (this.mounted && hostedView.mount)
9582
9601
  hostedView.mount(this.view);
9583
9602
  return hostedView;
@@ -9622,7 +9641,7 @@ class HoverTooltipHost {
9622
9641
  get resize() { return this.passProp("resize"); }
9623
9642
  }
9624
9643
  const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
9625
- let tooltips = state.facet(showHoverTooltip).filter(t => t);
9644
+ let tooltips = state.facet(showHoverTooltip);
9626
9645
  if (tooltips.length === 0)
9627
9646
  return null;
9628
9647
  return {
@@ -9660,7 +9679,7 @@ class HoverPlugin {
9660
9679
  }
9661
9680
  checkHover() {
9662
9681
  this.hoverTimeout = -1;
9663
- if (this.active)
9682
+ if (this.active.length)
9664
9683
  return;
9665
9684
  let hovered = Date.now() - this.lastMove.time;
9666
9685
  if (hovered < this.hoverTime)
@@ -9698,13 +9717,13 @@ class HoverPlugin {
9698
9717
  open.then(result => {
9699
9718
  if (this.pending == pending) {
9700
9719
  this.pending = null;
9701
- if (result)
9702
- view.dispatch({ effects: this.setHover.of(result) });
9720
+ if (result && !(Array.isArray(result) && !result.length))
9721
+ view.dispatch({ effects: this.setHover.of(Array.isArray(result) ? result : [result]) });
9703
9722
  }
9704
9723
  }, e => logException(view.state, e, "hover tooltip"));
9705
9724
  }
9706
- else if (open) {
9707
- view.dispatch({ effects: this.setHover.of(open) });
9725
+ else if (open && !(Array.isArray(open) && !open.length)) {
9726
+ view.dispatch({ effects: this.setHover.of(Array.isArray(open) ? open : [open]) });
9708
9727
  }
9709
9728
  }
9710
9729
  get tooltip() {
@@ -9713,16 +9732,16 @@ class HoverPlugin {
9713
9732
  return index > -1 ? plugin.manager.tooltipViews[index] : null;
9714
9733
  }
9715
9734
  mousemove(event) {
9716
- var _a;
9735
+ var _a, _b;
9717
9736
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9718
9737
  if (this.hoverTimeout < 0)
9719
9738
  this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
9720
9739
  let { active, tooltip } = this;
9721
- if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9722
- let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9740
+ if (active.length && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9741
+ let { pos } = active[0] || this.pending, end = (_b = (_a = active[0]) === null || _a === void 0 ? void 0 : _a.end) !== null && _b !== void 0 ? _b : pos;
9723
9742
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9724
9743
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9725
- this.view.dispatch({ effects: this.setHover.of(null) });
9744
+ this.view.dispatch({ effects: this.setHover.of([]) });
9726
9745
  this.pending = null;
9727
9746
  }
9728
9747
  }
@@ -9731,11 +9750,11 @@ class HoverPlugin {
9731
9750
  clearTimeout(this.hoverTimeout);
9732
9751
  this.hoverTimeout = -1;
9733
9752
  let { active } = this;
9734
- if (active) {
9753
+ if (active.length) {
9735
9754
  let { tooltip } = this;
9736
9755
  let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9737
9756
  if (!inTooltip)
9738
- this.view.dispatch({ effects: this.setHover.of(null) });
9757
+ this.view.dispatch({ effects: this.setHover.of([]) });
9739
9758
  else
9740
9759
  this.watchTooltipLeave(tooltip.dom);
9741
9760
  }
@@ -9743,8 +9762,8 @@ class HoverPlugin {
9743
9762
  watchTooltipLeave(tooltip) {
9744
9763
  let watch = (event) => {
9745
9764
  tooltip.removeEventListener("mouseleave", watch);
9746
- if (this.active && !this.view.dom.contains(event.relatedTarget))
9747
- this.view.dispatch({ effects: this.setHover.of(null) });
9765
+ if (this.active.length && !this.view.dom.contains(event.relatedTarget))
9766
+ this.view.dispatch({ effects: this.setHover.of([]) });
9748
9767
  };
9749
9768
  tooltip.addEventListener("mouseleave", watch);
9750
9769
  }
@@ -9784,26 +9803,30 @@ range to be "merged" together without overlapping.
9784
9803
  function hoverTooltip(source, options = {}) {
9785
9804
  let setHover = state.StateEffect.define();
9786
9805
  let hoverState = state.StateField.define({
9787
- create() { return null; },
9806
+ create() { return []; },
9788
9807
  update(value, tr) {
9789
- if (value && (options.hideOnChange && (tr.docChanged || tr.selection) ||
9790
- options.hideOn && options.hideOn(tr, value)))
9791
- return null;
9792
- if (value && tr.docChanged) {
9793
- let newPos = tr.changes.mapPos(value.pos, -1, state.MapMode.TrackDel);
9794
- if (newPos == null)
9795
- return null;
9796
- let copy = Object.assign(Object.create(null), value);
9797
- copy.pos = newPos;
9798
- if (value.end != null)
9799
- copy.end = tr.changes.mapPos(value.end);
9800
- value = copy;
9808
+ if (value.length) {
9809
+ if (options.hideOnChange && (tr.docChanged || tr.selection))
9810
+ value = [];
9811
+ else if (options.hideOn)
9812
+ value = value.filter(v => !options.hideOn(tr, v));
9813
+ if (tr.docChanged) {
9814
+ for (let tooltip of value) {
9815
+ let newPos = tr.changes.mapPos(tooltip.pos, -1, state.MapMode.TrackDel);
9816
+ if (newPos != null) {
9817
+ let copy = Object.assign(Object.create(null), tooltip);
9818
+ copy.pos = newPos;
9819
+ if (copy.end != null)
9820
+ copy.end = tr.changes.mapPos(copy.end);
9821
+ }
9822
+ }
9823
+ }
9801
9824
  }
9802
9825
  for (let effect of tr.effects) {
9803
9826
  if (effect.is(setHover))
9804
9827
  value = effect.value;
9805
9828
  if (effect.is(closeHoverTooltipEffect))
9806
- value = null;
9829
+ value = [];
9807
9830
  }
9808
9831
  return value;
9809
9832
  },
package/dist/index.d.cts CHANGED
@@ -1889,6 +1889,7 @@ interface TooltipView {
1889
1889
  Facet to which an extension can add a value to show a tooltip.
1890
1890
  */
1891
1891
  declare const showTooltip: Facet<Tooltip | null, readonly (Tooltip | null)[]>;
1892
+ type HoverSource = (view: EditorView, pos: number, side: -1 | 1) => Tooltip | readonly Tooltip[] | null | Promise<Tooltip | readonly Tooltip[] | null>;
1892
1893
  /**
1893
1894
  Set up a hover tooltip, which shows up when the pointer hovers
1894
1895
  over ranges of text. The callback is called when the mouse hovers
@@ -1902,7 +1903,7 @@ Note that all hover tooltips are hosted within a single tooltip
1902
1903
  container element. This allows multiple tooltips over the same
1903
1904
  range to be "merged" together without overlapping.
1904
1905
  */
1905
- declare function hoverTooltip(source: (view: EditorView, pos: number, side: -1 | 1) => Tooltip | null | Promise<Tooltip | null>, options?: {
1906
+ declare function hoverTooltip(source: HoverSource, options?: {
1906
1907
  /**
1907
1908
  Controls whether a transaction hides the tooltip. The default
1908
1909
  is to not hide.
package/dist/index.d.ts CHANGED
@@ -1889,6 +1889,7 @@ interface TooltipView {
1889
1889
  Facet to which an extension can add a value to show a tooltip.
1890
1890
  */
1891
1891
  declare const showTooltip: Facet<Tooltip | null, readonly (Tooltip | null)[]>;
1892
+ type HoverSource = (view: EditorView, pos: number, side: -1 | 1) => Tooltip | readonly Tooltip[] | null | Promise<Tooltip | readonly Tooltip[] | null>;
1892
1893
  /**
1893
1894
  Set up a hover tooltip, which shows up when the pointer hovers
1894
1895
  over ranges of text. The callback is called when the mouse hovers
@@ -1902,7 +1903,7 @@ Note that all hover tooltips are hosted within a single tooltip
1902
1903
  container element. This allows multiple tooltips over the same
1903
1904
  range to be "merged" together without overlapping.
1904
1905
  */
1905
- declare function hoverTooltip(source: (view: EditorView, pos: number, side: -1 | 1) => Tooltip | null | Promise<Tooltip | null>, options?: {
1906
+ declare function hoverTooltip(source: HoverSource, options?: {
1906
1907
  /**
1907
1908
  Controls whether a transaction hides the tooltip. The default
1908
1909
  is to not hide.
package/dist/index.js CHANGED
@@ -3189,6 +3189,7 @@ class BlockGapWidget extends WidgetType {
3189
3189
  }
3190
3190
  get editable() { return true; }
3191
3191
  get estimatedHeight() { return this.height; }
3192
+ ignoreEvent() { return false; }
3192
3193
  }
3193
3194
  function findCompositionNode(view, headPos) {
3194
3195
  let sel = view.observer.selectionRange;
@@ -6203,12 +6204,16 @@ class DOMChange {
6203
6204
  !contains(view.contentDOM, domSel.anchorNode)
6204
6205
  ? view.state.selection.main.anchor
6205
6206
  : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
6206
- // iOS will refuse to select the block gaps when doing select-all
6207
+ // iOS will refuse to select the block gaps when doing
6208
+ // select-all.
6209
+ // Chrome will put the selection *inside* them, confusing
6210
+ // posFromDOM
6207
6211
  let vp = view.viewport;
6208
- if (browser.ios && view.state.selection.main.empty && head != anchor &&
6212
+ if ((browser.ios || browser.chrome) && view.state.selection.main.empty && head != anchor &&
6209
6213
  (vp.from > 0 || vp.to < view.state.doc.length)) {
6210
- let offFrom = vp.from - Math.min(head, anchor), offTo = vp.to - Math.max(head, anchor);
6211
- if ((offFrom == 0 || offFrom == 1) && (offTo == 0 || offTo == -1)) {
6214
+ let from = Math.min(head, anchor), to = Math.max(head, anchor);
6215
+ let offFrom = vp.from - from, offTo = vp.to - to;
6216
+ if ((offFrom == 0 || offFrom == 1 || from == 0) && (offTo == 0 || offTo == -1 || to == view.state.doc.length)) {
6212
6217
  head = 0;
6213
6218
  anchor = view.state.doc.length;
6214
6219
  }
@@ -9174,12 +9179,14 @@ function crosshairCursor(options = {}) {
9174
9179
 
9175
9180
  const Outside = "-10000px";
9176
9181
  class TooltipViewManager {
9177
- constructor(view, facet, createTooltipView) {
9182
+ constructor(view, facet, createTooltipView, removeTooltipView) {
9178
9183
  this.facet = facet;
9179
9184
  this.createTooltipView = createTooltipView;
9185
+ this.removeTooltipView = removeTooltipView;
9180
9186
  this.input = view.state.facet(facet);
9181
9187
  this.tooltips = this.input.filter(t => t);
9182
- this.tooltipViews = this.tooltips.map(createTooltipView);
9188
+ let prev = null;
9189
+ this.tooltipViews = this.tooltips.map(t => prev = createTooltipView(t, prev));
9183
9190
  }
9184
9191
  update(update, above) {
9185
9192
  var _a;
@@ -9202,7 +9209,7 @@ class TooltipViewManager {
9202
9209
  known = i;
9203
9210
  }
9204
9211
  if (known < 0) {
9205
- tooltipViews[i] = this.createTooltipView(tip);
9212
+ tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
9206
9213
  if (newAbove)
9207
9214
  newAbove[i] = !!tip.above;
9208
9215
  }
@@ -9216,7 +9223,7 @@ class TooltipViewManager {
9216
9223
  }
9217
9224
  for (let t of this.tooltipViews)
9218
9225
  if (tooltipViews.indexOf(t) < 0) {
9219
- t.dom.remove();
9226
+ this.removeTooltipView(t);
9220
9227
  (_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
9221
9228
  }
9222
9229
  if (above) {
@@ -9264,7 +9271,13 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9264
9271
  this.classes = view.themeClasses;
9265
9272
  this.createContainer();
9266
9273
  this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
9267
- this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
9274
+ this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
9275
+ this.manager = new TooltipViewManager(view, showTooltip, (t, p) => this.createTooltip(t, p), t => {
9276
+ if (this.resizeObserver)
9277
+ this.resizeObserver.unobserve(t.dom);
9278
+ t.dom.remove();
9279
+ });
9280
+ this.above = this.manager.tooltips.map(t => !!t.above);
9268
9281
  this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
9269
9282
  if (Date.now() > this.lastTransaction - 50 &&
9270
9283
  entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
@@ -9328,24 +9341,27 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9328
9341
  if (shouldMeasure)
9329
9342
  this.maybeMeasure();
9330
9343
  }
9331
- createTooltip(tooltip) {
9344
+ createTooltip(tooltip, prev) {
9332
9345
  let tooltipView = tooltip.create(this.view);
9346
+ let before = prev ? prev.dom : null;
9333
9347
  tooltipView.dom.classList.add("cm-tooltip");
9334
9348
  if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
9335
9349
  let arrow = document.createElement("div");
9336
9350
  arrow.className = "cm-tooltip-arrow";
9337
- tooltipView.dom.appendChild(arrow);
9351
+ tooltipView.dom.insertBefore(arrow, before);
9338
9352
  }
9339
9353
  tooltipView.dom.style.position = this.position;
9340
9354
  tooltipView.dom.style.top = Outside;
9341
9355
  tooltipView.dom.style.left = "0px";
9342
- this.container.appendChild(tooltipView.dom);
9356
+ this.container.insertBefore(tooltipView.dom, before);
9343
9357
  if (tooltipView.mount)
9344
9358
  tooltipView.mount(this.view);
9359
+ if (this.resizeObserver)
9360
+ this.resizeObserver.observe(tooltipView.dom);
9345
9361
  return tooltipView;
9346
9362
  }
9347
9363
  destroy() {
9348
- var _a, _b;
9364
+ var _a, _b, _c;
9349
9365
  this.view.win.removeEventListener("resize", this.measureSoon);
9350
9366
  for (let tooltipView of this.manager.tooltipViews) {
9351
9367
  tooltipView.dom.remove();
@@ -9353,7 +9369,8 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9353
9369
  }
9354
9370
  if (this.parent)
9355
9371
  this.container.remove();
9356
- (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
9372
+ (_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
9373
+ (_c = this.intersectionObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
9357
9374
  clearTimeout(this.measureTimeout);
9358
9375
  }
9359
9376
  readMeasure() {
@@ -9556,7 +9573,9 @@ Facet to which an extension can add a value to show a tooltip.
9556
9573
  const showTooltip = /*@__PURE__*/Facet.define({
9557
9574
  enables: [tooltipPlugin, baseTheme]
9558
9575
  });
9559
- const showHoverTooltip = /*@__PURE__*/Facet.define();
9576
+ const showHoverTooltip = /*@__PURE__*/Facet.define({
9577
+ combine: inputs => inputs.reduce((a, i) => a.concat(i), [])
9578
+ });
9560
9579
  class HoverTooltipHost {
9561
9580
  // Needs to be static so that host tooltip instances always match
9562
9581
  static create(view) {
@@ -9567,12 +9586,12 @@ class HoverTooltipHost {
9567
9586
  this.mounted = false;
9568
9587
  this.dom = document.createElement("div");
9569
9588
  this.dom.classList.add("cm-tooltip-hover");
9570
- this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
9589
+ this.manager = new TooltipViewManager(view, showHoverTooltip, (t, p) => this.createHostedView(t, p), t => t.dom.remove());
9571
9590
  }
9572
- createHostedView(tooltip) {
9591
+ createHostedView(tooltip, prev) {
9573
9592
  let hostedView = tooltip.create(this.view);
9574
9593
  hostedView.dom.classList.add("cm-tooltip-section");
9575
- this.dom.appendChild(hostedView.dom);
9594
+ this.dom.insertBefore(hostedView.dom, prev ? prev.dom.nextSibling : this.dom.firstChild);
9576
9595
  if (this.mounted && hostedView.mount)
9577
9596
  hostedView.mount(this.view);
9578
9597
  return hostedView;
@@ -9617,7 +9636,7 @@ class HoverTooltipHost {
9617
9636
  get resize() { return this.passProp("resize"); }
9618
9637
  }
9619
9638
  const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => {
9620
- let tooltips = state.facet(showHoverTooltip).filter(t => t);
9639
+ let tooltips = state.facet(showHoverTooltip);
9621
9640
  if (tooltips.length === 0)
9622
9641
  return null;
9623
9642
  return {
@@ -9655,7 +9674,7 @@ class HoverPlugin {
9655
9674
  }
9656
9675
  checkHover() {
9657
9676
  this.hoverTimeout = -1;
9658
- if (this.active)
9677
+ if (this.active.length)
9659
9678
  return;
9660
9679
  let hovered = Date.now() - this.lastMove.time;
9661
9680
  if (hovered < this.hoverTime)
@@ -9693,13 +9712,13 @@ class HoverPlugin {
9693
9712
  open.then(result => {
9694
9713
  if (this.pending == pending) {
9695
9714
  this.pending = null;
9696
- if (result)
9697
- view.dispatch({ effects: this.setHover.of(result) });
9715
+ if (result && !(Array.isArray(result) && !result.length))
9716
+ view.dispatch({ effects: this.setHover.of(Array.isArray(result) ? result : [result]) });
9698
9717
  }
9699
9718
  }, e => logException(view.state, e, "hover tooltip"));
9700
9719
  }
9701
- else if (open) {
9702
- view.dispatch({ effects: this.setHover.of(open) });
9720
+ else if (open && !(Array.isArray(open) && !open.length)) {
9721
+ view.dispatch({ effects: this.setHover.of(Array.isArray(open) ? open : [open]) });
9703
9722
  }
9704
9723
  }
9705
9724
  get tooltip() {
@@ -9708,16 +9727,16 @@ class HoverPlugin {
9708
9727
  return index > -1 ? plugin.manager.tooltipViews[index] : null;
9709
9728
  }
9710
9729
  mousemove(event) {
9711
- var _a;
9730
+ var _a, _b;
9712
9731
  this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
9713
9732
  if (this.hoverTimeout < 0)
9714
9733
  this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
9715
9734
  let { active, tooltip } = this;
9716
- if (active && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9717
- let { pos } = active || this.pending, end = (_a = active === null || active === void 0 ? void 0 : active.end) !== null && _a !== void 0 ? _a : pos;
9735
+ if (active.length && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
9736
+ let { pos } = active[0] || this.pending, end = (_b = (_a = active[0]) === null || _a === void 0 ? void 0 : _a.end) !== null && _b !== void 0 ? _b : pos;
9718
9737
  if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
9719
9738
  : !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
9720
- this.view.dispatch({ effects: this.setHover.of(null) });
9739
+ this.view.dispatch({ effects: this.setHover.of([]) });
9721
9740
  this.pending = null;
9722
9741
  }
9723
9742
  }
@@ -9726,11 +9745,11 @@ class HoverPlugin {
9726
9745
  clearTimeout(this.hoverTimeout);
9727
9746
  this.hoverTimeout = -1;
9728
9747
  let { active } = this;
9729
- if (active) {
9748
+ if (active.length) {
9730
9749
  let { tooltip } = this;
9731
9750
  let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
9732
9751
  if (!inTooltip)
9733
- this.view.dispatch({ effects: this.setHover.of(null) });
9752
+ this.view.dispatch({ effects: this.setHover.of([]) });
9734
9753
  else
9735
9754
  this.watchTooltipLeave(tooltip.dom);
9736
9755
  }
@@ -9738,8 +9757,8 @@ class HoverPlugin {
9738
9757
  watchTooltipLeave(tooltip) {
9739
9758
  let watch = (event) => {
9740
9759
  tooltip.removeEventListener("mouseleave", watch);
9741
- if (this.active && !this.view.dom.contains(event.relatedTarget))
9742
- this.view.dispatch({ effects: this.setHover.of(null) });
9760
+ if (this.active.length && !this.view.dom.contains(event.relatedTarget))
9761
+ this.view.dispatch({ effects: this.setHover.of([]) });
9743
9762
  };
9744
9763
  tooltip.addEventListener("mouseleave", watch);
9745
9764
  }
@@ -9779,26 +9798,30 @@ range to be "merged" together without overlapping.
9779
9798
  function hoverTooltip(source, options = {}) {
9780
9799
  let setHover = StateEffect.define();
9781
9800
  let hoverState = StateField.define({
9782
- create() { return null; },
9801
+ create() { return []; },
9783
9802
  update(value, tr) {
9784
- if (value && (options.hideOnChange && (tr.docChanged || tr.selection) ||
9785
- options.hideOn && options.hideOn(tr, value)))
9786
- return null;
9787
- if (value && tr.docChanged) {
9788
- let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel);
9789
- if (newPos == null)
9790
- return null;
9791
- let copy = Object.assign(Object.create(null), value);
9792
- copy.pos = newPos;
9793
- if (value.end != null)
9794
- copy.end = tr.changes.mapPos(value.end);
9795
- value = copy;
9803
+ if (value.length) {
9804
+ if (options.hideOnChange && (tr.docChanged || tr.selection))
9805
+ value = [];
9806
+ else if (options.hideOn)
9807
+ value = value.filter(v => !options.hideOn(tr, v));
9808
+ if (tr.docChanged) {
9809
+ for (let tooltip of value) {
9810
+ let newPos = tr.changes.mapPos(tooltip.pos, -1, MapMode.TrackDel);
9811
+ if (newPos != null) {
9812
+ let copy = Object.assign(Object.create(null), tooltip);
9813
+ copy.pos = newPos;
9814
+ if (copy.end != null)
9815
+ copy.end = tr.changes.mapPos(copy.end);
9816
+ }
9817
+ }
9818
+ }
9796
9819
  }
9797
9820
  for (let effect of tr.effects) {
9798
9821
  if (effect.is(setHover))
9799
9822
  value = effect.value;
9800
9823
  if (effect.is(closeHoverTooltipEffect))
9801
- value = null;
9824
+ value = [];
9802
9825
  }
9803
9826
  return value;
9804
9827
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.23.0",
3
+ "version": "6.24.0",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",