@codemirror/view 0.19.13 → 0.19.14

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,11 @@
1
+ ## 0.19.14 (2021-11-07)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where typing into a read-only editor would move the selection.
6
+
7
+ Fix slowness when backspace is held down on iOS.
8
+
1
9
  ## 0.19.13 (2021-11-06)
2
10
 
3
11
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -267,9 +267,9 @@ function contentEditablePlainTextSupported() {
267
267
  }
268
268
  function getRoot(node) {
269
269
  while (node) {
270
- node = node.assignedSlot || node.parentNode;
271
270
  if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
272
271
  return node;
272
+ node = node.assignedSlot || node.parentNode;
273
273
  }
274
274
  return null;
275
275
  }
@@ -3078,10 +3078,6 @@ class InputState {
3078
3078
  constructor(view) {
3079
3079
  this.lastKeyCode = 0;
3080
3080
  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
3081
  // On Chrome Android, backspace near widgets is just completely
3086
3082
  // broken, and there are no key events, so we need to handle the
3087
3083
  // beforeinput event. Deleting stuff will often create a flurry of
@@ -3089,12 +3085,11 @@ class InputState {
3089
3085
  // subsequent events even more broken, so again, we hold off doing
3090
3086
  // anything until the browser is finished with whatever it is trying
3091
3087
  // 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;
3088
+ this.pendingAndroidKey = undefined;
3089
+ // On iOS, some keys need to have their default behavior happen
3090
+ // (after which we retroactively handle them and reset the DOM) to
3091
+ // avoid messing up the virtual keyboard state.
3092
+ this.pendingIOSKey = undefined;
3098
3093
  this.lastSelectionOrigin = null;
3099
3094
  this.lastSelectionTime = 0;
3100
3095
  this.lastEscPress = 0;
@@ -3206,28 +3201,36 @@ class InputState {
3206
3201
  let pending;
3207
3202
  if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
3208
3203
  !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
3209
- this.setPendingKey(view, pending);
3204
+ this.pendingIOSKey = pending;
3205
+ setTimeout(() => this.flushIOSKey(view), 250);
3210
3206
  return true;
3211
3207
  }
3212
3208
  return false;
3213
3209
  }
3214
- setPendingKey(view, pending) {
3215
- this.pendingKey = pending;
3216
- let flush = () => {
3217
- if (!this.pendingKey)
3218
- return false;
3219
- let key = this.pendingKey;
3220
- this.pendingKey = undefined;
3210
+ flushIOSKey(view) {
3211
+ let key = this.pendingIOSKey;
3212
+ if (!key)
3213
+ return false;
3214
+ this.pendingIOSKey = undefined;
3215
+ return dispatchKey(view.contentDOM, key.key, key.keyCode);
3216
+ }
3217
+ // This causes the DOM observer to pause for a bit, and sets an
3218
+ // animation frame (which seems the most reliable way to detect
3219
+ // 'Chrome is done flailing about messing with the DOM') to fire a
3220
+ // fake key event and re-sync the view again.
3221
+ setPendingAndroidKey(view, pending) {
3222
+ this.pendingAndroidKey = pending;
3223
+ requestAnimationFrame(() => {
3224
+ let key = this.pendingAndroidKey;
3225
+ if (!key)
3226
+ return;
3227
+ this.pendingAndroidKey = undefined;
3221
3228
  view.observer.processRecords();
3222
3229
  let startState = view.state;
3223
3230
  dispatchKey(view.contentDOM, key.key, key.keyCode);
3224
3231
  if (view.state == startState)
3225
3232
  view.docView.reset(true);
3226
- };
3227
- if (browser.ios)
3228
- setTimeout(() => requestAnimationFrame(flush), 50);
3229
- else
3230
- requestAnimationFrame(flush);
3233
+ });
3231
3234
  }
3232
3235
  ignoreDuringComposition(event) {
3233
3236
  if (!/^key/.test(event.type))
@@ -3735,7 +3738,7 @@ handlers.beforeinput = (view, event) => {
3735
3738
  // seems to do nothing at all on Chrome).
3736
3739
  let pending;
3737
3740
  if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
3738
- view.inputState.setPendingKey(view, pending);
3741
+ view.inputState.setPendingAndroidKey(view, pending);
3739
3742
  if (pending.key == "Backspace" || pending.key == "Delete") {
3740
3743
  let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
3741
3744
  setTimeout(() => {
@@ -5283,7 +5286,7 @@ class DOMObserver {
5283
5286
  // Completely hold off flushing when pending keys are set—the code
5284
5287
  // managing those will make sure processRecords is called and the
5285
5288
  // view is resynchronized after
5286
- if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
5289
+ if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
5287
5290
  return;
5288
5291
  this.lastFlush = Date.now();
5289
5292
  let { from, to, typeOver } = this.processRecords();
@@ -5370,8 +5373,11 @@ function safariSelectionRangeHack(view) {
5370
5373
 
5371
5374
  function applyDOMChange(view, start, end, typeOver) {
5372
5375
  let change, newSel;
5373
- let sel = view.state.selection.main, bounds;
5374
- if (start > -1 && !view.state.readOnly && (bounds = view.docView.domBoundsAround(start, end, 0))) {
5376
+ let sel = view.state.selection.main;
5377
+ if (start > -1) {
5378
+ let bounds = view.docView.domBoundsAround(start, end, 0);
5379
+ if (!bounds || view.state.readOnly)
5380
+ return;
5375
5381
  let { from, to } = bounds;
5376
5382
  let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
5377
5383
  let reader = new DOMReader(selPoints, view);
@@ -5425,16 +5431,8 @@ function applyDOMChange(view, start, end, typeOver) {
5425
5431
  // backspace, or delete. So this detects changes that look like
5426
5432
  // they're caused by those keys, and reinterprets them as key
5427
5433
  // events.
5428
- if (browser.android &&
5429
- ((change.from == sel.from && change.to == sel.to &&
5430
- change.insert.length == 1 && change.insert.lines == 2 &&
5431
- dispatchKey(view.contentDOM, "Enter", 13)) ||
5432
- (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
5433
- dispatchKey(view.contentDOM, "Backspace", 8)) ||
5434
- (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
5435
- dispatchKey(view.contentDOM, "Delete", 46)))) {
5434
+ if (browser.ios && view.inputState.flushIOSKey(view))
5436
5435
  return;
5437
- }
5438
5436
  let text = change.insert.toString();
5439
5437
  if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
5440
5438
  return;
package/dist/index.js CHANGED
@@ -264,9 +264,9 @@ function contentEditablePlainTextSupported() {
264
264
  }
265
265
  function getRoot(node) {
266
266
  while (node) {
267
- node = node.assignedSlot || node.parentNode;
268
267
  if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
269
268
  return node;
269
+ node = node.assignedSlot || node.parentNode;
270
270
  }
271
271
  return null;
272
272
  }
@@ -3073,10 +3073,6 @@ class InputState {
3073
3073
  constructor(view) {
3074
3074
  this.lastKeyCode = 0;
3075
3075
  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
3076
  // On Chrome Android, backspace near widgets is just completely
3081
3077
  // broken, and there are no key events, so we need to handle the
3082
3078
  // beforeinput event. Deleting stuff will often create a flurry of
@@ -3084,12 +3080,11 @@ class InputState {
3084
3080
  // subsequent events even more broken, so again, we hold off doing
3085
3081
  // anything until the browser is finished with whatever it is trying
3086
3082
  // 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;
3083
+ this.pendingAndroidKey = undefined;
3084
+ // On iOS, some keys need to have their default behavior happen
3085
+ // (after which we retroactively handle them and reset the DOM) to
3086
+ // avoid messing up the virtual keyboard state.
3087
+ this.pendingIOSKey = undefined;
3093
3088
  this.lastSelectionOrigin = null;
3094
3089
  this.lastSelectionTime = 0;
3095
3090
  this.lastEscPress = 0;
@@ -3201,28 +3196,36 @@ class InputState {
3201
3196
  let pending;
3202
3197
  if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
3203
3198
  !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
3204
- this.setPendingKey(view, pending);
3199
+ this.pendingIOSKey = pending;
3200
+ setTimeout(() => this.flushIOSKey(view), 250);
3205
3201
  return true;
3206
3202
  }
3207
3203
  return false;
3208
3204
  }
3209
- setPendingKey(view, pending) {
3210
- this.pendingKey = pending;
3211
- let flush = () => {
3212
- if (!this.pendingKey)
3213
- return false;
3214
- let key = this.pendingKey;
3215
- this.pendingKey = undefined;
3205
+ flushIOSKey(view) {
3206
+ let key = this.pendingIOSKey;
3207
+ if (!key)
3208
+ return false;
3209
+ this.pendingIOSKey = undefined;
3210
+ return dispatchKey(view.contentDOM, key.key, key.keyCode);
3211
+ }
3212
+ // This causes the DOM observer to pause for a bit, and sets an
3213
+ // animation frame (which seems the most reliable way to detect
3214
+ // 'Chrome is done flailing about messing with the DOM') to fire a
3215
+ // fake key event and re-sync the view again.
3216
+ setPendingAndroidKey(view, pending) {
3217
+ this.pendingAndroidKey = pending;
3218
+ requestAnimationFrame(() => {
3219
+ let key = this.pendingAndroidKey;
3220
+ if (!key)
3221
+ return;
3222
+ this.pendingAndroidKey = undefined;
3216
3223
  view.observer.processRecords();
3217
3224
  let startState = view.state;
3218
3225
  dispatchKey(view.contentDOM, key.key, key.keyCode);
3219
3226
  if (view.state == startState)
3220
3227
  view.docView.reset(true);
3221
- };
3222
- if (browser.ios)
3223
- setTimeout(() => requestAnimationFrame(flush), 50);
3224
- else
3225
- requestAnimationFrame(flush);
3228
+ });
3226
3229
  }
3227
3230
  ignoreDuringComposition(event) {
3228
3231
  if (!/^key/.test(event.type))
@@ -3730,7 +3733,7 @@ handlers.beforeinput = (view, event) => {
3730
3733
  // seems to do nothing at all on Chrome).
3731
3734
  let pending;
3732
3735
  if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
3733
- view.inputState.setPendingKey(view, pending);
3736
+ view.inputState.setPendingAndroidKey(view, pending);
3734
3737
  if (pending.key == "Backspace" || pending.key == "Delete") {
3735
3738
  let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
3736
3739
  setTimeout(() => {
@@ -5277,7 +5280,7 @@ class DOMObserver {
5277
5280
  // Completely hold off flushing when pending keys are set—the code
5278
5281
  // managing those will make sure processRecords is called and the
5279
5282
  // view is resynchronized after
5280
- if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
5283
+ if (this.delayedFlush >= 0 || this.view.inputState.pendingAndroidKey)
5281
5284
  return;
5282
5285
  this.lastFlush = Date.now();
5283
5286
  let { from, to, typeOver } = this.processRecords();
@@ -5364,8 +5367,11 @@ function safariSelectionRangeHack(view) {
5364
5367
 
5365
5368
  function applyDOMChange(view, start, end, typeOver) {
5366
5369
  let change, newSel;
5367
- let sel = view.state.selection.main, bounds;
5368
- if (start > -1 && !view.state.readOnly && (bounds = view.docView.domBoundsAround(start, end, 0))) {
5370
+ let sel = view.state.selection.main;
5371
+ if (start > -1) {
5372
+ let bounds = view.docView.domBoundsAround(start, end, 0);
5373
+ if (!bounds || view.state.readOnly)
5374
+ return;
5369
5375
  let { from, to } = bounds;
5370
5376
  let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
5371
5377
  let reader = new DOMReader(selPoints, view);
@@ -5419,16 +5425,8 @@ function applyDOMChange(view, start, end, typeOver) {
5419
5425
  // backspace, or delete. So this detects changes that look like
5420
5426
  // they're caused by those keys, and reinterprets them as key
5421
5427
  // events.
5422
- if (browser.android &&
5423
- ((change.from == sel.from && change.to == sel.to &&
5424
- change.insert.length == 1 && change.insert.lines == 2 &&
5425
- dispatchKey(view.contentDOM, "Enter", 13)) ||
5426
- (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
5427
- dispatchKey(view.contentDOM, "Backspace", 8)) ||
5428
- (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
5429
- dispatchKey(view.contentDOM, "Delete", 46)))) {
5428
+ if (browser.ios && view.inputState.flushIOSKey(view))
5430
5429
  return;
5431
- }
5432
5430
  let text = change.insert.toString();
5433
5431
  if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
5434
5432
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "0.19.13",
3
+ "version": "0.19.14",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",