@codemirror/view 6.9.3 → 6.9.4

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,21 @@
1
+ ## 6.9.4 (2023-04-11)
2
+
3
+ ### Bug fixes
4
+
5
+ Make the editor scroll while dragging a selection near its sides, even if the cursor isn't outside the scrollable element.
6
+
7
+ Fix a bug that interrupted composition after widgets in some circumstances on Firefox.
8
+
9
+ Make sure the last change in a composition has its user event set to `input.type.compose`, even if the `compositionend` event fires before the changes are applied.
10
+
11
+ Make it possible to remove additional selection ranges by clicking on them with ctrl/cmd held, even if they aren't cursors.
12
+
13
+ Keep widget buffers between widgets and compositions, since removing them confuses IME on macOS Firefox.
14
+
15
+ Fix a bug where, for DOM changes that put the selection in the middle of the changed range, the editor incorrectly set its selection state.
16
+
17
+ Fix a bug where `coordsAtPos` could return a coordinates before the line break when querying a line-wrapped position with a positive `side`.
18
+
1
19
  ## 6.9.3 (2023-03-21)
2
20
 
3
21
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -520,6 +520,7 @@ class ContentView {
520
520
  static get(node) { return node.cmView; }
521
521
  get isEditable() { return true; }
522
522
  get isWidget() { return false; }
523
+ get isHidden() { return false; }
523
524
  merge(from, to, source, hasStart, openStart, openEnd) {
524
525
  return false;
525
526
  }
@@ -857,7 +858,7 @@ class WidgetView extends ContentView {
857
858
  become(other) {
858
859
  if (other.length == this.length && other instanceof WidgetView && other.side == this.side) {
859
860
  if (this.widget.constructor == other.widget.constructor) {
860
- if (!this.widget.eq(other.widget))
861
+ if (!this.widget.compare(other.widget))
861
862
  this.markDirty(true);
862
863
  if (this.dom && !this.prevWidget)
863
864
  this.prevWidget = this.widget;
@@ -879,7 +880,9 @@ class WidgetView extends ContentView {
879
880
  return text ? text.slice(start, start + this.length) : state.Text.empty;
880
881
  }
881
882
  domAtPos(pos) {
882
- return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
883
+ return (this.length ? pos == 0 : this.side > 0)
884
+ ? DOMPos.before(this.dom)
885
+ : DOMPos.after(this.dom, pos == this.length);
883
886
  }
884
887
  domBoundsAround() { return null; }
885
888
  coordsAt(pos, side) {
@@ -895,6 +898,7 @@ class WidgetView extends ContentView {
895
898
  }
896
899
  get isEditable() { return false; }
897
900
  get isWidget() { return true; }
901
+ get isHidden() { return this.widget.isHidden; }
898
902
  destroy() {
899
903
  super.destroy();
900
904
  if (this.dom)
@@ -1007,6 +1011,7 @@ class WidgetBufferView extends ContentView {
1007
1011
  get overrideDOMText() {
1008
1012
  return state.Text.empty;
1009
1013
  }
1014
+ get isHidden() { return true; }
1010
1015
  }
1011
1016
  TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
1012
1017
  function inlineSiblingRect(view, side) {
@@ -1080,7 +1085,8 @@ function coordsInChildren(view, pos, side) {
1080
1085
  if (child.children.length) {
1081
1086
  scan(child, pos - off);
1082
1087
  }
1083
- else if (!after && (end > pos || off == end && child.getSide() > 0)) {
1088
+ else if ((!after || after instanceof WidgetBufferView && side > 0) &&
1089
+ (end > pos || off == end && child.getSide() > 0)) {
1084
1090
  after = child;
1085
1091
  afterPos = pos - off;
1086
1092
  }
@@ -1194,6 +1200,10 @@ class WidgetType {
1194
1200
  */
1195
1201
  get customView() { return null; }
1196
1202
  /**
1203
+ @internal
1204
+ */
1205
+ get isHidden() { return false; }
1206
+ /**
1197
1207
  This is called when the an instance of the widget is removed
1198
1208
  from the editor view.
1199
1209
  */
@@ -1605,7 +1615,7 @@ class BlockWidgetView extends ContentView {
1605
1615
  become(other) {
1606
1616
  if (other instanceof BlockWidgetView && other.type == this.type &&
1607
1617
  other.widget.constructor == this.widget.constructor) {
1608
- if (!other.widget.eq(this.widget))
1618
+ if (!other.widget.compare(this.widget))
1609
1619
  this.markDirty(true);
1610
1620
  if (this.dom && !this.prevWidget)
1611
1621
  this.prevWidget = this.widget;
@@ -1736,10 +1746,11 @@ class ContentBuilder {
1736
1746
  }
1737
1747
  else {
1738
1748
  let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
1739
- let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
1749
+ let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
1750
+ (from < to || deco.startSide > 0);
1740
1751
  let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
1741
1752
  let line = this.getLine();
1742
- if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
1753
+ if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
1743
1754
  this.pendingBuffer = 0 /* Buf.No */;
1744
1755
  this.flushBuffer(active);
1745
1756
  if (cursorBefore) {
@@ -1793,6 +1804,7 @@ class NullWidget extends WidgetType {
1793
1804
  eq(other) { return other.tag == this.tag; }
1794
1805
  toDOM() { return document.createElement(this.tag); }
1795
1806
  updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
1807
+ get isHidden() { return true; }
1796
1808
  }
1797
1809
 
1798
1810
  const clickAddsSelectionRange = state.Facet.define();
@@ -2646,7 +2658,7 @@ class DocView extends ContentView {
2646
2658
  let head = main.empty ? anchor : this.domAtPos(main.head);
2647
2659
  // Always reset on Firefox when next to an uneditable node to
2648
2660
  // avoid invisible cursor bugs (#111)
2649
- if (browser.gecko && main.empty && betweenUneditable(anchor)) {
2661
+ if (browser.gecko && main.empty && !this.compositionDeco.size && betweenUneditable(anchor)) {
2650
2662
  let dummy = document.createTextNode("");
2651
2663
  this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
2652
2664
  anchor = head = new DOMPos(dummy, 0);
@@ -3440,7 +3452,15 @@ class InputState {
3440
3452
  // first, false means first has already been marked for this
3441
3453
  // composition)
3442
3454
  this.compositionFirstChange = null;
3455
+ // End time of the previous composition
3443
3456
  this.compositionEndedAt = 0;
3457
+ // Used in a kludge to detect when an Enter keypress should be
3458
+ // considered part of the composition on Safari, which fires events
3459
+ // in the wrong order
3460
+ this.compositionPendingKey = false;
3461
+ // Used to categorize changes as part of a composition, even when
3462
+ // the mutation events fire shortly after the compositionend event
3463
+ this.compositionPendingChange = false;
3444
3464
  this.mouseSelection = null;
3445
3465
  let handleEvent = (handler, event) => {
3446
3466
  if (this.ignoreDuringComposition(event))
@@ -3597,8 +3617,8 @@ class InputState {
3597
3617
  // compositionend and keydown events are sometimes emitted in the
3598
3618
  // wrong order. The key event should still be ignored, even when
3599
3619
  // it happens after the compositionend event.
3600
- if (browser.safari && !browser.ios && Date.now() - this.compositionEndedAt < 100) {
3601
- this.compositionEndedAt = 0;
3620
+ if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
3621
+ this.compositionPendingKey = false;
3602
3622
  return true;
3603
3623
  }
3604
3624
  return false;
@@ -3630,8 +3650,9 @@ const PendingKeys = [
3630
3650
  const EmacsyPendingKeys = "dthko";
3631
3651
  // Key codes for modifier keys
3632
3652
  const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
3653
+ const dragScrollMargin = 6;
3633
3654
  function dragScrollSpeed(dist) {
3634
- return dist * 0.7 + 8;
3655
+ return Math.max(0, dist) * 0.7 + 8;
3635
3656
  }
3636
3657
  class MouseSelection {
3637
3658
  constructor(view, startEvent, style, mustSelect) {
@@ -3668,13 +3689,13 @@ class MouseSelection {
3668
3689
  let sx = 0, sy = 0;
3669
3690
  let rect = ((_a = this.scrollParent) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect())
3670
3691
  || { left: 0, top: 0, right: this.view.win.innerWidth, bottom: this.view.win.innerHeight };
3671
- if (event.clientX <= rect.left)
3692
+ if (event.clientX <= rect.left + dragScrollMargin)
3672
3693
  sx = -dragScrollSpeed(rect.left - event.clientX);
3673
- else if (event.clientX >= rect.right)
3694
+ else if (event.clientX >= rect.right - dragScrollMargin)
3674
3695
  sx = dragScrollSpeed(event.clientX - rect.right);
3675
- if (event.clientY <= rect.top)
3696
+ if (event.clientY <= rect.top + dragScrollMargin)
3676
3697
  sy = -dragScrollSpeed(rect.top - event.clientY);
3677
- else if (event.clientY >= rect.bottom)
3698
+ else if (event.clientY >= rect.bottom - dragScrollMargin)
3678
3699
  sy = dragScrollSpeed(event.clientY - rect.bottom);
3679
3700
  this.setScrollSpeed(sx, sy);
3680
3701
  }
@@ -3921,7 +3942,7 @@ function basicMouseSelection(view, event) {
3921
3942
  }
3922
3943
  },
3923
3944
  get(event, extend, multiple) {
3924
- let cur = queryPos(view, event);
3945
+ let cur = queryPos(view, event), removed;
3925
3946
  let range = rangeForClick(view, cur.pos, cur.bias, type);
3926
3947
  if (start.pos != cur.pos && !extend) {
3927
3948
  let startRange = rangeForClick(view, start.pos, start.bias, type);
@@ -3930,8 +3951,8 @@ function basicMouseSelection(view, event) {
3930
3951
  }
3931
3952
  if (extend)
3932
3953
  return startSel.replaceRange(startSel.main.extend(range.from, range.to));
3933
- else if (multiple && startSel.ranges.length > 1 && startSel.ranges.some(r => r.eq(range)))
3934
- return removeRange(startSel, range);
3954
+ else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
3955
+ return removed;
3935
3956
  else if (multiple)
3936
3957
  return startSel.addRange(range);
3937
3958
  else
@@ -3939,11 +3960,13 @@ function basicMouseSelection(view, event) {
3939
3960
  }
3940
3961
  };
3941
3962
  }
3942
- function removeRange(sel, range) {
3943
- for (let i = 0;; i++) {
3944
- if (sel.ranges[i].eq(range))
3963
+ function removeRangeAround(sel, pos) {
3964
+ for (let i = 0; i < sel.ranges.length; i++) {
3965
+ let { from, to } = sel.ranges[i];
3966
+ if (from <= pos && to >= pos)
3945
3967
  return state.EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
3946
3968
  }
3969
+ return null;
3947
3970
  }
3948
3971
  handlers.dragstart = (view, event) => {
3949
3972
  let { selection: { main } } = view.state;
@@ -4120,6 +4143,8 @@ handlers.compositionstart = handlers.compositionupdate = view => {
4120
4143
  handlers.compositionend = view => {
4121
4144
  view.inputState.composing = -1;
4122
4145
  view.inputState.compositionEndedAt = Date.now();
4146
+ view.inputState.compositionPendingKey = true;
4147
+ view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
4123
4148
  view.inputState.compositionFirstChange = null;
4124
4149
  if (browser.chrome && browser.android)
4125
4150
  view.observer.flushSoon();
@@ -5775,8 +5800,7 @@ function applyDOMChange(view, domChange) {
5775
5800
  }
5776
5801
  else {
5777
5802
  let changes = startState.changes(change);
5778
- let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
5779
- ? newSel.main : undefined;
5803
+ let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
5780
5804
  // Try to apply a composition change to all cursors
5781
5805
  if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
5782
5806
  change.to <= sel.to && change.to >= sel.to - 10) {
@@ -5810,7 +5834,9 @@ function applyDOMChange(view, domChange) {
5810
5834
  }
5811
5835
  }
5812
5836
  let userEvent = "input.type";
5813
- if (view.composing) {
5837
+ if (view.composing ||
5838
+ view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
5839
+ view.inputState.compositionPendingChange = false;
5814
5840
  userEvent += ".compose";
5815
5841
  if (view.inputState.compositionFirstChange) {
5816
5842
  userEvent += ".start";
@@ -6186,10 +6212,13 @@ class DOMObserver {
6186
6212
  }
6187
6213
  this.flush();
6188
6214
  }
6189
- processRecords() {
6190
- let records = this.queue;
6215
+ pendingRecords() {
6191
6216
  for (let mut of this.observer.takeRecords())
6192
- records.push(mut);
6217
+ this.queue.push(mut);
6218
+ return this.queue;
6219
+ }
6220
+ processRecords() {
6221
+ let records = this.pendingRecords();
6193
6222
  if (records.length)
6194
6223
  this.queue = [];
6195
6224
  let from = -1, to = -1, typeOver = false;
package/dist/index.js CHANGED
@@ -516,6 +516,7 @@ class ContentView {
516
516
  static get(node) { return node.cmView; }
517
517
  get isEditable() { return true; }
518
518
  get isWidget() { return false; }
519
+ get isHidden() { return false; }
519
520
  merge(from, to, source, hasStart, openStart, openEnd) {
520
521
  return false;
521
522
  }
@@ -853,7 +854,7 @@ class WidgetView extends ContentView {
853
854
  become(other) {
854
855
  if (other.length == this.length && other instanceof WidgetView && other.side == this.side) {
855
856
  if (this.widget.constructor == other.widget.constructor) {
856
- if (!this.widget.eq(other.widget))
857
+ if (!this.widget.compare(other.widget))
857
858
  this.markDirty(true);
858
859
  if (this.dom && !this.prevWidget)
859
860
  this.prevWidget = this.widget;
@@ -875,7 +876,9 @@ class WidgetView extends ContentView {
875
876
  return text ? text.slice(start, start + this.length) : Text.empty;
876
877
  }
877
878
  domAtPos(pos) {
878
- return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
879
+ return (this.length ? pos == 0 : this.side > 0)
880
+ ? DOMPos.before(this.dom)
881
+ : DOMPos.after(this.dom, pos == this.length);
879
882
  }
880
883
  domBoundsAround() { return null; }
881
884
  coordsAt(pos, side) {
@@ -891,6 +894,7 @@ class WidgetView extends ContentView {
891
894
  }
892
895
  get isEditable() { return false; }
893
896
  get isWidget() { return true; }
897
+ get isHidden() { return this.widget.isHidden; }
894
898
  destroy() {
895
899
  super.destroy();
896
900
  if (this.dom)
@@ -1003,6 +1007,7 @@ class WidgetBufferView extends ContentView {
1003
1007
  get overrideDOMText() {
1004
1008
  return Text.empty;
1005
1009
  }
1010
+ get isHidden() { return true; }
1006
1011
  }
1007
1012
  TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
1008
1013
  function inlineSiblingRect(view, side) {
@@ -1076,7 +1081,8 @@ function coordsInChildren(view, pos, side) {
1076
1081
  if (child.children.length) {
1077
1082
  scan(child, pos - off);
1078
1083
  }
1079
- else if (!after && (end > pos || off == end && child.getSide() > 0)) {
1084
+ else if ((!after || after instanceof WidgetBufferView && side > 0) &&
1085
+ (end > pos || off == end && child.getSide() > 0)) {
1080
1086
  after = child;
1081
1087
  afterPos = pos - off;
1082
1088
  }
@@ -1190,6 +1196,10 @@ class WidgetType {
1190
1196
  */
1191
1197
  get customView() { return null; }
1192
1198
  /**
1199
+ @internal
1200
+ */
1201
+ get isHidden() { return false; }
1202
+ /**
1193
1203
  This is called when the an instance of the widget is removed
1194
1204
  from the editor view.
1195
1205
  */
@@ -1600,7 +1610,7 @@ class BlockWidgetView extends ContentView {
1600
1610
  become(other) {
1601
1611
  if (other instanceof BlockWidgetView && other.type == this.type &&
1602
1612
  other.widget.constructor == this.widget.constructor) {
1603
- if (!other.widget.eq(this.widget))
1613
+ if (!other.widget.compare(this.widget))
1604
1614
  this.markDirty(true);
1605
1615
  if (this.dom && !this.prevWidget)
1606
1616
  this.prevWidget = this.widget;
@@ -1731,10 +1741,11 @@ class ContentBuilder {
1731
1741
  }
1732
1742
  else {
1733
1743
  let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
1734
- let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
1744
+ let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
1745
+ (from < to || deco.startSide > 0);
1735
1746
  let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
1736
1747
  let line = this.getLine();
1737
- if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
1748
+ if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
1738
1749
  this.pendingBuffer = 0 /* Buf.No */;
1739
1750
  this.flushBuffer(active);
1740
1751
  if (cursorBefore) {
@@ -1788,6 +1799,7 @@ class NullWidget extends WidgetType {
1788
1799
  eq(other) { return other.tag == this.tag; }
1789
1800
  toDOM() { return document.createElement(this.tag); }
1790
1801
  updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
1802
+ get isHidden() { return true; }
1791
1803
  }
1792
1804
 
1793
1805
  const clickAddsSelectionRange = /*@__PURE__*/Facet.define();
@@ -2640,7 +2652,7 @@ class DocView extends ContentView {
2640
2652
  let head = main.empty ? anchor : this.domAtPos(main.head);
2641
2653
  // Always reset on Firefox when next to an uneditable node to
2642
2654
  // avoid invisible cursor bugs (#111)
2643
- if (browser.gecko && main.empty && betweenUneditable(anchor)) {
2655
+ if (browser.gecko && main.empty && !this.compositionDeco.size && betweenUneditable(anchor)) {
2644
2656
  let dummy = document.createTextNode("");
2645
2657
  this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
2646
2658
  anchor = head = new DOMPos(dummy, 0);
@@ -3434,7 +3446,15 @@ class InputState {
3434
3446
  // first, false means first has already been marked for this
3435
3447
  // composition)
3436
3448
  this.compositionFirstChange = null;
3449
+ // End time of the previous composition
3437
3450
  this.compositionEndedAt = 0;
3451
+ // Used in a kludge to detect when an Enter keypress should be
3452
+ // considered part of the composition on Safari, which fires events
3453
+ // in the wrong order
3454
+ this.compositionPendingKey = false;
3455
+ // Used to categorize changes as part of a composition, even when
3456
+ // the mutation events fire shortly after the compositionend event
3457
+ this.compositionPendingChange = false;
3438
3458
  this.mouseSelection = null;
3439
3459
  let handleEvent = (handler, event) => {
3440
3460
  if (this.ignoreDuringComposition(event))
@@ -3591,8 +3611,8 @@ class InputState {
3591
3611
  // compositionend and keydown events are sometimes emitted in the
3592
3612
  // wrong order. The key event should still be ignored, even when
3593
3613
  // it happens after the compositionend event.
3594
- if (browser.safari && !browser.ios && Date.now() - this.compositionEndedAt < 100) {
3595
- this.compositionEndedAt = 0;
3614
+ if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
3615
+ this.compositionPendingKey = false;
3596
3616
  return true;
3597
3617
  }
3598
3618
  return false;
@@ -3624,8 +3644,9 @@ const PendingKeys = [
3624
3644
  const EmacsyPendingKeys = "dthko";
3625
3645
  // Key codes for modifier keys
3626
3646
  const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
3647
+ const dragScrollMargin = 6;
3627
3648
  function dragScrollSpeed(dist) {
3628
- return dist * 0.7 + 8;
3649
+ return Math.max(0, dist) * 0.7 + 8;
3629
3650
  }
3630
3651
  class MouseSelection {
3631
3652
  constructor(view, startEvent, style, mustSelect) {
@@ -3662,13 +3683,13 @@ class MouseSelection {
3662
3683
  let sx = 0, sy = 0;
3663
3684
  let rect = ((_a = this.scrollParent) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect())
3664
3685
  || { left: 0, top: 0, right: this.view.win.innerWidth, bottom: this.view.win.innerHeight };
3665
- if (event.clientX <= rect.left)
3686
+ if (event.clientX <= rect.left + dragScrollMargin)
3666
3687
  sx = -dragScrollSpeed(rect.left - event.clientX);
3667
- else if (event.clientX >= rect.right)
3688
+ else if (event.clientX >= rect.right - dragScrollMargin)
3668
3689
  sx = dragScrollSpeed(event.clientX - rect.right);
3669
- if (event.clientY <= rect.top)
3690
+ if (event.clientY <= rect.top + dragScrollMargin)
3670
3691
  sy = -dragScrollSpeed(rect.top - event.clientY);
3671
- else if (event.clientY >= rect.bottom)
3692
+ else if (event.clientY >= rect.bottom - dragScrollMargin)
3672
3693
  sy = dragScrollSpeed(event.clientY - rect.bottom);
3673
3694
  this.setScrollSpeed(sx, sy);
3674
3695
  }
@@ -3915,7 +3936,7 @@ function basicMouseSelection(view, event) {
3915
3936
  }
3916
3937
  },
3917
3938
  get(event, extend, multiple) {
3918
- let cur = queryPos(view, event);
3939
+ let cur = queryPos(view, event), removed;
3919
3940
  let range = rangeForClick(view, cur.pos, cur.bias, type);
3920
3941
  if (start.pos != cur.pos && !extend) {
3921
3942
  let startRange = rangeForClick(view, start.pos, start.bias, type);
@@ -3924,8 +3945,8 @@ function basicMouseSelection(view, event) {
3924
3945
  }
3925
3946
  if (extend)
3926
3947
  return startSel.replaceRange(startSel.main.extend(range.from, range.to));
3927
- else if (multiple && startSel.ranges.length > 1 && startSel.ranges.some(r => r.eq(range)))
3928
- return removeRange(startSel, range);
3948
+ else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
3949
+ return removed;
3929
3950
  else if (multiple)
3930
3951
  return startSel.addRange(range);
3931
3952
  else
@@ -3933,11 +3954,13 @@ function basicMouseSelection(view, event) {
3933
3954
  }
3934
3955
  };
3935
3956
  }
3936
- function removeRange(sel, range) {
3937
- for (let i = 0;; i++) {
3938
- if (sel.ranges[i].eq(range))
3957
+ function removeRangeAround(sel, pos) {
3958
+ for (let i = 0; i < sel.ranges.length; i++) {
3959
+ let { from, to } = sel.ranges[i];
3960
+ if (from <= pos && to >= pos)
3939
3961
  return EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
3940
3962
  }
3963
+ return null;
3941
3964
  }
3942
3965
  handlers.dragstart = (view, event) => {
3943
3966
  let { selection: { main } } = view.state;
@@ -4114,6 +4137,8 @@ handlers.compositionstart = handlers.compositionupdate = view => {
4114
4137
  handlers.compositionend = view => {
4115
4138
  view.inputState.composing = -1;
4116
4139
  view.inputState.compositionEndedAt = Date.now();
4140
+ view.inputState.compositionPendingKey = true;
4141
+ view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
4117
4142
  view.inputState.compositionFirstChange = null;
4118
4143
  if (browser.chrome && browser.android)
4119
4144
  view.observer.flushSoon();
@@ -5768,8 +5793,7 @@ function applyDOMChange(view, domChange) {
5768
5793
  }
5769
5794
  else {
5770
5795
  let changes = startState.changes(change);
5771
- let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
5772
- ? newSel.main : undefined;
5796
+ let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
5773
5797
  // Try to apply a composition change to all cursors
5774
5798
  if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
5775
5799
  change.to <= sel.to && change.to >= sel.to - 10) {
@@ -5803,7 +5827,9 @@ function applyDOMChange(view, domChange) {
5803
5827
  }
5804
5828
  }
5805
5829
  let userEvent = "input.type";
5806
- if (view.composing) {
5830
+ if (view.composing ||
5831
+ view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
5832
+ view.inputState.compositionPendingChange = false;
5807
5833
  userEvent += ".compose";
5808
5834
  if (view.inputState.compositionFirstChange) {
5809
5835
  userEvent += ".start";
@@ -6179,10 +6205,13 @@ class DOMObserver {
6179
6205
  }
6180
6206
  this.flush();
6181
6207
  }
6182
- processRecords() {
6183
- let records = this.queue;
6208
+ pendingRecords() {
6184
6209
  for (let mut of this.observer.takeRecords())
6185
- records.push(mut);
6210
+ this.queue.push(mut);
6211
+ return this.queue;
6212
+ }
6213
+ processRecords() {
6214
+ let records = this.pendingRecords();
6186
6215
  if (records.length)
6187
6216
  this.queue = [];
6188
6217
  let from = -1, to = -1, typeOver = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.9.3",
3
+ "version": "6.9.4",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",