@codemirror/view 6.35.2 → 6.36.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,25 @@
1
+ ## 6.36.0 (2024-12-17)
2
+
3
+ ### Bug fixes
4
+
5
+ Make selection rectangles verticaly align precisely, rather than introducing a slight overlap.
6
+
7
+ Fix an issue in `MatchDecorator` that caused it to fully rebuild its decorations on normal edits.
8
+
9
+ ### New features
10
+
11
+ View updates now have a `viewportMoved` flag that is only true when a viewport change originated from something other than mapping the viewport over a document change.
12
+
13
+ ## 6.35.3 (2024-12-09)
14
+
15
+ ### Bug fixes
16
+
17
+ Fix an issue where mark decorations that got merged or split weren't properly redrawn.
18
+
19
+ Avoid spurious focus events by not updating the DOM selection when the editor is unfocused but focusable.
20
+
21
+ Disable `writingsuggestions` for the editable element, to opt out of Safari's new intelligence completions (which mess up in the editor).
22
+
1
23
  ## 6.35.2 (2024-12-07)
2
24
 
3
25
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2691,6 +2691,15 @@ class ViewUpdate {
2691
2691
  return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
2692
2692
  }
2693
2693
  /**
2694
+ Returns true when
2695
+ [`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
2696
+ and the viewport change is not just the result of mapping it in
2697
+ response to document changes.
2698
+ */
2699
+ get viewportMoved() {
2700
+ return (this.flags & 8 /* UpdateFlag.ViewportMoved */) > 0;
2701
+ }
2702
+ /**
2694
2703
  Indicates whether the height of a block element in the editor
2695
2704
  changed in this update.
2696
2705
  */
@@ -2702,7 +2711,7 @@ class ViewUpdate {
2702
2711
  editor, or elements within the editor, changed.
2703
2712
  */
2704
2713
  get geometryChanged() {
2705
- return this.docChanged || (this.flags & (8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
2714
+ return this.docChanged || (this.flags & (16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
2706
2715
  }
2707
2716
  /**
2708
2717
  True when this update indicates a focus change.
@@ -2927,7 +2936,7 @@ class DocView extends ContentView {
2927
2936
  if (mustRead || !this.view.observer.selectionRange.focusNode)
2928
2937
  this.view.observer.readSelectionRange();
2929
2938
  let activeElt = this.view.root.activeElement, focused = activeElt == this.dom;
2930
- let selectionNotFocus = !focused &&
2939
+ let selectionNotFocus = !focused && !(this.view.state.facet(editable) || this.dom.tabIndex > -1) &&
2931
2940
  hasSelection(this.dom, this.view.observer.selectionRange) && !(activeElt && this.dom.contains(activeElt));
2932
2941
  if (!(focused || fromPointer || selectionNotFocus))
2933
2942
  return;
@@ -3353,6 +3362,7 @@ let DecorationComparator$1 = class DecorationComparator {
3353
3362
  }
3354
3363
  compareRange(from, to) { addRange(from, to, this.changes); }
3355
3364
  comparePoint(from, to) { addRange(from, to, this.changes); }
3365
+ boundChange(pos) { addRange(pos, pos, this.changes); }
3356
3366
  };
3357
3367
  function findChangedDeco(a, b, diff) {
3358
3368
  let comp = new DecorationComparator$1;
@@ -5928,7 +5938,7 @@ class ViewState {
5928
5938
  this.updateViewportLines();
5929
5939
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
5930
5940
  this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
5931
- update.flags |= this.computeVisibleRanges();
5941
+ update.flags |= this.computeVisibleRanges(update.changes);
5932
5942
  if (scrollTarget)
5933
5943
  this.scrollTarget = scrollTarget;
5934
5944
  if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
@@ -5953,7 +5963,7 @@ class ViewState {
5953
5963
  scaleY > .005 && Math.abs(this.scaleY - scaleY) > .005) {
5954
5964
  this.scaleX = scaleX;
5955
5965
  this.scaleY = scaleY;
5956
- result |= 8 /* UpdateFlag.Geometry */;
5966
+ result |= 16 /* UpdateFlag.Geometry */;
5957
5967
  refresh = measureContent = true;
5958
5968
  }
5959
5969
  }
@@ -5963,13 +5973,13 @@ class ViewState {
5963
5973
  if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
5964
5974
  this.paddingTop = paddingTop;
5965
5975
  this.paddingBottom = paddingBottom;
5966
- result |= 8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
5976
+ result |= 16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
5967
5977
  }
5968
5978
  if (this.editorWidth != view.scrollDOM.clientWidth) {
5969
5979
  if (oracle.lineWrapping)
5970
5980
  measureContent = true;
5971
5981
  this.editorWidth = view.scrollDOM.clientWidth;
5972
- result |= 8 /* UpdateFlag.Geometry */;
5982
+ result |= 16 /* UpdateFlag.Geometry */;
5973
5983
  }
5974
5984
  let scrollTop = view.scrollDOM.scrollTop * this.scaleY;
5975
5985
  if (this.scrollTop != scrollTop) {
@@ -5993,7 +6003,7 @@ class ViewState {
5993
6003
  if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
5994
6004
  this.contentDOMWidth = domRect.width;
5995
6005
  this.editorHeight = view.scrollDOM.clientHeight;
5996
- result |= 8 /* UpdateFlag.Geometry */;
6006
+ result |= 16 /* UpdateFlag.Geometry */;
5997
6007
  }
5998
6008
  if (measureContent) {
5999
6009
  let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
@@ -6004,7 +6014,7 @@ class ViewState {
6004
6014
  refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
6005
6015
  if (refresh) {
6006
6016
  view.docView.minWidth = 0;
6007
- result |= 8 /* UpdateFlag.Geometry */;
6017
+ result |= 16 /* UpdateFlag.Geometry */;
6008
6018
  }
6009
6019
  }
6010
6020
  if (dTop > 0 && dBottom > 0)
@@ -6217,7 +6227,7 @@ class ViewState {
6217
6227
  this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
6218
6228
  }
6219
6229
  }
6220
- computeVisibleRanges() {
6230
+ computeVisibleRanges(changes) {
6221
6231
  let deco = this.stateDeco;
6222
6232
  if (this.lineGaps.length)
6223
6233
  deco = deco.concat(this.lineGapDeco);
@@ -6226,10 +6236,22 @@ class ViewState {
6226
6236
  span(from, to) { ranges.push({ from, to }); },
6227
6237
  point() { }
6228
6238
  }, 20);
6229
- let changed = ranges.length != this.visibleRanges.length ||
6230
- this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to);
6239
+ let changed = 0;
6240
+ if (ranges.length != this.visibleRanges.length) {
6241
+ changed = 8 /* UpdateFlag.ViewportMoved */ | 4 /* UpdateFlag.Viewport */;
6242
+ }
6243
+ else {
6244
+ for (let i = 0; i < ranges.length && !(changed & 8 /* UpdateFlag.ViewportMoved */); i++) {
6245
+ let old = this.visibleRanges[i], nw = ranges[i];
6246
+ if (old.from != nw.from || old.to != nw.to) {
6247
+ changed |= 4 /* UpdateFlag.Viewport */;
6248
+ if (!(changes && changes.mapPos(old.from, -1) == nw.from && changes.mapPos(old.to, 1) == nw.to))
6249
+ changed |= 8 /* UpdateFlag.ViewportMoved */;
6250
+ }
6251
+ }
6252
+ }
6231
6253
  this.visibleRanges = ranges;
6232
- return changed ? 4 /* UpdateFlag.Viewport */ : 0;
6254
+ return changed;
6233
6255
  }
6234
6256
  lineBlockAt(pos) {
6235
6257
  return (pos >= this.viewport.from && pos <= this.viewport.to &&
@@ -7796,6 +7818,7 @@ class EditorView {
7796
7818
  spellcheck: "false",
7797
7819
  autocorrect: "off",
7798
7820
  autocapitalize: "off",
7821
+ writingsuggestions: "false",
7799
7822
  translate: "no",
7800
7823
  contenteditable: !this.state.facet(editable) ? "false" : "true",
7801
7824
  class: "cm-content",
@@ -8843,7 +8866,7 @@ function rectanglesForRange(view, className, range) {
8843
8866
  return pieces(top).concat(between).concat(pieces(bottom));
8844
8867
  }
8845
8868
  function piece(left, top, right, bottom) {
8846
- return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
8869
+ return new RectangleMarker(className, left - base.left, top - base.top, right - left, bottom - top);
8847
8870
  }
8848
8871
  function pieces({ top, bottom, horizontal }) {
8849
8872
  let pieces = [];
@@ -9275,7 +9298,7 @@ class MatchDecorator {
9275
9298
  changeTo = Math.max(to, changeTo);
9276
9299
  }
9277
9300
  });
9278
- if (update.viewportChanged || changeTo - changeFrom > 1000)
9301
+ if (update.viewportMoved || changeTo - changeFrom > 1000)
9279
9302
  return this.createDeco(update.view);
9280
9303
  if (changeTo > -1)
9281
9304
  return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo);
package/dist/index.d.cts CHANGED
@@ -523,6 +523,13 @@ declare class ViewUpdate {
523
523
  */
524
524
  get viewportChanged(): boolean;
525
525
  /**
526
+ Returns true when
527
+ [`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
528
+ and the viewport change is not just the result of mapping it in
529
+ response to document changes.
530
+ */
531
+ get viewportMoved(): boolean;
532
+ /**
526
533
  Indicates whether the height of a block element in the editor
527
534
  changed in this update.
528
535
  */
package/dist/index.d.ts CHANGED
@@ -523,6 +523,13 @@ declare class ViewUpdate {
523
523
  */
524
524
  get viewportChanged(): boolean;
525
525
  /**
526
+ Returns true when
527
+ [`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
528
+ and the viewport change is not just the result of mapping it in
529
+ response to document changes.
530
+ */
531
+ get viewportMoved(): boolean;
532
+ /**
526
533
  Indicates whether the height of a block element in the editor
527
534
  changed in this update.
528
535
  */
package/dist/index.js CHANGED
@@ -2687,6 +2687,15 @@ class ViewUpdate {
2687
2687
  return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
2688
2688
  }
2689
2689
  /**
2690
+ Returns true when
2691
+ [`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
2692
+ and the viewport change is not just the result of mapping it in
2693
+ response to document changes.
2694
+ */
2695
+ get viewportMoved() {
2696
+ return (this.flags & 8 /* UpdateFlag.ViewportMoved */) > 0;
2697
+ }
2698
+ /**
2690
2699
  Indicates whether the height of a block element in the editor
2691
2700
  changed in this update.
2692
2701
  */
@@ -2698,7 +2707,7 @@ class ViewUpdate {
2698
2707
  editor, or elements within the editor, changed.
2699
2708
  */
2700
2709
  get geometryChanged() {
2701
- return this.docChanged || (this.flags & (8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
2710
+ return this.docChanged || (this.flags & (16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
2702
2711
  }
2703
2712
  /**
2704
2713
  True when this update indicates a focus change.
@@ -2923,7 +2932,7 @@ class DocView extends ContentView {
2923
2932
  if (mustRead || !this.view.observer.selectionRange.focusNode)
2924
2933
  this.view.observer.readSelectionRange();
2925
2934
  let activeElt = this.view.root.activeElement, focused = activeElt == this.dom;
2926
- let selectionNotFocus = !focused &&
2935
+ let selectionNotFocus = !focused && !(this.view.state.facet(editable) || this.dom.tabIndex > -1) &&
2927
2936
  hasSelection(this.dom, this.view.observer.selectionRange) && !(activeElt && this.dom.contains(activeElt));
2928
2937
  if (!(focused || fromPointer || selectionNotFocus))
2929
2938
  return;
@@ -3349,6 +3358,7 @@ let DecorationComparator$1 = class DecorationComparator {
3349
3358
  }
3350
3359
  compareRange(from, to) { addRange(from, to, this.changes); }
3351
3360
  comparePoint(from, to) { addRange(from, to, this.changes); }
3361
+ boundChange(pos) { addRange(pos, pos, this.changes); }
3352
3362
  };
3353
3363
  function findChangedDeco(a, b, diff) {
3354
3364
  let comp = new DecorationComparator$1;
@@ -5923,7 +5933,7 @@ class ViewState {
5923
5933
  this.updateViewportLines();
5924
5934
  if (this.lineGaps.length || this.viewport.to - this.viewport.from > (2000 /* LG.Margin */ << 1))
5925
5935
  this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
5926
- update.flags |= this.computeVisibleRanges();
5936
+ update.flags |= this.computeVisibleRanges(update.changes);
5927
5937
  if (scrollTarget)
5928
5938
  this.scrollTarget = scrollTarget;
5929
5939
  if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
@@ -5948,7 +5958,7 @@ class ViewState {
5948
5958
  scaleY > .005 && Math.abs(this.scaleY - scaleY) > .005) {
5949
5959
  this.scaleX = scaleX;
5950
5960
  this.scaleY = scaleY;
5951
- result |= 8 /* UpdateFlag.Geometry */;
5961
+ result |= 16 /* UpdateFlag.Geometry */;
5952
5962
  refresh = measureContent = true;
5953
5963
  }
5954
5964
  }
@@ -5958,13 +5968,13 @@ class ViewState {
5958
5968
  if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
5959
5969
  this.paddingTop = paddingTop;
5960
5970
  this.paddingBottom = paddingBottom;
5961
- result |= 8 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
5971
+ result |= 16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */;
5962
5972
  }
5963
5973
  if (this.editorWidth != view.scrollDOM.clientWidth) {
5964
5974
  if (oracle.lineWrapping)
5965
5975
  measureContent = true;
5966
5976
  this.editorWidth = view.scrollDOM.clientWidth;
5967
- result |= 8 /* UpdateFlag.Geometry */;
5977
+ result |= 16 /* UpdateFlag.Geometry */;
5968
5978
  }
5969
5979
  let scrollTop = view.scrollDOM.scrollTop * this.scaleY;
5970
5980
  if (this.scrollTop != scrollTop) {
@@ -5988,7 +5998,7 @@ class ViewState {
5988
5998
  if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
5989
5999
  this.contentDOMWidth = domRect.width;
5990
6000
  this.editorHeight = view.scrollDOM.clientHeight;
5991
- result |= 8 /* UpdateFlag.Geometry */;
6001
+ result |= 16 /* UpdateFlag.Geometry */;
5992
6002
  }
5993
6003
  if (measureContent) {
5994
6004
  let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
@@ -5999,7 +6009,7 @@ class ViewState {
5999
6009
  refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
6000
6010
  if (refresh) {
6001
6011
  view.docView.minWidth = 0;
6002
- result |= 8 /* UpdateFlag.Geometry */;
6012
+ result |= 16 /* UpdateFlag.Geometry */;
6003
6013
  }
6004
6014
  }
6005
6015
  if (dTop > 0 && dBottom > 0)
@@ -6212,7 +6222,7 @@ class ViewState {
6212
6222
  this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
6213
6223
  }
6214
6224
  }
6215
- computeVisibleRanges() {
6225
+ computeVisibleRanges(changes) {
6216
6226
  let deco = this.stateDeco;
6217
6227
  if (this.lineGaps.length)
6218
6228
  deco = deco.concat(this.lineGapDeco);
@@ -6221,10 +6231,22 @@ class ViewState {
6221
6231
  span(from, to) { ranges.push({ from, to }); },
6222
6232
  point() { }
6223
6233
  }, 20);
6224
- let changed = ranges.length != this.visibleRanges.length ||
6225
- this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to);
6234
+ let changed = 0;
6235
+ if (ranges.length != this.visibleRanges.length) {
6236
+ changed = 8 /* UpdateFlag.ViewportMoved */ | 4 /* UpdateFlag.Viewport */;
6237
+ }
6238
+ else {
6239
+ for (let i = 0; i < ranges.length && !(changed & 8 /* UpdateFlag.ViewportMoved */); i++) {
6240
+ let old = this.visibleRanges[i], nw = ranges[i];
6241
+ if (old.from != nw.from || old.to != nw.to) {
6242
+ changed |= 4 /* UpdateFlag.Viewport */;
6243
+ if (!(changes && changes.mapPos(old.from, -1) == nw.from && changes.mapPos(old.to, 1) == nw.to))
6244
+ changed |= 8 /* UpdateFlag.ViewportMoved */;
6245
+ }
6246
+ }
6247
+ }
6226
6248
  this.visibleRanges = ranges;
6227
- return changed ? 4 /* UpdateFlag.Viewport */ : 0;
6249
+ return changed;
6228
6250
  }
6229
6251
  lineBlockAt(pos) {
6230
6252
  return (pos >= this.viewport.from && pos <= this.viewport.to &&
@@ -7791,6 +7813,7 @@ class EditorView {
7791
7813
  spellcheck: "false",
7792
7814
  autocorrect: "off",
7793
7815
  autocapitalize: "off",
7816
+ writingsuggestions: "false",
7794
7817
  translate: "no",
7795
7818
  contenteditable: !this.state.facet(editable) ? "false" : "true",
7796
7819
  class: "cm-content",
@@ -8838,7 +8861,7 @@ function rectanglesForRange(view, className, range) {
8838
8861
  return pieces(top).concat(between).concat(pieces(bottom));
8839
8862
  }
8840
8863
  function piece(left, top, right, bottom) {
8841
- return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
8864
+ return new RectangleMarker(className, left - base.left, top - base.top, right - left, bottom - top);
8842
8865
  }
8843
8866
  function pieces({ top, bottom, horizontal }) {
8844
8867
  let pieces = [];
@@ -9270,7 +9293,7 @@ class MatchDecorator {
9270
9293
  changeTo = Math.max(to, changeTo);
9271
9294
  }
9272
9295
  });
9273
- if (update.viewportChanged || changeTo - changeFrom > 1000)
9296
+ if (update.viewportMoved || changeTo - changeFrom > 1000)
9274
9297
  return this.createDeco(update.view);
9275
9298
  if (changeTo > -1)
9276
9299
  return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.35.2",
3
+ "version": "6.36.0",
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/state": "^6.4.0",
29
+ "@codemirror/state": "^6.5.0",
30
30
  "style-mod": "^4.1.0",
31
31
  "w3c-keyname": "^2.2.4"
32
32
  },