@codemirror/view 6.38.4 → 6.38.6

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,19 @@
1
+ ## 6.38.6 (2025-10-13)
2
+
3
+ ### Bug fixes
4
+
5
+ Work around a regression in Safari 26 that causes fragments of old selections to remain visible.
6
+
7
+ ## 6.38.5 (2025-10-07)
8
+
9
+ ### Bug fixes
10
+
11
+ Avoid firing text changes that cover unchanged text on Android.
12
+
13
+ Fix an issue where the editor could, in some circumstances, insert a stray newline when typing over a document that ended in a block widget.
14
+
15
+ Work around an issue in Safari 26 that causes inappropriate scrolling on focus in some circumstances.
16
+
1
17
  ## 6.38.4 (2025-09-28)
2
18
 
3
19
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -5,6 +5,36 @@ var styleMod = require('style-mod');
5
5
  var w3cKeyname = require('w3c-keyname');
6
6
  var elt = require('crelt');
7
7
 
8
+ let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
9
+ let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
10
+ const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
11
+ const ie_upto10 = /MSIE \d/.test(nav.userAgent);
12
+ const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
13
+ const ie = !!(ie_upto10 || ie_11up || ie_edge);
14
+ const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent);
15
+ const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent);
16
+ const webkit = "webkitFontSmoothing" in doc.documentElement.style;
17
+ const safari = !ie && /Apple Computer/.test(nav.vendor);
18
+ const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
19
+ var browser = {
20
+ mac: ios || /Mac/.test(nav.platform),
21
+ windows: /Win/.test(nav.platform),
22
+ linux: /Linux|X11/.test(nav.platform),
23
+ ie,
24
+ ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
25
+ gecko,
26
+ gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
27
+ chrome: !!chrome,
28
+ chrome_version: chrome ? +chrome[1] : 0,
29
+ ios,
30
+ android: /Android\b/.test(nav.userAgent),
31
+ webkit,
32
+ webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
33
+ safari,
34
+ safari_version: safari ? +(/\bVersion\/(\d+(\.\d+)?)/.exec(nav.userAgent) || [0, 0])[1] : 0,
35
+ tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
36
+ };
37
+
8
38
  function getSelection(root) {
9
39
  let target;
10
40
  // Browsers differ on whether shadow roots have a getSelection
@@ -255,6 +285,9 @@ class DOMSelectionState {
255
285
  }
256
286
  }
257
287
  let preventScrollSupported = null;
288
+ // Safari 26 breaks preventScroll support
289
+ if (browser.safari && browser.safari_version >= 26)
290
+ preventScrollSupported = false;
258
291
  // Feature-detects support for .focus({preventScroll: true}), and uses
259
292
  // a fallback kludge when not supported.
260
293
  function focusPreventScroll(dom) {
@@ -724,35 +757,6 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
724
757
  replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
725
758
  }
726
759
 
727
- let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
728
- let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
729
- const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
730
- const ie_upto10 = /MSIE \d/.test(nav.userAgent);
731
- const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
732
- const ie = !!(ie_upto10 || ie_11up || ie_edge);
733
- const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent);
734
- const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent);
735
- const webkit = "webkitFontSmoothing" in doc.documentElement.style;
736
- const safari = !ie && /Apple Computer/.test(nav.vendor);
737
- const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
738
- var browser = {
739
- mac: ios || /Mac/.test(nav.platform),
740
- windows: /Win/.test(nav.platform),
741
- linux: /Linux|X11/.test(nav.platform),
742
- ie,
743
- ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
744
- gecko,
745
- gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
746
- chrome: !!chrome,
747
- chrome_version: chrome ? +chrome[1] : 0,
748
- ios,
749
- android: /Android\b/.test(nav.userAgent),
750
- webkit,
751
- safari,
752
- webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
753
- tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
754
- };
755
-
756
760
  const MaxJoinLen = 256;
757
761
  class TextView extends ContentView {
758
762
  constructor(text) {
@@ -3858,9 +3862,10 @@ class DOMReader {
3858
3862
  if (next == end)
3859
3863
  break;
3860
3864
  let view = ContentView.get(cur), nextView = ContentView.get(next);
3861
- if (view && nextView ? view.breakAfter :
3865
+ if ((view && nextView ? view.breakAfter :
3862
3866
  (view ? view.breakAfter : isBlockElement(cur)) ||
3863
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
3867
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen)) &&
3868
+ !isEmptyToEnd(next, end))
3864
3869
  this.lineBreak();
3865
3870
  cur = next;
3866
3871
  }
@@ -3939,6 +3944,25 @@ function isAtEnd(parent, node, offset) {
3939
3944
  node = node.parentNode;
3940
3945
  }
3941
3946
  }
3947
+ function isEmptyToEnd(node, end) {
3948
+ let widgets;
3949
+ for (;; node = node.nextSibling) {
3950
+ if (node == end || !node)
3951
+ break;
3952
+ let view = ContentView.get(node);
3953
+ if (!((view === null || view === void 0 ? void 0 : view.isWidget) || node.cmIgnore))
3954
+ return false;
3955
+ if (view)
3956
+ (widgets || (widgets = [])).push(view);
3957
+ }
3958
+ if (widgets)
3959
+ for (let w of widgets) {
3960
+ let override = w.overrideDOMText;
3961
+ if (override === null || override === void 0 ? void 0 : override.length)
3962
+ return false;
3963
+ }
3964
+ return true;
3965
+ }
3942
3966
  class DOMPoint {
3943
3967
  constructor(node, offset) {
3944
3968
  this.node = node;
@@ -4380,7 +4404,7 @@ class InputState {
4380
4404
  return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
4381
4405
  }
4382
4406
  ignoreDuringComposition(event) {
4383
- if (!/^key/.test(event.type))
4407
+ if (!/^key/.test(event.type) || event.synthetic)
4384
4408
  return false;
4385
4409
  if (this.composing > 0)
4386
4410
  return true;
@@ -7285,20 +7309,23 @@ class EditContextManager {
7285
7309
  let from = this.toEditorPos(e.updateRangeStart), to = this.toEditorPos(e.updateRangeEnd);
7286
7310
  if (view.inputState.composing >= 0 && !this.composing)
7287
7311
  this.composing = { contextBase: e.updateRangeStart, editorBase: from, drifted: false };
7288
- let change = { from, to, insert: state.Text.of(e.text.split("\n")) };
7312
+ let deletes = to - from > e.text.length;
7289
7313
  // If the window doesn't include the anchor, assume changes
7290
7314
  // adjacent to a side go up to the anchor.
7291
- if (change.from == this.from && anchor < this.from)
7292
- change.from = anchor;
7293
- else if (change.to == this.to && anchor > this.to)
7294
- change.to = anchor;
7315
+ if (from == this.from && anchor < this.from)
7316
+ from = anchor;
7317
+ else if (to == this.to && anchor > this.to)
7318
+ to = anchor;
7319
+ let diff = findDiff(view.state.sliceDoc(from, to), e.text, (deletes ? main.from : main.to) - from, deletes ? "end" : null);
7295
7320
  // Edit contexts sometimes fire empty changes
7296
- if (change.from == change.to && !change.insert.length) {
7321
+ if (!diff) {
7297
7322
  let newSel = state.EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
7298
7323
  if (!newSel.main.eq(main))
7299
7324
  view.dispatch({ selection: newSel, userEvent: "select" });
7300
7325
  return;
7301
7326
  }
7327
+ let change = { from: diff.from + from, to: diff.toA + from,
7328
+ insert: state.Text.of(e.text.slice(diff.from, diff.toB).split("\n")) };
7302
7329
  if ((browser.mac || browser.android) && change.from == head - 1 &&
7303
7330
  /^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off")
7304
7331
  change = { from, to, insert: state.Text.of([e.text.replace(".", " ")]) };
@@ -9103,7 +9130,7 @@ class LayerView {
9103
9130
  old = next;
9104
9131
  }
9105
9132
  this.drawn = markers;
9106
- if (browser.ios) // Issue #1600
9133
+ if (browser.safari && browser.safari_version >= 26) // Issue #1600, 1627
9107
9134
  this.dom.style.display = this.dom.firstChild ? "" : "none";
9108
9135
  }
9109
9136
  }
package/dist/index.js CHANGED
@@ -3,6 +3,36 @@ import { StyleModule } from 'style-mod';
3
3
  import { keyName, base, shift } from 'w3c-keyname';
4
4
  import elt from 'crelt';
5
5
 
6
+ let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
7
+ let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
8
+ const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
9
+ const ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent);
10
+ const ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
11
+ const ie = !!(ie_upto10 || ie_11up || ie_edge);
12
+ const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
13
+ const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
14
+ const webkit = "webkitFontSmoothing" in doc.documentElement.style;
15
+ const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
16
+ const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
17
+ var browser = {
18
+ mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
19
+ windows: /*@__PURE__*//Win/.test(nav.platform),
20
+ linux: /*@__PURE__*//Linux|X11/.test(nav.platform),
21
+ ie,
22
+ ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
23
+ gecko,
24
+ gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
25
+ chrome: !!chrome,
26
+ chrome_version: chrome ? +chrome[1] : 0,
27
+ ios,
28
+ android: /*@__PURE__*//Android\b/.test(nav.userAgent),
29
+ webkit,
30
+ webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
31
+ safari,
32
+ safari_version: safari ? +(/*@__PURE__*//\bVersion\/(\d+(\.\d+)?)/.exec(nav.userAgent) || [0, 0])[1] : 0,
33
+ tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
34
+ };
35
+
6
36
  function getSelection(root) {
7
37
  let target;
8
38
  // Browsers differ on whether shadow roots have a getSelection
@@ -253,6 +283,9 @@ class DOMSelectionState {
253
283
  }
254
284
  }
255
285
  let preventScrollSupported = null;
286
+ // Safari 26 breaks preventScroll support
287
+ if (browser.safari && browser.safari_version >= 26)
288
+ preventScrollSupported = false;
256
289
  // Feature-detects support for .focus({preventScroll: true}), and uses
257
290
  // a fallback kludge when not supported.
258
291
  function focusPreventScroll(dom) {
@@ -722,35 +755,6 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
722
755
  replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
723
756
  }
724
757
 
725
- let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
726
- let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
727
- const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
728
- const ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent);
729
- const ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
730
- const ie = !!(ie_upto10 || ie_11up || ie_edge);
731
- const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
732
- const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
733
- const webkit = "webkitFontSmoothing" in doc.documentElement.style;
734
- const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
735
- const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
736
- var browser = {
737
- mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
738
- windows: /*@__PURE__*//Win/.test(nav.platform),
739
- linux: /*@__PURE__*//Linux|X11/.test(nav.platform),
740
- ie,
741
- ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
742
- gecko,
743
- gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
744
- chrome: !!chrome,
745
- chrome_version: chrome ? +chrome[1] : 0,
746
- ios,
747
- android: /*@__PURE__*//Android\b/.test(nav.userAgent),
748
- webkit,
749
- safari,
750
- webkit_version: webkit ? +(/*@__PURE__*//\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
751
- tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
752
- };
753
-
754
758
  const MaxJoinLen = 256;
755
759
  class TextView extends ContentView {
756
760
  constructor(text) {
@@ -3854,9 +3858,10 @@ class DOMReader {
3854
3858
  if (next == end)
3855
3859
  break;
3856
3860
  let view = ContentView.get(cur), nextView = ContentView.get(next);
3857
- if (view && nextView ? view.breakAfter :
3861
+ if ((view && nextView ? view.breakAfter :
3858
3862
  (view ? view.breakAfter : isBlockElement(cur)) ||
3859
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
3863
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen)) &&
3864
+ !isEmptyToEnd(next, end))
3860
3865
  this.lineBreak();
3861
3866
  cur = next;
3862
3867
  }
@@ -3935,6 +3940,25 @@ function isAtEnd(parent, node, offset) {
3935
3940
  node = node.parentNode;
3936
3941
  }
3937
3942
  }
3943
+ function isEmptyToEnd(node, end) {
3944
+ let widgets;
3945
+ for (;; node = node.nextSibling) {
3946
+ if (node == end || !node)
3947
+ break;
3948
+ let view = ContentView.get(node);
3949
+ if (!((view === null || view === void 0 ? void 0 : view.isWidget) || node.cmIgnore))
3950
+ return false;
3951
+ if (view)
3952
+ (widgets || (widgets = [])).push(view);
3953
+ }
3954
+ if (widgets)
3955
+ for (let w of widgets) {
3956
+ let override = w.overrideDOMText;
3957
+ if (override === null || override === void 0 ? void 0 : override.length)
3958
+ return false;
3959
+ }
3960
+ return true;
3961
+ }
3938
3962
  class DOMPoint {
3939
3963
  constructor(node, offset) {
3940
3964
  this.node = node;
@@ -4376,7 +4400,7 @@ class InputState {
4376
4400
  return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : undefined);
4377
4401
  }
4378
4402
  ignoreDuringComposition(event) {
4379
- if (!/^key/.test(event.type))
4403
+ if (!/^key/.test(event.type) || event.synthetic)
4380
4404
  return false;
4381
4405
  if (this.composing > 0)
4382
4406
  return true;
@@ -7280,20 +7304,23 @@ class EditContextManager {
7280
7304
  let from = this.toEditorPos(e.updateRangeStart), to = this.toEditorPos(e.updateRangeEnd);
7281
7305
  if (view.inputState.composing >= 0 && !this.composing)
7282
7306
  this.composing = { contextBase: e.updateRangeStart, editorBase: from, drifted: false };
7283
- let change = { from, to, insert: Text.of(e.text.split("\n")) };
7307
+ let deletes = to - from > e.text.length;
7284
7308
  // If the window doesn't include the anchor, assume changes
7285
7309
  // adjacent to a side go up to the anchor.
7286
- if (change.from == this.from && anchor < this.from)
7287
- change.from = anchor;
7288
- else if (change.to == this.to && anchor > this.to)
7289
- change.to = anchor;
7310
+ if (from == this.from && anchor < this.from)
7311
+ from = anchor;
7312
+ else if (to == this.to && anchor > this.to)
7313
+ to = anchor;
7314
+ let diff = findDiff(view.state.sliceDoc(from, to), e.text, (deletes ? main.from : main.to) - from, deletes ? "end" : null);
7290
7315
  // Edit contexts sometimes fire empty changes
7291
- if (change.from == change.to && !change.insert.length) {
7316
+ if (!diff) {
7292
7317
  let newSel = EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
7293
7318
  if (!newSel.main.eq(main))
7294
7319
  view.dispatch({ selection: newSel, userEvent: "select" });
7295
7320
  return;
7296
7321
  }
7322
+ let change = { from: diff.from + from, to: diff.toA + from,
7323
+ insert: Text.of(e.text.slice(diff.from, diff.toB).split("\n")) };
7297
7324
  if ((browser.mac || browser.android) && change.from == head - 1 &&
7298
7325
  /^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off")
7299
7326
  change = { from, to, insert: Text.of([e.text.replace(".", " ")]) };
@@ -9098,7 +9125,7 @@ class LayerView {
9098
9125
  old = next;
9099
9126
  }
9100
9127
  this.drawn = markers;
9101
- if (browser.ios) // Issue #1600
9128
+ if (browser.safari && browser.safari_version >= 26) // Issue #1600, 1627
9102
9129
  this.dom.style.display = this.dom.firstChild ? "" : "none";
9103
9130
  }
9104
9131
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.38.4",
3
+ "version": "6.38.6",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",