@codemirror/view 6.5.1 → 6.7.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/dist/index.js CHANGED
@@ -1598,6 +1598,7 @@ class ContentBuilder {
1598
1598
  this.curLine = null;
1599
1599
  this.breakAtStart = 0;
1600
1600
  this.pendingBuffer = 0 /* Buf.No */;
1601
+ this.bufferMarks = [];
1601
1602
  // Set to false directly after a widget that covers the position after it
1602
1603
  this.atCursorPos = true;
1603
1604
  this.openStart = -1;
@@ -1620,20 +1621,20 @@ class ContentBuilder {
1620
1621
  }
1621
1622
  return this.curLine;
1622
1623
  }
1623
- flushBuffer(active) {
1624
+ flushBuffer(active = this.bufferMarks) {
1624
1625
  if (this.pendingBuffer) {
1625
1626
  this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
1626
1627
  this.pendingBuffer = 0 /* Buf.No */;
1627
1628
  }
1628
1629
  }
1629
1630
  addBlockWidget(view) {
1630
- this.flushBuffer([]);
1631
+ this.flushBuffer();
1631
1632
  this.curLine = null;
1632
1633
  this.content.push(view);
1633
1634
  }
1634
1635
  finish(openEnd) {
1635
- if (!openEnd)
1636
- this.flushBuffer([]);
1636
+ if (this.pendingBuffer && openEnd <= this.bufferMarks.length)
1637
+ this.flushBuffer();
1637
1638
  else
1638
1639
  this.pendingBuffer = 0 /* Buf.No */;
1639
1640
  if (!this.posCovered())
@@ -1653,8 +1654,9 @@ class ContentBuilder {
1653
1654
  this.content[this.content.length - 1].breakAfter = 1;
1654
1655
  else
1655
1656
  this.breakAtStart = 1;
1656
- this.flushBuffer([]);
1657
+ this.flushBuffer();
1657
1658
  this.curLine = null;
1659
+ this.atCursorPos = true;
1658
1660
  length--;
1659
1661
  continue;
1660
1662
  }
@@ -1696,7 +1698,7 @@ class ContentBuilder {
1696
1698
  else {
1697
1699
  let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
1698
1700
  let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
1699
- let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
1701
+ let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
1700
1702
  let line = this.getLine();
1701
1703
  if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
1702
1704
  this.pendingBuffer = 0 /* Buf.No */;
@@ -1707,7 +1709,9 @@ class ContentBuilder {
1707
1709
  }
1708
1710
  line.append(wrapMarks(view, active), openStart);
1709
1711
  this.atCursorPos = cursorAfter;
1710
- this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
1712
+ this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to || openStart > active.length ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
1713
+ if (this.pendingBuffer)
1714
+ this.bufferMarks = active.slice();
1711
1715
  }
1712
1716
  }
1713
1717
  else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
@@ -5284,7 +5288,6 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5284
5288
  margin: 0,
5285
5289
  flexGrow: 2,
5286
5290
  flexShrink: 0,
5287
- minHeight: "100%",
5288
5291
  display: "block",
5289
5292
  whiteSpace: "pre",
5290
5293
  wordWrap: "normal",
@@ -5306,14 +5309,13 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5306
5309
  "&dark .cm-content": { caretColor: "white" },
5307
5310
  ".cm-line": {
5308
5311
  display: "block",
5309
- padding: "0 2px 0 4px"
5310
- },
5311
- ".cm-selectionLayer": {
5312
- zIndex: -1,
5313
- contain: "size style"
5312
+ padding: "0 2px 0 6px"
5314
5313
  },
5315
- ".cm-selectionBackground": {
5316
- position: "absolute",
5314
+ ".cm-layer": {
5315
+ contain: "size style",
5316
+ "& > *": {
5317
+ position: "absolute"
5318
+ }
5317
5319
  },
5318
5320
  "&light .cm-selectionBackground": {
5319
5321
  background: "#d9d9d9"
@@ -5328,8 +5330,6 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5328
5330
  background: "#233"
5329
5331
  },
5330
5332
  ".cm-cursorLayer": {
5331
- zIndex: 100,
5332
- contain: "size style",
5333
5333
  pointerEvents: "none"
5334
5334
  },
5335
5335
  "&.cm-focused .cm-cursorLayer": {
@@ -5341,7 +5341,6 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5341
5341
  "@keyframes cm-blink": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
5342
5342
  "@keyframes cm-blink2": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
5343
5343
  ".cm-cursor, .cm-dropCursor": {
5344
- position: "absolute",
5345
5344
  borderLeft: "1.2px solid black",
5346
5345
  marginLeft: "-0.6px",
5347
5346
  pointerEvents: "none",
@@ -5435,6 +5434,21 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5435
5434
  display: "inline-block",
5436
5435
  verticalAlign: "top",
5437
5436
  },
5437
+ ".cm-highlightSpace:before": {
5438
+ content: "attr(data-display)",
5439
+ position: "absolute",
5440
+ pointerEvents: "none",
5441
+ color: "#888"
5442
+ },
5443
+ ".cm-highlightTab": {
5444
+ backgroundImage: `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20"><path stroke="%23888" stroke-width="1" fill="none" d="M1 10H196L190 5M190 15L196 10M197 4L197 16"/></svg>')`,
5445
+ backgroundSize: "auto 100%",
5446
+ backgroundPosition: "right 90%",
5447
+ backgroundRepeat: "no-repeat"
5448
+ },
5449
+ ".cm-trailingSpace": {
5450
+ backgroundColor: "#ff332255"
5451
+ },
5438
5452
  ".cm-button": {
5439
5453
  verticalAlign: "middle",
5440
5454
  color: "inherit",
@@ -5737,7 +5751,8 @@ class DOMObserver {
5737
5751
  this.lastChange = 0;
5738
5752
  this.scrollTargets = [];
5739
5753
  this.intersection = null;
5740
- this.resize = null;
5754
+ this.resizeScroll = null;
5755
+ this.resizeContent = null;
5741
5756
  this.intersecting = false;
5742
5757
  this.gapIntersection = null;
5743
5758
  this.gaps = [];
@@ -5775,12 +5790,14 @@ class DOMObserver {
5775
5790
  this.onPrint = this.onPrint.bind(this);
5776
5791
  this.onScroll = this.onScroll.bind(this);
5777
5792
  if (typeof ResizeObserver == "function") {
5778
- this.resize = new ResizeObserver(() => {
5793
+ this.resizeScroll = new ResizeObserver(() => {
5779
5794
  var _a;
5780
5795
  if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
5781
5796
  this.onResize();
5782
5797
  });
5783
- this.resize.observe(view.scrollDOM);
5798
+ this.resizeScroll.observe(view.scrollDOM);
5799
+ this.resizeContent = new ResizeObserver(() => this.view.requestMeasure());
5800
+ this.resizeContent.observe(view.contentDOM);
5784
5801
  }
5785
5802
  this.addWindowListeners(this.win = view.win);
5786
5803
  this.start();
@@ -6099,11 +6116,12 @@ class DOMObserver {
6099
6116
  win.document.removeEventListener("selectionchange", this.onSelectionChange);
6100
6117
  }
6101
6118
  destroy() {
6102
- var _a, _b, _c;
6119
+ var _a, _b, _c, _d;
6103
6120
  this.stop();
6104
6121
  (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
6105
6122
  (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
6106
- (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
6123
+ (_c = this.resizeScroll) === null || _c === void 0 ? void 0 : _c.disconnect();
6124
+ (_d = this.resizeContent) === null || _d === void 0 ? void 0 : _d.disconnect();
6107
6125
  for (let dom of this.scrollTargets)
6108
6126
  dom.removeEventListener("scroll", this.onScroll);
6109
6127
  this.removeWindowListeners(this.win);
@@ -6202,7 +6220,7 @@ class EditorView {
6202
6220
  this.scrollDOM.className = "cm-scroller";
6203
6221
  this.scrollDOM.appendChild(this.contentDOM);
6204
6222
  this.announceDOM = document.createElement("div");
6205
- this.announceDOM.style.cssText = "position: absolute; top: -10000px";
6223
+ this.announceDOM.style.cssText = "position: fixed; top: -10000px";
6206
6224
  this.announceDOM.setAttribute("aria-live", "polite");
6207
6225
  this.dom = document.createElement("div");
6208
6226
  this.dom.appendChild(this.announceDOM);
@@ -7287,51 +7305,21 @@ function runHandlers(map, event, view, scope) {
7287
7305
  return fallthrough;
7288
7306
  }
7289
7307
 
7290
- const CanHidePrimary = !browser.ios; // FIXME test IE
7291
- const selectionConfig = /*@__PURE__*/Facet.define({
7292
- combine(configs) {
7293
- return combineConfig(configs, {
7294
- cursorBlinkRate: 1200,
7295
- drawRangeCursor: true
7296
- }, {
7297
- cursorBlinkRate: (a, b) => Math.min(a, b),
7298
- drawRangeCursor: (a, b) => a || b
7299
- });
7300
- }
7301
- });
7302
7308
  /**
7303
- Returns an extension that hides the browser's native selection and
7304
- cursor, replacing the selection with a background behind the text
7305
- (with the `cm-selectionBackground` class), and the
7306
- cursors with elements overlaid over the code (using
7307
- `cm-cursor-primary` and `cm-cursor-secondary`).
7308
-
7309
- This allows the editor to display secondary selection ranges, and
7310
- tends to produce a type of selection more in line with that users
7311
- expect in a text editor (the native selection styling will often
7312
- leave gaps between lines and won't fill the horizontal space after
7313
- a line when the selection continues past it).
7314
-
7315
- It does have a performance cost, in that it requires an extra DOM
7316
- layout cycle for many updates (the selection is drawn based on DOM
7317
- layout information that's only available after laying out the
7318
- content).
7309
+ Implementation of [`LayerMarker`](https://codemirror.net/6/docs/ref/#view.LayerMarker) that creates
7310
+ a rectangle at a given set of coordinates.
7319
7311
  */
7320
- function drawSelection(config = {}) {
7321
- return [
7322
- selectionConfig.of(config),
7323
- drawSelectionPlugin,
7324
- hideNativeSelection,
7325
- nativeSelectionHidden.of(true)
7326
- ];
7327
- }
7328
- class Piece {
7329
- constructor(left, top, width, height, className) {
7312
+ class RectangleMarker {
7313
+ /**
7314
+ Create a marker with the given class and dimensions. If `width`
7315
+ is null, the DOM element will get no width style.
7316
+ */
7317
+ constructor(className, left, top, width, height) {
7318
+ this.className = className;
7330
7319
  this.left = left;
7331
7320
  this.top = top;
7332
7321
  this.width = width;
7333
7322
  this.height = height;
7334
- this.className = className;
7335
7323
  }
7336
7324
  draw() {
7337
7325
  let elt = document.createElement("div");
@@ -7339,10 +7327,16 @@ class Piece {
7339
7327
  this.adjust(elt);
7340
7328
  return elt;
7341
7329
  }
7330
+ update(elt, prev) {
7331
+ if (prev.className != this.className)
7332
+ return false;
7333
+ this.adjust(elt);
7334
+ return true;
7335
+ }
7342
7336
  adjust(elt) {
7343
7337
  elt.style.left = this.left + "px";
7344
7338
  elt.style.top = this.top + "px";
7345
- if (this.width >= 0)
7339
+ if (this.width != null)
7346
7340
  elt.style.width = this.width + "px";
7347
7341
  elt.style.height = this.height + "px";
7348
7342
  }
@@ -7350,82 +7344,26 @@ class Piece {
7350
7344
  return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height &&
7351
7345
  this.className == p.className;
7352
7346
  }
7353
- }
7354
- const drawSelectionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
7355
- constructor(view) {
7356
- this.view = view;
7357
- this.rangePieces = [];
7358
- this.cursors = [];
7359
- this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) };
7360
- this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div"));
7361
- this.selectionLayer.className = "cm-selectionLayer";
7362
- this.selectionLayer.setAttribute("aria-hidden", "true");
7363
- this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div"));
7364
- this.cursorLayer.className = "cm-cursorLayer";
7365
- this.cursorLayer.setAttribute("aria-hidden", "true");
7366
- view.requestMeasure(this.measureReq);
7367
- this.setBlinkRate();
7368
- }
7369
- setBlinkRate() {
7370
- this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms";
7371
- }
7372
- update(update) {
7373
- let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
7374
- if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged)
7375
- this.view.requestMeasure(this.measureReq);
7376
- if (update.transactions.some(tr => tr.scrollIntoView))
7377
- this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
7378
- if (confChanged)
7379
- this.setBlinkRate();
7380
- }
7381
- readPos() {
7382
- let { state } = this.view, conf = state.facet(selectionConfig);
7383
- let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b));
7384
- let cursors = [];
7385
- for (let r of state.selection.ranges) {
7386
- let prim = r == state.selection.main;
7387
- if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
7388
- let piece = measureCursor(this.view, r, prim);
7389
- if (piece)
7390
- cursors.push(piece);
7391
- }
7392
- }
7393
- return { rangePieces, cursors };
7394
- }
7395
- drawSel({ rangePieces, cursors }) {
7396
- if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) {
7397
- this.selectionLayer.textContent = "";
7398
- for (let p of rangePieces)
7399
- this.selectionLayer.appendChild(p.draw());
7400
- this.rangePieces = rangePieces;
7347
+ /**
7348
+ Create a set of rectangles for the given selection range,
7349
+ assigning them theclass`className`. Will create a single
7350
+ rectangle for empty ranges, and a set of selection-style
7351
+ rectangles covering the range's content (in a bidi-aware
7352
+ way) for non-empty ones.
7353
+ */
7354
+ static forRange(view, className, range) {
7355
+ if (range.empty) {
7356
+ let pos = view.coordsAtPos(range.head, range.assoc || 1);
7357
+ if (!pos)
7358
+ return [];
7359
+ let base = getBase(view);
7360
+ return [new RectangleMarker(className, pos.left - base.left, pos.top - base.top, null, pos.bottom - pos.top)];
7401
7361
  }
7402
- if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) {
7403
- let oldCursors = this.cursorLayer.children;
7404
- if (oldCursors.length !== cursors.length) {
7405
- this.cursorLayer.textContent = "";
7406
- for (const c of cursors)
7407
- this.cursorLayer.appendChild(c.draw());
7408
- }
7409
- else {
7410
- cursors.forEach((c, idx) => c.adjust(oldCursors[idx]));
7411
- }
7412
- this.cursors = cursors;
7362
+ else {
7363
+ return rectanglesForRange(view, className, range);
7413
7364
  }
7414
7365
  }
7415
- destroy() {
7416
- this.selectionLayer.remove();
7417
- this.cursorLayer.remove();
7418
- }
7419
- });
7420
- const themeSpec = {
7421
- ".cm-line": {
7422
- "& ::selection": { backgroundColor: "transparent !important" },
7423
- "&::selection": { backgroundColor: "transparent !important" }
7424
- }
7425
- };
7426
- if (CanHidePrimary)
7427
- themeSpec[".cm-line"].caretColor = "transparent !important";
7428
- const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
7366
+ }
7429
7367
  function getBase(view) {
7430
7368
  let rect = view.scrollDOM.getBoundingClientRect();
7431
7369
  let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
@@ -7446,7 +7384,7 @@ function blockAt(view, pos) {
7446
7384
  }
7447
7385
  return line;
7448
7386
  }
7449
- function measureRange(view, range) {
7387
+ function rectanglesForRange(view, className, range) {
7450
7388
  if (range.to <= view.viewport.from || range.from >= view.viewport.to)
7451
7389
  return [];
7452
7390
  let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
@@ -7478,7 +7416,7 @@ function measureRange(view, range) {
7478
7416
  return pieces(top).concat(between).concat(pieces(bottom));
7479
7417
  }
7480
7418
  function piece(left, top, right, bottom) {
7481
- return new Piece(left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */, "cm-selectionBackground");
7419
+ return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
7482
7420
  }
7483
7421
  function pieces({ top, bottom, horizontal }) {
7484
7422
  let pieces = [];
@@ -7530,13 +7468,174 @@ function measureRange(view, range) {
7530
7468
  return { top: y, bottom: y, horizontal: [] };
7531
7469
  }
7532
7470
  }
7533
- function measureCursor(view, cursor, primary) {
7534
- let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
7535
- if (!pos)
7536
- return null;
7537
- let base = getBase(view);
7538
- return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary");
7471
+ function sameMarker(a, b) {
7472
+ return a.constructor == b.constructor && a.eq(b);
7539
7473
  }
7474
+ class LayerView {
7475
+ constructor(view, layer) {
7476
+ this.view = view;
7477
+ this.layer = layer;
7478
+ this.drawn = [];
7479
+ this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
7480
+ this.dom = view.scrollDOM.appendChild(document.createElement("div"));
7481
+ this.dom.classList.add("cm-layer");
7482
+ if (layer.above)
7483
+ this.dom.classList.add("cm-layer-above");
7484
+ if (layer.class)
7485
+ this.dom.classList.add(layer.class);
7486
+ this.dom.setAttribute("aria-hidden", "true");
7487
+ this.setOrder(view.state);
7488
+ view.requestMeasure(this.measureReq);
7489
+ if (layer.mount)
7490
+ layer.mount(this.dom, view);
7491
+ }
7492
+ update(update) {
7493
+ if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
7494
+ this.setOrder(update.state);
7495
+ if (this.layer.update(update, this.dom) || update.geometryChanged)
7496
+ update.view.requestMeasure(this.measureReq);
7497
+ }
7498
+ setOrder(state) {
7499
+ let pos = 0, order = state.facet(layerOrder);
7500
+ while (pos < order.length && order[pos] != this.layer)
7501
+ pos++;
7502
+ this.dom.style.zIndex = String((this.layer.above ? 150 : -1) - pos);
7503
+ }
7504
+ measure() {
7505
+ return this.layer.markers(this.view);
7506
+ }
7507
+ draw(markers) {
7508
+ if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
7509
+ let old = this.dom.firstChild, oldI = 0;
7510
+ for (let marker of markers) {
7511
+ if (marker.update && old && marker.constructor && this.drawn[oldI].constructor &&
7512
+ marker.update(old, this.drawn[oldI])) {
7513
+ old = old.nextSibling;
7514
+ oldI++;
7515
+ }
7516
+ else {
7517
+ this.dom.insertBefore(marker.draw(), old);
7518
+ }
7519
+ }
7520
+ while (old) {
7521
+ let next = old.nextSibling;
7522
+ old.remove();
7523
+ old = next;
7524
+ }
7525
+ this.drawn = markers;
7526
+ }
7527
+ }
7528
+ destroy() {
7529
+ if (this.layer.destroy)
7530
+ this.layer.destroy(this.dom, this.view);
7531
+ this.dom.remove();
7532
+ }
7533
+ }
7534
+ const layerOrder = /*@__PURE__*/Facet.define();
7535
+ /**
7536
+ Define a layer.
7537
+ */
7538
+ function layer(config) {
7539
+ return [
7540
+ ViewPlugin.define(v => new LayerView(v, config)),
7541
+ layerOrder.of(config)
7542
+ ];
7543
+ }
7544
+
7545
+ const CanHidePrimary = !browser.ios; // FIXME test IE
7546
+ const selectionConfig = /*@__PURE__*/Facet.define({
7547
+ combine(configs) {
7548
+ return combineConfig(configs, {
7549
+ cursorBlinkRate: 1200,
7550
+ drawRangeCursor: true
7551
+ }, {
7552
+ cursorBlinkRate: (a, b) => Math.min(a, b),
7553
+ drawRangeCursor: (a, b) => a || b
7554
+ });
7555
+ }
7556
+ });
7557
+ /**
7558
+ Returns an extension that hides the browser's native selection and
7559
+ cursor, replacing the selection with a background behind the text
7560
+ (with the `cm-selectionBackground` class), and the
7561
+ cursors with elements overlaid over the code (using
7562
+ `cm-cursor-primary` and `cm-cursor-secondary`).
7563
+
7564
+ This allows the editor to display secondary selection ranges, and
7565
+ tends to produce a type of selection more in line with that users
7566
+ expect in a text editor (the native selection styling will often
7567
+ leave gaps between lines and won't fill the horizontal space after
7568
+ a line when the selection continues past it).
7569
+
7570
+ It does have a performance cost, in that it requires an extra DOM
7571
+ layout cycle for many updates (the selection is drawn based on DOM
7572
+ layout information that's only available after laying out the
7573
+ content).
7574
+ */
7575
+ function drawSelection(config = {}) {
7576
+ return [
7577
+ selectionConfig.of(config),
7578
+ cursorLayer,
7579
+ selectionLayer,
7580
+ hideNativeSelection,
7581
+ nativeSelectionHidden.of(true)
7582
+ ];
7583
+ }
7584
+ function configChanged(update) {
7585
+ return update.startState.facet(selectionConfig) != update.startState.facet(selectionConfig);
7586
+ }
7587
+ const cursorLayer = /*@__PURE__*/layer({
7588
+ above: true,
7589
+ markers(view) {
7590
+ let { state } = view, conf = state.facet(selectionConfig);
7591
+ let cursors = [];
7592
+ for (let r of state.selection.ranges) {
7593
+ let prim = r == state.selection.main;
7594
+ if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
7595
+ let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
7596
+ let cursor = r.empty ? r : EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
7597
+ for (let piece of RectangleMarker.forRange(view, className, cursor))
7598
+ cursors.push(piece);
7599
+ }
7600
+ }
7601
+ return cursors;
7602
+ },
7603
+ update(update, dom) {
7604
+ if (update.transactions.some(tr => tr.scrollIntoView))
7605
+ dom.style.animationName = dom.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
7606
+ let confChange = configChanged(update);
7607
+ if (confChange)
7608
+ setBlinkRate(update.state, dom);
7609
+ return update.docChanged || update.selectionSet || confChange;
7610
+ },
7611
+ mount(dom, view) {
7612
+ setBlinkRate(view.state, dom);
7613
+ },
7614
+ class: "cm-cursorLayer"
7615
+ });
7616
+ function setBlinkRate(state, dom) {
7617
+ dom.style.animationDuration = state.facet(selectionConfig).cursorBlinkRate + "ms";
7618
+ }
7619
+ const selectionLayer = /*@__PURE__*/layer({
7620
+ above: false,
7621
+ markers(view) {
7622
+ return view.state.selection.ranges.map(r => r.empty ? [] : RectangleMarker.forRange(view, "cm-selectionBackground", r))
7623
+ .reduce((a, b) => a.concat(b));
7624
+ },
7625
+ update(update, dom) {
7626
+ return update.docChanged || update.selectionSet || update.viewportChanged || configChanged(update);
7627
+ },
7628
+ class: "cm-selectionLayer"
7629
+ });
7630
+ const themeSpec = {
7631
+ ".cm-line": {
7632
+ "& ::selection": { backgroundColor: "transparent !important" },
7633
+ "&::selection": { backgroundColor: "transparent !important" }
7634
+ }
7635
+ };
7636
+ if (CanHidePrimary)
7637
+ themeSpec[".cm-line"].caretColor = "transparent !important";
7638
+ const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
7540
7639
 
7541
7640
  const setDropCursorPos = /*@__PURE__*/StateEffect.define({
7542
7641
  map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
@@ -8329,6 +8428,17 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8329
8428
  : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
8330
8429
  above == (space.bottom - pos.bottom > pos.top - space.top))
8331
8430
  above = !above;
8431
+ let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
8432
+ if (spaceVert < height && tView.resize !== false) {
8433
+ if (spaceVert < this.view.defaultLineHeight) {
8434
+ dom.style.top = Outside;
8435
+ continue;
8436
+ }
8437
+ dom.style.height = (height = spaceVert) + "px";
8438
+ }
8439
+ else if (dom.style.height) {
8440
+ dom.style.height = "";
8441
+ }
8332
8442
  let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
8333
8443
  let right = left + width;
8334
8444
  if (tView.overlap !== true)
@@ -8372,7 +8482,8 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8372
8482
  });
8373
8483
  const baseTheme = /*@__PURE__*/EditorView.baseTheme({
8374
8484
  ".cm-tooltip": {
8375
- zIndex: 100
8485
+ zIndex: 100,
8486
+ boxSizing: "border-box"
8376
8487
  },
8377
8488
  "&light .cm-tooltip": {
8378
8489
  border: "1px solid #bbb",
@@ -9291,9 +9402,60 @@ function highlightActiveLineGutter() {
9291
9402
  return activeLineGutterHighlighter;
9292
9403
  }
9293
9404
 
9405
+ const WhitespaceDeco = /*@__PURE__*/new Map();
9406
+ function getWhitespaceDeco(space) {
9407
+ let deco = WhitespaceDeco.get(space);
9408
+ if (!deco)
9409
+ WhitespaceDeco.set(space, deco = Decoration.mark({
9410
+ attributes: space === "\t" ? {
9411
+ class: "cm-highlightTab",
9412
+ } : {
9413
+ class: "cm-highlightSpace",
9414
+ "data-display": space.replace(/ /g, "·")
9415
+ }
9416
+ }));
9417
+ return deco;
9418
+ }
9419
+ function matcher(decorator) {
9420
+ return ViewPlugin.define(view => ({
9421
+ decorations: decorator.createDeco(view),
9422
+ update(u) {
9423
+ this.decorations = decorator.updateDeco(u, this.decorations);
9424
+ },
9425
+ }), {
9426
+ decorations: v => v.decorations
9427
+ });
9428
+ }
9429
+ const whitespaceHighlighter = /*@__PURE__*/matcher(/*@__PURE__*/new MatchDecorator({
9430
+ regexp: /\t| +/g,
9431
+ decoration: match => getWhitespaceDeco(match[0]),
9432
+ boundary: /\S/,
9433
+ }));
9434
+ /**
9435
+ Returns an extension that highlights whitespace, adding a
9436
+ `cm-highlightSpace` class to stretches of spaces, and a
9437
+ `cm-highlightTab` class to individual tab characters. By default,
9438
+ the former are shown as faint dots, and the latter as arrows.
9439
+ */
9440
+ function highlightWhitespace() {
9441
+ return whitespaceHighlighter;
9442
+ }
9443
+ const trailingHighlighter = /*@__PURE__*/matcher(/*@__PURE__*/new MatchDecorator({
9444
+ regexp: /\s+$/g,
9445
+ decoration: /*@__PURE__*/Decoration.mark({ class: "cm-trailingSpace" }),
9446
+ boundary: /\S/,
9447
+ }));
9448
+ /**
9449
+ Returns an extension that adds a `cm-trailingSpace` class to all
9450
+ trailing whitespace.
9451
+ */
9452
+ function highlightTrailingWhitespace() {
9453
+ return trailingHighlighter;
9454
+ }
9455
+
9294
9456
  /**
9295
9457
  @internal
9296
9458
  */
9297
9459
  const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
9298
9460
 
9299
- export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, GutterMarker, MatchDecorator, ViewPlugin, ViewUpdate, WidgetType, __test, closeHoverTooltips, crosshairCursor, drawSelection, dropCursor, getPanel, getTooltip, gutter, gutterLineClass, gutters, hasHoverTooltips, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, hoverTooltip, keymap, lineNumberMarkers, lineNumbers, logException, panels, placeholder, rectangularSelection, repositionTooltips, runScopeHandlers, scrollPastEnd, showPanel, showTooltip, tooltips };
9461
+ export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, GutterMarker, MatchDecorator, RectangleMarker, ViewPlugin, ViewUpdate, WidgetType, __test, closeHoverTooltips, crosshairCursor, drawSelection, dropCursor, getPanel, getTooltip, gutter, gutterLineClass, gutters, hasHoverTooltips, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, highlightTrailingWhitespace, highlightWhitespace, hoverTooltip, keymap, layer, lineNumberMarkers, lineNumbers, logException, panels, placeholder, rectangularSelection, repositionTooltips, runScopeHandlers, scrollPastEnd, showPanel, showTooltip, tooltips };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.5.1",
3
+ "version": "6.7.0",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",