@codemirror/view 0.19.34 → 0.19.35

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,13 @@
1
+ ## 0.19.35 (2021-12-20)
2
+
3
+ ### Bug fixes
4
+
5
+ The editor will now handle double-taps as if they are double-clicks, rather than letting the browser's native behavior happen (because the latter often does the wrong thing).
6
+
7
+ Fix an issue where backspacing out a selection on Chrome Android would sometimes only delete the last character due to event order issues.
8
+
9
+ `posAtCoords`, without second argument, will no longer return null for positions below or above the document.
10
+
1
11
  ## 0.19.34 (2021-12-17)
2
12
 
3
13
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -2990,12 +2990,8 @@ function domPosInText(node, x, y) {
2990
2990
  function posAtCoords(view, { x, y }, precise, bias = -1) {
2991
2991
  var _a;
2992
2992
  let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
2993
- let block, yOffset = y - docTop, { docHeight } = view.viewState;
2994
- if (yOffset < 0 || yOffset > docHeight) {
2995
- if (precise)
2996
- return null;
2997
- yOffset = yOffset < 0 ? 0 : docHeight;
2998
- }
2993
+ let block, { docHeight } = view.viewState;
2994
+ let yOffset = Math.max(0, Math.min(y - docTop, docHeight));
2999
2995
  // Scan for a text block near the queried y position
3000
2996
  for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
3001
2997
  block = view.elementAtHeight(yOffset);
@@ -3016,20 +3012,29 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
3016
3012
  }
3017
3013
  y = docTop + yOffset;
3018
3014
  let lineStart = block.from;
3019
- // Clip x to the viewport sides
3020
- x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
3021
3015
  // If this is outside of the rendered viewport, we can't determine a position
3022
3016
  if (lineStart < view.viewport.from)
3023
- return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
3017
+ return view.viewport.from == 0 ? 0 : precise ? posAtCoordsImprecise(view, content, block, x, y) : null;
3024
3018
  if (lineStart > view.viewport.to)
3025
- return view.viewport.to == view.state.doc.length ? view.state.doc.length : posAtCoordsImprecise(view, content, block, x, y);
3019
+ return view.viewport.to == view.state.doc.length ? view.state.doc.length :
3020
+ precise ? posAtCoordsImprecise(view, content, block, x, y) : null;
3026
3021
  // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not
3027
3022
  let doc = view.dom.ownerDocument;
3028
- let element = (view.root.elementFromPoint ? view.root : doc).elementFromPoint(x, y);
3023
+ let root = view.root.elementFromPoint ? view.root : doc;
3024
+ let element = root.elementFromPoint(x, y);
3025
+ if (element && !view.contentDOM.contains(element))
3026
+ element = null;
3027
+ // If the element is unexpected, clip x at the sides of the content area and try again
3028
+ if (!element) {
3029
+ x = Math.max(content.left + 1, Math.min(content.right - 1, x));
3030
+ element = root.elementFromPoint(x, y);
3031
+ if (element && !view.contentDOM.contains(element))
3032
+ element = null;
3033
+ }
3029
3034
  // There's visible editor content under the point, so we can try
3030
3035
  // using caret(Position|Range)FromPoint as a shortcut
3031
3036
  let node, offset = -1;
3032
- if (element && view.contentDOM.contains(element) && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
3037
+ if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
3033
3038
  if (doc.caretPositionFromPoint) {
3034
3039
  let pos = doc.caretPositionFromPoint(x, y);
3035
3040
  if (pos)
@@ -3510,7 +3515,7 @@ handlers.touchmove = view => {
3510
3515
  };
3511
3516
  handlers.mousedown = (view, event) => {
3512
3517
  view.observer.flush();
3513
- if (lastTouch > Date.now() - 2000)
3518
+ if (lastTouch > Date.now() - 2000 && getClickType(event) == 1)
3514
3519
  return; // Ignore touch interaction
3515
3520
  let style = null;
3516
3521
  for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
@@ -3632,9 +3637,9 @@ handlers.dragstart = (view, event) => {
3632
3637
  }
3633
3638
  };
3634
3639
  function dropText(view, event, text, direct) {
3635
- let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY });
3636
- if (dropPos == null || !text)
3640
+ if (!text)
3637
3641
  return;
3642
+ let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
3638
3643
  event.preventDefault();
3639
3644
  let { mouseSelection } = view.inputState;
3640
3645
  let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ?
@@ -4745,7 +4750,7 @@ class ViewState {
4745
4750
  let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
4746
4751
  if (scrollTarget.y == "center")
4747
4752
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
4748
- else if (scrollTarget.y == "start" || head < viewport.from)
4753
+ else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
4749
4754
  topPos = block.top;
4750
4755
  else
4751
4756
  topPos = block.bottom - viewHeight;
@@ -5292,8 +5297,10 @@ class DOMObserver {
5292
5297
  // Deletions on IE11 fire their events in the wrong order, giving
5293
5298
  // us a selection change event before the DOM changes are
5294
5299
  // reported.
5295
- // (Selection.isCollapsed isn't reliable on IE)
5296
- if (browser.ie && browser.ie_version <= 11 && !view.state.selection.main.empty &&
5300
+ // Chrome Android has a similar issue when backspacing out a
5301
+ // selection (#645).
5302
+ if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty &&
5303
+ // (Selection.isCollapsed isn't reliable on IE)
5297
5304
  sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
5298
5305
  this.flushSoon();
5299
5306
  else
package/dist/index.d.ts CHANGED
@@ -937,8 +937,11 @@ declare class EditorView {
937
937
  */
938
938
  posAtDOM(node: Node, offset?: number): number;
939
939
  /**
940
- Get the document position at the given screen coordinates.
941
- Returns null if no valid position could be found.
940
+ Get the document position at the given screen coordinates. For
941
+ positions not covered by the visible viewport's DOM structure,
942
+ this will return null, unless `false` is passed as second
943
+ argument, in which case it'll return an estimated position that
944
+ would be near the coordinates if it were rendered.
942
945
  */
943
946
  posAtCoords(coords: {
944
947
  x: number;
package/dist/index.js CHANGED
@@ -2985,12 +2985,8 @@ function domPosInText(node, x, y) {
2985
2985
  function posAtCoords(view, { x, y }, precise, bias = -1) {
2986
2986
  var _a;
2987
2987
  let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
2988
- let block, yOffset = y - docTop, { docHeight } = view.viewState;
2989
- if (yOffset < 0 || yOffset > docHeight) {
2990
- if (precise)
2991
- return null;
2992
- yOffset = yOffset < 0 ? 0 : docHeight;
2993
- }
2988
+ let block, { docHeight } = view.viewState;
2989
+ let yOffset = Math.max(0, Math.min(y - docTop, docHeight));
2994
2990
  // Scan for a text block near the queried y position
2995
2991
  for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
2996
2992
  block = view.elementAtHeight(yOffset);
@@ -3011,20 +3007,29 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
3011
3007
  }
3012
3008
  y = docTop + yOffset;
3013
3009
  let lineStart = block.from;
3014
- // Clip x to the viewport sides
3015
- x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
3016
3010
  // If this is outside of the rendered viewport, we can't determine a position
3017
3011
  if (lineStart < view.viewport.from)
3018
- return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
3012
+ return view.viewport.from == 0 ? 0 : precise ? posAtCoordsImprecise(view, content, block, x, y) : null;
3019
3013
  if (lineStart > view.viewport.to)
3020
- return view.viewport.to == view.state.doc.length ? view.state.doc.length : posAtCoordsImprecise(view, content, block, x, y);
3014
+ return view.viewport.to == view.state.doc.length ? view.state.doc.length :
3015
+ precise ? posAtCoordsImprecise(view, content, block, x, y) : null;
3021
3016
  // Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not
3022
3017
  let doc = view.dom.ownerDocument;
3023
- let element = (view.root.elementFromPoint ? view.root : doc).elementFromPoint(x, y);
3018
+ let root = view.root.elementFromPoint ? view.root : doc;
3019
+ let element = root.elementFromPoint(x, y);
3020
+ if (element && !view.contentDOM.contains(element))
3021
+ element = null;
3022
+ // If the element is unexpected, clip x at the sides of the content area and try again
3023
+ if (!element) {
3024
+ x = Math.max(content.left + 1, Math.min(content.right - 1, x));
3025
+ element = root.elementFromPoint(x, y);
3026
+ if (element && !view.contentDOM.contains(element))
3027
+ element = null;
3028
+ }
3024
3029
  // There's visible editor content under the point, so we can try
3025
3030
  // using caret(Position|Range)FromPoint as a shortcut
3026
3031
  let node, offset = -1;
3027
- if (element && view.contentDOM.contains(element) && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
3032
+ if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
3028
3033
  if (doc.caretPositionFromPoint) {
3029
3034
  let pos = doc.caretPositionFromPoint(x, y);
3030
3035
  if (pos)
@@ -3505,7 +3510,7 @@ handlers.touchmove = view => {
3505
3510
  };
3506
3511
  handlers.mousedown = (view, event) => {
3507
3512
  view.observer.flush();
3508
- if (lastTouch > Date.now() - 2000)
3513
+ if (lastTouch > Date.now() - 2000 && getClickType(event) == 1)
3509
3514
  return; // Ignore touch interaction
3510
3515
  let style = null;
3511
3516
  for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
@@ -3627,9 +3632,9 @@ handlers.dragstart = (view, event) => {
3627
3632
  }
3628
3633
  };
3629
3634
  function dropText(view, event, text, direct) {
3630
- let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY });
3631
- if (dropPos == null || !text)
3635
+ if (!text)
3632
3636
  return;
3637
+ let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
3633
3638
  event.preventDefault();
3634
3639
  let { mouseSelection } = view.inputState;
3635
3640
  let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ?
@@ -4739,7 +4744,7 @@ class ViewState {
4739
4744
  let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
4740
4745
  if (scrollTarget.y == "center")
4741
4746
  topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
4742
- else if (scrollTarget.y == "start" || head < viewport.from)
4747
+ else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
4743
4748
  topPos = block.top;
4744
4749
  else
4745
4750
  topPos = block.bottom - viewHeight;
@@ -5286,8 +5291,10 @@ class DOMObserver {
5286
5291
  // Deletions on IE11 fire their events in the wrong order, giving
5287
5292
  // us a selection change event before the DOM changes are
5288
5293
  // reported.
5289
- // (Selection.isCollapsed isn't reliable on IE)
5290
- if (browser.ie && browser.ie_version <= 11 && !view.state.selection.main.empty &&
5294
+ // Chrome Android has a similar issue when backspacing out a
5295
+ // selection (#645).
5296
+ if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty &&
5297
+ // (Selection.isCollapsed isn't reliable on IE)
5291
5298
  sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
5292
5299
  this.flushSoon();
5293
5300
  else
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "0.19.34",
3
+ "version": "0.19.35",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",