@codemirror/view 0.19.30 → 0.19.34

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,45 @@
1
+ ## 0.19.34 (2021-12-17)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a bug where content line elements would in some cases lose their `cm-line` class. Move test to scrollIntoView
6
+
7
+ ## 0.19.33 (2021-12-16)
8
+
9
+ ### Breaking changes
10
+
11
+ `EditorView.scrollTo` and `EditorView.centerOn` are deprecated in favor of `EditorView.scrollIntoView`, and will be removed in the next breaking release.
12
+
13
+ ### Bug fixes
14
+
15
+ Fix an issue that could cause the editor to unnecessarily interfere with composition (especially visible on macOS Chrome).
16
+
17
+ A composition started with multiple lines selected will no longer be interruptd by the editor.
18
+
19
+ ### New features
20
+
21
+ The new `EditorView.scrollIntoView` function allows you to do more fine-grained scrolling.
22
+
23
+ ## 0.19.32 (2021-12-15)
24
+
25
+ ### Bug fixes
26
+
27
+ Fix a bug where CodeMirror's own event handers would run even after a user-supplied handler called `preventDefault` on an event.
28
+
29
+ Properly draw selections when negative text-indent is used for soft wrapping.
30
+
31
+ Fix an issue where `viewportLineBlocks` could hold inaccurate height information when the vertical scaling changed.
32
+
33
+ Fixes drop cursor positioning when the document is scrolled. Force a content measure when the editor comes into view
34
+
35
+ Fix a bug that could cause the editor to not measure its layout the first time it came into view.
36
+
37
+ ## 0.19.31 (2021-12-13)
38
+
39
+ ### New features
40
+
41
+ The package now exports a `dropCursor` extension that draws a cursor at the current drop position when dragging content over the editor.
42
+
1
43
  ## 0.19.30 (2021-12-13)
2
44
 
3
45
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -101,8 +101,7 @@ function windowRect(win) {
101
101
  return { left: 0, right: win.innerWidth,
102
102
  top: 0, bottom: win.innerHeight };
103
103
  }
104
- const ScrollSpace = 5;
105
- function scrollRectIntoView(dom, rect, side, center) {
104
+ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
106
105
  let doc = dom.ownerDocument, win = doc.defaultView;
107
106
  for (let cur = dom; cur;) {
108
107
  if (cur.nodeType == 1) { // Element
@@ -121,38 +120,42 @@ function scrollRectIntoView(dom, rect, side, center) {
121
120
  top: rect.top, bottom: rect.top + cur.clientHeight };
122
121
  }
123
122
  let moveX = 0, moveY = 0;
124
- if (center) {
123
+ if (y == "nearest") {
124
+ if (rect.top < bounding.top) {
125
+ moveY = -(bounding.top - rect.top + yMargin);
126
+ if (side > 0 && rect.bottom > bounding.bottom + moveY)
127
+ moveY = rect.bottom - bounding.bottom + moveY + yMargin;
128
+ }
129
+ else if (rect.bottom > bounding.bottom) {
130
+ moveY = rect.bottom - bounding.bottom + yMargin;
131
+ if (side < 0 && (rect.top - moveY) < bounding.top)
132
+ moveY = -(bounding.top + moveY - rect.top + yMargin);
133
+ }
134
+ }
135
+ else {
125
136
  let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
126
- let targetTop;
127
- if (rectHeight <= boundingHeight)
128
- targetTop = rect.top + rectHeight / 2 - boundingHeight / 2;
129
- else if (side < 0)
130
- targetTop = rect.top - ScrollSpace;
131
- else
132
- targetTop = rect.bottom + ScrollSpace - boundingHeight;
137
+ let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
138
+ y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
139
+ rect.bottom - boundingHeight + yMargin;
133
140
  moveY = targetTop - bounding.top;
134
- if (Math.abs(moveY) <= 1)
135
- moveY = 0;
136
- }
137
- else if (rect.top < bounding.top) {
138
- moveY = -(bounding.top - rect.top + ScrollSpace);
139
- if (side > 0 && rect.bottom > bounding.bottom + moveY)
140
- moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
141
141
  }
142
- else if (rect.bottom > bounding.bottom) {
143
- moveY = rect.bottom - bounding.bottom + ScrollSpace;
144
- if (side < 0 && (rect.top - moveY) < bounding.top)
145
- moveY = -(bounding.top + moveY - rect.top + ScrollSpace);
146
- }
147
- if (rect.left < bounding.left) {
148
- moveX = -(bounding.left - rect.left + ScrollSpace);
149
- if (side > 0 && rect.right > bounding.right + moveX)
150
- moveX = rect.right - bounding.right + moveX + ScrollSpace;
142
+ if (x == "nearest") {
143
+ if (rect.left < bounding.left) {
144
+ moveX = -(bounding.left - rect.left + xMargin);
145
+ if (side > 0 && rect.right > bounding.right + moveX)
146
+ moveX = rect.right - bounding.right + moveX + xMargin;
147
+ }
148
+ else if (rect.right > bounding.right) {
149
+ moveX = rect.right - bounding.right + xMargin;
150
+ if (side < 0 && rect.left < bounding.left + moveX)
151
+ moveX = -(bounding.left + moveX - rect.left + xMargin);
152
+ }
151
153
  }
152
- else if (rect.right > bounding.right) {
153
- moveX = rect.right - bounding.right + ScrollSpace;
154
- if (side < 0 && rect.left < bounding.left + moveX)
155
- moveX = -(bounding.left + moveX - rect.left + ScrollSpace);
154
+ else {
155
+ let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
156
+ (x == "start") == ltr ? rect.left - xMargin :
157
+ rect.right - (bounding.right - bounding.left) + xMargin;
158
+ moveX = targetLeft - bounding.left;
156
159
  }
157
160
  if (moveX || moveY) {
158
161
  if (top) {
@@ -176,7 +179,7 @@ function scrollRectIntoView(dom, rect, side, center) {
176
179
  if (top)
177
180
  break;
178
181
  cur = cur.assignedSlot || cur.parentNode;
179
- center = false;
182
+ x = y = "nearest";
180
183
  }
181
184
  else if (cur.nodeType == 11) { // A shadow root
182
185
  cur = cur.host;
@@ -263,6 +266,10 @@ function getRoot(node) {
263
266
  }
264
267
  return null;
265
268
  }
269
+ function clearAttributes(node) {
270
+ while (node.attributes.length)
271
+ node.removeAttributeNode(node.attributes[0]);
272
+ }
266
273
 
267
274
  class DOMPos {
268
275
  constructor(node, offset, precise = true) {
@@ -309,14 +316,16 @@ class ContentView {
309
316
  // given position.
310
317
  coordsAt(_pos, _side) { return null; }
311
318
  sync(track) {
312
- var _a;
313
319
  if (this.dirty & 2 /* Node */) {
314
320
  let parent = this.dom;
315
321
  let pos = parent.firstChild;
316
322
  for (let child of this.children) {
317
323
  if (child.dirty) {
318
- if (!child.dom && pos && !((_a = ContentView.get(pos)) === null || _a === void 0 ? void 0 : _a.parent))
319
- child.reuseDOM(pos);
324
+ if (!child.dom && pos) {
325
+ let contentView = ContentView.get(pos);
326
+ if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
327
+ child.reuseDOM(pos);
328
+ }
320
329
  child.sync(track);
321
330
  child.dirty = 0 /* Not */;
322
331
  }
@@ -344,7 +353,7 @@ class ContentView {
344
353
  }
345
354
  }
346
355
  }
347
- reuseDOM(_dom) { return false; }
356
+ reuseDOM(_dom) { }
348
357
  localPosFromDOM(node, offset) {
349
358
  let after;
350
359
  if (node == this.dom) {
@@ -643,10 +652,8 @@ class TextView extends ContentView {
643
652
  }
644
653
  }
645
654
  reuseDOM(dom) {
646
- if (dom.nodeType != 3)
647
- return false;
648
- this.createDOM(dom);
649
- return true;
655
+ if (dom.nodeType == 3)
656
+ this.createDOM(dom);
650
657
  }
651
658
  merge(from, to, source) {
652
659
  if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen))
@@ -681,18 +688,26 @@ class MarkView extends ContentView {
681
688
  for (let ch of children)
682
689
  ch.setParent(this);
683
690
  }
684
- createDOM() {
685
- let dom = document.createElement(this.mark.tagName);
691
+ setAttrs(dom) {
692
+ clearAttributes(dom);
686
693
  if (this.mark.class)
687
694
  dom.className = this.mark.class;
688
695
  if (this.mark.attrs)
689
696
  for (let name in this.mark.attrs)
690
697
  dom.setAttribute(name, this.mark.attrs[name]);
691
- this.setDOM(dom);
698
+ return dom;
699
+ }
700
+ reuseDOM(node) {
701
+ if (node.nodeName == this.mark.tagName.toUpperCase()) {
702
+ this.setDOM(node);
703
+ this.dirty |= 4 /* Attrs */ | 2 /* Node */;
704
+ }
692
705
  }
693
706
  sync(track) {
694
- if (!this.dom || (this.dirty & 4 /* Attrs */))
695
- this.createDOM();
707
+ if (!this.dom)
708
+ this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
709
+ else if (this.dirty & 4 /* Attrs */)
710
+ this.setAttrs(this.dom);
696
711
  super.sync(track);
697
712
  }
698
713
  merge(from, to, source, _hasStart, openStart, openEnd) {
@@ -836,8 +851,7 @@ class WidgetView extends ContentView {
836
851
  }
837
852
  class CompositionView extends WidgetView {
838
853
  domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
839
- sync() { if (!this.dom)
840
- this.setDOM(this.widget.toDOM()); }
854
+ sync() { this.setDOM(this.widget.toDOM()); }
841
855
  localPosFromDOM(node, offset) {
842
856
  return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length;
843
857
  }
@@ -1302,13 +1316,24 @@ class LineView extends ContentView {
1302
1316
  domAtPos(pos) {
1303
1317
  return inlineDOMAtPos(this.dom, this.children, pos);
1304
1318
  }
1319
+ reuseDOM(node) {
1320
+ if (node.nodeName == "DIV") {
1321
+ this.setDOM(node);
1322
+ this.dirty |= 4 /* Attrs */ | 2 /* Node */;
1323
+ }
1324
+ }
1305
1325
  sync(track) {
1306
1326
  var _a;
1307
- if (!this.dom || (this.dirty & 4 /* Attrs */)) {
1327
+ if (!this.dom) {
1308
1328
  this.setDOM(document.createElement("div"));
1309
1329
  this.dom.className = "cm-line";
1310
1330
  this.prevAttrs = this.attrs ? null : undefined;
1311
1331
  }
1332
+ else if (this.dirty & 4 /* Attrs */) {
1333
+ clearAttributes(this.dom);
1334
+ this.dom.className = "cm-line";
1335
+ this.prevAttrs = this.attrs ? null : undefined;
1336
+ }
1312
1337
  if (this.prevAttrs !== undefined) {
1313
1338
  updateAttrs(this.dom, this.prevAttrs, this.attrs);
1314
1339
  this.dom.classList.add("cm-line");
@@ -1580,12 +1605,27 @@ const mouseSelectionStyle = state.Facet.define();
1580
1605
  const exceptionSink = state.Facet.define();
1581
1606
  const updateListener = state.Facet.define();
1582
1607
  const inputHandler = state.Facet.define();
1608
+ // FIXME remove
1583
1609
  const scrollTo = state.StateEffect.define({
1584
1610
  map: (range, changes) => range.map(changes)
1585
1611
  });
1612
+ // FIXME remove
1586
1613
  const centerOn = state.StateEffect.define({
1587
1614
  map: (range, changes) => range.map(changes)
1588
1615
  });
1616
+ class ScrollTarget {
1617
+ constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
1618
+ this.range = range;
1619
+ this.y = y;
1620
+ this.x = x;
1621
+ this.yMargin = yMargin;
1622
+ this.xMargin = xMargin;
1623
+ }
1624
+ map(changes) {
1625
+ return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin);
1626
+ }
1627
+ }
1628
+ const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) });
1589
1629
  /**
1590
1630
  Log or report an unhandled exception in client code. Should
1591
1631
  probably only be used by extension code that allows client code to
@@ -2664,7 +2704,8 @@ class DocView extends ContentView {
2664
2704
  this.view.viewState.lineGapDeco
2665
2705
  ];
2666
2706
  }
2667
- scrollIntoView({ range, center }) {
2707
+ scrollIntoView(target) {
2708
+ let { range } = target;
2668
2709
  let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
2669
2710
  if (!rect)
2670
2711
  return;
@@ -2684,10 +2725,11 @@ class DocView extends ContentView {
2684
2725
  if (bottom != null)
2685
2726
  mBottom = Math.max(mBottom, bottom);
2686
2727
  }
2687
- scrollRectIntoView(this.view.scrollDOM, {
2728
+ let targetRect = {
2688
2729
  left: rect.left - mLeft, top: rect.top - mTop,
2689
2730
  right: rect.right + mRight, bottom: rect.bottom + mBottom
2690
- }, range.head < range.anchor ? -1 : 1, center);
2731
+ };
2732
+ scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == exports.Direction.LTR);
2691
2733
  }
2692
2734
  }
2693
2735
  function betweenUneditable(pos) {
@@ -3199,7 +3241,7 @@ class InputState {
3199
3241
  let handler = set.handlers[type];
3200
3242
  if (handler) {
3201
3243
  try {
3202
- if (handler.call(set.plugin, event, view))
3244
+ if (handler.call(set.plugin, event, view) || event.defaultPrevented)
3203
3245
  return true;
3204
3246
  }
3205
3247
  catch (e) {
@@ -4521,15 +4563,6 @@ class LineGapWidget extends WidgetType {
4521
4563
  }
4522
4564
  get estimatedHeight() { return this.vertical ? this.size : -1; }
4523
4565
  }
4524
- class ScrollTarget {
4525
- constructor(range, center = false) {
4526
- this.range = range;
4527
- this.center = center;
4528
- }
4529
- map(changes) {
4530
- return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
4531
- }
4532
- }
4533
4566
  class ViewState {
4534
4567
  constructor(state) {
4535
4568
  this.state = state;
@@ -4604,9 +4637,9 @@ class ViewState {
4604
4637
  let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) ||
4605
4638
  viewport.from != this.viewport.from || viewport.to != this.viewport.to;
4606
4639
  this.viewport = viewport;
4640
+ this.updateForViewport();
4607
4641
  if (updateLines)
4608
4642
  this.updateViewportLines();
4609
- this.updateForViewport();
4610
4643
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4611
4644
  this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
4612
4645
  update.flags |= this.computeVisibleRanges();
@@ -4638,7 +4671,12 @@ class ViewState {
4638
4671
  let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 } : visiblePixelRange(dom, this.paddingTop);
4639
4672
  let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
4640
4673
  this.pixelViewport = pixelViewport;
4641
- this.inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
4674
+ let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
4675
+ if (inView != this.inView) {
4676
+ this.inView = inView;
4677
+ if (inView)
4678
+ measureContent = true;
4679
+ }
4642
4680
  if (!this.inView)
4643
4681
  return 0;
4644
4682
  if (measureContent) {
@@ -4675,9 +4713,9 @@ class ViewState {
4675
4713
  this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
4676
4714
  if (viewportChange)
4677
4715
  this.viewport = this.getViewport(bias, this.scrollTarget);
4716
+ this.updateForViewport();
4678
4717
  if ((result & 2 /* Height */) || viewportChange)
4679
4718
  this.updateViewportLines();
4680
- this.updateForViewport();
4681
4719
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4682
4720
  this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
4683
4721
  result |= this.computeVisibleRanges();
@@ -4705,9 +4743,9 @@ class ViewState {
4705
4743
  let { head } = scrollTarget.range, viewHeight = this.editorHeight;
4706
4744
  if (head < viewport.from || head > viewport.to) {
4707
4745
  let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
4708
- if (scrollTarget.center)
4746
+ if (scrollTarget.y == "center")
4709
4747
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
4710
- else if (head < viewport.from)
4748
+ else if (scrollTarget.y == "start" || head < viewport.from)
4711
4749
  topPos = block.top;
4712
4750
  else
4713
4751
  topPos = block.bottom - viewHeight;
@@ -5065,11 +5103,13 @@ const baseTheme = buildTheme("." + baseThemeID, {
5065
5103
  // recomputation.
5066
5104
  "@keyframes cm-blink": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
5067
5105
  "@keyframes cm-blink2": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
5068
- ".cm-cursor": {
5106
+ ".cm-cursor, .cm-dropCursor": {
5069
5107
  position: "absolute",
5070
5108
  borderLeft: "1.2px solid black",
5071
5109
  marginLeft: "-0.6px",
5072
5110
  pointerEvents: "none",
5111
+ },
5112
+ ".cm-cursor": {
5073
5113
  display: "none"
5074
5114
  },
5075
5115
  "&dark .cm-cursor": {
@@ -5211,7 +5251,7 @@ class DOMObserver {
5211
5251
  this.intersection = new IntersectionObserver(entries => {
5212
5252
  if (this.parentCheck < 0)
5213
5253
  this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
5214
- if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
5254
+ if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) {
5215
5255
  this.intersecting = !this.intersecting;
5216
5256
  if (this.intersecting != this.view.inView)
5217
5257
  this.onScrollChanged(document.createEvent("Event"));
@@ -5811,7 +5851,9 @@ class EditorView {
5811
5851
  if (e.is(scrollTo))
5812
5852
  scrollTarget = new ScrollTarget(e.value);
5813
5853
  else if (e.is(centerOn))
5814
- scrollTarget = new ScrollTarget(e.value, true);
5854
+ scrollTarget = new ScrollTarget(e.value, "center");
5855
+ else if (e.is(scrollIntoView))
5856
+ scrollTarget = e.value;
5815
5857
  }
5816
5858
  }
5817
5859
  this.viewState.update(update, scrollTarget);
@@ -6379,6 +6421,14 @@ class EditorView {
6379
6421
  this.destroyed = true;
6380
6422
  }
6381
6423
  /**
6424
+ Returns an effect that can be
6425
+ [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
6426
+ cause it to scroll the given position or range into view.
6427
+ */
6428
+ static scrollIntoView(pos, options = {}) {
6429
+ return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
6430
+ }
6431
+ /**
6382
6432
  Facet that can be used to add DOM event handlers. The value
6383
6433
  should be an object mapping event names to handler functions. The
6384
6434
  first such function to return true will be assumed to have handled
@@ -6432,11 +6482,15 @@ class EditorView {
6432
6482
  /**
6433
6483
  Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
6434
6484
  transaction to make it scroll the given range into view.
6485
+
6486
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6435
6487
  */
6436
6488
  EditorView.scrollTo = scrollTo;
6437
6489
  /**
6438
6490
  Effect that makes the editor scroll the given range to the
6439
6491
  center of the visible view.
6492
+
6493
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6440
6494
  */
6441
6495
  EditorView.centerOn = centerOn;
6442
6496
  /**
@@ -6905,7 +6959,7 @@ function measureRange(view, range) {
6905
6959
  let ltr = view.textDirection == exports.Direction.LTR;
6906
6960
  let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
6907
6961
  let lineStyle = window.getComputedStyle(content.firstChild);
6908
- let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft);
6962
+ let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent));
6909
6963
  let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
6910
6964
  let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
6911
6965
  let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null;
@@ -6990,6 +7044,98 @@ function measureCursor(view, cursor, primary) {
6990
7044
  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");
6991
7045
  }
6992
7046
 
7047
+ const setDropCursorPos = state.StateEffect.define({
7048
+ map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
7049
+ });
7050
+ const dropCursorPos = state.StateField.define({
7051
+ create() { return null; },
7052
+ update(pos, tr) {
7053
+ if (pos != null)
7054
+ pos = tr.changes.mapPos(pos);
7055
+ return tr.effects.reduce((pos, e) => e.is(setDropCursorPos) ? e.value : pos, pos);
7056
+ }
7057
+ });
7058
+ const drawDropCursor = ViewPlugin.fromClass(class {
7059
+ constructor(view) {
7060
+ this.view = view;
7061
+ this.cursor = null;
7062
+ this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) };
7063
+ }
7064
+ update(update) {
7065
+ var _a;
7066
+ let cursorPos = update.state.field(dropCursorPos);
7067
+ if (cursorPos == null) {
7068
+ if (this.cursor != null) {
7069
+ (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove();
7070
+ this.cursor = null;
7071
+ }
7072
+ }
7073
+ else {
7074
+ if (!this.cursor) {
7075
+ this.cursor = this.view.scrollDOM.appendChild(document.createElement("div"));
7076
+ this.cursor.className = "cm-dropCursor";
7077
+ }
7078
+ if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged)
7079
+ this.view.requestMeasure(this.measureReq);
7080
+ }
7081
+ }
7082
+ readPos() {
7083
+ let pos = this.view.state.field(dropCursorPos);
7084
+ let rect = pos != null && this.view.coordsAtPos(pos);
7085
+ if (!rect)
7086
+ return null;
7087
+ let outer = this.view.scrollDOM.getBoundingClientRect();
7088
+ return {
7089
+ left: rect.left - outer.left + this.view.scrollDOM.scrollLeft,
7090
+ top: rect.top - outer.top + this.view.scrollDOM.scrollTop,
7091
+ height: rect.bottom - rect.top
7092
+ };
7093
+ }
7094
+ drawCursor(pos) {
7095
+ if (this.cursor) {
7096
+ if (pos) {
7097
+ this.cursor.style.left = pos.left + "px";
7098
+ this.cursor.style.top = pos.top + "px";
7099
+ this.cursor.style.height = pos.height + "px";
7100
+ }
7101
+ else {
7102
+ this.cursor.style.left = "-100000px";
7103
+ }
7104
+ }
7105
+ }
7106
+ destroy() {
7107
+ if (this.cursor)
7108
+ this.cursor.remove();
7109
+ }
7110
+ setDropPos(pos) {
7111
+ if (this.view.state.field(dropCursorPos) != pos)
7112
+ this.view.dispatch({ effects: setDropCursorPos.of(pos) });
7113
+ }
7114
+ }, {
7115
+ eventHandlers: {
7116
+ dragover(event) {
7117
+ this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
7118
+ },
7119
+ dragleave(event) {
7120
+ if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget))
7121
+ this.setDropPos(null);
7122
+ },
7123
+ dragend() {
7124
+ this.setDropPos(null);
7125
+ },
7126
+ drop() {
7127
+ this.setDropPos(null);
7128
+ }
7129
+ }
7130
+ });
7131
+ /**
7132
+ Draws a cursor at the current drop position when something is
7133
+ dragged over the editor.
7134
+ */
7135
+ function dropCursor() {
7136
+ return [dropCursorPos, drawDropCursor];
7137
+ }
7138
+
6993
7139
  function iterMatches(doc, re, from, to, f) {
6994
7140
  re.lastIndex = 0;
6995
7141
  for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) {
@@ -7357,6 +7503,7 @@ exports.ViewUpdate = ViewUpdate;
7357
7503
  exports.WidgetType = WidgetType;
7358
7504
  exports.__test = __test;
7359
7505
  exports.drawSelection = drawSelection;
7506
+ exports.dropCursor = dropCursor;
7360
7507
  exports.highlightActiveLine = highlightActiveLine;
7361
7508
  exports.highlightSpecialChars = highlightSpecialChars;
7362
7509
  exports.keymap = keymap;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as _codemirror_rangeset from '@codemirror/rangeset';
2
2
  import { RangeSet, RangeValue, Range } from '@codemirror/rangeset';
3
3
  export { Range } from '@codemirror/rangeset';
4
4
  import * as _codemirror_state from '@codemirror/state';
5
- import { EditorState, Extension, Transaction, ChangeSet, EditorSelection, TransactionSpec, SelectionRange, Facet } from '@codemirror/state';
5
+ import { EditorState, Extension, Transaction, ChangeSet, EditorSelection, TransactionSpec, SelectionRange, StateEffect, Facet } from '@codemirror/state';
6
6
  import { Line } from '@codemirror/text';
7
7
  import { StyleModule, StyleSpec } from 'style-mod';
8
8
 
@@ -264,6 +264,7 @@ interface Rect {
264
264
  readonly top: number;
265
265
  readonly bottom: number;
266
266
  }
267
+ declare type ScrollStrategy = "nearest" | "start" | "end" | "center";
267
268
 
268
269
  /**
269
270
  Command functions are used in key bindings and other types of user
@@ -1006,14 +1007,49 @@ declare class EditorView {
1006
1007
  /**
1007
1008
  Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
1008
1009
  transaction to make it scroll the given range into view.
1010
+
1011
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
1009
1012
  */
1010
1013
  static scrollTo: _codemirror_state.StateEffectType<SelectionRange>;
1011
1014
  /**
1012
1015
  Effect that makes the editor scroll the given range to the
1013
1016
  center of the visible view.
1017
+
1018
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
1014
1019
  */
1015
1020
  static centerOn: _codemirror_state.StateEffectType<SelectionRange>;
1016
1021
  /**
1022
+ Returns an effect that can be
1023
+ [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
1024
+ cause it to scroll the given position or range into view.
1025
+ */
1026
+ static scrollIntoView(pos: number | SelectionRange, options?: {
1027
+ /**
1028
+ By default (`"nearest"`) the position will be vertically
1029
+ scrolled only the minimal amount required to move the given
1030
+ position into view. You can set this to `"start"` to move it
1031
+ to the top of the view, `"end"` to move it to the bottom, or
1032
+ `"center"` to move it to the center.
1033
+ */
1034
+ y?: ScrollStrategy;
1035
+ /**
1036
+ Effect similar to
1037
+ [`y`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView^options.y), but for the
1038
+ horizontal scroll position.
1039
+ */
1040
+ x?: ScrollStrategy;
1041
+ /**
1042
+ Extra vertical distance to add when moving something into
1043
+ view. Not used with the `"center"` strategy. Defaults to 5.
1044
+ */
1045
+ yMargin?: number;
1046
+ /**
1047
+ Extra horizontal distance to add. Not used with the `"center"`
1048
+ strategy. Defaults to 5.
1049
+ */
1050
+ xMargin?: number;
1051
+ }): StateEffect<unknown>;
1052
+ /**
1017
1053
  Facet to add a [style
1018
1054
  module](https://github.com/marijnh/style-mod#documentation) to
1019
1055
  an editor view. The view will ensure that the module is
@@ -1291,6 +1327,12 @@ content).
1291
1327
  */
1292
1328
  declare function drawSelection(config?: SelectionConfig): Extension;
1293
1329
 
1330
+ /**
1331
+ Draws a cursor at the current drop position when something is
1332
+ dragged over the editor.
1333
+ */
1334
+ declare function dropCursor(): Extension;
1335
+
1294
1336
  interface SpecialCharConfig {
1295
1337
  /**
1296
1338
  An optional function that renders the placeholder elements.
@@ -1409,4 +1451,4 @@ declare class MatchDecorator {
1409
1451
  private updateRange;
1410
1452
  }
1411
1453
 
1412
- export { BidiSpan, BlockInfo, BlockType, Command, DOMEventHandlers, DOMEventMap, Decoration, DecorationSet, Direction, EditorView, KeyBinding, MatchDecorator, MouseSelectionStyle, PluginField, PluginFieldProvider, PluginSpec, PluginValue, Rect, ViewPlugin, ViewUpdate, WidgetType, drawSelection, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
1454
+ export { BidiSpan, BlockInfo, BlockType, Command, DOMEventHandlers, DOMEventMap, Decoration, DecorationSet, Direction, EditorView, KeyBinding, MatchDecorator, MouseSelectionStyle, PluginField, PluginFieldProvider, PluginSpec, PluginValue, Rect, ViewPlugin, ViewUpdate, WidgetType, drawSelection, dropCursor, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection, CharCategory, EditorState, Transaction, Prec, combineConfig } from '@codemirror/state';
1
+ import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection, CharCategory, EditorState, Transaction, Prec, combineConfig, StateField } from '@codemirror/state';
2
2
  import { StyleModule } from 'style-mod';
3
3
  import { RangeSet, RangeValue, RangeSetBuilder } from '@codemirror/rangeset';
4
4
  export { Range } from '@codemirror/rangeset';
@@ -98,8 +98,7 @@ function windowRect(win) {
98
98
  return { left: 0, right: win.innerWidth,
99
99
  top: 0, bottom: win.innerHeight };
100
100
  }
101
- const ScrollSpace = 5;
102
- function scrollRectIntoView(dom, rect, side, center) {
101
+ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
103
102
  let doc = dom.ownerDocument, win = doc.defaultView;
104
103
  for (let cur = dom; cur;) {
105
104
  if (cur.nodeType == 1) { // Element
@@ -118,38 +117,42 @@ function scrollRectIntoView(dom, rect, side, center) {
118
117
  top: rect.top, bottom: rect.top + cur.clientHeight };
119
118
  }
120
119
  let moveX = 0, moveY = 0;
121
- if (center) {
120
+ if (y == "nearest") {
121
+ if (rect.top < bounding.top) {
122
+ moveY = -(bounding.top - rect.top + yMargin);
123
+ if (side > 0 && rect.bottom > bounding.bottom + moveY)
124
+ moveY = rect.bottom - bounding.bottom + moveY + yMargin;
125
+ }
126
+ else if (rect.bottom > bounding.bottom) {
127
+ moveY = rect.bottom - bounding.bottom + yMargin;
128
+ if (side < 0 && (rect.top - moveY) < bounding.top)
129
+ moveY = -(bounding.top + moveY - rect.top + yMargin);
130
+ }
131
+ }
132
+ else {
122
133
  let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
123
- let targetTop;
124
- if (rectHeight <= boundingHeight)
125
- targetTop = rect.top + rectHeight / 2 - boundingHeight / 2;
126
- else if (side < 0)
127
- targetTop = rect.top - ScrollSpace;
128
- else
129
- targetTop = rect.bottom + ScrollSpace - boundingHeight;
134
+ let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
135
+ y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
136
+ rect.bottom - boundingHeight + yMargin;
130
137
  moveY = targetTop - bounding.top;
131
- if (Math.abs(moveY) <= 1)
132
- moveY = 0;
133
- }
134
- else if (rect.top < bounding.top) {
135
- moveY = -(bounding.top - rect.top + ScrollSpace);
136
- if (side > 0 && rect.bottom > bounding.bottom + moveY)
137
- moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
138
138
  }
139
- else if (rect.bottom > bounding.bottom) {
140
- moveY = rect.bottom - bounding.bottom + ScrollSpace;
141
- if (side < 0 && (rect.top - moveY) < bounding.top)
142
- moveY = -(bounding.top + moveY - rect.top + ScrollSpace);
143
- }
144
- if (rect.left < bounding.left) {
145
- moveX = -(bounding.left - rect.left + ScrollSpace);
146
- if (side > 0 && rect.right > bounding.right + moveX)
147
- moveX = rect.right - bounding.right + moveX + ScrollSpace;
139
+ if (x == "nearest") {
140
+ if (rect.left < bounding.left) {
141
+ moveX = -(bounding.left - rect.left + xMargin);
142
+ if (side > 0 && rect.right > bounding.right + moveX)
143
+ moveX = rect.right - bounding.right + moveX + xMargin;
144
+ }
145
+ else if (rect.right > bounding.right) {
146
+ moveX = rect.right - bounding.right + xMargin;
147
+ if (side < 0 && rect.left < bounding.left + moveX)
148
+ moveX = -(bounding.left + moveX - rect.left + xMargin);
149
+ }
148
150
  }
149
- else if (rect.right > bounding.right) {
150
- moveX = rect.right - bounding.right + ScrollSpace;
151
- if (side < 0 && rect.left < bounding.left + moveX)
152
- moveX = -(bounding.left + moveX - rect.left + ScrollSpace);
151
+ else {
152
+ let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
153
+ (x == "start") == ltr ? rect.left - xMargin :
154
+ rect.right - (bounding.right - bounding.left) + xMargin;
155
+ moveX = targetLeft - bounding.left;
153
156
  }
154
157
  if (moveX || moveY) {
155
158
  if (top) {
@@ -173,7 +176,7 @@ function scrollRectIntoView(dom, rect, side, center) {
173
176
  if (top)
174
177
  break;
175
178
  cur = cur.assignedSlot || cur.parentNode;
176
- center = false;
179
+ x = y = "nearest";
177
180
  }
178
181
  else if (cur.nodeType == 11) { // A shadow root
179
182
  cur = cur.host;
@@ -260,6 +263,10 @@ function getRoot(node) {
260
263
  }
261
264
  return null;
262
265
  }
266
+ function clearAttributes(node) {
267
+ while (node.attributes.length)
268
+ node.removeAttributeNode(node.attributes[0]);
269
+ }
263
270
 
264
271
  class DOMPos {
265
272
  constructor(node, offset, precise = true) {
@@ -306,14 +313,16 @@ class ContentView {
306
313
  // given position.
307
314
  coordsAt(_pos, _side) { return null; }
308
315
  sync(track) {
309
- var _a;
310
316
  if (this.dirty & 2 /* Node */) {
311
317
  let parent = this.dom;
312
318
  let pos = parent.firstChild;
313
319
  for (let child of this.children) {
314
320
  if (child.dirty) {
315
- if (!child.dom && pos && !((_a = ContentView.get(pos)) === null || _a === void 0 ? void 0 : _a.parent))
316
- child.reuseDOM(pos);
321
+ if (!child.dom && pos) {
322
+ let contentView = ContentView.get(pos);
323
+ if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
324
+ child.reuseDOM(pos);
325
+ }
317
326
  child.sync(track);
318
327
  child.dirty = 0 /* Not */;
319
328
  }
@@ -341,7 +350,7 @@ class ContentView {
341
350
  }
342
351
  }
343
352
  }
344
- reuseDOM(_dom) { return false; }
353
+ reuseDOM(_dom) { }
345
354
  localPosFromDOM(node, offset) {
346
355
  let after;
347
356
  if (node == this.dom) {
@@ -640,10 +649,8 @@ class TextView extends ContentView {
640
649
  }
641
650
  }
642
651
  reuseDOM(dom) {
643
- if (dom.nodeType != 3)
644
- return false;
645
- this.createDOM(dom);
646
- return true;
652
+ if (dom.nodeType == 3)
653
+ this.createDOM(dom);
647
654
  }
648
655
  merge(from, to, source) {
649
656
  if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen))
@@ -678,18 +685,26 @@ class MarkView extends ContentView {
678
685
  for (let ch of children)
679
686
  ch.setParent(this);
680
687
  }
681
- createDOM() {
682
- let dom = document.createElement(this.mark.tagName);
688
+ setAttrs(dom) {
689
+ clearAttributes(dom);
683
690
  if (this.mark.class)
684
691
  dom.className = this.mark.class;
685
692
  if (this.mark.attrs)
686
693
  for (let name in this.mark.attrs)
687
694
  dom.setAttribute(name, this.mark.attrs[name]);
688
- this.setDOM(dom);
695
+ return dom;
696
+ }
697
+ reuseDOM(node) {
698
+ if (node.nodeName == this.mark.tagName.toUpperCase()) {
699
+ this.setDOM(node);
700
+ this.dirty |= 4 /* Attrs */ | 2 /* Node */;
701
+ }
689
702
  }
690
703
  sync(track) {
691
- if (!this.dom || (this.dirty & 4 /* Attrs */))
692
- this.createDOM();
704
+ if (!this.dom)
705
+ this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
706
+ else if (this.dirty & 4 /* Attrs */)
707
+ this.setAttrs(this.dom);
693
708
  super.sync(track);
694
709
  }
695
710
  merge(from, to, source, _hasStart, openStart, openEnd) {
@@ -833,8 +848,7 @@ class WidgetView extends ContentView {
833
848
  }
834
849
  class CompositionView extends WidgetView {
835
850
  domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
836
- sync() { if (!this.dom)
837
- this.setDOM(this.widget.toDOM()); }
851
+ sync() { this.setDOM(this.widget.toDOM()); }
838
852
  localPosFromDOM(node, offset) {
839
853
  return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length;
840
854
  }
@@ -1298,13 +1312,24 @@ class LineView extends ContentView {
1298
1312
  domAtPos(pos) {
1299
1313
  return inlineDOMAtPos(this.dom, this.children, pos);
1300
1314
  }
1315
+ reuseDOM(node) {
1316
+ if (node.nodeName == "DIV") {
1317
+ this.setDOM(node);
1318
+ this.dirty |= 4 /* Attrs */ | 2 /* Node */;
1319
+ }
1320
+ }
1301
1321
  sync(track) {
1302
1322
  var _a;
1303
- if (!this.dom || (this.dirty & 4 /* Attrs */)) {
1323
+ if (!this.dom) {
1304
1324
  this.setDOM(document.createElement("div"));
1305
1325
  this.dom.className = "cm-line";
1306
1326
  this.prevAttrs = this.attrs ? null : undefined;
1307
1327
  }
1328
+ else if (this.dirty & 4 /* Attrs */) {
1329
+ clearAttributes(this.dom);
1330
+ this.dom.className = "cm-line";
1331
+ this.prevAttrs = this.attrs ? null : undefined;
1332
+ }
1308
1333
  if (this.prevAttrs !== undefined) {
1309
1334
  updateAttrs(this.dom, this.prevAttrs, this.attrs);
1310
1335
  this.dom.classList.add("cm-line");
@@ -1576,12 +1601,27 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
1576
1601
  const exceptionSink = /*@__PURE__*/Facet.define();
1577
1602
  const updateListener = /*@__PURE__*/Facet.define();
1578
1603
  const inputHandler = /*@__PURE__*/Facet.define();
1604
+ // FIXME remove
1579
1605
  const scrollTo = /*@__PURE__*/StateEffect.define({
1580
1606
  map: (range, changes) => range.map(changes)
1581
1607
  });
1608
+ // FIXME remove
1582
1609
  const centerOn = /*@__PURE__*/StateEffect.define({
1583
1610
  map: (range, changes) => range.map(changes)
1584
1611
  });
1612
+ class ScrollTarget {
1613
+ constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
1614
+ this.range = range;
1615
+ this.y = y;
1616
+ this.x = x;
1617
+ this.yMargin = yMargin;
1618
+ this.xMargin = xMargin;
1619
+ }
1620
+ map(changes) {
1621
+ return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin);
1622
+ }
1623
+ }
1624
+ const scrollIntoView = /*@__PURE__*/StateEffect.define({ map: (t, ch) => t.map(ch) });
1585
1625
  /**
1586
1626
  Log or report an unhandled exception in client code. Should
1587
1627
  probably only be used by extension code that allows client code to
@@ -2659,7 +2699,8 @@ class DocView extends ContentView {
2659
2699
  this.view.viewState.lineGapDeco
2660
2700
  ];
2661
2701
  }
2662
- scrollIntoView({ range, center }) {
2702
+ scrollIntoView(target) {
2703
+ let { range } = target;
2663
2704
  let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
2664
2705
  if (!rect)
2665
2706
  return;
@@ -2679,10 +2720,11 @@ class DocView extends ContentView {
2679
2720
  if (bottom != null)
2680
2721
  mBottom = Math.max(mBottom, bottom);
2681
2722
  }
2682
- scrollRectIntoView(this.view.scrollDOM, {
2723
+ let targetRect = {
2683
2724
  left: rect.left - mLeft, top: rect.top - mTop,
2684
2725
  right: rect.right + mRight, bottom: rect.bottom + mBottom
2685
- }, range.head < range.anchor ? -1 : 1, center);
2726
+ };
2727
+ scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == Direction.LTR);
2686
2728
  }
2687
2729
  }
2688
2730
  function betweenUneditable(pos) {
@@ -3194,7 +3236,7 @@ class InputState {
3194
3236
  let handler = set.handlers[type];
3195
3237
  if (handler) {
3196
3238
  try {
3197
- if (handler.call(set.plugin, event, view))
3239
+ if (handler.call(set.plugin, event, view) || event.defaultPrevented)
3198
3240
  return true;
3199
3241
  }
3200
3242
  catch (e) {
@@ -4515,15 +4557,6 @@ class LineGapWidget extends WidgetType {
4515
4557
  }
4516
4558
  get estimatedHeight() { return this.vertical ? this.size : -1; }
4517
4559
  }
4518
- class ScrollTarget {
4519
- constructor(range, center = false) {
4520
- this.range = range;
4521
- this.center = center;
4522
- }
4523
- map(changes) {
4524
- return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
4525
- }
4526
- }
4527
4560
  class ViewState {
4528
4561
  constructor(state) {
4529
4562
  this.state = state;
@@ -4598,9 +4631,9 @@ class ViewState {
4598
4631
  let updateLines = !update.changes.empty || (update.flags & 2 /* Height */) ||
4599
4632
  viewport.from != this.viewport.from || viewport.to != this.viewport.to;
4600
4633
  this.viewport = viewport;
4634
+ this.updateForViewport();
4601
4635
  if (updateLines)
4602
4636
  this.updateViewportLines();
4603
- this.updateForViewport();
4604
4637
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4605
4638
  this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
4606
4639
  update.flags |= this.computeVisibleRanges();
@@ -4632,7 +4665,12 @@ class ViewState {
4632
4665
  let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 } : visiblePixelRange(dom, this.paddingTop);
4633
4666
  let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
4634
4667
  this.pixelViewport = pixelViewport;
4635
- this.inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
4668
+ let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
4669
+ if (inView != this.inView) {
4670
+ this.inView = inView;
4671
+ if (inView)
4672
+ measureContent = true;
4673
+ }
4636
4674
  if (!this.inView)
4637
4675
  return 0;
4638
4676
  if (measureContent) {
@@ -4669,9 +4707,9 @@ class ViewState {
4669
4707
  this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
4670
4708
  if (viewportChange)
4671
4709
  this.viewport = this.getViewport(bias, this.scrollTarget);
4710
+ this.updateForViewport();
4672
4711
  if ((result & 2 /* Height */) || viewportChange)
4673
4712
  this.updateViewportLines();
4674
- this.updateForViewport();
4675
4713
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 /* DoubleMargin */)
4676
4714
  this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
4677
4715
  result |= this.computeVisibleRanges();
@@ -4699,9 +4737,9 @@ class ViewState {
4699
4737
  let { head } = scrollTarget.range, viewHeight = this.editorHeight;
4700
4738
  if (head < viewport.from || head > viewport.to) {
4701
4739
  let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
4702
- if (scrollTarget.center)
4740
+ if (scrollTarget.y == "center")
4703
4741
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
4704
- else if (head < viewport.from)
4742
+ else if (scrollTarget.y == "start" || head < viewport.from)
4705
4743
  topPos = block.top;
4706
4744
  else
4707
4745
  topPos = block.bottom - viewHeight;
@@ -5059,11 +5097,13 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5059
5097
  // recomputation.
5060
5098
  "@keyframes cm-blink": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
5061
5099
  "@keyframes cm-blink2": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
5062
- ".cm-cursor": {
5100
+ ".cm-cursor, .cm-dropCursor": {
5063
5101
  position: "absolute",
5064
5102
  borderLeft: "1.2px solid black",
5065
5103
  marginLeft: "-0.6px",
5066
5104
  pointerEvents: "none",
5105
+ },
5106
+ ".cm-cursor": {
5067
5107
  display: "none"
5068
5108
  },
5069
5109
  "&dark .cm-cursor": {
@@ -5205,7 +5245,7 @@ class DOMObserver {
5205
5245
  this.intersection = new IntersectionObserver(entries => {
5206
5246
  if (this.parentCheck < 0)
5207
5247
  this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
5208
- if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
5248
+ if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) {
5209
5249
  this.intersecting = !this.intersecting;
5210
5250
  if (this.intersecting != this.view.inView)
5211
5251
  this.onScrollChanged(document.createEvent("Event"));
@@ -5805,7 +5845,9 @@ class EditorView {
5805
5845
  if (e.is(scrollTo))
5806
5846
  scrollTarget = new ScrollTarget(e.value);
5807
5847
  else if (e.is(centerOn))
5808
- scrollTarget = new ScrollTarget(e.value, true);
5848
+ scrollTarget = new ScrollTarget(e.value, "center");
5849
+ else if (e.is(scrollIntoView))
5850
+ scrollTarget = e.value;
5809
5851
  }
5810
5852
  }
5811
5853
  this.viewState.update(update, scrollTarget);
@@ -6373,6 +6415,14 @@ class EditorView {
6373
6415
  this.destroyed = true;
6374
6416
  }
6375
6417
  /**
6418
+ Returns an effect that can be
6419
+ [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
6420
+ cause it to scroll the given position or range into view.
6421
+ */
6422
+ static scrollIntoView(pos, options = {}) {
6423
+ return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
6424
+ }
6425
+ /**
6376
6426
  Facet that can be used to add DOM event handlers. The value
6377
6427
  should be an object mapping event names to handler functions. The
6378
6428
  first such function to return true will be assumed to have handled
@@ -6426,11 +6476,15 @@ class EditorView {
6426
6476
  /**
6427
6477
  Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
6428
6478
  transaction to make it scroll the given range into view.
6479
+
6480
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6429
6481
  */
6430
6482
  EditorView.scrollTo = scrollTo;
6431
6483
  /**
6432
6484
  Effect that makes the editor scroll the given range to the
6433
6485
  center of the visible view.
6486
+
6487
+ *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6434
6488
  */
6435
6489
  EditorView.centerOn = centerOn;
6436
6490
  /**
@@ -6899,7 +6953,7 @@ function measureRange(view, range) {
6899
6953
  let ltr = view.textDirection == Direction.LTR;
6900
6954
  let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
6901
6955
  let lineStyle = window.getComputedStyle(content.firstChild);
6902
- let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft);
6956
+ let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent));
6903
6957
  let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
6904
6958
  let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
6905
6959
  let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
@@ -6984,6 +7038,98 @@ function measureCursor(view, cursor, primary) {
6984
7038
  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");
6985
7039
  }
6986
7040
 
7041
+ const setDropCursorPos = /*@__PURE__*/StateEffect.define({
7042
+ map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
7043
+ });
7044
+ const dropCursorPos = /*@__PURE__*/StateField.define({
7045
+ create() { return null; },
7046
+ update(pos, tr) {
7047
+ if (pos != null)
7048
+ pos = tr.changes.mapPos(pos);
7049
+ return tr.effects.reduce((pos, e) => e.is(setDropCursorPos) ? e.value : pos, pos);
7050
+ }
7051
+ });
7052
+ const drawDropCursor = /*@__PURE__*/ViewPlugin.fromClass(class {
7053
+ constructor(view) {
7054
+ this.view = view;
7055
+ this.cursor = null;
7056
+ this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) };
7057
+ }
7058
+ update(update) {
7059
+ var _a;
7060
+ let cursorPos = update.state.field(dropCursorPos);
7061
+ if (cursorPos == null) {
7062
+ if (this.cursor != null) {
7063
+ (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove();
7064
+ this.cursor = null;
7065
+ }
7066
+ }
7067
+ else {
7068
+ if (!this.cursor) {
7069
+ this.cursor = this.view.scrollDOM.appendChild(document.createElement("div"));
7070
+ this.cursor.className = "cm-dropCursor";
7071
+ }
7072
+ if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged)
7073
+ this.view.requestMeasure(this.measureReq);
7074
+ }
7075
+ }
7076
+ readPos() {
7077
+ let pos = this.view.state.field(dropCursorPos);
7078
+ let rect = pos != null && this.view.coordsAtPos(pos);
7079
+ if (!rect)
7080
+ return null;
7081
+ let outer = this.view.scrollDOM.getBoundingClientRect();
7082
+ return {
7083
+ left: rect.left - outer.left + this.view.scrollDOM.scrollLeft,
7084
+ top: rect.top - outer.top + this.view.scrollDOM.scrollTop,
7085
+ height: rect.bottom - rect.top
7086
+ };
7087
+ }
7088
+ drawCursor(pos) {
7089
+ if (this.cursor) {
7090
+ if (pos) {
7091
+ this.cursor.style.left = pos.left + "px";
7092
+ this.cursor.style.top = pos.top + "px";
7093
+ this.cursor.style.height = pos.height + "px";
7094
+ }
7095
+ else {
7096
+ this.cursor.style.left = "-100000px";
7097
+ }
7098
+ }
7099
+ }
7100
+ destroy() {
7101
+ if (this.cursor)
7102
+ this.cursor.remove();
7103
+ }
7104
+ setDropPos(pos) {
7105
+ if (this.view.state.field(dropCursorPos) != pos)
7106
+ this.view.dispatch({ effects: setDropCursorPos.of(pos) });
7107
+ }
7108
+ }, {
7109
+ eventHandlers: {
7110
+ dragover(event) {
7111
+ this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
7112
+ },
7113
+ dragleave(event) {
7114
+ if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget))
7115
+ this.setDropPos(null);
7116
+ },
7117
+ dragend() {
7118
+ this.setDropPos(null);
7119
+ },
7120
+ drop() {
7121
+ this.setDropPos(null);
7122
+ }
7123
+ }
7124
+ });
7125
+ /**
7126
+ Draws a cursor at the current drop position when something is
7127
+ dragged over the editor.
7128
+ */
7129
+ function dropCursor() {
7130
+ return [dropCursorPos, drawDropCursor];
7131
+ }
7132
+
6987
7133
  function iterMatches(doc, re, from, to, f) {
6988
7134
  re.lastIndex = 0;
6989
7135
  for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) {
@@ -7335,4 +7481,4 @@ function placeholder(content) {
7335
7481
  */
7336
7482
  const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
7337
7483
 
7338
- export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, MatchDecorator, PluginField, PluginFieldProvider, ViewPlugin, ViewUpdate, WidgetType, __test, drawSelection, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
7484
+ export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, MatchDecorator, PluginField, PluginFieldProvider, ViewPlugin, ViewUpdate, WidgetType, __test, drawSelection, dropCursor, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "0.19.30",
3
+ "version": "0.19.34",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -26,7 +26,7 @@
26
26
  "sideEffects": false,
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "@codemirror/rangeset": "^0.19.0",
29
+ "@codemirror/rangeset": "^0.19.4",
30
30
  "@codemirror/state": "^0.19.3",
31
31
  "@codemirror/text": "^0.19.0",
32
32
  "style-mod": "^4.0.0",