prosemirror-view 1.40.1 → 1.41.1

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.41.1 (2025-09-19)
2
+
3
+ ### Bug fixes
4
+
5
+ Consistently set `draggable` on a node's inner DOM representation, not a decoration wrapper element.
6
+
7
+ ## 1.41.0 (2025-09-06)
8
+
9
+ ### Bug fixes
10
+
11
+ Make sure `transformPasted` is properly called when pasting into a code block.
12
+
13
+ Fix an issue where the editor didn't properly set the DOM selection in a shadow DOM on Safari in some situations.
14
+
15
+ Work around a Safari issue that broke composition right after changing the set of active marks.
16
+
17
+ ### New features
18
+
19
+ Pass an argument to `transformPasted` that tells the handler whether the paste is plain text. Call transformPasted when pasting into a code block
20
+
1
21
  ## 1.40.1 (2025-07-18)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -998,7 +998,7 @@ var ViewDesc = function () {
998
998
  }
999
999
  if (!(force || brKludge && safari) && isEquivalentPosition(anchorDOM.node, anchorDOM.offset, selRange.anchorNode, selRange.anchorOffset) && isEquivalentPosition(headDOM.node, headDOM.offset, selRange.focusNode, selRange.focusOffset)) return;
1000
1000
  var domSelExtended = false;
1001
- if ((domSel.extend || anchor == head) && !brKludge) {
1001
+ if ((domSel.extend || anchor == head) && !(brKludge && gecko)) {
1002
1002
  domSel.collapse(anchorDOM.node, anchorDOM.offset);
1003
1003
  try {
1004
1004
  if (anchor != head) domSel.extend(headDOM.node, headDOM.offset);
@@ -1427,15 +1427,17 @@ var NodeViewDesc = function (_ViewDesc4) {
1427
1427
  }, {
1428
1428
  key: "selectNode",
1429
1429
  value: function selectNode() {
1430
- if (this.nodeDOM.nodeType == 1) this.nodeDOM.classList.add("ProseMirror-selectednode");
1431
- if (this.contentDOM || !this.node.type.spec.draggable) this.dom.draggable = true;
1430
+ if (this.nodeDOM.nodeType == 1) {
1431
+ this.nodeDOM.classList.add("ProseMirror-selectednode");
1432
+ if (this.contentDOM || !this.node.type.spec.draggable) this.nodeDOM.draggable = true;
1433
+ }
1432
1434
  }
1433
1435
  }, {
1434
1436
  key: "deselectNode",
1435
1437
  value: function deselectNode() {
1436
1438
  if (this.nodeDOM.nodeType == 1) {
1437
1439
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
1438
- if (this.contentDOM || !this.node.type.spec.draggable) this.dom.removeAttribute("draggable");
1440
+ if (this.contentDOM || !this.node.type.spec.draggable) this.nodeDOM.removeAttribute("draggable");
1439
1441
  }
1440
1442
  }
1441
1443
  }, {
@@ -2271,15 +2273,11 @@ function removeClassOnSelectionChange(view) {
2271
2273
  });
2272
2274
  }
2273
2275
  function selectCursorWrapper(view) {
2274
- var domSel = view.domSelection(),
2275
- range = document.createRange();
2276
+ var domSel = view.domSelection();
2276
2277
  if (!domSel) return;
2277
2278
  var node = view.cursorWrapper.dom,
2278
2279
  img = node.nodeName == "IMG";
2279
- if (img) range.setStart(node.parentNode, domIndex(node) + 1);else range.setStart(node, 0);
2280
- range.collapse(true);
2281
- domSel.removeAllRanges();
2282
- domSel.addRange(range);
2280
+ if (img) domSel.collapse(node.parentNode, domIndex(node) + 1);else domSel.collapse(node, 0);
2283
2281
  if (!img && !view.state.selection.visible && ie && ie_version <= 11) {
2284
2282
  node.disabled = true;
2285
2283
  node.disabled = false;
@@ -2677,12 +2675,18 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2677
2675
  var inCode = $context.parent.type.spec.code;
2678
2676
  var dom, slice;
2679
2677
  if (!html && !text) return null;
2680
- var asText = text && (plainText || inCode || !html);
2678
+ var asText = !!text && (plainText || inCode || !html);
2681
2679
  if (asText) {
2682
2680
  view.someProp("transformPastedText", function (f) {
2683
2681
  text = f(text, inCode || plainText, view);
2684
2682
  });
2685
- if (inCode) return text ? new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : prosemirrorModel.Slice.empty;
2683
+ if (inCode) {
2684
+ slice = new prosemirrorModel.Slice(prosemirrorModel.Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0);
2685
+ view.someProp("transformPasted", function (f) {
2686
+ slice = f(slice, view, true);
2687
+ });
2688
+ return slice;
2689
+ }
2686
2690
  var parsed = view.someProp("clipboardTextParser", function (f) {
2687
2691
  return f(text, $context, plainText, view);
2688
2692
  });
@@ -2739,7 +2743,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2739
2743
  }
2740
2744
  }
2741
2745
  view.someProp("transformPasted", function (f) {
2742
- slice = f(slice, view);
2746
+ slice = f(slice, view, asText);
2743
2747
  });
2744
2748
  return slice;
2745
2749
  }
@@ -3169,7 +3173,7 @@ var MouseDown = function () {
3169
3173
  }
3170
3174
  var target = flushed ? null : event.target;
3171
3175
  var targetDesc = target ? view.docView.nearestDesc(target, true) : null;
3172
- this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom : null;
3176
+ this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
3173
3177
  var selection = view.state.selection;
3174
3178
  if (event.button == 0 && targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false || selection instanceof prosemirrorState.NodeSelection && selection.from <= targetPos && selection.to > targetPos) this.mightDrag = {
3175
3179
  node: targetNode,
@@ -3492,7 +3496,7 @@ editHandlers.drop = function (view, _event) {
3492
3496
  var slice = dragging && dragging.slice;
3493
3497
  if (slice) {
3494
3498
  view.someProp("transformPasted", function (f) {
3495
- slice = f(slice, view);
3499
+ slice = f(slice, view, false);
3496
3500
  });
3497
3501
  } else {
3498
3502
  slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
package/dist/index.d.cts CHANGED
@@ -757,9 +757,10 @@ interface EditorProps<P = any> {
757
757
  clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
758
758
  /**
759
759
  Can be used to transform pasted or dragged-and-dropped content
760
- before it is applied to the document.
760
+ before it is applied to the document. The `plain` flag will be
761
+ true when the text is pasted as plain text.
761
762
  */
762
- transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
763
+ transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice;
763
764
  /**
764
765
  Can be used to transform copied or cut content before it is
765
766
  serialized to the clipboard.
package/dist/index.d.ts CHANGED
@@ -757,9 +757,10 @@ interface EditorProps<P = any> {
757
757
  clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice;
758
758
  /**
759
759
  Can be used to transform pasted or dragged-and-dropped content
760
- before it is applied to the document.
760
+ before it is applied to the document. The `plain` flag will be
761
+ true when the text is pasted as plain text.
761
762
  */
762
- transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice;
763
+ transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice;
763
764
  /**
764
765
  Can be used to transform copied or cut content before it is
765
766
  serialized to the clipboard.
package/dist/index.js CHANGED
@@ -1072,7 +1072,7 @@ class ViewDesc {
1072
1072
  // (one where the focus is before the anchor), but not all
1073
1073
  // browsers support it yet.
1074
1074
  let domSelExtended = false;
1075
- if ((domSel.extend || anchor == head) && !brKludge) {
1075
+ if ((domSel.extend || anchor == head) && !(brKludge && gecko)) {
1076
1076
  domSel.collapse(anchorDOM.node, anchorDOM.offset);
1077
1077
  try {
1078
1078
  if (anchor != head)
@@ -1484,17 +1484,18 @@ class NodeViewDesc extends ViewDesc {
1484
1484
  }
1485
1485
  // Mark this node as being the selected node.
1486
1486
  selectNode() {
1487
- if (this.nodeDOM.nodeType == 1)
1487
+ if (this.nodeDOM.nodeType == 1) {
1488
1488
  this.nodeDOM.classList.add("ProseMirror-selectednode");
1489
- if (this.contentDOM || !this.node.type.spec.draggable)
1490
- this.dom.draggable = true;
1489
+ if (this.contentDOM || !this.node.type.spec.draggable)
1490
+ this.nodeDOM.draggable = true;
1491
+ }
1491
1492
  }
1492
1493
  // Remove selected node marking from this node.
1493
1494
  deselectNode() {
1494
1495
  if (this.nodeDOM.nodeType == 1) {
1495
1496
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
1496
1497
  if (this.contentDOM || !this.node.type.spec.draggable)
1497
- this.dom.removeAttribute("draggable");
1498
+ this.nodeDOM.removeAttribute("draggable");
1498
1499
  }
1499
1500
  }
1500
1501
  get domAtom() { return this.node.isAtom; }
@@ -2333,17 +2334,14 @@ function removeClassOnSelectionChange(view) {
2333
2334
  });
2334
2335
  }
2335
2336
  function selectCursorWrapper(view) {
2336
- let domSel = view.domSelection(), range = document.createRange();
2337
+ let domSel = view.domSelection();
2337
2338
  if (!domSel)
2338
2339
  return;
2339
2340
  let node = view.cursorWrapper.dom, img = node.nodeName == "IMG";
2340
2341
  if (img)
2341
- range.setStart(node.parentNode, domIndex(node) + 1);
2342
+ domSel.collapse(node.parentNode, domIndex(node) + 1);
2342
2343
  else
2343
- range.setStart(node, 0);
2344
- range.collapse(true);
2345
- domSel.removeAllRanges();
2346
- domSel.addRange(range);
2344
+ domSel.collapse(node, 0);
2347
2345
  // Kludge to kill 'control selection' in IE11 when selecting an
2348
2346
  // invisible cursor wrapper, since that would result in those weird
2349
2347
  // resize handles and a selection that considers the absolutely
@@ -2821,11 +2819,14 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2821
2819
  let dom, slice;
2822
2820
  if (!html && !text)
2823
2821
  return null;
2824
- let asText = text && (plainText || inCode || !html);
2822
+ let asText = !!text && (plainText || inCode || !html);
2825
2823
  if (asText) {
2826
2824
  view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view); });
2827
- if (inCode)
2828
- return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty;
2825
+ if (inCode) {
2826
+ slice = new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0);
2827
+ view.someProp("transformPasted", f => { slice = f(slice, view, true); });
2828
+ return slice;
2829
+ }
2829
2830
  let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view));
2830
2831
  if (parsed) {
2831
2832
  slice = parsed;
@@ -2883,7 +2884,7 @@ function parseFromClipboard(view, text, html, plainText, $context) {
2883
2884
  slice = closeSlice(slice, openStart, openEnd);
2884
2885
  }
2885
2886
  }
2886
- view.someProp("transformPasted", f => { slice = f(slice, view); });
2887
+ view.someProp("transformPasted", f => { slice = f(slice, view, asText); });
2887
2888
  return slice;
2888
2889
  }
2889
2890
  const inlineParents = /^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var)$/i;
@@ -3346,7 +3347,7 @@ class MouseDown {
3346
3347
  }
3347
3348
  const target = flushed ? null : event.target;
3348
3349
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
3349
- this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom : null;
3350
+ this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
3350
3351
  let { selection } = view.state;
3351
3352
  if (event.button == 0 &&
3352
3353
  targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
@@ -3743,7 +3744,7 @@ editHandlers.drop = (view, _event) => {
3743
3744
  let $mouse = view.state.doc.resolve(eventPos.pos);
3744
3745
  let slice = dragging && dragging.slice;
3745
3746
  if (slice) {
3746
- view.someProp("transformPasted", f => { slice = f(slice, view); });
3747
+ view.someProp("transformPasted", f => { slice = f(slice, view, false); });
3747
3748
  }
3748
3749
  else {
3749
3750
  slice = parseFromClipboard(view, getText(event.dataTransfer), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.40.1",
3
+ "version": "1.41.1",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/clipboard.ts CHANGED
@@ -44,10 +44,14 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
44
44
  let inCode = $context.parent.type.spec.code
45
45
  let dom: HTMLElement | undefined, slice: Slice | undefined
46
46
  if (!html && !text) return null
47
- let asText = text && (plainText || inCode || !html)
47
+ let asText = !!text && (plainText || inCode || !html)
48
48
  if (asText) {
49
49
  view.someProp("transformPastedText", f => { text = f(text, inCode || plainText, view) })
50
- if (inCode) return text ? new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0) : Slice.empty
50
+ if (inCode) {
51
+ slice = new Slice(Fragment.from(view.state.schema.text(text.replace(/\r\n?/g, "\n"))), 0, 0)
52
+ view.someProp("transformPasted", f => { slice = f(slice!, view, true) })
53
+ return slice
54
+ }
51
55
  let parsed = view.someProp("clipboardTextParser", f => f(text, $context, plainText, view))
52
56
  if (parsed) {
53
57
  slice = parsed
@@ -101,7 +105,7 @@ export function parseFromClipboard(view: EditorView, text: string, html: string
101
105
  }
102
106
  }
103
107
 
104
- view.someProp("transformPasted", f => { slice = f(slice!, view) })
108
+ view.someProp("transformPasted", f => { slice = f(slice!, view, asText) })
105
109
  return slice
106
110
  }
107
111
 
package/src/index.ts CHANGED
@@ -714,8 +714,9 @@ export interface EditorProps<P = any> {
714
714
  clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean, view: EditorView) => Slice
715
715
 
716
716
  /// Can be used to transform pasted or dragged-and-dropped content
717
- /// before it is applied to the document.
718
- transformPasted?: (this: P, slice: Slice, view: EditorView) => Slice
717
+ /// before it is applied to the document. The `plain` flag will be
718
+ /// true when the text is pasted as plain text.
719
+ transformPasted?: (this: P, slice: Slice, view: EditorView, plain: boolean) => Slice
719
720
 
720
721
  /// Can be used to transform copied or cut content before it is
721
722
  /// serialized to the clipboard.
package/src/input.ts CHANGED
@@ -329,7 +329,7 @@ class MouseDown {
329
329
 
330
330
  const target = flushed ? null : event.target as HTMLElement
331
331
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null
332
- this.target = targetDesc && targetDesc.dom.nodeType == 1 ? targetDesc.dom as HTMLElement : null
332
+ this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM as HTMLElement : null
333
333
 
334
334
  let {selection} = view.state
335
335
  if (event.button == 0 &&
@@ -718,7 +718,7 @@ editHandlers.drop = (view, _event) => {
718
718
  let $mouse = view.state.doc.resolve(eventPos.pos)
719
719
  let slice = dragging && dragging.slice
720
720
  if (slice) {
721
- view.someProp("transformPasted", f => { slice = f(slice!, view) })
721
+ view.someProp("transformPasted", f => { slice = f(slice!, view, false) })
722
722
  } else {
723
723
  slice = parseFromClipboard(view, getText(event.dataTransfer),
724
724
  brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse)
package/src/selection.ts CHANGED
@@ -147,14 +147,11 @@ function removeClassOnSelectionChange(view: EditorView) {
147
147
  }
148
148
 
149
149
  function selectCursorWrapper(view: EditorView) {
150
- let domSel = view.domSelection(), range = document.createRange()
150
+ let domSel = view.domSelection()
151
151
  if (!domSel) return
152
152
  let node = view.cursorWrapper!.dom, img = node.nodeName == "IMG"
153
- if (img) range.setStart(node.parentNode!, domIndex(node) + 1)
154
- else range.setStart(node, 0)
155
- range.collapse(true)
156
- domSel.removeAllRanges()
157
- domSel.addRange(range)
153
+ if (img) domSel.collapse(node.parentNode!, domIndex(node) + 1)
154
+ else domSel.collapse(node, 0)
158
155
  // Kludge to kill 'control selection' in IE11 when selecting an
159
156
  // invisible cursor wrapper, since that would result in those weird
160
157
  // resize handles and a selection that considers the absolutely
package/src/viewdesc.ts CHANGED
@@ -460,7 +460,7 @@ export class ViewDesc {
460
460
  // (one where the focus is before the anchor), but not all
461
461
  // browsers support it yet.
462
462
  let domSelExtended = false
463
- if ((domSel.extend || anchor == head) && !brKludge) {
463
+ if ((domSel.extend || anchor == head) && !(brKludge && browser.gecko)) {
464
464
  domSel.collapse(anchorDOM.node, anchorDOM.offset)
465
465
  try {
466
466
  if (anchor != head)
@@ -884,15 +884,17 @@ export class NodeViewDesc extends ViewDesc {
884
884
 
885
885
  // Mark this node as being the selected node.
886
886
  selectNode() {
887
- if (this.nodeDOM.nodeType == 1) (this.nodeDOM as HTMLElement).classList.add("ProseMirror-selectednode")
888
- if (this.contentDOM || !this.node.type.spec.draggable) (this.dom as HTMLElement).draggable = true
887
+ if (this.nodeDOM.nodeType == 1) {
888
+ ;(this.nodeDOM as HTMLElement).classList.add("ProseMirror-selectednode")
889
+ if (this.contentDOM || !this.node.type.spec.draggable) (this.nodeDOM as HTMLElement).draggable = true
890
+ }
889
891
  }
890
892
 
891
893
  // Remove selected node marking from this node.
892
894
  deselectNode() {
893
895
  if (this.nodeDOM.nodeType == 1) {
894
896
  ;(this.nodeDOM as HTMLElement).classList.remove("ProseMirror-selectednode")
895
- if (this.contentDOM || !this.node.type.spec.draggable) (this.dom as HTMLElement).removeAttribute("draggable")
897
+ if (this.contentDOM || !this.node.type.spec.draggable) (this.nodeDOM as HTMLElement).removeAttribute("draggable")
896
898
  }
897
899
  }
898
900