@codemirror/view 0.19.12 → 0.19.16

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,37 @@
1
+ ## 0.19.16 (2021-11-11)
2
+
3
+ ### Breaking changes
4
+
5
+ Block replacement decorations now default to inclusive, because non-inclusive block decorations are rarely what you need.
6
+
7
+ ### Bug fixes
8
+
9
+ Fix an issue that caused block widgets to always have a large side value, making it impossible to show them between to replacement decorations.
10
+
11
+ Fix a crash that could happen after some types of viewport changes, due to a bug in the block widget view data structure.
12
+
13
+ ## 0.19.15 (2021-11-09)
14
+
15
+ ### Bug fixes
16
+
17
+ Fix a bug where the editor would think it was invisible when the document body was given screen height and scroll behavior.
18
+
19
+ Fix selection reading inside a shadow root on iOS.
20
+
21
+ ## 0.19.14 (2021-11-07)
22
+
23
+ ### Bug fixes
24
+
25
+ Fix an issue where typing into a read-only editor would move the selection.
26
+
27
+ Fix slowness when backspace is held down on iOS.
28
+
29
+ ## 0.19.13 (2021-11-06)
30
+
31
+ ### Bug fixes
32
+
33
+ Fix a bug where backspace, enter, and delete would get applied twice on iOS.
34
+
1
35
  ## 0.19.12 (2021-11-04)
2
36
 
3
37
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -252,24 +252,11 @@ function dispatchKey(elt, name, code) {
252
252
  elt.dispatchEvent(up);
253
253
  return down.defaultPrevented || up.defaultPrevented;
254
254
  }
255
- let _plainTextSupported = null;
256
- function contentEditablePlainTextSupported() {
257
- if (_plainTextSupported == null) {
258
- _plainTextSupported = false;
259
- let dummy = document.createElement("div");
260
- try {
261
- dummy.contentEditable = "plaintext-only";
262
- _plainTextSupported = dummy.contentEditable == "plaintext-only";
263
- }
264
- catch (_) { }
265
- }
266
- return _plainTextSupported;
267
- }
268
255
  function getRoot(node) {
269
256
  while (node) {
270
- node = node.assignedSlot || node.parentNode;
271
257
  if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
272
258
  return node;
259
+ node = node.assignedSlot || node.parentNode;
273
260
  }
274
261
  return null;
275
262
  }
@@ -1097,8 +1084,6 @@ class Decoration extends rangeset.RangeValue {
1097
1084
  */
1098
1085
  static widget(spec) {
1099
1086
  let side = spec.side || 0;
1100
- if (spec.block)
1101
- side += (200000000 /* BigBlock */ + 1) * (side > 0 ? 1 : -1);
1102
1087
  return new PointDecoration(spec, side, side, !!spec.block, spec.widget || null, false);
1103
1088
  }
1104
1089
  /**
@@ -1107,9 +1092,9 @@ class Decoration extends rangeset.RangeValue {
1107
1092
  */
1108
1093
  static replace(spec) {
1109
1094
  let block = !!spec.block;
1110
- let { start, end } = getInclusive(spec);
1111
- let startSide = block ? -200000000 /* BigBlock */ * (start ? 2 : 1) : 100000000 /* BigInline */ * (start ? -1 : 1);
1112
- let endSide = block ? 200000000 /* BigBlock */ * (end ? 2 : 1) : 100000000 /* BigInline */ * (end ? 1 : -1);
1095
+ let { start, end } = getInclusive(spec, block);
1096
+ let startSide = 100000000 /* Big */ * (start ? -1 : 1) * (block ? 2 : 1);
1097
+ let endSide = 100000000 /* Big */ * (end ? 1 : -1) * (block ? 2 : 1);
1113
1098
  return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
1114
1099
  }
1115
1100
  /**
@@ -1139,7 +1124,7 @@ Decoration.none = rangeset.RangeSet.empty;
1139
1124
  class MarkDecoration extends Decoration {
1140
1125
  constructor(spec) {
1141
1126
  let { start, end } = getInclusive(spec);
1142
- super(100000000 /* BigInline */ * (start ? -1 : 1), 100000000 /* BigInline */ * (end ? 1 : -1), null, spec);
1127
+ super(100000000 /* Big */ * (start ? -1 : 1), 100000000 /* Big */ * (end ? 1 : -1), null, spec);
1143
1128
  this.tagName = spec.tagName || "span";
1144
1129
  this.class = spec.class || "";
1145
1130
  this.attrs = spec.attributes || null;
@@ -1160,7 +1145,7 @@ class MarkDecoration extends Decoration {
1160
1145
  MarkDecoration.prototype.point = false;
1161
1146
  class LineDecoration extends Decoration {
1162
1147
  constructor(spec) {
1163
- super(-100000000 /* BigInline */, -100000000 /* BigInline */, null, spec);
1148
+ super(-100000000 /* Big */, -100000000 /* Big */, null, spec);
1164
1149
  }
1165
1150
  eq(other) {
1166
1151
  return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
@@ -1201,13 +1186,13 @@ class PointDecoration extends Decoration {
1201
1186
  }
1202
1187
  }
1203
1188
  PointDecoration.prototype.point = true;
1204
- function getInclusive(spec) {
1189
+ function getInclusive(spec, block = false) {
1205
1190
  let { inclusiveStart: start, inclusiveEnd: end } = spec;
1206
1191
  if (start == null)
1207
1192
  start = spec.inclusive;
1208
1193
  if (end == null)
1209
1194
  end = spec.inclusive;
1210
- return { start: start || false, end: end || false };
1195
+ return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
1211
1196
  }
1212
1197
  function widgetsEq(a, b) {
1213
1198
  return a == b || !!(a && b && a.compare(b));
@@ -1375,7 +1360,9 @@ class BlockWidgetView extends ContentView {
1375
1360
  split(at) {
1376
1361
  let len = this.length - at;
1377
1362
  this.length = at;
1378
- return new BlockWidgetView(this.widget, len, this.type);
1363
+ let end = new BlockWidgetView(this.widget, len, this.type);
1364
+ end.breakAfter = this.breakAfter;
1365
+ return end;
1379
1366
  }
1380
1367
  get children() { return none$1; }
1381
1368
  sync() {
@@ -3078,10 +3065,6 @@ class InputState {
3078
3065
  constructor(view) {
3079
3066
  this.lastKeyCode = 0;
3080
3067
  this.lastKeyTime = 0;
3081
- // On iOS, some keys need to have their default behavior happen
3082
- // (after which we retroactively handle them and reset the DOM) to
3083
- // avoid messing up the virtual keyboard state.
3084
- //
3085
3068
  // On Chrome Android, backspace near widgets is just completely
3086
3069
  // broken, and there are no key events, so we need to handle the
3087
3070
  // beforeinput event. Deleting stuff will often create a flurry of
@@ -3089,12 +3072,11 @@ class InputState {
3089
3072
  // subsequent events even more broken, so again, we hold off doing
3090
3073
  // anything until the browser is finished with whatever it is trying
3091
3074
  // to do.
3092
- //
3093
- // setPendingKey sets this, causing the DOM observer to pause for a
3094
- // bit, and setting an animation frame (which seems the most
3095
- // reliable way to detect 'browser is done flailing') to fire a fake
3096
- // key event and re-sync the view again.
3097
- this.pendingKey = undefined;
3075
+ this.pendingAndroidKey = undefined;
3076
+ // On iOS, some keys need to have their default behavior happen
3077
+ // (after which we retroactively handle them and reset the DOM) to
3078
+ // avoid messing up the virtual keyboard state.
3079
+ this.pendingIOSKey = undefined;
3098
3080
  this.lastSelectionOrigin = null;
3099
3081
  this.lastSelectionTime = 0;
3100
3082
  this.lastEscPress = 0;
@@ -3206,18 +3188,30 @@ class InputState {
3206
3188
  let pending;
3207
3189
  if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
3208
3190
  !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
3209
- this.setPendingKey(view, pending);
3191
+ this.pendingIOSKey = pending;
3192
+ setTimeout(() => this.flushIOSKey(view), 250);
3210
3193
  return true;
3211
3194
  }
3212
3195
  return false;
3213
3196
  }
3214
- setPendingKey(view, pending) {
3215
- this.pendingKey = pending;
3197
+ flushIOSKey(view) {
3198
+ let key = this.pendingIOSKey;
3199
+ if (!key)
3200
+ return false;
3201
+ this.pendingIOSKey = undefined;
3202
+ return dispatchKey(view.contentDOM, key.key, key.keyCode);
3203
+ }
3204
+ // This causes the DOM observer to pause for a bit, and sets an
3205
+ // animation frame (which seems the most reliable way to detect
3206
+ // 'Chrome is done flailing about messing with the DOM') to fire a
3207
+ // fake key event and re-sync the view again.
3208
+ setPendingAndroidKey(view, pending) {
3209
+ this.pendingAndroidKey = pending;
3216
3210
  requestAnimationFrame(() => {
3217
- if (!this.pendingKey)
3218
- return false;
3219
- let key = this.pendingKey;
3220
- this.pendingKey = undefined;
3211
+ let key = this.pendingAndroidKey;
3212
+ if (!key)
3213
+ return;
3214
+ this.pendingAndroidKey = undefined;
3221
3215
  view.observer.processRecords();
3222
3216
  let startState = view.state;
3223
3217
  dispatchKey(view.contentDOM, key.key, key.keyCode);
@@ -3731,7 +3725,7 @@ handlers.beforeinput = (view, event) => {
3731
3725
  // seems to do nothing at all on Chrome).
3732
3726
  let pending;
3733
3727
  if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
3734
- view.inputState.setPendingKey(view, pending);
3728
+ view.inputState.setPendingAndroidKey(view, pending);
3735
3729
  if (pending.key == "Backspace" || pending.key == "Delete") {
3736
3730
  let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
3737
3731
  setTimeout(() => {
@@ -4395,18 +4389,20 @@ function visiblePixelRange(dom, paddingTop) {
4395
4389
  let rect = dom.getBoundingClientRect();
4396
4390
  let left = Math.max(0, rect.left), right = Math.min(innerWidth, rect.right);
4397
4391
  let top = Math.max(0, rect.top), bottom = Math.min(innerHeight, rect.bottom);
4398
- for (let parent = dom.parentNode; parent;) { // (Cast to any because TypeScript is useless with Node types)
4392
+ let body = dom.ownerDocument.body;
4393
+ for (let parent = dom.parentNode; parent && parent != body;) {
4399
4394
  if (parent.nodeType == 1) {
4400
- let style = window.getComputedStyle(parent);
4401
- if ((parent.scrollHeight > parent.clientHeight || parent.scrollWidth > parent.clientWidth) &&
4395
+ let elt = parent;
4396
+ let style = window.getComputedStyle(elt);
4397
+ if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) &&
4402
4398
  style.overflow != "visible") {
4403
- let parentRect = parent.getBoundingClientRect();
4399
+ let parentRect = elt.getBoundingClientRect();
4404
4400
  left = Math.max(left, parentRect.left);
4405
4401
  right = Math.min(right, parentRect.right);
4406
4402
  top = Math.max(top, parentRect.top);
4407
4403
  bottom = Math.min(bottom, parentRect.bottom);
4408
4404
  }
4409
- parent = style.position == "absolute" || style.position == "fixed" ? parent.offsetParent : parent.parentNode;
4405
+ parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode;
4410
4406
  }
4411
4407
  else if (parent.nodeType == 11) { // Shadow root
4412
4408
  parent = parent.host;
@@ -4936,7 +4932,10 @@ const baseTheme = buildTheme("." + baseThemeID, {
4936
4932
  wordWrap: "normal",
4937
4933
  boxSizing: "border-box",
4938
4934
  padding: "4px 0",
4939
- outline: "none"
4935
+ outline: "none",
4936
+ "&[contenteditable=true]": {
4937
+ WebkitUserModify: "read-write-plaintext-only",
4938
+ }
4940
4939
  },
4941
4940
  ".cm-lineWrapping": {
4942
4941
  whiteSpace: "pre-wrap",
@@ -5279,7 +5278,7 @@ class DOMObserver {
5279
5278
  // Completely hold off flushing when pending keys are set—the code
5280
5279
  // managing those will make sure processRecords is called and the
5281
5280
  // view is resynchronized after
5282
- if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
5281
+ if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
5283
5282
  return;
5284
5283
  this.lastFlush = Date.now();
5285
5284
  let { from, to, typeOver } = this.processRecords();
@@ -5366,8 +5365,11 @@ function safariSelectionRangeHack(view) {
5366
5365
 
5367
5366
  function applyDOMChange(view, start, end, typeOver) {
5368
5367
  let change, newSel;
5369
- let sel = view.state.selection.main, bounds;
5370
- if (start > -1 && !view.state.readOnly && (bounds = view.docView.domBoundsAround(start, end, 0))) {
5368
+ let sel = view.state.selection.main;
5369
+ if (start > -1) {
5370
+ let bounds = view.docView.domBoundsAround(start, end, 0);
5371
+ if (!bounds || view.state.readOnly)
5372
+ return;
5371
5373
  let { from, to } = bounds;
5372
5374
  let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
5373
5375
  let reader = new DOMReader(selPoints, view);
@@ -5421,16 +5423,8 @@ function applyDOMChange(view, start, end, typeOver) {
5421
5423
  // backspace, or delete. So this detects changes that look like
5422
5424
  // they're caused by those keys, and reinterprets them as key
5423
5425
  // events.
5424
- if (browser.android &&
5425
- ((change.from == sel.from && change.to == sel.to &&
5426
- change.insert.length == 1 && change.insert.lines == 2 &&
5427
- dispatchKey(view.contentDOM, "Enter", 13)) ||
5428
- (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
5429
- dispatchKey(view.contentDOM, "Backspace", 8)) ||
5430
- (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
5431
- dispatchKey(view.contentDOM, "Delete", 46)))) {
5426
+ if (browser.ios && view.inputState.flushIOSKey(view))
5432
5427
  return;
5433
- }
5434
5428
  let text = change.insert.toString();
5435
5429
  if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
5436
5430
  return;
@@ -5923,7 +5917,7 @@ class EditorView {
5923
5917
  autocorrect: "off",
5924
5918
  autocapitalize: "off",
5925
5919
  translate: "no",
5926
- contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
5920
+ contenteditable: !this.state.facet(editable) ? "false" : "true",
5927
5921
  class: "cm-content",
5928
5922
  style: `${browser.tabSize}: ${this.state.tabSize}`,
5929
5923
  role: "textbox",
package/dist/index.d.ts CHANGED
@@ -91,7 +91,8 @@ interface ReplaceDecorationSpec {
91
91
  /**
92
92
  Whether this range covers the positions on its sides. This
93
93
  influences whether new content becomes part of the range and
94
- whether the cursor can be drawn on its sides. Defaults to false.
94
+ whether the cursor can be drawn on its sides. Defaults to false
95
+ for inline replacements, and true for block replacements.
95
96
  */
96
97
  inclusive?: boolean;
97
98
  /**
package/dist/index.js CHANGED
@@ -249,24 +249,11 @@ function dispatchKey(elt, name, code) {
249
249
  elt.dispatchEvent(up);
250
250
  return down.defaultPrevented || up.defaultPrevented;
251
251
  }
252
- let _plainTextSupported = null;
253
- function contentEditablePlainTextSupported() {
254
- if (_plainTextSupported == null) {
255
- _plainTextSupported = false;
256
- let dummy = document.createElement("div");
257
- try {
258
- dummy.contentEditable = "plaintext-only";
259
- _plainTextSupported = dummy.contentEditable == "plaintext-only";
260
- }
261
- catch (_) { }
262
- }
263
- return _plainTextSupported;
264
- }
265
252
  function getRoot(node) {
266
253
  while (node) {
267
- node = node.assignedSlot || node.parentNode;
268
254
  if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
269
255
  return node;
256
+ node = node.assignedSlot || node.parentNode;
270
257
  }
271
258
  return null;
272
259
  }
@@ -1093,8 +1080,6 @@ class Decoration extends RangeValue {
1093
1080
  */
1094
1081
  static widget(spec) {
1095
1082
  let side = spec.side || 0;
1096
- if (spec.block)
1097
- side += (200000000 /* BigBlock */ + 1) * (side > 0 ? 1 : -1);
1098
1083
  return new PointDecoration(spec, side, side, !!spec.block, spec.widget || null, false);
1099
1084
  }
1100
1085
  /**
@@ -1103,9 +1088,9 @@ class Decoration extends RangeValue {
1103
1088
  */
1104
1089
  static replace(spec) {
1105
1090
  let block = !!spec.block;
1106
- let { start, end } = getInclusive(spec);
1107
- let startSide = block ? -200000000 /* BigBlock */ * (start ? 2 : 1) : 100000000 /* BigInline */ * (start ? -1 : 1);
1108
- let endSide = block ? 200000000 /* BigBlock */ * (end ? 2 : 1) : 100000000 /* BigInline */ * (end ? 1 : -1);
1091
+ let { start, end } = getInclusive(spec, block);
1092
+ let startSide = 100000000 /* Big */ * (start ? -1 : 1) * (block ? 2 : 1);
1093
+ let endSide = 100000000 /* Big */ * (end ? 1 : -1) * (block ? 2 : 1);
1109
1094
  return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
1110
1095
  }
1111
1096
  /**
@@ -1135,7 +1120,7 @@ Decoration.none = RangeSet.empty;
1135
1120
  class MarkDecoration extends Decoration {
1136
1121
  constructor(spec) {
1137
1122
  let { start, end } = getInclusive(spec);
1138
- super(100000000 /* BigInline */ * (start ? -1 : 1), 100000000 /* BigInline */ * (end ? 1 : -1), null, spec);
1123
+ super(100000000 /* Big */ * (start ? -1 : 1), 100000000 /* Big */ * (end ? 1 : -1), null, spec);
1139
1124
  this.tagName = spec.tagName || "span";
1140
1125
  this.class = spec.class || "";
1141
1126
  this.attrs = spec.attributes || null;
@@ -1156,7 +1141,7 @@ class MarkDecoration extends Decoration {
1156
1141
  MarkDecoration.prototype.point = false;
1157
1142
  class LineDecoration extends Decoration {
1158
1143
  constructor(spec) {
1159
- super(-100000000 /* BigInline */, -100000000 /* BigInline */, null, spec);
1144
+ super(-100000000 /* Big */, -100000000 /* Big */, null, spec);
1160
1145
  }
1161
1146
  eq(other) {
1162
1147
  return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
@@ -1197,13 +1182,13 @@ class PointDecoration extends Decoration {
1197
1182
  }
1198
1183
  }
1199
1184
  PointDecoration.prototype.point = true;
1200
- function getInclusive(spec) {
1185
+ function getInclusive(spec, block = false) {
1201
1186
  let { inclusiveStart: start, inclusiveEnd: end } = spec;
1202
1187
  if (start == null)
1203
1188
  start = spec.inclusive;
1204
1189
  if (end == null)
1205
1190
  end = spec.inclusive;
1206
- return { start: start || false, end: end || false };
1191
+ return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
1207
1192
  }
1208
1193
  function widgetsEq(a, b) {
1209
1194
  return a == b || !!(a && b && a.compare(b));
@@ -1371,7 +1356,9 @@ class BlockWidgetView extends ContentView {
1371
1356
  split(at) {
1372
1357
  let len = this.length - at;
1373
1358
  this.length = at;
1374
- return new BlockWidgetView(this.widget, len, this.type);
1359
+ let end = new BlockWidgetView(this.widget, len, this.type);
1360
+ end.breakAfter = this.breakAfter;
1361
+ return end;
1375
1362
  }
1376
1363
  get children() { return none$1; }
1377
1364
  sync() {
@@ -3073,10 +3060,6 @@ class InputState {
3073
3060
  constructor(view) {
3074
3061
  this.lastKeyCode = 0;
3075
3062
  this.lastKeyTime = 0;
3076
- // On iOS, some keys need to have their default behavior happen
3077
- // (after which we retroactively handle them and reset the DOM) to
3078
- // avoid messing up the virtual keyboard state.
3079
- //
3080
3063
  // On Chrome Android, backspace near widgets is just completely
3081
3064
  // broken, and there are no key events, so we need to handle the
3082
3065
  // beforeinput event. Deleting stuff will often create a flurry of
@@ -3084,12 +3067,11 @@ class InputState {
3084
3067
  // subsequent events even more broken, so again, we hold off doing
3085
3068
  // anything until the browser is finished with whatever it is trying
3086
3069
  // to do.
3087
- //
3088
- // setPendingKey sets this, causing the DOM observer to pause for a
3089
- // bit, and setting an animation frame (which seems the most
3090
- // reliable way to detect 'browser is done flailing') to fire a fake
3091
- // key event and re-sync the view again.
3092
- this.pendingKey = undefined;
3070
+ this.pendingAndroidKey = undefined;
3071
+ // On iOS, some keys need to have their default behavior happen
3072
+ // (after which we retroactively handle them and reset the DOM) to
3073
+ // avoid messing up the virtual keyboard state.
3074
+ this.pendingIOSKey = undefined;
3093
3075
  this.lastSelectionOrigin = null;
3094
3076
  this.lastSelectionTime = 0;
3095
3077
  this.lastEscPress = 0;
@@ -3201,18 +3183,30 @@ class InputState {
3201
3183
  let pending;
3202
3184
  if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
3203
3185
  !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
3204
- this.setPendingKey(view, pending);
3186
+ this.pendingIOSKey = pending;
3187
+ setTimeout(() => this.flushIOSKey(view), 250);
3205
3188
  return true;
3206
3189
  }
3207
3190
  return false;
3208
3191
  }
3209
- setPendingKey(view, pending) {
3210
- this.pendingKey = pending;
3192
+ flushIOSKey(view) {
3193
+ let key = this.pendingIOSKey;
3194
+ if (!key)
3195
+ return false;
3196
+ this.pendingIOSKey = undefined;
3197
+ return dispatchKey(view.contentDOM, key.key, key.keyCode);
3198
+ }
3199
+ // This causes the DOM observer to pause for a bit, and sets an
3200
+ // animation frame (which seems the most reliable way to detect
3201
+ // 'Chrome is done flailing about messing with the DOM') to fire a
3202
+ // fake key event and re-sync the view again.
3203
+ setPendingAndroidKey(view, pending) {
3204
+ this.pendingAndroidKey = pending;
3211
3205
  requestAnimationFrame(() => {
3212
- if (!this.pendingKey)
3213
- return false;
3214
- let key = this.pendingKey;
3215
- this.pendingKey = undefined;
3206
+ let key = this.pendingAndroidKey;
3207
+ if (!key)
3208
+ return;
3209
+ this.pendingAndroidKey = undefined;
3216
3210
  view.observer.processRecords();
3217
3211
  let startState = view.state;
3218
3212
  dispatchKey(view.contentDOM, key.key, key.keyCode);
@@ -3726,7 +3720,7 @@ handlers.beforeinput = (view, event) => {
3726
3720
  // seems to do nothing at all on Chrome).
3727
3721
  let pending;
3728
3722
  if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
3729
- view.inputState.setPendingKey(view, pending);
3723
+ view.inputState.setPendingAndroidKey(view, pending);
3730
3724
  if (pending.key == "Backspace" || pending.key == "Delete") {
3731
3725
  let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
3732
3726
  setTimeout(() => {
@@ -4389,18 +4383,20 @@ function visiblePixelRange(dom, paddingTop) {
4389
4383
  let rect = dom.getBoundingClientRect();
4390
4384
  let left = Math.max(0, rect.left), right = Math.min(innerWidth, rect.right);
4391
4385
  let top = Math.max(0, rect.top), bottom = Math.min(innerHeight, rect.bottom);
4392
- for (let parent = dom.parentNode; parent;) { // (Cast to any because TypeScript is useless with Node types)
4386
+ let body = dom.ownerDocument.body;
4387
+ for (let parent = dom.parentNode; parent && parent != body;) {
4393
4388
  if (parent.nodeType == 1) {
4394
- let style = window.getComputedStyle(parent);
4395
- if ((parent.scrollHeight > parent.clientHeight || parent.scrollWidth > parent.clientWidth) &&
4389
+ let elt = parent;
4390
+ let style = window.getComputedStyle(elt);
4391
+ if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) &&
4396
4392
  style.overflow != "visible") {
4397
- let parentRect = parent.getBoundingClientRect();
4393
+ let parentRect = elt.getBoundingClientRect();
4398
4394
  left = Math.max(left, parentRect.left);
4399
4395
  right = Math.min(right, parentRect.right);
4400
4396
  top = Math.max(top, parentRect.top);
4401
4397
  bottom = Math.min(bottom, parentRect.bottom);
4402
4398
  }
4403
- parent = style.position == "absolute" || style.position == "fixed" ? parent.offsetParent : parent.parentNode;
4399
+ parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode;
4404
4400
  }
4405
4401
  else if (parent.nodeType == 11) { // Shadow root
4406
4402
  parent = parent.host;
@@ -4930,7 +4926,10 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
4930
4926
  wordWrap: "normal",
4931
4927
  boxSizing: "border-box",
4932
4928
  padding: "4px 0",
4933
- outline: "none"
4929
+ outline: "none",
4930
+ "&[contenteditable=true]": {
4931
+ WebkitUserModify: "read-write-plaintext-only",
4932
+ }
4934
4933
  },
4935
4934
  ".cm-lineWrapping": {
4936
4935
  whiteSpace: "pre-wrap",
@@ -5273,7 +5272,7 @@ class DOMObserver {
5273
5272
  // Completely hold off flushing when pending keys are set—the code
5274
5273
  // managing those will make sure processRecords is called and the
5275
5274
  // view is resynchronized after
5276
- if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
5275
+ if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
5277
5276
  return;
5278
5277
  this.lastFlush = Date.now();
5279
5278
  let { from, to, typeOver } = this.processRecords();
@@ -5360,8 +5359,11 @@ function safariSelectionRangeHack(view) {
5360
5359
 
5361
5360
  function applyDOMChange(view, start, end, typeOver) {
5362
5361
  let change, newSel;
5363
- let sel = view.state.selection.main, bounds;
5364
- if (start > -1 && !view.state.readOnly && (bounds = view.docView.domBoundsAround(start, end, 0))) {
5362
+ let sel = view.state.selection.main;
5363
+ if (start > -1) {
5364
+ let bounds = view.docView.domBoundsAround(start, end, 0);
5365
+ if (!bounds || view.state.readOnly)
5366
+ return;
5365
5367
  let { from, to } = bounds;
5366
5368
  let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
5367
5369
  let reader = new DOMReader(selPoints, view);
@@ -5415,16 +5417,8 @@ function applyDOMChange(view, start, end, typeOver) {
5415
5417
  // backspace, or delete. So this detects changes that look like
5416
5418
  // they're caused by those keys, and reinterprets them as key
5417
5419
  // events.
5418
- if (browser.android &&
5419
- ((change.from == sel.from && change.to == sel.to &&
5420
- change.insert.length == 1 && change.insert.lines == 2 &&
5421
- dispatchKey(view.contentDOM, "Enter", 13)) ||
5422
- (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
5423
- dispatchKey(view.contentDOM, "Backspace", 8)) ||
5424
- (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
5425
- dispatchKey(view.contentDOM, "Delete", 46)))) {
5420
+ if (browser.ios && view.inputState.flushIOSKey(view))
5426
5421
  return;
5427
- }
5428
5422
  let text = change.insert.toString();
5429
5423
  if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
5430
5424
  return;
@@ -5917,7 +5911,7 @@ class EditorView {
5917
5911
  autocorrect: "off",
5918
5912
  autocapitalize: "off",
5919
5913
  translate: "no",
5920
- contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
5914
+ contenteditable: !this.state.facet(editable) ? "false" : "true",
5921
5915
  class: "cm-content",
5922
5916
  style: `${browser.tabSize}: ${this.state.tabSize}`,
5923
5917
  role: "textbox",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "0.19.12",
3
+ "version": "0.19.16",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",