prosemirror-view 1.31.4 → 1.31.6

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,23 @@
1
+ ## 1.31.6 (2023-07-14)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a bug that caused `posAtCoords` to return incorrect results for coordinates over inline-decorated text.
6
+
7
+ Don't try to scroll fixed-positioned elements into view by scrolling their parent elements.
8
+
9
+ ## 1.31.5 (2023-06-19)
10
+
11
+ ### Bug fixes
12
+
13
+ Fix a bug where the editor accidentally blocked shift-delete when the whole document is selected.
14
+
15
+ Bring back workaround for an issue where Firefox draws the cursor in the wrong place in a code block.
16
+
17
+ Fix an issue where Shift-Insert pastes pasted plain text (because Shift was being held).
18
+
19
+ Fix an issue where selecting across paragraph and starting a composition would update the state as if Enter was pressed and disrupt the composition.
20
+
1
21
  ## 1.31.4 (2023-05-31)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -238,7 +238,7 @@ function scrollRectIntoView(view, rect, startDOM) {
238
238
  }
239
239
  }
240
240
 
241
- if (atTop) break;
241
+ if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent).position)) break;
242
242
  }
243
243
  }
244
244
 
@@ -441,7 +441,7 @@ function posFromCaret(view, node, offset, coords) {
441
441
  if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore;else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter;
442
442
  }
443
443
 
444
- if (!desc.contentDOM && outsideBlock < 0) {
444
+ if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
445
445
  var before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2 : coords.left < (rect.left + rect.right) / 2;
446
446
  return before ? desc.posBefore : desc.posAfter;
447
447
  }
@@ -1134,6 +1134,21 @@ var ViewDesc = function () {
1134
1134
 
1135
1135
  if (node.nodeType == 3) {
1136
1136
  brKludge = !!(_offset && node.nodeValue[_offset - 1] == "\n");
1137
+
1138
+ if (brKludge && _offset == node.nodeValue.length) {
1139
+ for (var scan = node, after; scan; scan = scan.parentNode) {
1140
+ if (after = scan.nextSibling) {
1141
+ if (after.nodeName == "BR") anchorDOM = headDOM = {
1142
+ node: after.parentNode,
1143
+ offset: domIndex(after) + 1
1144
+ };
1145
+ break;
1146
+ }
1147
+
1148
+ var desc = scan.pmViewDesc;
1149
+ if (desc && desc.node && desc.node.isBlock) break;
1150
+ }
1151
+ }
1137
1152
  } else {
1138
1153
  var prev = node.childNodes[_offset - 1];
1139
1154
  brKludge = prev && (prev.nodeName == "BR" || prev.contentEditable == "false");
@@ -1141,8 +1156,8 @@ var ViewDesc = function () {
1141
1156
  }
1142
1157
 
1143
1158
  if (gecko && domSel.focusNode && domSel.focusNode != headDOM.node && domSel.focusNode.nodeType == 1) {
1144
- var after = domSel.focusNode.childNodes[domSel.focusOffset];
1145
- if (after && after.contentEditable == "false") force = true;
1159
+ var _after2 = domSel.focusNode.childNodes[domSel.focusOffset];
1160
+ if (_after2 && _after2.contentEditable == "false") force = true;
1146
1161
  }
1147
1162
 
1148
1163
  if (!(force || brKludge && safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, domSel.anchorNode, domSel.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, domSel.focusNode, domSel.focusOffset)) return;
@@ -1378,7 +1393,7 @@ var MarkViewDesc = function (_ViewDesc3) {
1378
1393
  return {
1379
1394
  mark: this.mark.type.name,
1380
1395
  attrs: this.mark.attrs,
1381
- contentElement: this.contentDOM || undefined
1396
+ contentElement: this.contentDOM
1382
1397
  };
1383
1398
  }
1384
1399
  }, {
@@ -2991,7 +3006,7 @@ function captureKeyDown(view, event) {
2991
3006
 
2992
3007
  if (code == 8 || mac && code == 72 && mods == "c") {
2993
3008
  return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1);
2994
- } else if (code == 46 || mac && code == 68 && mods == "c") {
3009
+ } else if (code == 46 && !event.shiftKey || mac && code == 68 && mods == "c") {
2995
3010
  return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1);
2996
3011
  } else if (code == 13 || code == 27) {
2997
3012
  return true;
@@ -3895,10 +3910,11 @@ function capturePaste(view, event) {
3895
3910
  if (!plainText) target.contentEditable = "true";
3896
3911
  target.style.cssText = "position: fixed; left: -10000px; top: 10px";
3897
3912
  target.focus();
3913
+ var plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3898
3914
  setTimeout(function () {
3899
3915
  view.focus();
3900
3916
  if (target.parentNode) target.parentNode.removeChild(target);
3901
- if (plainText) doPaste(view, target.value, null, view.input.shiftKey, event);else doPaste(view, target.textContent, target.innerHTML, view.input.shiftKey, event);
3917
+ if (plainText) doPaste(view, target.value, null, plain, event);else doPaste(view, target.textContent, target.innerHTML, plain, event);
3902
3918
  }, 50);
3903
3919
  }
3904
3920
 
@@ -3909,7 +3925,7 @@ function doPaste(view, text, html, preferPlain, event) {
3909
3925
  })) return true;
3910
3926
  if (!slice) return false;
3911
3927
  var singleNode = sliceSingleNode(slice);
3912
- var tr = singleNode ? view.state.tr.replaceSelectionWith(singleNode, view.input.shiftKey) : view.state.tr.replaceSelection(slice);
3928
+ var tr = singleNode ? view.state.tr.replaceSelectionWith(singleNode, preferPlain) : view.state.tr.replaceSelection(slice);
3913
3929
  view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
3914
3930
  return true;
3915
3931
  }
@@ -3918,7 +3934,8 @@ editHandlers.paste = function (view, _event) {
3918
3934
  var event = _event;
3919
3935
  if (view.composing && !android) return;
3920
3936
  var data = brokenClipboardAPI ? null : event.clipboardData;
3921
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event)) event.preventDefault();else capturePaste(view, event);
3937
+ var plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3938
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), plain, event)) event.preventDefault();else capturePaste(view, event);
3922
3939
  };
3923
3940
 
3924
3941
  var Dragging = _createClass(function Dragging(slice, move) {
@@ -5372,7 +5389,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
5372
5389
 
5373
5390
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 && (!inlineChange || addedNodes.some(function (n) {
5374
5391
  return n.nodeName == "DIV" || n.nodeName == "P";
5375
- })) || !inlineChange && $from.pos < parse.doc.content.size && (nextSel = prosemirrorState.Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) && nextSel.head == $to.pos) && view.someProp("handleKeyDown", function (f) {
5392
+ })) || !inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) && (nextSel = prosemirrorState.Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) && nextSel.head == $to.pos) && view.someProp("handleKeyDown", function (f) {
5376
5393
  return f(view, keyEvent(13, "Enter"));
5377
5394
  })) {
5378
5395
  view.input.lastIOSEnter = 0;
package/dist/index.js CHANGED
@@ -182,7 +182,7 @@ function scrollRectIntoView(view, rect, startDOM) {
182
182
  rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
183
183
  }
184
184
  }
185
- if (atTop)
185
+ if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent).position))
186
186
  break;
187
187
  }
188
188
  }
@@ -356,7 +356,7 @@ function posFromCaret(view, node, offset, coords) {
356
356
  else if (rect.right < coords.left || rect.bottom < coords.top)
357
357
  outsideBlock = desc.posAfter;
358
358
  }
359
- if (!desc.contentDOM && outsideBlock < 0) {
359
+ if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
360
360
  // If we are inside a leaf, return the side of the leaf closer to the coords
361
361
  let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2
362
362
  : coords.left < (rect.left + rect.right) / 2;
@@ -957,6 +957,19 @@ class ViewDesc {
957
957
  let { node, offset } = anchorDOM;
958
958
  if (node.nodeType == 3) {
959
959
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
960
+ // Issue #1128
961
+ if (brKludge && offset == node.nodeValue.length) {
962
+ for (let scan = node, after; scan; scan = scan.parentNode) {
963
+ if (after = scan.nextSibling) {
964
+ if (after.nodeName == "BR")
965
+ anchorDOM = headDOM = { node: after.parentNode, offset: domIndex(after) + 1 };
966
+ break;
967
+ }
968
+ let desc = scan.pmViewDesc;
969
+ if (desc && desc.node && desc.node.isBlock)
970
+ break;
971
+ }
972
+ }
960
973
  }
961
974
  else {
962
975
  let prev = node.childNodes[offset - 1];
@@ -1132,7 +1145,7 @@ class MarkViewDesc extends ViewDesc {
1132
1145
  parseRule() {
1133
1146
  if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)
1134
1147
  return null;
1135
- return { mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM || undefined };
1148
+ return { mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM };
1136
1149
  }
1137
1150
  matchesMark(mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark); }
1138
1151
  markDirty(from, to) {
@@ -2586,7 +2599,7 @@ function captureKeyDown(view, event) {
2586
2599
  if (code == 8 || (mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
2587
2600
  return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1);
2588
2601
  }
2589
- else if (code == 46 || (mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
2602
+ else if ((code == 46 && !event.shiftKey) || (mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
2590
2603
  return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1);
2591
2604
  }
2592
2605
  else if (code == 13 || code == 27) { // Enter, Esc
@@ -3414,14 +3427,15 @@ function capturePaste(view, event) {
3414
3427
  target.contentEditable = "true";
3415
3428
  target.style.cssText = "position: fixed; left: -10000px; top: 10px";
3416
3429
  target.focus();
3430
+ let plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3417
3431
  setTimeout(() => {
3418
3432
  view.focus();
3419
3433
  if (target.parentNode)
3420
3434
  target.parentNode.removeChild(target);
3421
3435
  if (plainText)
3422
- doPaste(view, target.value, null, view.input.shiftKey, event);
3436
+ doPaste(view, target.value, null, plain, event);
3423
3437
  else
3424
- doPaste(view, target.textContent, target.innerHTML, view.input.shiftKey, event);
3438
+ doPaste(view, target.textContent, target.innerHTML, plain, event);
3425
3439
  }, 50);
3426
3440
  }
3427
3441
  function doPaste(view, text, html, preferPlain, event) {
@@ -3432,7 +3446,7 @@ function doPaste(view, text, html, preferPlain, event) {
3432
3446
  return false;
3433
3447
  let singleNode = sliceSingleNode(slice);
3434
3448
  let tr = singleNode
3435
- ? view.state.tr.replaceSelectionWith(singleNode, view.input.shiftKey)
3449
+ ? view.state.tr.replaceSelectionWith(singleNode, preferPlain)
3436
3450
  : view.state.tr.replaceSelection(slice);
3437
3451
  view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
3438
3452
  return true;
@@ -3446,7 +3460,8 @@ editHandlers.paste = (view, _event) => {
3446
3460
  if (view.composing && !android)
3447
3461
  return;
3448
3462
  let data = brokenClipboardAPI ? null : event.clipboardData;
3449
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event))
3463
+ let plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3464
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), plain, event))
3450
3465
  event.preventDefault();
3451
3466
  else
3452
3467
  capturePaste(view, event);
@@ -4752,7 +4767,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
4752
4767
  // as being an iOS enter press), just dispatch an Enter key instead.
4753
4768
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
4754
4769
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
4755
- (!inlineChange && $from.pos < parse.doc.content.size &&
4770
+ (!inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) &&
4756
4771
  (nextSel = Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) &&
4757
4772
  nextSel.head == $to.pos)) &&
4758
4773
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.31.4",
3
+ "version": "1.31.6",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -278,7 +278,7 @@ export function captureKeyDown(view: EditorView, event: KeyboardEvent) {
278
278
  let code = event.keyCode, mods = getMods(event)
279
279
  if (code == 8 || (browser.mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
280
280
  return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodes(view, -1)
281
- } else if (code == 46 || (browser.mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
281
+ } else if ((code == 46 && !event.shiftKey) || (browser.mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
282
282
  return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodes(view, 1)
283
283
  } else if (code == 13 || code == 27) { // Enter, Esc
284
284
  return true
package/src/domchange.ts CHANGED
@@ -185,7 +185,7 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
185
185
  // as being an iOS enter press), just dispatch an Enter key instead.
186
186
  if (((browser.ios && view.input.lastIOSEnter > Date.now() - 225 &&
187
187
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
188
- (!inlineChange && $from.pos < parse.doc.content.size &&
188
+ (!inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) &&
189
189
  (nextSel = Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) &&
190
190
  nextSel.head == $to.pos)) &&
191
191
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
package/src/domcoords.ts CHANGED
@@ -53,7 +53,7 @@ export function scrollRectIntoView(view: EditorView, rect: Rect, startDOM: Node)
53
53
  rect = {left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY}
54
54
  }
55
55
  }
56
- if (atTop) break
56
+ if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent as HTMLElement).position)) break
57
57
  }
58
58
  }
59
59
 
@@ -227,7 +227,7 @@ function posFromCaret(view: EditorView, node: Node, offset: number, coords: {top
227
227
  if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore
228
228
  else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter
229
229
  }
230
- if (!desc.contentDOM && outsideBlock < 0) {
230
+ if (!desc.contentDOM && outsideBlock < 0 && !desc.node.isText) {
231
231
  // If we are inside a leaf, return the side of the leaf closer to the coords
232
232
  let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2
233
233
  : coords.left < (rect.left + rect.right) / 2
package/src/input.ts CHANGED
@@ -582,11 +582,12 @@ function capturePaste(view: EditorView, event: ClipboardEvent) {
582
582
  if (!plainText) target.contentEditable = "true"
583
583
  target.style.cssText = "position: fixed; left: -10000px; top: 10px"
584
584
  target.focus()
585
+ let plain = view.input.shiftKey && view.input.lastKeyCode != 45
585
586
  setTimeout(() => {
586
587
  view.focus()
587
588
  if (target.parentNode) target.parentNode.removeChild(target)
588
- if (plainText) doPaste(view, (target as HTMLTextAreaElement).value, null, view.input.shiftKey, event)
589
- else doPaste(view, target.textContent!, target.innerHTML, view.input.shiftKey, event)
589
+ if (plainText) doPaste(view, (target as HTMLTextAreaElement).value, null, plain, event)
590
+ else doPaste(view, target.textContent!, target.innerHTML, plain, event)
590
591
  }, 50)
591
592
  }
592
593
 
@@ -597,7 +598,7 @@ export function doPaste(view: EditorView, text: string, html: string | null, pre
597
598
 
598
599
  let singleNode = sliceSingleNode(slice)
599
600
  let tr = singleNode
600
- ? view.state.tr.replaceSelectionWith(singleNode, view.input.shiftKey)
601
+ ? view.state.tr.replaceSelectionWith(singleNode, preferPlain)
601
602
  : view.state.tr.replaceSelection(slice)
602
603
  view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"))
603
604
  return true
@@ -611,7 +612,8 @@ editHandlers.paste = (view, _event) => {
611
612
  // where the editor is almost always composing.
612
613
  if (view.composing && !browser.android) return
613
614
  let data = brokenClipboardAPI ? null : event.clipboardData
614
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event))
615
+ let plain = view.input.shiftKey && view.input.lastKeyCode != 45
616
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), plain, event))
615
617
  event.preventDefault()
616
618
  else
617
619
  capturePaste(view, event)
package/src/viewdesc.ts CHANGED
@@ -385,6 +385,18 @@ export class ViewDesc {
385
385
  let {node, offset} = anchorDOM
386
386
  if (node.nodeType == 3) {
387
387
  brKludge = !!(offset && node.nodeValue![offset - 1] == "\n")
388
+ // Issue #1128
389
+ if (brKludge && offset == node.nodeValue!.length) {
390
+ for (let scan: DOMNode | null = node, after; scan; scan = scan.parentNode) {
391
+ if (after = scan.nextSibling) {
392
+ if (after.nodeName == "BR")
393
+ anchorDOM = headDOM = {node: after.parentNode!, offset: domIndex(after) + 1}
394
+ break
395
+ }
396
+ let desc = scan.pmViewDesc
397
+ if (desc && desc.node && desc.node.isBlock) break
398
+ }
399
+ }
388
400
  } else {
389
401
  let prev = node.childNodes[offset - 1]
390
402
  brKludge = prev && (prev.nodeName == "BR" || (prev as HTMLElement).contentEditable == "false")
@@ -550,7 +562,7 @@ class CompositionViewDesc extends ViewDesc {
550
562
  // some cases they will be split more often than would appear
551
563
  // necessary.
552
564
  class MarkViewDesc extends ViewDesc {
553
- constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement | null) {
565
+ constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement) {
554
566
  super(parent, [], dom, contentDOM)
555
567
  }
556
568
 
@@ -564,7 +576,7 @@ class MarkViewDesc extends ViewDesc {
564
576
 
565
577
  parseRule(): ParseRule | null {
566
578
  if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView) return null
567
- return {mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM || undefined}
579
+ return {mark: this.mark.type.name, attrs: this.mark.attrs, contentElement: this.contentDOM!}
568
580
  }
569
581
 
570
582
  matchesMark(mark: Mark) { return this.dirty != NODE_DIRTY && this.mark.eq(mark) }