@codemirror/view 6.9.0 → 6.9.2

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.2 (2023-03-08)
2
+
3
+ ### Bug fixes
4
+
5
+ Work around a Firefox CSS bug that caused cursors to stop blinking in a scrolled editor.
6
+
7
+ Fix an issue in `drawSelection` where the selection extended into the editor's padding.
8
+
9
+ Fix pasting of links copied from iOS share sheet.
10
+
11
+ ## 6.9.1 (2023-02-17)
12
+
13
+ ### Bug fixes
14
+
15
+ Improve the way `posAtCoords` picks the side of a widget to return by comparing the coordinates the center of the widget.
16
+
17
+ Fix an issue where transactions created for the `focusChangeEffect` facet were sometimes not dispatched.
18
+
1
19
  ## 6.9.0 (2023-02-15)
2
20
 
3
21
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -519,6 +519,7 @@ class ContentView {
519
519
  }
520
520
  static get(node) { return node.cmView; }
521
521
  get isEditable() { return true; }
522
+ get isWidget() { return false; }
522
523
  merge(from, to, source, hasStart, openStart, openEnd) {
523
524
  return false;
524
525
  }
@@ -893,6 +894,7 @@ class WidgetView extends ContentView {
893
894
  return this.length ? rect : flattenRect(rect, this.side > 0);
894
895
  }
895
896
  get isEditable() { return false; }
897
+ get isWidget() { return true; }
896
898
  destroy() {
897
899
  super.destroy();
898
900
  if (this.dom)
@@ -1603,6 +1605,8 @@ class BlockWidgetView extends ContentView {
1603
1605
  }
1604
1606
  ignoreMutation() { return true; }
1605
1607
  ignoreEvent(event) { return this.widget.ignoreEvent(event); }
1608
+ get isEditable() { return false; }
1609
+ get isWidget() { return true; }
1606
1610
  destroy() {
1607
1611
  super.destroy();
1608
1612
  if (this.dom)
@@ -2027,11 +2031,6 @@ class ViewUpdate {
2027
2031
  let changedRanges = [];
2028
2032
  this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
2029
2033
  this.changedRanges = changedRanges;
2030
- let focus = view.hasFocus;
2031
- if (focus != view.inputState.notifiedFocused) {
2032
- view.inputState.notifiedFocused = focus;
2033
- this.flags |= 1 /* UpdateFlag.Focus */;
2034
- }
2035
2034
  }
2036
2035
  /**
2037
2036
  @internal
@@ -3167,11 +3166,11 @@ function domPosInText(node, x, y) {
3167
3166
  }
3168
3167
  return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
3169
3168
  }
3170
- function posAtCoords(view, { x, y }, precise, bias = -1) {
3171
- var _a;
3169
+ function posAtCoords(view, coords, precise, bias = -1) {
3170
+ var _a, _b;
3172
3171
  let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
3173
3172
  let block, { docHeight } = view.viewState;
3174
- let yOffset = y - docTop;
3173
+ let { x, y } = coords, yOffset = y - docTop;
3175
3174
  if (yOffset < 0)
3176
3175
  return 0;
3177
3176
  if (yOffset > docHeight)
@@ -3242,7 +3241,17 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
3242
3241
  return yOffset > block.top + block.height / 2 ? block.to : block.from;
3243
3242
  ({ node, offset } = domPosAtCoords(line.dom, x, y));
3244
3243
  }
3245
- return view.docView.posFromDOM(node, offset);
3244
+ let nearest = view.docView.nearest(node);
3245
+ if (!nearest)
3246
+ return null;
3247
+ if (nearest.isWidget && ((_b = nearest.dom) === null || _b === void 0 ? void 0 : _b.nodeType) == 1) {
3248
+ let rect = nearest.dom.getBoundingClientRect();
3249
+ return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
3250
+ ? nearest.posAtStart : nearest.posAtEnd;
3251
+ }
3252
+ else {
3253
+ return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
3254
+ }
3246
3255
  }
3247
3256
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
3248
3257
  let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
@@ -3965,7 +3974,7 @@ handlers.paste = (view, event) => {
3965
3974
  view.observer.flush();
3966
3975
  let data = brokenClipboardAPI ? null : event.clipboardData;
3967
3976
  if (data) {
3968
- doPaste(view, data.getData("text/plain"));
3977
+ doPaste(view, data.getData("text/plain") || data.getData("text/uri-text"));
3969
3978
  event.preventDefault();
3970
3979
  }
3971
3980
  else {
@@ -4033,17 +4042,23 @@ handlers.copy = handlers.cut = (view, event) => {
4033
4042
  userEvent: "delete.cut"
4034
4043
  });
4035
4044
  };
4045
+ const isFocusChange = state.Annotation.define();
4046
+ function focusChangeTransaction(state, focus) {
4047
+ let effects = [];
4048
+ for (let getEffect of state.facet(focusChangeEffect)) {
4049
+ let effect = getEffect(state, focus);
4050
+ if (effect)
4051
+ effects.push(effect);
4052
+ }
4053
+ return effects ? state.update({ effects, annotations: isFocusChange.of(true) }) : null;
4054
+ }
4036
4055
  function updateForFocusChange(view) {
4037
4056
  setTimeout(() => {
4038
- if (view.hasFocus != view.inputState.notifiedFocused) {
4039
- let effects = [], focus = !view.inputState.notifiedFocused;
4040
- for (let getEffect of view.state.facet(focusChangeEffect)) {
4041
- let effect = getEffect(view.state, focus);
4042
- if (effect)
4043
- effects.push(effect);
4044
- }
4045
- if (effects.length)
4046
- view.dispatch({ effects });
4057
+ let focus = view.hasFocus;
4058
+ if (focus != view.inputState.notifiedFocused) {
4059
+ let tr = focusChangeTransaction(view.state, focus);
4060
+ if (tr)
4061
+ view.dispatch(tr);
4047
4062
  else
4048
4063
  view.update([]);
4049
4064
  }
@@ -5420,6 +5435,9 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
5420
5435
  padding: "0 2px 0 6px"
5421
5436
  },
5422
5437
  ".cm-layer": {
5438
+ position: "absolute",
5439
+ left: 0,
5440
+ top: 0,
5423
5441
  contain: "size style",
5424
5442
  "& > *": {
5425
5443
  position: "absolute"
@@ -6427,6 +6445,20 @@ class EditorView {
6427
6445
  this.viewState.state = state$1;
6428
6446
  return;
6429
6447
  }
6448
+ let focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
6449
+ if (transactions.some(tr => tr.annotation(isFocusChange))) {
6450
+ this.inputState.notifiedFocused = focus;
6451
+ // If a focus-change transaction is being dispatched, set this update flag.
6452
+ focusFlag = 1 /* UpdateFlag.Focus */;
6453
+ }
6454
+ else if (focus != this.inputState.notifiedFocused) {
6455
+ this.inputState.notifiedFocused = focus;
6456
+ // Schedule a separate focus transaction if necessary, otherwise
6457
+ // add a flag to this update
6458
+ dispatchFocus = focusChangeTransaction(state$1, focus);
6459
+ if (!dispatchFocus)
6460
+ focusFlag = 1 /* UpdateFlag.Focus */;
6461
+ }
6430
6462
  // If there was a pending DOM change, eagerly read it and try to
6431
6463
  // apply it after the given transactions.
6432
6464
  let pendingKey = this.observer.delayedAndroidKey, domChange = null;
@@ -6445,6 +6477,7 @@ class EditorView {
6445
6477
  if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
6446
6478
  return this.setState(state$1);
6447
6479
  update = ViewUpdate.create(this, state$1, transactions);
6480
+ update.flags |= focusFlag;
6448
6481
  let scrollTarget = this.viewState.scrollTarget;
6449
6482
  try {
6450
6483
  this.updateState = 2 /* UpdateState.Updating */;
@@ -6482,10 +6515,15 @@ class EditorView {
6482
6515
  if (!update.empty)
6483
6516
  for (let listener of this.state.facet(updateListener))
6484
6517
  listener(update);
6485
- if (domChange) {
6486
- if (!applyDOMChange(this, domChange) && pendingKey.force)
6487
- dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
6488
- }
6518
+ if (dispatchFocus || domChange)
6519
+ Promise.resolve().then(() => {
6520
+ if (dispatchFocus && this.state == dispatchFocus.startState)
6521
+ this.dispatch(dispatchFocus);
6522
+ if (domChange) {
6523
+ if (!applyDOMChange(this, domChange) && pendingKey.force)
6524
+ dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
6525
+ }
6526
+ });
6489
6527
  }
6490
6528
  /**
6491
6529
  Reset the view to the given state. (This will cause the entire
@@ -6560,7 +6598,7 @@ class EditorView {
6560
6598
  if (this.destroyed)
6561
6599
  return;
6562
6600
  if (this.measureScheduled > -1)
6563
- cancelAnimationFrame(this.measureScheduled);
6601
+ this.win.cancelAnimationFrame(this.measureScheduled);
6564
6602
  this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
6565
6603
  if (flush)
6566
6604
  this.observer.forceFlush();
@@ -6998,7 +7036,7 @@ class EditorView {
6998
7036
  this.dom.remove();
6999
7037
  this.observer.destroy();
7000
7038
  if (this.measureScheduled > -1)
7001
- cancelAnimationFrame(this.measureScheduled);
7039
+ this.win.cancelAnimationFrame(this.measureScheduled);
7002
7040
  this.destroyed = true;
7003
7041
  }
7004
7042
  /**
@@ -7510,9 +7548,10 @@ function rectanglesForRange(view, className, range) {
7510
7548
  let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
7511
7549
  let ltr = view.textDirection == exports.Direction.LTR;
7512
7550
  let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
7513
- let lineStyle = window.getComputedStyle(content.firstChild);
7514
- let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent));
7515
- let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
7551
+ let lineElt = content.querySelector(".cm-line"), lineStyle = lineElt && window.getComputedStyle(lineElt);
7552
+ let leftSide = contentRect.left +
7553
+ (lineStyle ? parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)) : 0);
7554
+ let rightSide = contentRect.right - (lineStyle ? parseInt(lineStyle.paddingRight) : 0);
7516
7555
  let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
7517
7556
  let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null;
7518
7557
  let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
1
+ import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Annotation, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
2
2
  import { StyleModule } from 'style-mod';
3
3
  import { keyName, base, shift } from 'w3c-keyname';
4
4
 
@@ -515,6 +515,7 @@ class ContentView {
515
515
  }
516
516
  static get(node) { return node.cmView; }
517
517
  get isEditable() { return true; }
518
+ get isWidget() { return false; }
518
519
  merge(from, to, source, hasStart, openStart, openEnd) {
519
520
  return false;
520
521
  }
@@ -889,6 +890,7 @@ class WidgetView extends ContentView {
889
890
  return this.length ? rect : flattenRect(rect, this.side > 0);
890
891
  }
891
892
  get isEditable() { return false; }
893
+ get isWidget() { return true; }
892
894
  destroy() {
893
895
  super.destroy();
894
896
  if (this.dom)
@@ -1598,6 +1600,8 @@ class BlockWidgetView extends ContentView {
1598
1600
  }
1599
1601
  ignoreMutation() { return true; }
1600
1602
  ignoreEvent(event) { return this.widget.ignoreEvent(event); }
1603
+ get isEditable() { return false; }
1604
+ get isWidget() { return true; }
1601
1605
  destroy() {
1602
1606
  super.destroy();
1603
1607
  if (this.dom)
@@ -2022,11 +2026,6 @@ class ViewUpdate {
2022
2026
  let changedRanges = [];
2023
2027
  this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
2024
2028
  this.changedRanges = changedRanges;
2025
- let focus = view.hasFocus;
2026
- if (focus != view.inputState.notifiedFocused) {
2027
- view.inputState.notifiedFocused = focus;
2028
- this.flags |= 1 /* UpdateFlag.Focus */;
2029
- }
2030
2029
  }
2031
2030
  /**
2032
2031
  @internal
@@ -3161,11 +3160,11 @@ function domPosInText(node, x, y) {
3161
3160
  }
3162
3161
  return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
3163
3162
  }
3164
- function posAtCoords(view, { x, y }, precise, bias = -1) {
3165
- var _a;
3163
+ function posAtCoords(view, coords, precise, bias = -1) {
3164
+ var _a, _b;
3166
3165
  let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
3167
3166
  let block, { docHeight } = view.viewState;
3168
- let yOffset = y - docTop;
3167
+ let { x, y } = coords, yOffset = y - docTop;
3169
3168
  if (yOffset < 0)
3170
3169
  return 0;
3171
3170
  if (yOffset > docHeight)
@@ -3236,7 +3235,17 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
3236
3235
  return yOffset > block.top + block.height / 2 ? block.to : block.from;
3237
3236
  ({ node, offset } = domPosAtCoords(line.dom, x, y));
3238
3237
  }
3239
- return view.docView.posFromDOM(node, offset);
3238
+ let nearest = view.docView.nearest(node);
3239
+ if (!nearest)
3240
+ return null;
3241
+ if (nearest.isWidget && ((_b = nearest.dom) === null || _b === void 0 ? void 0 : _b.nodeType) == 1) {
3242
+ let rect = nearest.dom.getBoundingClientRect();
3243
+ return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
3244
+ ? nearest.posAtStart : nearest.posAtEnd;
3245
+ }
3246
+ else {
3247
+ return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
3248
+ }
3240
3249
  }
3241
3250
  function posAtCoordsImprecise(view, contentRect, block, x, y) {
3242
3251
  let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
@@ -3959,7 +3968,7 @@ handlers.paste = (view, event) => {
3959
3968
  view.observer.flush();
3960
3969
  let data = brokenClipboardAPI ? null : event.clipboardData;
3961
3970
  if (data) {
3962
- doPaste(view, data.getData("text/plain"));
3971
+ doPaste(view, data.getData("text/plain") || data.getData("text/uri-text"));
3963
3972
  event.preventDefault();
3964
3973
  }
3965
3974
  else {
@@ -4027,17 +4036,23 @@ handlers.copy = handlers.cut = (view, event) => {
4027
4036
  userEvent: "delete.cut"
4028
4037
  });
4029
4038
  };
4039
+ const isFocusChange = /*@__PURE__*/Annotation.define();
4040
+ function focusChangeTransaction(state, focus) {
4041
+ let effects = [];
4042
+ for (let getEffect of state.facet(focusChangeEffect)) {
4043
+ let effect = getEffect(state, focus);
4044
+ if (effect)
4045
+ effects.push(effect);
4046
+ }
4047
+ return effects ? state.update({ effects, annotations: isFocusChange.of(true) }) : null;
4048
+ }
4030
4049
  function updateForFocusChange(view) {
4031
4050
  setTimeout(() => {
4032
- if (view.hasFocus != view.inputState.notifiedFocused) {
4033
- let effects = [], focus = !view.inputState.notifiedFocused;
4034
- for (let getEffect of view.state.facet(focusChangeEffect)) {
4035
- let effect = getEffect(view.state, focus);
4036
- if (effect)
4037
- effects.push(effect);
4038
- }
4039
- if (effects.length)
4040
- view.dispatch({ effects });
4051
+ let focus = view.hasFocus;
4052
+ if (focus != view.inputState.notifiedFocused) {
4053
+ let tr = focusChangeTransaction(view.state, focus);
4054
+ if (tr)
4055
+ view.dispatch(tr);
4041
4056
  else
4042
4057
  view.update([]);
4043
4058
  }
@@ -5413,6 +5428,9 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5413
5428
  padding: "0 2px 0 6px"
5414
5429
  },
5415
5430
  ".cm-layer": {
5431
+ position: "absolute",
5432
+ left: 0,
5433
+ top: 0,
5416
5434
  contain: "size style",
5417
5435
  "& > *": {
5418
5436
  position: "absolute"
@@ -6420,6 +6438,20 @@ class EditorView {
6420
6438
  this.viewState.state = state;
6421
6439
  return;
6422
6440
  }
6441
+ let focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
6442
+ if (transactions.some(tr => tr.annotation(isFocusChange))) {
6443
+ this.inputState.notifiedFocused = focus;
6444
+ // If a focus-change transaction is being dispatched, set this update flag.
6445
+ focusFlag = 1 /* UpdateFlag.Focus */;
6446
+ }
6447
+ else if (focus != this.inputState.notifiedFocused) {
6448
+ this.inputState.notifiedFocused = focus;
6449
+ // Schedule a separate focus transaction if necessary, otherwise
6450
+ // add a flag to this update
6451
+ dispatchFocus = focusChangeTransaction(state, focus);
6452
+ if (!dispatchFocus)
6453
+ focusFlag = 1 /* UpdateFlag.Focus */;
6454
+ }
6423
6455
  // If there was a pending DOM change, eagerly read it and try to
6424
6456
  // apply it after the given transactions.
6425
6457
  let pendingKey = this.observer.delayedAndroidKey, domChange = null;
@@ -6438,6 +6470,7 @@ class EditorView {
6438
6470
  if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
6439
6471
  return this.setState(state);
6440
6472
  update = ViewUpdate.create(this, state, transactions);
6473
+ update.flags |= focusFlag;
6441
6474
  let scrollTarget = this.viewState.scrollTarget;
6442
6475
  try {
6443
6476
  this.updateState = 2 /* UpdateState.Updating */;
@@ -6475,10 +6508,15 @@ class EditorView {
6475
6508
  if (!update.empty)
6476
6509
  for (let listener of this.state.facet(updateListener))
6477
6510
  listener(update);
6478
- if (domChange) {
6479
- if (!applyDOMChange(this, domChange) && pendingKey.force)
6480
- dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
6481
- }
6511
+ if (dispatchFocus || domChange)
6512
+ Promise.resolve().then(() => {
6513
+ if (dispatchFocus && this.state == dispatchFocus.startState)
6514
+ this.dispatch(dispatchFocus);
6515
+ if (domChange) {
6516
+ if (!applyDOMChange(this, domChange) && pendingKey.force)
6517
+ dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
6518
+ }
6519
+ });
6482
6520
  }
6483
6521
  /**
6484
6522
  Reset the view to the given state. (This will cause the entire
@@ -6553,7 +6591,7 @@ class EditorView {
6553
6591
  if (this.destroyed)
6554
6592
  return;
6555
6593
  if (this.measureScheduled > -1)
6556
- cancelAnimationFrame(this.measureScheduled);
6594
+ this.win.cancelAnimationFrame(this.measureScheduled);
6557
6595
  this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
6558
6596
  if (flush)
6559
6597
  this.observer.forceFlush();
@@ -6991,7 +7029,7 @@ class EditorView {
6991
7029
  this.dom.remove();
6992
7030
  this.observer.destroy();
6993
7031
  if (this.measureScheduled > -1)
6994
- cancelAnimationFrame(this.measureScheduled);
7032
+ this.win.cancelAnimationFrame(this.measureScheduled);
6995
7033
  this.destroyed = true;
6996
7034
  }
6997
7035
  /**
@@ -7503,9 +7541,10 @@ function rectanglesForRange(view, className, range) {
7503
7541
  let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
7504
7542
  let ltr = view.textDirection == Direction.LTR;
7505
7543
  let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
7506
- let lineStyle = window.getComputedStyle(content.firstChild);
7507
- let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent));
7508
- let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
7544
+ let lineElt = content.querySelector(".cm-line"), lineStyle = lineElt && window.getComputedStyle(lineElt);
7545
+ let leftSide = contentRect.left +
7546
+ (lineStyle ? parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)) : 0);
7547
+ let rightSide = contentRect.right - (lineStyle ? parseInt(lineStyle.paddingRight) : 0);
7509
7548
  let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
7510
7549
  let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
7511
7550
  let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.9.0",
3
+ "version": "6.9.2",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",