prosemirror-view 1.38.0 → 1.39.0

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.39.0 (2025-04-04)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix an issue where, with some types of schemas, pressing Enter on Android with a Chinese keyboard wouldn't properly detect the Enter press.
6
+
7
+ ### New features
8
+
9
+ The new `dragCopies` prop can be used to configure whether a drag event inside the editor copies or moves content.
10
+
11
+ ## 1.38.1 (2025-03-04)
12
+
13
+ ### Bug fixes
14
+
15
+ Fix a regression in 1.38.0 that breaks scrolling back to the selection after Chrome tries to reset it on focus.
16
+
17
+ Remove some internally used types from the public type declaration files. Include file extension in web test local imports
18
+
19
+ Fix an issue where scrolling the cursor into view could inappropriately scroll parent nodes of absolutely positioned elements.
20
+
1
21
  ## 1.38.0 (2025-02-12)
2
22
 
3
23
  ### New features
package/dist/index.cjs CHANGED
@@ -200,9 +200,12 @@ function scrollRectIntoView(view, rect, startDOM) {
200
200
  var scrollThreshold = view.someProp("scrollThreshold") || 0,
201
201
  scrollMargin = view.someProp("scrollMargin") || 5;
202
202
  var doc = view.dom.ownerDocument;
203
- for (var parent = startDOM || view.dom;; parent = parentNode(parent)) {
203
+ for (var parent = startDOM || view.dom;;) {
204
204
  if (!parent) break;
205
- if (parent.nodeType != 1) continue;
205
+ if (parent.nodeType != 1) {
206
+ parent = parentNode(parent);
207
+ continue;
208
+ }
206
209
  var elt = parent;
207
210
  var atTop = elt == doc.body;
208
211
  var bounding = atTop ? windowRect(doc) : clientRect(elt);
@@ -228,7 +231,9 @@ function scrollRectIntoView(view, rect, startDOM) {
228
231
  };
229
232
  }
230
233
  }
231
- if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent).position)) break;
234
+ var pos = atTop ? "fixed" : getComputedStyle(parent).position;
235
+ if (/^(fixed|sticky)$/.test(pos)) break;
236
+ parent = pos == "absolute" ? parent.offsetParent : parentNode(parent);
232
237
  }
233
238
  }
234
239
  function storeScrollPos(view) {
@@ -3406,6 +3411,7 @@ editHandlers.paste = function (view, _event) {
3406
3411
  if (view.composing && !android) return;
3407
3412
  var data = brokenClipboardAPI ? null : event.clipboardData;
3408
3413
  var plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3414
+ console.log("paste event", !!data, view.state.selection.from, view.state.selection.to);
3409
3415
  if (data && doPaste(view, getText(data), data.getData("text/html"), plain, event)) event.preventDefault();else capturePaste(view, event);
3410
3416
  };
3411
3417
  var Dragging = _createClass(function Dragging(slice, move, node) {
@@ -3415,6 +3421,12 @@ var Dragging = _createClass(function Dragging(slice, move, node) {
3415
3421
  this.node = node;
3416
3422
  });
3417
3423
  var dragCopyModifier = mac ? "altKey" : "ctrlKey";
3424
+ function dragMoves(view, event) {
3425
+ var moves = view.someProp("dragCopies", function (test) {
3426
+ return !test(event);
3427
+ });
3428
+ return moves != null ? moves : !event[dragCopyModifier];
3429
+ }
3418
3430
  handlers.dragstart = function (view, _event) {
3419
3431
  var event = _event;
3420
3432
  var mouseDown = view.input.mouseDown;
@@ -3438,7 +3450,7 @@ handlers.dragstart = function (view, _event) {
3438
3450
  event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML);
3439
3451
  event.dataTransfer.effectAllowed = "copyMove";
3440
3452
  if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text);
3441
- view.dragging = new Dragging(slice, !event[dragCopyModifier], node);
3453
+ view.dragging = new Dragging(slice, dragMoves(view, event), node);
3442
3454
  };
3443
3455
  handlers.dragend = function (view) {
3444
3456
  var dragging = view.dragging;
@@ -3465,7 +3477,7 @@ editHandlers.drop = function (view, _event) {
3465
3477
  } else {
3466
3478
  slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
3467
3479
  }
3468
- var move = !!(dragging && !event[dragCopyModifier]);
3480
+ var move = !!(dragging && dragMoves(view, event));
3469
3481
  if (view.someProp("handleDrop", function (f) {
3470
3482
  return f(view, event, slice || prosemirrorModel.Slice.empty, move);
3471
3483
  })) {
@@ -4369,6 +4381,7 @@ var DOMObserver = function () {
4369
4381
  view.input.lastFocus = 0;
4370
4382
  selectionToDOM(view);
4371
4383
  this.currentSelection.set(sel);
4384
+ view.scrollToSelection();
4372
4385
  } else if (from > -1 || newSel) {
4373
4386
  if (from > -1) {
4374
4387
  view.docView.markDirty(from, to);
@@ -4656,7 +4669,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
4656
4669
  var nextSel;
4657
4670
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 && (!inlineChange || addedNodes.some(function (n) {
4658
4671
  return n.nodeName == "DIV" || n.nodeName == "P";
4659
- })) || !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) {
4672
+ })) || !inlineChange && $from.pos < parse.doc.content.size && (!$from.sameParent($to) || !$from.parent.inlineContent) && (nextSel = prosemirrorState.Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) && nextSel.head > $from.pos) && view.someProp("handleKeyDown", function (f) {
4660
4673
  return f(view, keyEvent(13, "Enter"));
4661
4674
  })) {
4662
4675
  view.input.lastIOSEnter = 0;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
2
- import { Mark, Node, TagParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
2
+ import { Mark, Node, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
3
3
  import { Mapping } from 'prosemirror-transform';
4
4
 
5
5
  type DOMNode = InstanceType<typeof window.Node>;
@@ -234,7 +234,6 @@ declare class DecorationGroup implements DecorationSource {
234
234
 
235
235
  declare global {
236
236
  interface Node {
237
- pmViewDesc?: ViewDesc;
238
237
  }
239
238
  }
240
239
  /**
@@ -361,104 +360,6 @@ interface MarkView {
361
360
  */
362
361
  destroy?: () => void;
363
362
  }
364
- declare class ViewDesc {
365
- parent: ViewDesc | undefined;
366
- children: ViewDesc[];
367
- dom: DOMNode;
368
- contentDOM: HTMLElement | null;
369
- dirty: number;
370
- node: Node | null;
371
- constructor(parent: ViewDesc | undefined, children: ViewDesc[], dom: DOMNode, contentDOM: HTMLElement | null);
372
- matchesWidget(widget: Decoration): boolean;
373
- matchesMark(mark: Mark): boolean;
374
- matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
375
- matchesHack(nodeName: string): boolean;
376
- parseRule(): Omit<TagParseRule, "tag"> | null;
377
- stopEvent(event: Event): boolean;
378
- get size(): number;
379
- get border(): number;
380
- destroy(): void;
381
- posBeforeChild(child: ViewDesc): number;
382
- get posBefore(): number;
383
- get posAtStart(): number;
384
- get posAfter(): number;
385
- get posAtEnd(): number;
386
- localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
387
- nearestDesc(dom: DOMNode): ViewDesc | undefined;
388
- nearestDesc(dom: DOMNode, onlyNodes: true): NodeViewDesc | undefined;
389
- getDesc(dom: DOMNode): ViewDesc | undefined;
390
- posFromDOM(dom: DOMNode, offset: number, bias: number): number;
391
- descAt(pos: number): ViewDesc | undefined;
392
- domFromPos(pos: number, side: number): {
393
- node: DOMNode;
394
- offset: number;
395
- atom?: number;
396
- };
397
- parseRange(from: number, to: number, base?: number): {
398
- node: DOMNode;
399
- from: number;
400
- to: number;
401
- fromOffset: number;
402
- toOffset: number;
403
- };
404
- emptyChildAt(side: number): boolean;
405
- domAfterPos(pos: number): DOMNode;
406
- setSelection(anchor: number, head: number, view: EditorView, force?: boolean): void;
407
- ignoreMutation(mutation: ViewMutationRecord): boolean;
408
- get contentLost(): boolean | null;
409
- markDirty(from: number, to: number): void;
410
- markParentsDirty(): void;
411
- get domAtom(): boolean;
412
- get ignoreForCoords(): boolean;
413
- isText(text: string): boolean;
414
- }
415
- declare class NodeViewDesc extends ViewDesc {
416
- node: Node;
417
- outerDeco: readonly Decoration[];
418
- innerDeco: DecorationSource;
419
- readonly nodeDOM: DOMNode;
420
- constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, contentDOM: HTMLElement | null, nodeDOM: DOMNode, view: EditorView, pos: number);
421
- static create(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView, pos: number): NodeViewDesc | TextViewDesc;
422
- parseRule(): Omit<TagParseRule, "tag"> | null;
423
- matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
424
- get size(): number;
425
- get border(): 0 | 1;
426
- updateChildren(view: EditorView, pos: number): void;
427
- localCompositionInfo(view: EditorView, pos: number): {
428
- node: Text;
429
- pos: number;
430
- text: string;
431
- } | null;
432
- protectLocalComposition(view: EditorView, { node, pos, text }: {
433
- node: Text;
434
- pos: number;
435
- text: string;
436
- }): void;
437
- update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
438
- updateInner(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): void;
439
- updateOuterDeco(outerDeco: readonly Decoration[]): void;
440
- selectNode(): void;
441
- deselectNode(): void;
442
- get domAtom(): boolean;
443
- }
444
- declare class TextViewDesc extends NodeViewDesc {
445
- constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode, view: EditorView);
446
- parseRule(): {
447
- skip: any;
448
- };
449
- update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
450
- inParent(): boolean;
451
- domFromPos(pos: number): {
452
- node: globalThis.Node;
453
- offset: number;
454
- };
455
- localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
456
- ignoreMutation(mutation: ViewMutationRecord): boolean;
457
- slice(from: number, to: number, view: EditorView): TextViewDesc;
458
- markDirty(from: number, to: number): void;
459
- get domAtom(): boolean;
460
- isText(text: string): boolean;
461
- }
462
363
 
463
364
  /**
464
365
  An editor view manages the DOM structure that represents an
@@ -798,6 +699,12 @@ interface EditorProps<P = any> {
798
699
  */
799
700
  handleScrollToSelection?: (this: P, view: EditorView) => boolean;
800
701
  /**
702
+ Determines whether an in-editor drag event should copy or move
703
+ the selection. When not given, the event's `altKey` property is
704
+ used on macOS, `ctrlKey` on other platforms.
705
+ */
706
+ dragCopies?: (event: DragEvent) => boolean;
707
+ /**
801
708
  Can be used to override the way a selection is created when
802
709
  reading a DOM selection between the given anchor and head.
803
710
  */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EditorState, Transaction, Selection, Plugin } from 'prosemirror-state';
2
- import { Mark, Node, TagParseRule, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
2
+ import { Mark, Node, Slice, ResolvedPos, DOMParser, DOMSerializer } from 'prosemirror-model';
3
3
  import { Mapping } from 'prosemirror-transform';
4
4
 
5
5
  type DOMNode = InstanceType<typeof window.Node>;
@@ -234,7 +234,6 @@ declare class DecorationGroup implements DecorationSource {
234
234
 
235
235
  declare global {
236
236
  interface Node {
237
- pmViewDesc?: ViewDesc;
238
237
  }
239
238
  }
240
239
  /**
@@ -361,104 +360,6 @@ interface MarkView {
361
360
  */
362
361
  destroy?: () => void;
363
362
  }
364
- declare class ViewDesc {
365
- parent: ViewDesc | undefined;
366
- children: ViewDesc[];
367
- dom: DOMNode;
368
- contentDOM: HTMLElement | null;
369
- dirty: number;
370
- node: Node | null;
371
- constructor(parent: ViewDesc | undefined, children: ViewDesc[], dom: DOMNode, contentDOM: HTMLElement | null);
372
- matchesWidget(widget: Decoration): boolean;
373
- matchesMark(mark: Mark): boolean;
374
- matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
375
- matchesHack(nodeName: string): boolean;
376
- parseRule(): Omit<TagParseRule, "tag"> | null;
377
- stopEvent(event: Event): boolean;
378
- get size(): number;
379
- get border(): number;
380
- destroy(): void;
381
- posBeforeChild(child: ViewDesc): number;
382
- get posBefore(): number;
383
- get posAtStart(): number;
384
- get posAfter(): number;
385
- get posAtEnd(): number;
386
- localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
387
- nearestDesc(dom: DOMNode): ViewDesc | undefined;
388
- nearestDesc(dom: DOMNode, onlyNodes: true): NodeViewDesc | undefined;
389
- getDesc(dom: DOMNode): ViewDesc | undefined;
390
- posFromDOM(dom: DOMNode, offset: number, bias: number): number;
391
- descAt(pos: number): ViewDesc | undefined;
392
- domFromPos(pos: number, side: number): {
393
- node: DOMNode;
394
- offset: number;
395
- atom?: number;
396
- };
397
- parseRange(from: number, to: number, base?: number): {
398
- node: DOMNode;
399
- from: number;
400
- to: number;
401
- fromOffset: number;
402
- toOffset: number;
403
- };
404
- emptyChildAt(side: number): boolean;
405
- domAfterPos(pos: number): DOMNode;
406
- setSelection(anchor: number, head: number, view: EditorView, force?: boolean): void;
407
- ignoreMutation(mutation: ViewMutationRecord): boolean;
408
- get contentLost(): boolean | null;
409
- markDirty(from: number, to: number): void;
410
- markParentsDirty(): void;
411
- get domAtom(): boolean;
412
- get ignoreForCoords(): boolean;
413
- isText(text: string): boolean;
414
- }
415
- declare class NodeViewDesc extends ViewDesc {
416
- node: Node;
417
- outerDeco: readonly Decoration[];
418
- innerDeco: DecorationSource;
419
- readonly nodeDOM: DOMNode;
420
- constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, contentDOM: HTMLElement | null, nodeDOM: DOMNode, view: EditorView, pos: number);
421
- static create(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView, pos: number): NodeViewDesc | TextViewDesc;
422
- parseRule(): Omit<TagParseRule, "tag"> | null;
423
- matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
424
- get size(): number;
425
- get border(): 0 | 1;
426
- updateChildren(view: EditorView, pos: number): void;
427
- localCompositionInfo(view: EditorView, pos: number): {
428
- node: Text;
429
- pos: number;
430
- text: string;
431
- } | null;
432
- protectLocalComposition(view: EditorView, { node, pos, text }: {
433
- node: Text;
434
- pos: number;
435
- text: string;
436
- }): void;
437
- update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
438
- updateInner(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): void;
439
- updateOuterDeco(outerDeco: readonly Decoration[]): void;
440
- selectNode(): void;
441
- deselectNode(): void;
442
- get domAtom(): boolean;
443
- }
444
- declare class TextViewDesc extends NodeViewDesc {
445
- constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode, view: EditorView);
446
- parseRule(): {
447
- skip: any;
448
- };
449
- update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
450
- inParent(): boolean;
451
- domFromPos(pos: number): {
452
- node: globalThis.Node;
453
- offset: number;
454
- };
455
- localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
456
- ignoreMutation(mutation: ViewMutationRecord): boolean;
457
- slice(from: number, to: number, view: EditorView): TextViewDesc;
458
- markDirty(from: number, to: number): void;
459
- get domAtom(): boolean;
460
- isText(text: string): boolean;
461
- }
462
363
 
463
364
  /**
464
365
  An editor view manages the DOM structure that represents an
@@ -798,6 +699,12 @@ interface EditorProps<P = any> {
798
699
  */
799
700
  handleScrollToSelection?: (this: P, view: EditorView) => boolean;
800
701
  /**
702
+ Determines whether an in-editor drag event should copy or move
703
+ the selection. When not given, the event's `altKey` property is
704
+ used on macOS, `ctrlKey` on other platforms.
705
+ */
706
+ dragCopies?: (event: DragEvent) => boolean;
707
+ /**
801
708
  Can be used to override the way a selection is created when
802
709
  reading a DOM selection between the given anchor and head.
803
710
  */
package/dist/index.js CHANGED
@@ -201,11 +201,13 @@ function clientRect(node) {
201
201
  function scrollRectIntoView(view, rect, startDOM) {
202
202
  let scrollThreshold = view.someProp("scrollThreshold") || 0, scrollMargin = view.someProp("scrollMargin") || 5;
203
203
  let doc = view.dom.ownerDocument;
204
- for (let parent = startDOM || view.dom;; parent = parentNode(parent)) {
204
+ for (let parent = startDOM || view.dom;;) {
205
205
  if (!parent)
206
206
  break;
207
- if (parent.nodeType != 1)
207
+ if (parent.nodeType != 1) {
208
+ parent = parentNode(parent);
208
209
  continue;
210
+ }
209
211
  let elt = parent;
210
212
  let atTop = elt == doc.body;
211
213
  let bounding = atTop ? windowRect(doc) : clientRect(elt);
@@ -234,8 +236,10 @@ function scrollRectIntoView(view, rect, startDOM) {
234
236
  rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
235
237
  }
236
238
  }
237
- if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent).position))
239
+ let pos = atTop ? "fixed" : getComputedStyle(parent).position;
240
+ if (/^(fixed|sticky)$/.test(pos))
238
241
  break;
242
+ parent = pos == "absolute" ? parent.offsetParent : parentNode(parent);
239
243
  }
240
244
  }
241
245
  // Store the scroll position of the editor's parent nodes, along with
@@ -3659,6 +3663,7 @@ editHandlers.paste = (view, _event) => {
3659
3663
  return;
3660
3664
  let data = brokenClipboardAPI ? null : event.clipboardData;
3661
3665
  let plain = view.input.shiftKey && view.input.lastKeyCode != 45;
3666
+ console.log("paste event", !!data, view.state.selection.from, view.state.selection.to);
3662
3667
  if (data && doPaste(view, getText(data), data.getData("text/html"), plain, event))
3663
3668
  event.preventDefault();
3664
3669
  else
@@ -3672,6 +3677,10 @@ class Dragging {
3672
3677
  }
3673
3678
  }
3674
3679
  const dragCopyModifier = mac ? "altKey" : "ctrlKey";
3680
+ function dragMoves(view, event) {
3681
+ let moves = view.someProp("dragCopies", test => !test(event));
3682
+ return moves != null ? moves : !event[dragCopyModifier];
3683
+ }
3675
3684
  handlers.dragstart = (view, _event) => {
3676
3685
  let event = _event;
3677
3686
  let mouseDown = view.input.mouseDown;
@@ -3701,7 +3710,7 @@ handlers.dragstart = (view, _event) => {
3701
3710
  event.dataTransfer.effectAllowed = "copyMove";
3702
3711
  if (!brokenClipboardAPI)
3703
3712
  event.dataTransfer.setData("text/plain", text);
3704
- view.dragging = new Dragging(slice, !event[dragCopyModifier], node);
3713
+ view.dragging = new Dragging(slice, dragMoves(view, event), node);
3705
3714
  };
3706
3715
  handlers.dragend = view => {
3707
3716
  let dragging = view.dragging;
@@ -3728,7 +3737,7 @@ editHandlers.drop = (view, _event) => {
3728
3737
  else {
3729
3738
  slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
3730
3739
  }
3731
- let move = !!(dragging && !event[dragCopyModifier]);
3740
+ let move = !!(dragging && dragMoves(view, event));
3732
3741
  if (view.someProp("handleDrop", f => f(view, event, slice || Slice.empty, move))) {
3733
3742
  event.preventDefault();
3734
3743
  return;
@@ -4705,6 +4714,7 @@ class DOMObserver {
4705
4714
  view.input.lastFocus = 0;
4706
4715
  selectionToDOM(view);
4707
4716
  this.currentSelection.set(sel);
4717
+ view.scrollToSelection();
4708
4718
  }
4709
4719
  else if (from > -1 || newSel) {
4710
4720
  if (from > -1) {
@@ -5012,9 +5022,10 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
5012
5022
  // as being an iOS enter press), just dispatch an Enter key instead.
5013
5023
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
5014
5024
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
5015
- (!inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) &&
5025
+ (!inlineChange && $from.pos < parse.doc.content.size &&
5026
+ (!$from.sameParent($to) || !$from.parent.inlineContent) &&
5016
5027
  (nextSel = Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) &&
5017
- nextSel.head == $to.pos)) &&
5028
+ nextSel.head > $from.pos)) &&
5018
5029
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
5019
5030
  view.input.lastIOSEnter = 0;
5020
5031
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.38.0",
3
+ "version": "1.39.0",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/domchange.ts CHANGED
@@ -181,9 +181,10 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
181
181
  // as being an iOS enter press), just dispatch an Enter key instead.
182
182
  if (((browser.ios && view.input.lastIOSEnter > Date.now() - 225 &&
183
183
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
184
- (!inlineChange && $from.pos < parse.doc.content.size && !$from.sameParent($to) &&
184
+ (!inlineChange && $from.pos < parse.doc.content.size &&
185
+ (!$from.sameParent($to) || !$from.parent.inlineContent) &&
185
186
  (nextSel = Selection.findFrom(parse.doc.resolve($from.pos + 1), 1, true)) &&
186
- nextSel.head == $to.pos)) &&
187
+ nextSel.head > $from.pos)) &&
187
188
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
188
189
  view.input.lastIOSEnter = 0
189
190
  return
package/src/domcoords.ts CHANGED
@@ -32,9 +32,9 @@ function clientRect(node: HTMLElement): Rect {
32
32
  export function scrollRectIntoView(view: EditorView, rect: Rect, startDOM: Node) {
33
33
  let scrollThreshold = view.someProp("scrollThreshold") || 0, scrollMargin = view.someProp("scrollMargin") || 5
34
34
  let doc = view.dom.ownerDocument
35
- for (let parent: Node | null = startDOM || view.dom;; parent = parentNode(parent)) {
35
+ for (let parent: Node | null = startDOM || view.dom;;) {
36
36
  if (!parent) break
37
- if (parent.nodeType != 1) continue
37
+ if (parent.nodeType != 1) { parent = parentNode(parent); continue }
38
38
  let elt = parent as HTMLElement
39
39
  let atTop = elt == doc.body
40
40
  let bounding = atTop ? windowRect(doc) : clientRect(elt as HTMLElement)
@@ -60,7 +60,9 @@ export function scrollRectIntoView(view: EditorView, rect: Rect, startDOM: Node)
60
60
  rect = {left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY}
61
61
  }
62
62
  }
63
- if (atTop || /^(fixed|sticky)$/.test(getComputedStyle(parent as HTMLElement).position)) break
63
+ let pos: string = atTop ? "fixed" : getComputedStyle(parent as HTMLElement).position
64
+ if (/^(fixed|sticky)$/.test(pos)) break
65
+ parent = pos == "absolute" ? (parent as HTMLElement).offsetParent : parentNode(parent)
64
66
  }
65
67
  }
66
68
 
@@ -211,6 +211,7 @@ export class DOMObserver {
211
211
  view.input.lastFocus = 0
212
212
  selectionToDOM(view)
213
213
  this.currentSelection.set(sel)
214
+ view.scrollToSelection()
214
215
  } else if (from > -1 || newSel) {
215
216
  if (from > -1) {
216
217
  view.docView.markDirty(from, to)
package/src/index.ts CHANGED
@@ -51,7 +51,7 @@ export class EditorView {
51
51
  private prevDirectPlugins: readonly Plugin[] = []
52
52
  private pluginViews: PluginView[] = []
53
53
  /// @internal
54
- domObserver!: DOMObserver
54
+ declare domObserver: DOMObserver
55
55
  /// Holds `true` when a hack node is needed in Firefox to prevent the
56
56
  /// [space is eaten issue](https://github.com/ProseMirror/prosemirror/issues/651)
57
57
  /// @internal
@@ -673,6 +673,11 @@ export interface EditorProps<P = any> {
673
673
  /// handlers or the default behavior should be tried.
674
674
  handleScrollToSelection?: (this: P, view: EditorView) => boolean
675
675
 
676
+ /// Determines whether an in-editor drag event should copy or move
677
+ /// the selection. When not given, the event's `altKey` property is
678
+ /// used on macOS, `ctrlKey` on other platforms.
679
+ dragCopies?: (event: DragEvent) => boolean
680
+
676
681
  /// Can be used to override the way a selection is created when
677
682
  /// reading a DOM selection between the given anchor and head.
678
683
  createSelectionBetween?: (this: P, view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null
package/src/input.ts CHANGED
@@ -648,6 +648,7 @@ editHandlers.paste = (view, _event) => {
648
648
  if (view.composing && !browser.android) return
649
649
  let data = brokenClipboardAPI ? null : event.clipboardData
650
650
  let plain = view.input.shiftKey && view.input.lastKeyCode != 45
651
+ console.log("paste event", !!data, view.state.selection.from, view.state.selection.to)
651
652
  if (data && doPaste(view, getText(data), data.getData("text/html"), plain, event))
652
653
  event.preventDefault()
653
654
  else
@@ -660,6 +661,11 @@ export class Dragging {
660
661
 
661
662
  const dragCopyModifier: keyof DragEvent = browser.mac ? "altKey" : "ctrlKey"
662
663
 
664
+ function dragMoves(view: EditorView, event: DragEvent) {
665
+ let moves = view.someProp("dragCopies", test => !test(event))
666
+ return moves != null ? moves : !event[dragCopyModifier]
667
+ }
668
+
663
669
  handlers.dragstart = (view, _event) => {
664
670
  let event = _event as DragEvent
665
671
  let mouseDown = view.input.mouseDown
@@ -687,7 +693,7 @@ handlers.dragstart = (view, _event) => {
687
693
  // See https://github.com/ProseMirror/prosemirror/issues/1156
688
694
  event.dataTransfer.effectAllowed = "copyMove"
689
695
  if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text)
690
- view.dragging = new Dragging(slice, !event[dragCopyModifier], node)
696
+ view.dragging = new Dragging(slice, dragMoves(view, event), node)
691
697
  }
692
698
 
693
699
  handlers.dragend = view => {
@@ -716,7 +722,7 @@ editHandlers.drop = (view, _event) => {
716
722
  slice = parseFromClipboard(view, getText(event.dataTransfer),
717
723
  brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse)
718
724
  }
719
- let move = !!(dragging && !event[dragCopyModifier])
725
+ let move = !!(dragging && dragMoves(view, event))
720
726
  if (view.someProp("handleDrop", f => f(view, event, slice || Slice.empty, move))) {
721
727
  event.preventDefault()
722
728
  return
package/src/viewdesc.ts CHANGED
@@ -7,7 +7,10 @@ import {Decoration, DecorationSource, WidgetConstructor, WidgetType, NodeType} f
7
7
  import {EditorView} from "./index"
8
8
 
9
9
  declare global {
10
- interface Node { pmViewDesc?: ViewDesc }
10
+ interface Node {
11
+ /// @internal
12
+ pmViewDesc?: ViewDesc
13
+ }
11
14
  }
12
15
 
13
16
  /// A ViewMutationRecord represents a DOM
@@ -132,7 +135,7 @@ const NOT_DIRTY = 0, CHILD_DIRTY = 1, CONTENT_DIRTY = 2, NODE_DIRTY = 3
132
135
  // basic structure and shared methods.
133
136
  export class ViewDesc {
134
137
  dirty = NOT_DIRTY
135
- node!: Node | null
138
+ declare node: Node | null
136
139
 
137
140
  constructor(
138
141
  public parent: ViewDesc | undefined,