prosemirror-view 1.35.0 → 1.36.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,13 @@
1
+ ## 1.36.0 (2024-11-05)
2
+
3
+ ### Bug fixes
4
+
5
+ Don't recreated `TrustedTypePolicy` objects for every paste.
6
+
7
+ ### New features
8
+
9
+ Add support for a `destroy` method on custom mark views. Add MarkView to the doc template
10
+
1
11
  ## 1.35.0 (2024-10-29)
2
12
 
3
13
  ### New features
package/dist/index.cjs CHANGED
@@ -1167,11 +1167,12 @@ var CompositionViewDesc = function (_ViewDesc2) {
1167
1167
  var MarkViewDesc = function (_ViewDesc3) {
1168
1168
  _inherits(MarkViewDesc, _ViewDesc3);
1169
1169
  var _super3 = _createSuper(MarkViewDesc);
1170
- function MarkViewDesc(parent, mark, dom, contentDOM) {
1170
+ function MarkViewDesc(parent, mark, dom, contentDOM, spec) {
1171
1171
  var _this3;
1172
1172
  _classCallCheck(this, MarkViewDesc);
1173
1173
  _this3 = _super3.call(this, parent, [], dom, contentDOM);
1174
1174
  _this3.mark = mark;
1175
+ _this3.spec = spec;
1175
1176
  return _this3;
1176
1177
  }
1177
1178
  _createClass(MarkViewDesc, [{
@@ -1212,13 +1213,19 @@ var MarkViewDesc = function (_ViewDesc3) {
1212
1213
  copy.children = nodes;
1213
1214
  return copy;
1214
1215
  }
1216
+ }, {
1217
+ key: "destroy",
1218
+ value: function destroy() {
1219
+ if (this.spec.destroy) this.spec.destroy();
1220
+ _get(_getPrototypeOf(MarkViewDesc.prototype), "destroy", this).call(this);
1221
+ }
1215
1222
  }], [{
1216
1223
  key: "create",
1217
1224
  value: function create(parent, mark, inline, view) {
1218
1225
  var custom = view.nodeViews[mark.type.name];
1219
1226
  var spec = custom && custom(mark, view, inline);
1220
1227
  if (!spec || !spec.dom) spec = prosemirrorModel.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
1221
- return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
1228
+ return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);
1222
1229
  }
1223
1230
  }]);
1224
1231
  return MarkViewDesc;
@@ -2783,14 +2790,16 @@ var _detachedDoc = null;
2783
2790
  function detachedDoc() {
2784
2791
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
2785
2792
  }
2793
+ var _policy = null;
2786
2794
  function maybeWrapTrusted(html) {
2787
2795
  var trustedTypes = window.trustedTypes;
2788
2796
  if (!trustedTypes) return html;
2789
- return trustedTypes.createPolicy("detachedDocument", {
2797
+ if (!_policy) _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {
2790
2798
  createHTML: function createHTML(s) {
2791
2799
  return s;
2792
2800
  }
2793
- }).createHTML(html);
2801
+ });
2802
+ return _policy.createHTML(html);
2794
2803
  }
2795
2804
  function readHTML(html) {
2796
2805
  var metas = /^(\s*<meta [^>]*>)*/.exec(html);
package/dist/index.d.cts CHANGED
@@ -245,9 +245,6 @@ node-specific editing interfaces, you want more control over
245
245
  the behavior of a node's in-editor representation, and need to
246
246
  [define](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) a custom node view.
247
247
 
248
- Mark views only support `dom` and `contentDOM`, and don't support
249
- any of the node view methods.
250
-
251
248
  Objects returned as node views must conform to this interface.
252
249
  */
253
250
  interface NodeView {
@@ -323,7 +320,32 @@ interface NodeView {
323
320
  ignoreMutation?: (mutation: MutationRecord) => boolean;
324
321
  /**
325
322
  Called when the node view is removed from the editor or the whole
326
- editor is destroyed. (Not available for marks.)
323
+ editor is destroyed.
324
+ */
325
+ destroy?: () => void;
326
+ }
327
+ /**
328
+ By default, document marks are rendered using the result of the
329
+ [`toDOM`](https://prosemirror.net/docs/ref/#model.MarkSpec.toDOM) method of their spec, and managed entirely
330
+ by the editor. For some use cases, you want more control over the behavior
331
+ of a mark's in-editor representation, and need to
332
+ [define](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) a custom mark view.
333
+
334
+ Objects returned as mark views must conform to this interface.
335
+ */
336
+ interface MarkView {
337
+ /**
338
+ The outer DOM node that represents the document node.
339
+ */
340
+ dom: DOMNode;
341
+ /**
342
+ The DOM node that should hold the mark's content. When this is not
343
+ present, the `dom` property is used as the content DOM.
344
+ */
345
+ contentDOM?: HTMLElement | null;
346
+ /**
347
+ Called when the mark view is removed from the editor or the whole
348
+ editor is destroyed.
327
349
  */
328
350
  destroy?: () => void;
329
351
  }
@@ -650,10 +672,7 @@ type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number |
650
672
  The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
651
673
  mark views.
652
674
  */
653
- type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {
654
- dom: HTMLElement;
655
- contentDOM?: HTMLElement;
656
- };
675
+ type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView;
657
676
  /**
658
677
  Helper type that maps event names to event object types, but
659
678
  includes events that TypeScript's HTMLElementEventMap doesn't know
@@ -936,4 +955,4 @@ interface DirectEditorProps extends EditorProps {
936
955
  dispatchTransaction?: (tr: Transaction) => void;
937
956
  }
938
957
 
939
- export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
958
+ export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
package/dist/index.d.ts CHANGED
@@ -245,9 +245,6 @@ node-specific editing interfaces, you want more control over
245
245
  the behavior of a node's in-editor representation, and need to
246
246
  [define](https://prosemirror.net/docs/ref/#view.EditorProps.nodeViews) a custom node view.
247
247
 
248
- Mark views only support `dom` and `contentDOM`, and don't support
249
- any of the node view methods.
250
-
251
248
  Objects returned as node views must conform to this interface.
252
249
  */
253
250
  interface NodeView {
@@ -323,7 +320,32 @@ interface NodeView {
323
320
  ignoreMutation?: (mutation: MutationRecord) => boolean;
324
321
  /**
325
322
  Called when the node view is removed from the editor or the whole
326
- editor is destroyed. (Not available for marks.)
323
+ editor is destroyed.
324
+ */
325
+ destroy?: () => void;
326
+ }
327
+ /**
328
+ By default, document marks are rendered using the result of the
329
+ [`toDOM`](https://prosemirror.net/docs/ref/#model.MarkSpec.toDOM) method of their spec, and managed entirely
330
+ by the editor. For some use cases, you want more control over the behavior
331
+ of a mark's in-editor representation, and need to
332
+ [define](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) a custom mark view.
333
+
334
+ Objects returned as mark views must conform to this interface.
335
+ */
336
+ interface MarkView {
337
+ /**
338
+ The outer DOM node that represents the document node.
339
+ */
340
+ dom: DOMNode;
341
+ /**
342
+ The DOM node that should hold the mark's content. When this is not
343
+ present, the `dom` property is used as the content DOM.
344
+ */
345
+ contentDOM?: HTMLElement | null;
346
+ /**
347
+ Called when the mark view is removed from the editor or the whole
348
+ editor is destroyed.
327
349
  */
328
350
  destroy?: () => void;
329
351
  }
@@ -650,10 +672,7 @@ type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => number |
650
672
  The function types [used](https://prosemirror.net/docs/ref/#view.EditorProps.markViews) to create
651
673
  mark views.
652
674
  */
653
- type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {
654
- dom: HTMLElement;
655
- contentDOM?: HTMLElement;
656
- };
675
+ type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView;
657
676
  /**
658
677
  Helper type that maps event names to event object types, but
659
678
  includes events that TypeScript's HTMLElementEventMap doesn't know
@@ -936,4 +955,4 @@ interface DirectEditorProps extends EditorProps {
936
955
  dispatchTransaction?: (tr: Transaction) => void;
937
956
  }
938
957
 
939
- export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
958
+ export { type DOMEventMap, Decoration, type DecorationAttrs, DecorationSet, type DecorationSource, type DirectEditorProps, type EditorProps, EditorView, type MarkView, type MarkViewConstructor, type NodeView, type NodeViewConstructor };
package/dist/index.js CHANGED
@@ -1192,16 +1192,17 @@ class CompositionViewDesc extends ViewDesc {
1192
1192
  // some cases they will be split more often than would appear
1193
1193
  // necessary.
1194
1194
  class MarkViewDesc extends ViewDesc {
1195
- constructor(parent, mark, dom, contentDOM) {
1195
+ constructor(parent, mark, dom, contentDOM, spec) {
1196
1196
  super(parent, [], dom, contentDOM);
1197
1197
  this.mark = mark;
1198
+ this.spec = spec;
1198
1199
  }
1199
1200
  static create(parent, mark, inline, view) {
1200
1201
  let custom = view.nodeViews[mark.type.name];
1201
1202
  let spec = custom && custom(mark, view, inline);
1202
1203
  if (!spec || !spec.dom)
1203
1204
  spec = DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
1204
- return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
1205
+ return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);
1205
1206
  }
1206
1207
  parseRule() {
1207
1208
  if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)
@@ -1233,6 +1234,11 @@ class MarkViewDesc extends ViewDesc {
1233
1234
  copy.children = nodes;
1234
1235
  return copy;
1235
1236
  }
1237
+ destroy() {
1238
+ if (this.spec.destroy)
1239
+ this.spec.destroy();
1240
+ super.destroy();
1241
+ }
1236
1242
  }
1237
1243
  // Node view descs are the main, most common type of view desc, and
1238
1244
  // correspond to an actual node in the document. Unlike mark descs,
@@ -2953,6 +2959,7 @@ let _detachedDoc = null;
2953
2959
  function detachedDoc() {
2954
2960
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
2955
2961
  }
2962
+ let _policy = null;
2956
2963
  function maybeWrapTrusted(html) {
2957
2964
  let trustedTypes = window.trustedTypes;
2958
2965
  if (!trustedTypes)
@@ -2960,7 +2967,9 @@ function maybeWrapTrusted(html) {
2960
2967
  // With the require-trusted-types-for CSP, Chrome will block
2961
2968
  // innerHTML, even on a detached document. This wraps the string in
2962
2969
  // a way that makes the browser allow us to use its parser again.
2963
- return trustedTypes.createPolicy("detachedDocument", { createHTML: (s) => s }).createHTML(html);
2970
+ if (!_policy)
2971
+ _policy = trustedTypes.createPolicy("ProseMirrorClipboard", { createHTML: (s) => s });
2972
+ return _policy.createHTML(html);
2964
2973
  }
2965
2974
  function readHTML(html) {
2966
2975
  let metas = /^(\s*<meta [^>]*>)*/.exec(html);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.35.0",
3
+ "version": "1.36.0",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/README.md CHANGED
@@ -18,6 +18,8 @@ this module.
18
18
 
19
19
  @NodeView
20
20
 
21
+ @MarkView
22
+
21
23
  @DOMEventMap
22
24
 
23
25
  ### Decorations
package/src/clipboard.ts CHANGED
@@ -204,13 +204,16 @@ function detachedDoc() {
204
204
  return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"))
205
205
  }
206
206
 
207
+ let _policy: any = null
208
+
207
209
  function maybeWrapTrusted(html: string): string {
208
210
  let trustedTypes = (window as any).trustedTypes
209
211
  if (!trustedTypes) return html
210
212
  // With the require-trusted-types-for CSP, Chrome will block
211
213
  // innerHTML, even on a detached document. This wraps the string in
212
214
  // a way that makes the browser allow us to use its parser again.
213
- return trustedTypes.createPolicy("detachedDocument", {createHTML: (s: string) => s}).createHTML(html)
215
+ if (!_policy) _policy = trustedTypes.createPolicy("ProseMirrorClipboard", {createHTML: (s: string) => s})
216
+ return _policy.createHTML(html)
214
217
  }
215
218
 
216
219
  function readHTML(html: string) {
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import {Slice, ResolvedPos, DOMParser, DOMSerializer, Node, Mark} from "prosemir
3
3
 
4
4
  import {scrollRectIntoView, posAtCoords, coordsAtPos, endOfTextblock, storeScrollPos,
5
5
  resetScrollPos, focusPreventScroll} from "./domcoords"
6
- import {docViewDesc, ViewDesc, NodeView, NodeViewDesc} from "./viewdesc"
6
+ import {docViewDesc, ViewDesc, NodeView, NodeViewDesc, MarkView} from "./viewdesc"
7
7
  import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition,
8
8
  InputState, doPaste, Dragging, findCompositionNode} from "./input"
9
9
  import {selectionToDOM, anchorInRightPlace, syncNodeSelection} from "./selection"
@@ -14,7 +14,7 @@ import {DOMSelection, DOMNode, DOMSelectionRange, deepActiveElement, clearReused
14
14
  import * as browser from "./browser"
15
15
 
16
16
  export {Decoration, DecorationSet, DecorationAttrs, DecorationSource} from "./decoration"
17
- export {NodeView} from "./viewdesc"
17
+ export {NodeView, MarkView} from "./viewdesc"
18
18
 
19
19
  // Exported for testing
20
20
  import {serializeForClipboard, parseFromClipboard} from "./clipboard"
@@ -576,7 +576,7 @@ export type NodeViewConstructor = (node: Node, view: EditorView, getPos: () => n
576
576
 
577
577
  /// The function types [used](#view.EditorProps.markViews) to create
578
578
  /// mark views.
579
- export type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => {dom: HTMLElement, contentDOM?: HTMLElement}
579
+ export type MarkViewConstructor = (mark: Mark, view: EditorView, inline: boolean) => MarkView
580
580
 
581
581
  type NodeViewSet = {[name: string]: NodeViewConstructor | MarkViewConstructor}
582
582
 
package/src/viewdesc.ts CHANGED
@@ -17,9 +17,6 @@ declare global {
17
17
  /// the behavior of a node's in-editor representation, and need to
18
18
  /// [define](#view.EditorProps.nodeViews) a custom node view.
19
19
  ///
20
- /// Mark views only support `dom` and `contentDOM`, and don't support
21
- /// any of the node view methods.
22
- ///
23
20
  /// Objects returned as node views must conform to this interface.
24
21
  export interface NodeView {
25
22
  /// The outer DOM node that represents the document node.
@@ -84,7 +81,27 @@ export interface NodeView {
84
81
  ignoreMutation?: (mutation: MutationRecord) => boolean
85
82
 
86
83
  /// Called when the node view is removed from the editor or the whole
87
- /// editor is destroyed. (Not available for marks.)
84
+ /// editor is destroyed.
85
+ destroy?: () => void
86
+ }
87
+
88
+ /// By default, document marks are rendered using the result of the
89
+ /// [`toDOM`](#model.MarkSpec.toDOM) method of their spec, and managed entirely
90
+ /// by the editor. For some use cases, you want more control over the behavior
91
+ /// of a mark's in-editor representation, and need to
92
+ /// [define](#view.EditorProps.markViews) a custom mark view.
93
+ ///
94
+ /// Objects returned as mark views must conform to this interface.
95
+ export interface MarkView {
96
+ /// The outer DOM node that represents the document node.
97
+ dom: DOMNode
98
+
99
+ /// The DOM node that should hold the mark's content. When this is not
100
+ /// present, the `dom` property is used as the content DOM.
101
+ contentDOM?: HTMLElement | null
102
+
103
+ /// Called when the mark view is removed from the editor or the whole
104
+ /// editor is destroyed.
88
105
  destroy?: () => void
89
106
  }
90
107
 
@@ -572,7 +589,7 @@ class CompositionViewDesc extends ViewDesc {
572
589
  // some cases they will be split more often than would appear
573
590
  // necessary.
574
591
  class MarkViewDesc extends ViewDesc {
575
- constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement) {
592
+ constructor(parent: ViewDesc, readonly mark: Mark, dom: DOMNode, contentDOM: HTMLElement, readonly spec: MarkView) {
576
593
  super(parent, [], dom, contentDOM)
577
594
  }
578
595
 
@@ -581,7 +598,7 @@ class MarkViewDesc extends ViewDesc {
581
598
  let spec: {dom: HTMLElement, contentDOM?: HTMLElement} = custom && (custom as any)(mark, view, inline)
582
599
  if (!spec || !spec.dom)
583
600
  spec = (DOMSerializer.renderSpec as any)(document, mark.type.spec.toDOM!(mark, inline), null, mark.attrs) as any
584
- return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom as HTMLElement)
601
+ return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom as HTMLElement, spec)
585
602
  }
586
603
 
587
604
  parseRule() {
@@ -611,6 +628,11 @@ class MarkViewDesc extends ViewDesc {
611
628
  copy.children = nodes
612
629
  return copy
613
630
  }
631
+
632
+ destroy() {
633
+ if (this.spec.destroy) this.spec.destroy()
634
+ super.destroy()
635
+ }
614
636
  }
615
637
 
616
638
  // Node view descs are the main, most common type of view desc, and