@codemirror/view 6.8.0 → 6.9.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.9.0 (2023-02-15)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where inaccurate estimated vertical positions could cause the viewport to not converge in line-wrapped editors.
6
+
7
+ Don't suppress double-space to period conversion when autocorrect is enabled.
8
+
9
+ Make sure the measuring code notices when the scaling of the editor is changed, and does a full measure in that case.
10
+
11
+ ### New features
12
+
13
+ The new `EditorView.focusChangeEffect` facet can be used to dispatch a state effect when the editor is focused or blurred.
14
+
15
+ ## 6.8.1 (2023-02-08)
16
+
17
+ ### Bug fixes
18
+
19
+ Fix an issue where tooltips that have their height reduced have their height flicker when scrolling or otherwise interacting with the editor.
20
+
1
21
  ## 6.8.0 (2023-02-07)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1784,6 +1784,7 @@ const mouseSelectionStyle = state.Facet.define();
1784
1784
  const exceptionSink = state.Facet.define();
1785
1785
  const updateListener = state.Facet.define();
1786
1786
  const inputHandler = state.Facet.define();
1787
+ const focusChangeEffect = state.Facet.define();
1787
1788
  const perLineTextDirection = state.Facet.define({
1788
1789
  combine: values => values.some(x => x)
1789
1790
  });
@@ -4034,8 +4035,18 @@ handlers.copy = handlers.cut = (view, event) => {
4034
4035
  };
4035
4036
  function updateForFocusChange(view) {
4036
4037
  setTimeout(() => {
4037
- if (view.hasFocus != view.inputState.notifiedFocused)
4038
- view.update([]);
4038
+ if (view.hasFocus != view.inputState.notifiedFocused) {
4039
+ let effects = [], focus = !view.inputState.notifiedFocused;
4040
+ for (let getEffect of view.state.facet(focusChangeEffect)) {
4041
+ let effect = getEffect(view.state, focus);
4042
+ if (effect)
4043
+ effects.push(effect);
4044
+ }
4045
+ if (effects.length)
4046
+ view.dispatch({ effects });
4047
+ else
4048
+ view.update([]);
4049
+ }
4039
4050
  }, 10);
4040
4051
  }
4041
4052
  handlers.focus = view => {
@@ -4117,7 +4128,7 @@ class HeightOracle {
4117
4128
  heightForGap(from, to) {
4118
4129
  let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
4119
4130
  if (this.lineWrapping)
4120
- lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength);
4131
+ lines += Math.max(0, Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength));
4121
4132
  return this.lineHeight * lines;
4122
4133
  }
4123
4134
  heightForLine(length) {
@@ -4263,11 +4274,11 @@ class HeightMap {
4263
4274
  decomposeLeft(_to, result) { result.push(this); }
4264
4275
  decomposeRight(_from, result) { result.push(this); }
4265
4276
  applyChanges(decorations, oldDoc, oracle, changes) {
4266
- let me = this;
4277
+ let me = this, doc = oracle.doc;
4267
4278
  for (let i = changes.length - 1; i >= 0; i--) {
4268
4279
  let { fromA, toA, fromB, toB } = changes[i];
4269
- let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4270
- let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4280
+ let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
4281
+ let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
4271
4282
  toB += end.to - toA;
4272
4283
  toA = end.to;
4273
4284
  while (i > 0 && start.from <= changes[i - 1].toA) {
@@ -4275,11 +4286,11 @@ class HeightMap {
4275
4286
  fromB = changes[i - 1].fromB;
4276
4287
  i--;
4277
4288
  if (fromA < start.from)
4278
- start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4289
+ start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
4279
4290
  }
4280
4291
  fromB += start.from - fromA;
4281
4292
  fromA = start.from;
4282
- let nodes = NodeBuilder.build(oracle, decorations, fromB, toB);
4293
+ let nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
4283
4294
  me = me.replace(fromA, toA, nodes);
4284
4295
  }
4285
4296
  return me.updateHeight(oracle, 0);
@@ -4346,15 +4357,15 @@ class HeightMapBlock extends HeightMap {
4346
4357
  super(length, height);
4347
4358
  this.type = type;
4348
4359
  }
4349
- blockAt(_height, _doc, top, offset) {
4360
+ blockAt(_height, _oracle, top, offset) {
4350
4361
  return new BlockInfo(offset, this.length, top, this.height, this.type);
4351
4362
  }
4352
- lineAt(_value, _type, doc, top, offset) {
4353
- return this.blockAt(0, doc, top, offset);
4363
+ lineAt(_value, _type, oracle, top, offset) {
4364
+ return this.blockAt(0, oracle, top, offset);
4354
4365
  }
4355
- forEachLine(from, to, doc, top, offset, f) {
4366
+ forEachLine(from, to, oracle, top, offset, f) {
4356
4367
  if (from <= offset + this.length && to >= offset)
4357
- f(this.blockAt(0, doc, top, offset));
4368
+ f(this.blockAt(0, oracle, top, offset));
4358
4369
  }
4359
4370
  updateHeight(oracle, offset = 0, _force = false, measured) {
4360
4371
  if (measured && measured.from <= offset && measured.more)
@@ -4400,35 +4411,60 @@ class HeightMapText extends HeightMapBlock {
4400
4411
  }
4401
4412
  class HeightMapGap extends HeightMap {
4402
4413
  constructor(length) { super(length, 0); }
4403
- lines(doc, offset) {
4404
- let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number;
4405
- return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) };
4414
+ heightMetrics(oracle, offset) {
4415
+ let firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
4416
+ let lines = lastLine - firstLine + 1;
4417
+ let perLine, perChar = 0;
4418
+ if (oracle.lineWrapping) {
4419
+ let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
4420
+ perLine = totalPerLine / lines;
4421
+ perChar = (this.height - totalPerLine) / (this.length - lines - 1);
4422
+ }
4423
+ else {
4424
+ perLine = this.height / lines;
4425
+ }
4426
+ return { firstLine, lastLine, perLine, perChar };
4406
4427
  }
4407
- blockAt(height, doc, top, offset) {
4408
- let { firstLine, lastLine, lineHeight } = this.lines(doc, offset);
4409
- let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight)));
4410
- let { from, length } = doc.line(firstLine + line);
4411
- return new BlockInfo(from, length, top + lineHeight * line, lineHeight, exports.BlockType.Text);
4428
+ blockAt(height, oracle, top, offset) {
4429
+ let { firstLine, lastLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4430
+ if (oracle.lineWrapping) {
4431
+ let guess = offset + Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length);
4432
+ let line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
4433
+ let lineTop = Math.max(top, height - lineHeight / 2);
4434
+ return new BlockInfo(line.from, line.length, lineTop, lineHeight, exports.BlockType.Text);
4435
+ }
4436
+ else {
4437
+ let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
4438
+ let { from, length } = oracle.doc.line(firstLine + line);
4439
+ return new BlockInfo(from, length, top + perLine * line, perLine, exports.BlockType.Text);
4440
+ }
4412
4441
  }
4413
- lineAt(value, type, doc, top, offset) {
4442
+ lineAt(value, type, oracle, top, offset) {
4414
4443
  if (type == QueryType.ByHeight)
4415
- return this.blockAt(value, doc, top, offset);
4444
+ return this.blockAt(value, oracle, top, offset);
4416
4445
  if (type == QueryType.ByPosNoHeight) {
4417
- let { from, to } = doc.lineAt(value);
4446
+ let { from, to } = oracle.doc.lineAt(value);
4418
4447
  return new BlockInfo(from, to - from, 0, 0, exports.BlockType.Text);
4419
4448
  }
4420
- let { firstLine, lineHeight } = this.lines(doc, offset);
4421
- let { from, length, number } = doc.lineAt(value);
4422
- return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, exports.BlockType.Text);
4423
- }
4424
- forEachLine(from, to, doc, top, offset, f) {
4425
- let { firstLine, lineHeight } = this.lines(doc, offset);
4426
- for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) {
4427
- let line = doc.lineAt(pos);
4428
- if (pos == from)
4429
- top += lineHeight * (line.number - firstLine);
4430
- f(new BlockInfo(line.from, line.length, top, lineHeight, exports.BlockType.Text));
4431
- top += lineHeight;
4449
+ let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4450
+ let line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
4451
+ let linesAbove = line.number - firstLine;
4452
+ let lineTop = top + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
4453
+ return new BlockInfo(line.from, line.length, Math.max(top, Math.min(lineTop, top + this.height - lineHeight)), lineHeight, exports.BlockType.Text);
4454
+ }
4455
+ forEachLine(from, to, oracle, top, offset, f) {
4456
+ from = Math.max(from, offset);
4457
+ to = Math.min(to, offset + this.length);
4458
+ let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4459
+ for (let pos = from, lineTop = top; pos <= to;) {
4460
+ let line = oracle.doc.lineAt(pos);
4461
+ if (pos == from) {
4462
+ let linesAbove = line.number - firstLine;
4463
+ lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
4464
+ }
4465
+ let lineHeight = perLine + perChar * line.length;
4466
+ f(new BlockInfo(line.from, line.length, lineTop, lineHeight, exports.BlockType.Text));
4467
+ lineTop += lineHeight;
4432
4468
  pos = line.to + 1;
4433
4469
  }
4434
4470
  }
@@ -4464,7 +4500,6 @@ class HeightMapGap extends HeightMap {
4464
4500
  // they would already have been added to the heightmap (gaps
4465
4501
  // only contain plain text).
4466
4502
  let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
4467
- let wasChanged = oracle.heightChanged;
4468
4503
  if (measured.from > offset)
4469
4504
  nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
4470
4505
  while (pos <= end && measured.more) {
@@ -4484,8 +4519,9 @@ class HeightMapGap extends HeightMap {
4484
4519
  if (pos <= end)
4485
4520
  nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
4486
4521
  let result = HeightMap.of(nodes);
4487
- oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
4488
- Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon;
4522
+ if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
4523
+ Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon)
4524
+ oracle.heightChanged = true;
4489
4525
  return result;
4490
4526
  }
4491
4527
  else if (force || this.outdated) {
@@ -4504,40 +4540,40 @@ class HeightMapBranch extends HeightMap {
4504
4540
  this.size = left.size + right.size;
4505
4541
  }
4506
4542
  get break() { return this.flags & 1 /* Flag.Break */; }
4507
- blockAt(height, doc, top, offset) {
4543
+ blockAt(height, oracle, top, offset) {
4508
4544
  let mid = top + this.left.height;
4509
- return height < mid ? this.left.blockAt(height, doc, top, offset)
4510
- : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break);
4545
+ return height < mid ? this.left.blockAt(height, oracle, top, offset)
4546
+ : this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
4511
4547
  }
4512
- lineAt(value, type, doc, top, offset) {
4548
+ lineAt(value, type, oracle, top, offset) {
4513
4549
  let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
4514
4550
  let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
4515
- let base = left ? this.left.lineAt(value, type, doc, top, offset)
4516
- : this.right.lineAt(value, type, doc, rightTop, rightOffset);
4551
+ let base = left ? this.left.lineAt(value, type, oracle, top, offset)
4552
+ : this.right.lineAt(value, type, oracle, rightTop, rightOffset);
4517
4553
  if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
4518
4554
  return base;
4519
4555
  let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
4520
4556
  if (left)
4521
- return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset));
4557
+ return base.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));
4522
4558
  else
4523
- return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base);
4559
+ return this.left.lineAt(rightOffset, subQuery, oracle, top, offset).join(base);
4524
4560
  }
4525
- forEachLine(from, to, doc, top, offset, f) {
4561
+ forEachLine(from, to, oracle, top, offset, f) {
4526
4562
  let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
4527
4563
  if (this.break) {
4528
4564
  if (from < rightOffset)
4529
- this.left.forEachLine(from, to, doc, top, offset, f);
4565
+ this.left.forEachLine(from, to, oracle, top, offset, f);
4530
4566
  if (to >= rightOffset)
4531
- this.right.forEachLine(from, to, doc, rightTop, rightOffset, f);
4567
+ this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
4532
4568
  }
4533
4569
  else {
4534
- let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset);
4570
+ let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
4535
4571
  if (from < mid.from)
4536
- this.left.forEachLine(from, mid.from - 1, doc, top, offset, f);
4572
+ this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
4537
4573
  if (mid.to >= from && mid.from <= to)
4538
4574
  f(mid);
4539
4575
  if (to > mid.to)
4540
- this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f);
4576
+ this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
4541
4577
  }
4542
4578
  }
4543
4579
  replace(from, to, nodes) {
@@ -4887,11 +4923,11 @@ class ViewState {
4887
4923
  }
4888
4924
  this.viewports = viewports.sort((a, b) => a.from - b.from);
4889
4925
  this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
4890
- new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
4926
+ new BigScaler(this.heightOracle, this.heightMap, this.viewports);
4891
4927
  }
4892
4928
  updateViewportLines() {
4893
4929
  this.viewportLines = [];
4894
- this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
4930
+ this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
4895
4931
  this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
4896
4932
  });
4897
4933
  }
@@ -4931,8 +4967,9 @@ class ViewState {
4931
4967
  let whiteSpace = style.whiteSpace;
4932
4968
  this.defaultTextDirection = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
4933
4969
  let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
4934
- let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4935
- this.contentDOMHeight = dom.clientHeight;
4970
+ let domRect = dom.getBoundingClientRect();
4971
+ let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
4972
+ this.contentDOMHeight = domRect.height;
4936
4973
  this.mustMeasureContent = false;
4937
4974
  let result = 0, bias = 0;
4938
4975
  // Vertical padding
@@ -4960,9 +4997,9 @@ class ViewState {
4960
4997
  }
4961
4998
  if (!this.inView && !this.scrollTarget)
4962
4999
  return 0;
4963
- let contentWidth = dom.clientWidth;
5000
+ let contentWidth = domRect.width;
4964
5001
  if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
4965
- this.contentDOMWidth = contentWidth;
5002
+ this.contentDOMWidth = domRect.width;
4966
5003
  this.editorHeight = view.scrollDOM.clientHeight;
4967
5004
  result |= 8 /* UpdateFlag.Geometry */;
4968
5005
  }
@@ -4991,7 +5028,8 @@ class ViewState {
4991
5028
  result |= 2 /* UpdateFlag.Height */;
4992
5029
  }
4993
5030
  let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
4994
- this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
5031
+ this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
5032
+ this.scrollTarget.range.head > this.viewport.to);
4995
5033
  if (viewportChange)
4996
5034
  this.viewport = this.getViewport(bias, this.scrollTarget);
4997
5035
  this.updateForViewport();
@@ -5017,36 +5055,37 @@ class ViewState {
5017
5055
  // bottom, depending on the bias (the change in viewport position
5018
5056
  // since the last update). It'll hold a number between 0 and 1
5019
5057
  let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
5020
- let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
5021
- let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).to);
5058
+ let map = this.heightMap, oracle = this.heightOracle;
5059
+ let { visibleTop, visibleBottom } = this;
5060
+ let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).to);
5022
5061
  // If scrollTarget is given, make sure the viewport includes that position
5023
5062
  if (scrollTarget) {
5024
5063
  let { head } = scrollTarget.range;
5025
5064
  if (head < viewport.from || head > viewport.to) {
5026
5065
  let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
5027
- let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
5066
+ let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0), topPos;
5028
5067
  if (scrollTarget.y == "center")
5029
5068
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
5030
5069
  else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
5031
5070
  topPos = block.top;
5032
5071
  else
5033
5072
  topPos = block.bottom - viewHeight;
5034
- viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to);
5073
+ viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).to);
5035
5074
  }
5036
5075
  }
5037
5076
  return viewport;
5038
5077
  }
5039
5078
  mapViewport(viewport, changes) {
5040
5079
  let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
5041
- return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to);
5080
+ return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
5042
5081
  }
5043
5082
  // Checks if a given viewport covers the visible part of the
5044
5083
  // document and not too much beyond that.
5045
5084
  viewportIsAppropriate({ from, to }, bias = 0) {
5046
5085
  if (!this.inView)
5047
5086
  return true;
5048
- let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0);
5049
- let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0);
5087
+ let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
5088
+ let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
5050
5089
  let { visibleTop, visibleBottom } = this;
5051
5090
  return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) &&
5052
5091
  (to == this.state.doc.length ||
@@ -5183,13 +5222,13 @@ class ViewState {
5183
5222
  }
5184
5223
  lineBlockAt(pos) {
5185
5224
  return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
5186
- scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler);
5225
+ scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
5187
5226
  }
5188
5227
  lineBlockAtHeight(height) {
5189
- return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler);
5228
+ return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
5190
5229
  }
5191
5230
  elementAtHeight(height) {
5192
- return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
5231
+ return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
5193
5232
  }
5194
5233
  get docHeight() {
5195
5234
  return this.scaler.toDOM(this.heightMap.height);
@@ -5263,11 +5302,11 @@ const IdScaler = {
5263
5302
  // regions outside the viewports so that the total height is
5264
5303
  // VP.MaxDOMHeight.
5265
5304
  class BigScaler {
5266
- constructor(doc, heightMap, viewports) {
5305
+ constructor(oracle, heightMap, viewports) {
5267
5306
  let vpHeight = 0, base = 0, domBase = 0;
5268
5307
  this.viewports = viewports.map(({ from, to }) => {
5269
- let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top;
5270
- let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom;
5308
+ let top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
5309
+ let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
5271
5310
  vpHeight += bottom - top;
5272
5311
  return { from, to, top, bottom, domTop: 0, domBottom: 0 };
5273
5312
  });
@@ -5634,7 +5673,7 @@ function applyDOMChange(view, domChange) {
5634
5673
  };
5635
5674
  }
5636
5675
  else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
5637
- /^\. ?$/.test(change.insert.toString())) {
5676
+ /^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
5638
5677
  // Detect insert-period-on-double-space Mac and Android behavior,
5639
5678
  // and transform it into a regular space insert.
5640
5679
  if (newSel && change.insert.length == 2)
@@ -7048,6 +7087,11 @@ called and the default behavior is prevented.
7048
7087
  */
7049
7088
  EditorView.inputHandler = inputHandler;
7050
7089
  /**
7090
+ This facet can be used to provide functions that create effects
7091
+ to be dispatched when the editor's focus state changes.
7092
+ */
7093
+ EditorView.focusChangeEffect = focusChangeEffect;
7094
+ /**
7051
7095
  By default, the editor assumes all its content has the same
7052
7096
  [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
7053
7097
  value to make it read the text direction of every (rendered)
@@ -8363,6 +8407,7 @@ const tooltipConfig = state.Facet.define({
8363
8407
  });
8364
8408
  }
8365
8409
  });
8410
+ const knownHeight = new WeakMap();
8366
8411
  const tooltipPlugin = ViewPlugin.fromClass(class {
8367
8412
  constructor(view) {
8368
8413
  this.view = view;
@@ -8478,6 +8523,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8478
8523
  };
8479
8524
  }
8480
8525
  writeMeasure(measured) {
8526
+ var _a;
8481
8527
  let { editor, space } = measured;
8482
8528
  let others = [];
8483
8529
  for (let i = 0; i < this.manager.tooltips.length; i++) {
@@ -8493,7 +8539,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8493
8539
  }
8494
8540
  let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
8495
8541
  let arrowHeight = arrow ? 7 /* Arrow.Size */ : 0;
8496
- let width = size.right - size.left, height = size.bottom - size.top;
8542
+ let width = size.right - size.left, height = (_a = knownHeight.get(tView)) !== null && _a !== void 0 ? _a : size.bottom - size.top;
8497
8543
  let offset = tView.offset || noOffset, ltr = this.view.textDirection == exports.Direction.LTR;
8498
8544
  let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
8499
8545
  : ltr ? Math.min(pos.left - (arrow ? 14 /* Arrow.Offset */ : 0) + offset.x, space.right - width)
@@ -8510,6 +8556,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
8510
8556
  dom.style.top = Outside;
8511
8557
  continue;
8512
8558
  }
8559
+ knownHeight.set(tView, height);
8513
8560
  dom.style.height = (height = spaceVert) + "px";
8514
8561
  }
8515
8562
  else if (dom.style.height) {
package/dist/index.d.ts CHANGED
@@ -995,6 +995,11 @@ declare class EditorView {
995
995
  */
996
996
  static inputHandler: Facet<(view: EditorView, from: number, to: number, text: string) => boolean, readonly ((view: EditorView, from: number, to: number, text: string) => boolean)[]>;
997
997
  /**
998
+ This facet can be used to provide functions that create effects
999
+ to be dispatched when the editor's focus state changes.
1000
+ */
1001
+ static focusChangeEffect: Facet<(state: EditorState, focusing: boolean) => StateEffect<any> | null, readonly ((state: EditorState, focusing: boolean) => StateEffect<any> | null)[]>;
1002
+ /**
998
1003
  By default, the editor assumes all its content has the same
999
1004
  [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
1000
1005
  value to make it read the text direction of every (rendered)
package/dist/index.js CHANGED
@@ -1779,6 +1779,7 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
1779
1779
  const exceptionSink = /*@__PURE__*/Facet.define();
1780
1780
  const updateListener = /*@__PURE__*/Facet.define();
1781
1781
  const inputHandler = /*@__PURE__*/Facet.define();
1782
+ const focusChangeEffect = /*@__PURE__*/Facet.define();
1782
1783
  const perLineTextDirection = /*@__PURE__*/Facet.define({
1783
1784
  combine: values => values.some(x => x)
1784
1785
  });
@@ -4028,8 +4029,18 @@ handlers.copy = handlers.cut = (view, event) => {
4028
4029
  };
4029
4030
  function updateForFocusChange(view) {
4030
4031
  setTimeout(() => {
4031
- if (view.hasFocus != view.inputState.notifiedFocused)
4032
- view.update([]);
4032
+ if (view.hasFocus != view.inputState.notifiedFocused) {
4033
+ let effects = [], focus = !view.inputState.notifiedFocused;
4034
+ for (let getEffect of view.state.facet(focusChangeEffect)) {
4035
+ let effect = getEffect(view.state, focus);
4036
+ if (effect)
4037
+ effects.push(effect);
4038
+ }
4039
+ if (effects.length)
4040
+ view.dispatch({ effects });
4041
+ else
4042
+ view.update([]);
4043
+ }
4033
4044
  }, 10);
4034
4045
  }
4035
4046
  handlers.focus = view => {
@@ -4111,7 +4122,7 @@ class HeightOracle {
4111
4122
  heightForGap(from, to) {
4112
4123
  let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
4113
4124
  if (this.lineWrapping)
4114
- lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength);
4125
+ lines += Math.max(0, Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength));
4115
4126
  return this.lineHeight * lines;
4116
4127
  }
4117
4128
  heightForLine(length) {
@@ -4256,11 +4267,11 @@ class HeightMap {
4256
4267
  decomposeLeft(_to, result) { result.push(this); }
4257
4268
  decomposeRight(_from, result) { result.push(this); }
4258
4269
  applyChanges(decorations, oldDoc, oracle, changes) {
4259
- let me = this;
4270
+ let me = this, doc = oracle.doc;
4260
4271
  for (let i = changes.length - 1; i >= 0; i--) {
4261
4272
  let { fromA, toA, fromB, toB } = changes[i];
4262
- let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4263
- let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4273
+ let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
4274
+ let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
4264
4275
  toB += end.to - toA;
4265
4276
  toA = end.to;
4266
4277
  while (i > 0 && start.from <= changes[i - 1].toA) {
@@ -4268,11 +4279,11 @@ class HeightMap {
4268
4279
  fromB = changes[i - 1].fromB;
4269
4280
  i--;
4270
4281
  if (fromA < start.from)
4271
- start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
4282
+ start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
4272
4283
  }
4273
4284
  fromB += start.from - fromA;
4274
4285
  fromA = start.from;
4275
- let nodes = NodeBuilder.build(oracle, decorations, fromB, toB);
4286
+ let nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
4276
4287
  me = me.replace(fromA, toA, nodes);
4277
4288
  }
4278
4289
  return me.updateHeight(oracle, 0);
@@ -4339,15 +4350,15 @@ class HeightMapBlock extends HeightMap {
4339
4350
  super(length, height);
4340
4351
  this.type = type;
4341
4352
  }
4342
- blockAt(_height, _doc, top, offset) {
4353
+ blockAt(_height, _oracle, top, offset) {
4343
4354
  return new BlockInfo(offset, this.length, top, this.height, this.type);
4344
4355
  }
4345
- lineAt(_value, _type, doc, top, offset) {
4346
- return this.blockAt(0, doc, top, offset);
4356
+ lineAt(_value, _type, oracle, top, offset) {
4357
+ return this.blockAt(0, oracle, top, offset);
4347
4358
  }
4348
- forEachLine(from, to, doc, top, offset, f) {
4359
+ forEachLine(from, to, oracle, top, offset, f) {
4349
4360
  if (from <= offset + this.length && to >= offset)
4350
- f(this.blockAt(0, doc, top, offset));
4361
+ f(this.blockAt(0, oracle, top, offset));
4351
4362
  }
4352
4363
  updateHeight(oracle, offset = 0, _force = false, measured) {
4353
4364
  if (measured && measured.from <= offset && measured.more)
@@ -4393,35 +4404,60 @@ class HeightMapText extends HeightMapBlock {
4393
4404
  }
4394
4405
  class HeightMapGap extends HeightMap {
4395
4406
  constructor(length) { super(length, 0); }
4396
- lines(doc, offset) {
4397
- let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number;
4398
- return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) };
4407
+ heightMetrics(oracle, offset) {
4408
+ let firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
4409
+ let lines = lastLine - firstLine + 1;
4410
+ let perLine, perChar = 0;
4411
+ if (oracle.lineWrapping) {
4412
+ let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
4413
+ perLine = totalPerLine / lines;
4414
+ perChar = (this.height - totalPerLine) / (this.length - lines - 1);
4415
+ }
4416
+ else {
4417
+ perLine = this.height / lines;
4418
+ }
4419
+ return { firstLine, lastLine, perLine, perChar };
4399
4420
  }
4400
- blockAt(height, doc, top, offset) {
4401
- let { firstLine, lastLine, lineHeight } = this.lines(doc, offset);
4402
- let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight)));
4403
- let { from, length } = doc.line(firstLine + line);
4404
- return new BlockInfo(from, length, top + lineHeight * line, lineHeight, BlockType.Text);
4421
+ blockAt(height, oracle, top, offset) {
4422
+ let { firstLine, lastLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4423
+ if (oracle.lineWrapping) {
4424
+ let guess = offset + Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length);
4425
+ let line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
4426
+ let lineTop = Math.max(top, height - lineHeight / 2);
4427
+ return new BlockInfo(line.from, line.length, lineTop, lineHeight, BlockType.Text);
4428
+ }
4429
+ else {
4430
+ let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
4431
+ let { from, length } = oracle.doc.line(firstLine + line);
4432
+ return new BlockInfo(from, length, top + perLine * line, perLine, BlockType.Text);
4433
+ }
4405
4434
  }
4406
- lineAt(value, type, doc, top, offset) {
4435
+ lineAt(value, type, oracle, top, offset) {
4407
4436
  if (type == QueryType.ByHeight)
4408
- return this.blockAt(value, doc, top, offset);
4437
+ return this.blockAt(value, oracle, top, offset);
4409
4438
  if (type == QueryType.ByPosNoHeight) {
4410
- let { from, to } = doc.lineAt(value);
4439
+ let { from, to } = oracle.doc.lineAt(value);
4411
4440
  return new BlockInfo(from, to - from, 0, 0, BlockType.Text);
4412
4441
  }
4413
- let { firstLine, lineHeight } = this.lines(doc, offset);
4414
- let { from, length, number } = doc.lineAt(value);
4415
- return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, BlockType.Text);
4416
- }
4417
- forEachLine(from, to, doc, top, offset, f) {
4418
- let { firstLine, lineHeight } = this.lines(doc, offset);
4419
- for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) {
4420
- let line = doc.lineAt(pos);
4421
- if (pos == from)
4422
- top += lineHeight * (line.number - firstLine);
4423
- f(new BlockInfo(line.from, line.length, top, lineHeight, BlockType.Text));
4424
- top += lineHeight;
4442
+ let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4443
+ let line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
4444
+ let linesAbove = line.number - firstLine;
4445
+ let lineTop = top + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
4446
+ return new BlockInfo(line.from, line.length, Math.max(top, Math.min(lineTop, top + this.height - lineHeight)), lineHeight, BlockType.Text);
4447
+ }
4448
+ forEachLine(from, to, oracle, top, offset, f) {
4449
+ from = Math.max(from, offset);
4450
+ to = Math.min(to, offset + this.length);
4451
+ let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
4452
+ for (let pos = from, lineTop = top; pos <= to;) {
4453
+ let line = oracle.doc.lineAt(pos);
4454
+ if (pos == from) {
4455
+ let linesAbove = line.number - firstLine;
4456
+ lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
4457
+ }
4458
+ let lineHeight = perLine + perChar * line.length;
4459
+ f(new BlockInfo(line.from, line.length, lineTop, lineHeight, BlockType.Text));
4460
+ lineTop += lineHeight;
4425
4461
  pos = line.to + 1;
4426
4462
  }
4427
4463
  }
@@ -4457,7 +4493,6 @@ class HeightMapGap extends HeightMap {
4457
4493
  // they would already have been added to the heightmap (gaps
4458
4494
  // only contain plain text).
4459
4495
  let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
4460
- let wasChanged = oracle.heightChanged;
4461
4496
  if (measured.from > offset)
4462
4497
  nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
4463
4498
  while (pos <= end && measured.more) {
@@ -4477,8 +4512,9 @@ class HeightMapGap extends HeightMap {
4477
4512
  if (pos <= end)
4478
4513
  nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
4479
4514
  let result = HeightMap.of(nodes);
4480
- oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
4481
- Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon;
4515
+ if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
4516
+ Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon)
4517
+ oracle.heightChanged = true;
4482
4518
  return result;
4483
4519
  }
4484
4520
  else if (force || this.outdated) {
@@ -4497,40 +4533,40 @@ class HeightMapBranch extends HeightMap {
4497
4533
  this.size = left.size + right.size;
4498
4534
  }
4499
4535
  get break() { return this.flags & 1 /* Flag.Break */; }
4500
- blockAt(height, doc, top, offset) {
4536
+ blockAt(height, oracle, top, offset) {
4501
4537
  let mid = top + this.left.height;
4502
- return height < mid ? this.left.blockAt(height, doc, top, offset)
4503
- : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break);
4538
+ return height < mid ? this.left.blockAt(height, oracle, top, offset)
4539
+ : this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
4504
4540
  }
4505
- lineAt(value, type, doc, top, offset) {
4541
+ lineAt(value, type, oracle, top, offset) {
4506
4542
  let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
4507
4543
  let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
4508
- let base = left ? this.left.lineAt(value, type, doc, top, offset)
4509
- : this.right.lineAt(value, type, doc, rightTop, rightOffset);
4544
+ let base = left ? this.left.lineAt(value, type, oracle, top, offset)
4545
+ : this.right.lineAt(value, type, oracle, rightTop, rightOffset);
4510
4546
  if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
4511
4547
  return base;
4512
4548
  let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
4513
4549
  if (left)
4514
- return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset));
4550
+ return base.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));
4515
4551
  else
4516
- return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base);
4552
+ return this.left.lineAt(rightOffset, subQuery, oracle, top, offset).join(base);
4517
4553
  }
4518
- forEachLine(from, to, doc, top, offset, f) {
4554
+ forEachLine(from, to, oracle, top, offset, f) {
4519
4555
  let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
4520
4556
  if (this.break) {
4521
4557
  if (from < rightOffset)
4522
- this.left.forEachLine(from, to, doc, top, offset, f);
4558
+ this.left.forEachLine(from, to, oracle, top, offset, f);
4523
4559
  if (to >= rightOffset)
4524
- this.right.forEachLine(from, to, doc, rightTop, rightOffset, f);
4560
+ this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
4525
4561
  }
4526
4562
  else {
4527
- let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset);
4563
+ let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
4528
4564
  if (from < mid.from)
4529
- this.left.forEachLine(from, mid.from - 1, doc, top, offset, f);
4565
+ this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
4530
4566
  if (mid.to >= from && mid.from <= to)
4531
4567
  f(mid);
4532
4568
  if (to > mid.to)
4533
- this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f);
4569
+ this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
4534
4570
  }
4535
4571
  }
4536
4572
  replace(from, to, nodes) {
@@ -4880,11 +4916,11 @@ class ViewState {
4880
4916
  }
4881
4917
  this.viewports = viewports.sort((a, b) => a.from - b.from);
4882
4918
  this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
4883
- new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
4919
+ new BigScaler(this.heightOracle, this.heightMap, this.viewports);
4884
4920
  }
4885
4921
  updateViewportLines() {
4886
4922
  this.viewportLines = [];
4887
- this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
4923
+ this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
4888
4924
  this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
4889
4925
  });
4890
4926
  }
@@ -4924,8 +4960,9 @@ class ViewState {
4924
4960
  let whiteSpace = style.whiteSpace;
4925
4961
  this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
4926
4962
  let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
4927
- let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4928
- this.contentDOMHeight = dom.clientHeight;
4963
+ let domRect = dom.getBoundingClientRect();
4964
+ let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
4965
+ this.contentDOMHeight = domRect.height;
4929
4966
  this.mustMeasureContent = false;
4930
4967
  let result = 0, bias = 0;
4931
4968
  // Vertical padding
@@ -4953,9 +4990,9 @@ class ViewState {
4953
4990
  }
4954
4991
  if (!this.inView && !this.scrollTarget)
4955
4992
  return 0;
4956
- let contentWidth = dom.clientWidth;
4993
+ let contentWidth = domRect.width;
4957
4994
  if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
4958
- this.contentDOMWidth = contentWidth;
4995
+ this.contentDOMWidth = domRect.width;
4959
4996
  this.editorHeight = view.scrollDOM.clientHeight;
4960
4997
  result |= 8 /* UpdateFlag.Geometry */;
4961
4998
  }
@@ -4984,7 +5021,8 @@ class ViewState {
4984
5021
  result |= 2 /* UpdateFlag.Height */;
4985
5022
  }
4986
5023
  let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
4987
- this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
5024
+ this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
5025
+ this.scrollTarget.range.head > this.viewport.to);
4988
5026
  if (viewportChange)
4989
5027
  this.viewport = this.getViewport(bias, this.scrollTarget);
4990
5028
  this.updateForViewport();
@@ -5010,36 +5048,37 @@ class ViewState {
5010
5048
  // bottom, depending on the bias (the change in viewport position
5011
5049
  // since the last update). It'll hold a number between 0 and 1
5012
5050
  let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
5013
- let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
5014
- let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, doc, 0, 0).to);
5051
+ let map = this.heightMap, oracle = this.heightOracle;
5052
+ let { visibleTop, visibleBottom } = this;
5053
+ let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).to);
5015
5054
  // If scrollTarget is given, make sure the viewport includes that position
5016
5055
  if (scrollTarget) {
5017
5056
  let { head } = scrollTarget.range;
5018
5057
  if (head < viewport.from || head > viewport.to) {
5019
5058
  let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
5020
- let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
5059
+ let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0), topPos;
5021
5060
  if (scrollTarget.y == "center")
5022
5061
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
5023
5062
  else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
5024
5063
  topPos = block.top;
5025
5064
  else
5026
5065
  topPos = block.bottom - viewHeight;
5027
- viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to);
5066
+ viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).to);
5028
5067
  }
5029
5068
  }
5030
5069
  return viewport;
5031
5070
  }
5032
5071
  mapViewport(viewport, changes) {
5033
5072
  let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
5034
- return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to);
5073
+ return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
5035
5074
  }
5036
5075
  // Checks if a given viewport covers the visible part of the
5037
5076
  // document and not too much beyond that.
5038
5077
  viewportIsAppropriate({ from, to }, bias = 0) {
5039
5078
  if (!this.inView)
5040
5079
  return true;
5041
- let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0);
5042
- let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0);
5080
+ let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
5081
+ let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
5043
5082
  let { visibleTop, visibleBottom } = this;
5044
5083
  return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) &&
5045
5084
  (to == this.state.doc.length ||
@@ -5176,13 +5215,13 @@ class ViewState {
5176
5215
  }
5177
5216
  lineBlockAt(pos) {
5178
5217
  return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
5179
- scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler);
5218
+ scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
5180
5219
  }
5181
5220
  lineBlockAtHeight(height) {
5182
- return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler);
5221
+ return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
5183
5222
  }
5184
5223
  elementAtHeight(height) {
5185
- return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
5224
+ return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
5186
5225
  }
5187
5226
  get docHeight() {
5188
5227
  return this.scaler.toDOM(this.heightMap.height);
@@ -5256,11 +5295,11 @@ const IdScaler = {
5256
5295
  // regions outside the viewports so that the total height is
5257
5296
  // VP.MaxDOMHeight.
5258
5297
  class BigScaler {
5259
- constructor(doc, heightMap, viewports) {
5298
+ constructor(oracle, heightMap, viewports) {
5260
5299
  let vpHeight = 0, base = 0, domBase = 0;
5261
5300
  this.viewports = viewports.map(({ from, to }) => {
5262
- let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top;
5263
- let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom;
5301
+ let top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
5302
+ let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
5264
5303
  vpHeight += bottom - top;
5265
5304
  return { from, to, top, bottom, domTop: 0, domBottom: 0 };
5266
5305
  });
@@ -5627,7 +5666,7 @@ function applyDOMChange(view, domChange) {
5627
5666
  };
5628
5667
  }
5629
5668
  else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
5630
- /^\. ?$/.test(change.insert.toString())) {
5669
+ /^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
5631
5670
  // Detect insert-period-on-double-space Mac and Android behavior,
5632
5671
  // and transform it into a regular space insert.
5633
5672
  if (newSel && change.insert.length == 2)
@@ -7041,6 +7080,11 @@ called and the default behavior is prevented.
7041
7080
  */
7042
7081
  EditorView.inputHandler = inputHandler;
7043
7082
  /**
7083
+ This facet can be used to provide functions that create effects
7084
+ to be dispatched when the editor's focus state changes.
7085
+ */
7086
+ EditorView.focusChangeEffect = focusChangeEffect;
7087
+ /**
7044
7088
  By default, the editor assumes all its content has the same
7045
7089
  [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
7046
7090
  value to make it read the text direction of every (rendered)
@@ -8356,6 +8400,7 @@ const tooltipConfig = /*@__PURE__*/Facet.define({
8356
8400
  });
8357
8401
  }
8358
8402
  });
8403
+ const knownHeight = /*@__PURE__*/new WeakMap();
8359
8404
  const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8360
8405
  constructor(view) {
8361
8406
  this.view = view;
@@ -8471,6 +8516,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8471
8516
  };
8472
8517
  }
8473
8518
  writeMeasure(measured) {
8519
+ var _a;
8474
8520
  let { editor, space } = measured;
8475
8521
  let others = [];
8476
8522
  for (let i = 0; i < this.manager.tooltips.length; i++) {
@@ -8486,7 +8532,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8486
8532
  }
8487
8533
  let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
8488
8534
  let arrowHeight = arrow ? 7 /* Arrow.Size */ : 0;
8489
- let width = size.right - size.left, height = size.bottom - size.top;
8535
+ let width = size.right - size.left, height = (_a = knownHeight.get(tView)) !== null && _a !== void 0 ? _a : size.bottom - size.top;
8490
8536
  let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
8491
8537
  let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
8492
8538
  : ltr ? Math.min(pos.left - (arrow ? 14 /* Arrow.Offset */ : 0) + offset.x, space.right - width)
@@ -8503,6 +8549,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8503
8549
  dom.style.top = Outside;
8504
8550
  continue;
8505
8551
  }
8552
+ knownHeight.set(tView, height);
8506
8553
  dom.style.height = (height = spaceVert) + "px";
8507
8554
  }
8508
8555
  else if (dom.style.height) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.8.0",
3
+ "version": "6.9.0",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",