@tiptap/core 3.0.0-next.1 → 3.0.0-next.3

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.
Files changed (42) hide show
  1. package/dist/index.cjs +403 -137
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +177 -53
  4. package/dist/index.d.ts +177 -53
  5. package/dist/index.js +375 -108
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/Editor.ts +60 -10
  9. package/src/EventEmitter.ts +9 -0
  10. package/src/ExtensionManager.ts +16 -11
  11. package/src/InputRule.ts +45 -30
  12. package/src/Node.ts +19 -0
  13. package/src/NodePos.ts +9 -4
  14. package/src/NodeView.ts +43 -12
  15. package/src/PasteRule.ts +96 -42
  16. package/src/commands/focus.ts +1 -6
  17. package/src/commands/insertContent.ts +9 -9
  18. package/src/commands/insertContentAt.ts +23 -3
  19. package/src/commands/selectAll.ts +10 -5
  20. package/src/commands/setContent.ts +10 -14
  21. package/src/commands/setNode.ts +9 -2
  22. package/src/commands/toggleNode.ts +11 -2
  23. package/src/commands/updateAttributes.ts +72 -12
  24. package/src/extensions/drop.ts +26 -0
  25. package/src/extensions/index.ts +2 -0
  26. package/src/extensions/keymap.ts +5 -2
  27. package/src/extensions/paste.ts +26 -0
  28. package/src/helpers/createDocument.ts +4 -2
  29. package/src/helpers/createNodeFromContent.ts +11 -2
  30. package/src/helpers/getMarkRange.ts +35 -8
  31. package/src/helpers/getRenderedAttributes.ts +3 -0
  32. package/src/helpers/getSchemaByResolvedExtensions.ts +2 -1
  33. package/src/inputRules/markInputRule.ts +1 -1
  34. package/src/inputRules/nodeInputRule.ts +1 -1
  35. package/src/inputRules/textInputRule.ts +1 -1
  36. package/src/inputRules/textblockTypeInputRule.ts +1 -1
  37. package/src/inputRules/wrappingInputRule.ts +1 -1
  38. package/src/pasteRules/markPasteRule.ts +1 -1
  39. package/src/pasteRules/nodePasteRule.ts +1 -1
  40. package/src/pasteRules/textPasteRule.ts +1 -1
  41. package/src/types.ts +107 -19
  42. package/src/utilities/mergeAttributes.ts +18 -1
package/dist/index.js CHANGED
@@ -178,6 +178,13 @@ var EventEmitter = class {
178
178
  }
179
179
  return this;
180
180
  }
181
+ once(event, fn) {
182
+ const onceFn = (...args) => {
183
+ this.off(event, onceFn);
184
+ fn.apply(this, args);
185
+ };
186
+ return this.on(event, onceFn);
187
+ }
181
188
  removeAllListeners() {
182
189
  this.callbacks = {};
183
190
  }
@@ -324,7 +331,18 @@ function mergeAttributes(...objects) {
324
331
  );
325
332
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
326
333
  } else if (key === "style") {
327
- mergedAttributes[key] = [mergedAttributes[key], value].join("; ");
334
+ const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
335
+ const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
336
+ const styleMap = /* @__PURE__ */ new Map();
337
+ existingStyles.forEach((style2) => {
338
+ const [property, val] = style2.split(":").map((part) => part.trim());
339
+ styleMap.set(property, val);
340
+ });
341
+ newStyles.forEach((style2) => {
342
+ const [property, val] = style2.split(":").map((part) => part.trim());
343
+ styleMap.set(property, val);
344
+ });
345
+ mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
328
346
  } else {
329
347
  mergedAttributes[key] = value;
330
348
  }
@@ -335,7 +353,9 @@ function mergeAttributes(...objects) {
335
353
 
336
354
  // src/helpers/getRenderedAttributes.ts
337
355
  function getRenderedAttributes(nodeOrMark, extensionAttributes) {
338
- return extensionAttributes.filter((item) => item.attribute.rendered).map((item) => {
356
+ return extensionAttributes.filter(
357
+ (attribute) => attribute.type === nodeOrMark.type.name
358
+ ).filter((item) => item.attribute.rendered).map((item) => {
339
359
  if (!item.attribute.renderHTML) {
340
360
  return {
341
361
  [item.name]: nodeOrMark.attrs[item.name]
@@ -471,6 +491,7 @@ function getSchemaByResolvedExtensions(extensions, editor) {
471
491
  ),
472
492
  code: callOrReturn(getExtensionField(extension, "code", context)),
473
493
  whitespace: callOrReturn(getExtensionField(extension, "whitespace", context)),
494
+ linebreakReplacement: callOrReturn(getExtensionField(extension, "linebreakReplacement", context)),
474
495
  defining: callOrReturn(
475
496
  getExtensionField(extension, "defining", context)
476
497
  ),
@@ -598,8 +619,19 @@ function isExtensionRulesEnabled(extension, enabled) {
598
619
  }
599
620
 
600
621
  // src/InputRule.ts
622
+ import { Fragment as Fragment2 } from "@tiptap/pm/model";
601
623
  import { Plugin } from "@tiptap/pm/state";
602
624
 
625
+ // src/helpers/getHTMLFromFragment.ts
626
+ import { DOMSerializer } from "@tiptap/pm/model";
627
+ function getHTMLFromFragment(fragment, schema) {
628
+ const documentFragment = DOMSerializer.fromSchema(schema).serializeFragment(fragment);
629
+ const temporaryDocument = document.implementation.createHTMLDocument();
630
+ const container = temporaryDocument.createElement("div");
631
+ container.appendChild(documentFragment);
632
+ return container.innerHTML;
633
+ }
634
+
603
635
  // src/helpers/getTextContentFromNodes.ts
604
636
  var getTextContentFromNodes = ($from, maxMatch = 500) => {
605
637
  let textBefore = "";
@@ -728,7 +760,7 @@ function inputRulesPlugin(props) {
728
760
  init() {
729
761
  return null;
730
762
  },
731
- apply(tr, prev) {
763
+ apply(tr, prev, state) {
732
764
  const stored = tr.getMeta(plugin);
733
765
  if (stored) {
734
766
  return stored;
@@ -737,7 +769,13 @@ function inputRulesPlugin(props) {
737
769
  const isSimulatedInput = !!simulatedInputMeta;
738
770
  if (isSimulatedInput) {
739
771
  setTimeout(() => {
740
- const { from, text } = simulatedInputMeta;
772
+ let { text } = simulatedInputMeta;
773
+ if (typeof text === "string") {
774
+ text = text;
775
+ } else {
776
+ text = getHTMLFromFragment(Fragment2.from(text), state.schema);
777
+ }
778
+ const { from } = simulatedInputMeta;
741
779
  const to = from + text.length;
742
780
  run({
743
781
  editor,
@@ -929,6 +967,7 @@ var Mark = class _Mark {
929
967
  };
930
968
 
931
969
  // src/PasteRule.ts
970
+ import { Fragment as Fragment3 } from "@tiptap/pm/model";
932
971
  import { Plugin as Plugin2 } from "@tiptap/pm/state";
933
972
 
934
973
  // src/utilities/isNumber.ts
@@ -1016,6 +1055,7 @@ function run2(config) {
1016
1055
  const success = handlers.every((handler) => handler !== null);
1017
1056
  return success;
1018
1057
  }
1058
+ var tiptapDragFromOtherEditor = null;
1019
1059
  var createClipboardPasteEvent = (text) => {
1020
1060
  var _a;
1021
1061
  const event = new ClipboardEvent("paste", {
@@ -1030,7 +1070,12 @@ function pasteRulesPlugin(props) {
1030
1070
  let isPastedFromProseMirror = false;
1031
1071
  let isDroppedFromProseMirror = false;
1032
1072
  let pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
1033
- let dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1073
+ let dropEvent;
1074
+ try {
1075
+ dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1076
+ } catch (e) {
1077
+ dropEvent = null;
1078
+ }
1034
1079
  const processEvent = ({
1035
1080
  state,
1036
1081
  from,
@@ -1055,7 +1100,11 @@ function pasteRulesPlugin(props) {
1055
1100
  if (!handler || !tr.steps.length) {
1056
1101
  return;
1057
1102
  }
1058
- dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1103
+ try {
1104
+ dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1105
+ } catch (e) {
1106
+ dropEvent = null;
1107
+ }
1059
1108
  pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
1060
1109
  return tr;
1061
1110
  };
@@ -1066,11 +1115,21 @@ function pasteRulesPlugin(props) {
1066
1115
  const handleDragstart = (event) => {
1067
1116
  var _a;
1068
1117
  dragSourceElement = ((_a = view.dom.parentElement) == null ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
1118
+ if (dragSourceElement) {
1119
+ tiptapDragFromOtherEditor = editor;
1120
+ }
1121
+ };
1122
+ const handleDragend = () => {
1123
+ if (tiptapDragFromOtherEditor) {
1124
+ tiptapDragFromOtherEditor = null;
1125
+ }
1069
1126
  };
1070
1127
  window.addEventListener("dragstart", handleDragstart);
1128
+ window.addEventListener("dragend", handleDragend);
1071
1129
  return {
1072
1130
  destroy() {
1073
1131
  window.removeEventListener("dragstart", handleDragstart);
1132
+ window.removeEventListener("dragend", handleDragend);
1074
1133
  }
1075
1134
  };
1076
1135
  },
@@ -1079,6 +1138,17 @@ function pasteRulesPlugin(props) {
1079
1138
  drop: (view, event) => {
1080
1139
  isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement;
1081
1140
  dropEvent = event;
1141
+ if (!isDroppedFromProseMirror) {
1142
+ const dragFromOtherEditor = tiptapDragFromOtherEditor;
1143
+ if (dragFromOtherEditor) {
1144
+ setTimeout(() => {
1145
+ const selection = dragFromOtherEditor.state.selection;
1146
+ if (selection) {
1147
+ dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to });
1148
+ }
1149
+ }, 10);
1150
+ }
1151
+ }
1082
1152
  return false;
1083
1153
  },
1084
1154
  paste: (_view, event) => {
@@ -1100,7 +1170,13 @@ function pasteRulesPlugin(props) {
1100
1170
  return;
1101
1171
  }
1102
1172
  if (isSimulatedPaste) {
1103
- const { from: from2, text } = simulatedPasteMeta;
1173
+ let { text } = simulatedPasteMeta;
1174
+ if (typeof text === "string") {
1175
+ text = text;
1176
+ } else {
1177
+ text = getHTMLFromFragment(Fragment3.from(text), state.schema);
1178
+ }
1179
+ const { from: from2 } = simulatedPasteMeta;
1104
1180
  const to2 = from2 + text.length;
1105
1181
  const pasteEvt = createClipboardPasteEvent(text);
1106
1182
  return processEvent({
@@ -1339,15 +1415,19 @@ var ExtensionManager = class _ExtensionManager {
1339
1415
  if (!addNodeView) {
1340
1416
  return [];
1341
1417
  }
1342
- const nodeview = (node, view, getPos, decorations) => {
1418
+ const nodeview = (node, view, getPos, decorations, innerDecorations) => {
1343
1419
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
1344
1420
  return addNodeView()({
1345
- editor,
1421
+ // pass-through
1346
1422
  node,
1423
+ view,
1347
1424
  getPos,
1348
1425
  decorations,
1349
- HTMLAttributes,
1350
- extension
1426
+ innerDecorations,
1427
+ // tiptap-specific
1428
+ editor,
1429
+ extension,
1430
+ HTMLAttributes
1351
1431
  });
1352
1432
  };
1353
1433
  return [extension.name, nodeview];
@@ -1428,9 +1508,11 @@ var extensions_exports = {};
1428
1508
  __export(extensions_exports, {
1429
1509
  ClipboardTextSerializer: () => ClipboardTextSerializer,
1430
1510
  Commands: () => Commands,
1511
+ Drop: () => Drop,
1431
1512
  Editable: () => Editable,
1432
1513
  FocusEvents: () => FocusEvents,
1433
1514
  Keymap: () => Keymap,
1515
+ Paste: () => Paste,
1434
1516
  Tabindex: () => Tabindex
1435
1517
  });
1436
1518
 
@@ -1807,23 +1889,29 @@ function objectIncludes(object1, object2, options = { strict: true }) {
1807
1889
  // src/helpers/getMarkRange.ts
1808
1890
  function findMarkInSet(marks, type, attributes = {}) {
1809
1891
  return marks.find((item) => {
1810
- return item.type === type && objectIncludes(item.attrs, attributes);
1892
+ return item.type === type && objectIncludes(
1893
+ // Only check equality for the attributes that are provided
1894
+ Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])),
1895
+ attributes
1896
+ );
1811
1897
  });
1812
1898
  }
1813
1899
  function isMarkInSet(marks, type, attributes = {}) {
1814
1900
  return !!findMarkInSet(marks, type, attributes);
1815
1901
  }
1816
- function getMarkRange($pos, type, attributes = {}) {
1902
+ function getMarkRange($pos, type, attributes) {
1903
+ var _a;
1817
1904
  if (!$pos || !type) {
1818
1905
  return;
1819
1906
  }
1820
1907
  let start = $pos.parent.childAfter($pos.parentOffset);
1821
- if ($pos.parentOffset === start.offset && start.offset !== 0) {
1908
+ if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
1822
1909
  start = $pos.parent.childBefore($pos.parentOffset);
1823
1910
  }
1824
- if (!start.node) {
1911
+ if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
1825
1912
  return;
1826
1913
  }
1914
+ attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs);
1827
1915
  const mark = findMarkInSet([...start.node.marks], type, attributes);
1828
1916
  if (!mark) {
1829
1917
  return;
@@ -1832,8 +1920,7 @@ function getMarkRange($pos, type, attributes = {}) {
1832
1920
  let startPos = $pos.start() + start.offset;
1833
1921
  let endIndex = startIndex + 1;
1834
1922
  let endPos = startPos + start.node.nodeSize;
1835
- findMarkInSet([...start.node.marks], type, attributes);
1836
- while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
1923
+ while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
1837
1924
  startIndex -= 1;
1838
1925
  startPos -= $pos.parent.child(startIndex).nodeSize;
1839
1926
  }
@@ -1929,18 +2016,6 @@ function resolveFocusPosition(doc, position = null) {
1929
2016
  );
1930
2017
  }
1931
2018
 
1932
- // src/utilities/isiOS.ts
1933
- function isiOS() {
1934
- return [
1935
- "iPad Simulator",
1936
- "iPhone Simulator",
1937
- "iPod Simulator",
1938
- "iPad",
1939
- "iPhone",
1940
- "iPod"
1941
- ].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
1942
- }
1943
-
1944
2019
  // src/commands/focus.ts
1945
2020
  var focus = (position = null, options = {}) => ({
1946
2021
  editor,
@@ -1953,9 +2028,7 @@ var focus = (position = null, options = {}) => ({
1953
2028
  ...options
1954
2029
  };
1955
2030
  const delayedFocus = () => {
1956
- if (isiOS()) {
1957
- view.dom.focus();
1958
- }
2031
+ view.dom.focus();
1959
2032
  requestAnimationFrame(() => {
1960
2033
  if (!editor.isDestroyed) {
1961
2034
  view.focus();
@@ -2000,11 +2073,15 @@ var insertContent = (value, options) => ({ tr, commands }) => {
2000
2073
  );
2001
2074
  };
2002
2075
 
2076
+ // src/commands/insertContentAt.ts
2077
+ import { Fragment as Fragment5 } from "@tiptap/pm/model";
2078
+
2003
2079
  // src/helpers/createNodeFromContent.ts
2004
2080
  import {
2005
2081
  DOMParser,
2006
- Fragment,
2007
- Schema as Schema2
2082
+ Fragment as Fragment4,
2083
+ Node as ProseMirrorNode3,
2084
+ Schema as Schema3
2008
2085
  } from "@tiptap/pm/model";
2009
2086
 
2010
2087
  // src/utilities/elementFromString.ts
@@ -2028,6 +2105,9 @@ function elementFromString(value) {
2028
2105
 
2029
2106
  // src/helpers/createNodeFromContent.ts
2030
2107
  function createNodeFromContent(content, schema, options) {
2108
+ if (content instanceof ProseMirrorNode3 || content instanceof Fragment4) {
2109
+ return content;
2110
+ }
2031
2111
  options = {
2032
2112
  slice: true,
2033
2113
  parseOptions: {},
@@ -2039,9 +2119,13 @@ function createNodeFromContent(content, schema, options) {
2039
2119
  try {
2040
2120
  const isArrayContent = Array.isArray(content) && content.length > 0;
2041
2121
  if (isArrayContent) {
2042
- return Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
2122
+ return Fragment4.fromArray(content.map((item) => schema.nodeFromJSON(item)));
2123
+ }
2124
+ const node = schema.nodeFromJSON(content);
2125
+ if (options.errorOnInvalidContent) {
2126
+ node.check();
2043
2127
  }
2044
- return schema.nodeFromJSON(content);
2128
+ return node;
2045
2129
  } catch (error) {
2046
2130
  if (options.errorOnInvalidContent) {
2047
2131
  throw new Error("[tiptap error]: Invalid JSON content", { cause: error });
@@ -2054,7 +2138,7 @@ function createNodeFromContent(content, schema, options) {
2054
2138
  if (options.errorOnInvalidContent) {
2055
2139
  let hasInvalidContent = false;
2056
2140
  let invalidContent = "";
2057
- const contentCheckSchema = new Schema2({
2141
+ const contentCheckSchema = new Schema3({
2058
2142
  topNode: schema.spec.topNode,
2059
2143
  marks: schema.spec.marks,
2060
2144
  // Prosemirror's schemas are executed such that: the last to execute, matches last
@@ -2124,13 +2208,14 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2124
2208
  var _a;
2125
2209
  if (dispatch) {
2126
2210
  options = {
2127
- parseOptions: {},
2211
+ parseOptions: editor.options.parseOptions,
2128
2212
  updateSelection: true,
2129
2213
  applyInputRules: false,
2130
2214
  applyPasteRules: false,
2131
2215
  ...options
2132
2216
  };
2133
2217
  let content;
2218
+ const { selection } = editor.state;
2134
2219
  try {
2135
2220
  content = createNodeFromContent(value, editor.schema, {
2136
2221
  parseOptions: {
@@ -2144,7 +2229,9 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2144
2229
  editor,
2145
2230
  error: e,
2146
2231
  disableCollaboration: () => {
2147
- console.error("[tiptap error]: Unable to disable collaboration at this point in time");
2232
+ if (editor.storage.collaboration) {
2233
+ editor.storage.collaboration.isDisabled = true;
2234
+ }
2148
2235
  }
2149
2236
  });
2150
2237
  return false;
@@ -2170,6 +2257,14 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2170
2257
  if (isOnlyTextContent) {
2171
2258
  if (Array.isArray(value)) {
2172
2259
  newContent = value.map((v) => v.text || "").join("");
2260
+ } else if (value instanceof Fragment5) {
2261
+ let text = "";
2262
+ value.forEach((node) => {
2263
+ if (node.text) {
2264
+ text += node.text;
2265
+ }
2266
+ });
2267
+ newContent = text;
2173
2268
  } else if (typeof value === "object" && !!value && !!value.text) {
2174
2269
  newContent = value.text;
2175
2270
  } else {
@@ -2178,6 +2273,11 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2178
2273
  tr.insertText(newContent, from, to);
2179
2274
  } else {
2180
2275
  newContent = content;
2276
+ const fromSelectionAtStart = selection.$from.parentOffset === 0;
2277
+ const isTextSelection2 = selection.$from.node().isText || selection.$from.node().isTextblock;
2278
+ if (fromSelectionAtStart && isTextSelection2) {
2279
+ from = Math.max(0, from - 1);
2280
+ }
2181
2281
  tr.replaceWith(from, to, newContent);
2182
2282
  }
2183
2283
  if (options.updateSelection) {
@@ -2269,6 +2369,18 @@ var joinTextblockForward = () => ({ state, dispatch }) => {
2269
2369
  return originalCommand2(state, dispatch);
2270
2370
  };
2271
2371
 
2372
+ // src/utilities/isiOS.ts
2373
+ function isiOS() {
2374
+ return [
2375
+ "iPad Simulator",
2376
+ "iPhone Simulator",
2377
+ "iPod Simulator",
2378
+ "iPad",
2379
+ "iPhone",
2380
+ "iPod"
2381
+ ].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
2382
+ }
2383
+
2272
2384
  // src/utilities/isMacOS.ts
2273
2385
  function isMacOS() {
2274
2386
  return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
@@ -2482,11 +2594,13 @@ var scrollIntoView = () => ({ tr, dispatch }) => {
2482
2594
  };
2483
2595
 
2484
2596
  // src/commands/selectAll.ts
2485
- var selectAll = () => ({ tr, commands }) => {
2486
- return commands.setTextSelection({
2487
- from: 0,
2488
- to: tr.doc.content.size
2489
- });
2597
+ import { AllSelection } from "@tiptap/pm/state";
2598
+ var selectAll = () => ({ tr, dispatch }) => {
2599
+ if (dispatch) {
2600
+ const selection = new AllSelection(tr.doc);
2601
+ tr.setSelection(selection);
2602
+ }
2603
+ return true;
2490
2604
  };
2491
2605
 
2492
2606
  // src/commands/selectNodeBackward.ts
@@ -2549,14 +2663,10 @@ var setContent = (content, emitUpdate = false, parseOptions = {}, options = {})
2549
2663
  if (dispatch) {
2550
2664
  tr.setMeta("preventUpdate", !emitUpdate);
2551
2665
  }
2552
- return commands.insertContentAt(
2553
- { from: 0, to: doc.content.size },
2554
- content,
2555
- {
2556
- parseOptions,
2557
- errorOnInvalidContent: (_b = options.errorOnInvalidContent) != null ? _b : editor.options.enableContentCheck
2558
- }
2559
- );
2666
+ return commands.insertContentAt({ from: 0, to: doc.content.size }, content, {
2667
+ parseOptions,
2668
+ errorOnInvalidContent: (_b = options.errorOnInvalidContent) != null ? _b : editor.options.enableContentCheck
2669
+ });
2560
2670
  };
2561
2671
 
2562
2672
  // src/helpers/getMarkAttributes.ts
@@ -2655,16 +2765,6 @@ function findParentNode(predicate) {
2655
2765
  // src/helpers/generateHTML.ts
2656
2766
  import { Node } from "@tiptap/pm/model";
2657
2767
 
2658
- // src/helpers/getHTMLFromFragment.ts
2659
- import { DOMSerializer } from "@tiptap/pm/model";
2660
- function getHTMLFromFragment(fragment, schema) {
2661
- const documentFragment = DOMSerializer.fromSchema(schema).serializeFragment(fragment);
2662
- const temporaryDocument = document.implementation.createHTMLDocument();
2663
- const container = temporaryDocument.createElement("div");
2664
- container.appendChild(documentFragment);
2665
- return container.innerHTML;
2666
- }
2667
-
2668
2768
  // src/helpers/getSchema.ts
2669
2769
  function getSchema(extensions, editor) {
2670
2770
  const resolvedExtensions = ExtensionManager.resolve(extensions);
@@ -3173,18 +3273,22 @@ var setMeta = (key, value) => ({ tr }) => {
3173
3273
  import { setBlockType } from "@tiptap/pm/commands";
3174
3274
  var setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
3175
3275
  const type = getNodeType(typeOrName, state.schema);
3276
+ let attributesToCopy;
3277
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3278
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3279
+ }
3176
3280
  if (!type.isTextblock) {
3177
3281
  console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
3178
3282
  return false;
3179
3283
  }
3180
3284
  return chain().command(({ commands }) => {
3181
- const canSetBlock = setBlockType(type, attributes)(state);
3285
+ const canSetBlock = setBlockType(type, { ...attributesToCopy, ...attributes })(state);
3182
3286
  if (canSetBlock) {
3183
3287
  return true;
3184
3288
  }
3185
3289
  return commands.clearNodes();
3186
3290
  }).command(({ state: updatedState }) => {
3187
- return setBlockType(type, attributes)(updatedState, dispatch);
3291
+ return setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch);
3188
3292
  }).run();
3189
3293
  };
3190
3294
 
@@ -3304,7 +3408,7 @@ var splitBlock = ({ keepMarks = true } = {}) => ({
3304
3408
 
3305
3409
  // src/commands/splitListItem.ts
3306
3410
  import {
3307
- Fragment as Fragment3,
3411
+ Fragment as Fragment6,
3308
3412
  Slice
3309
3413
  } from "@tiptap/pm/model";
3310
3414
  import { TextSelection as TextSelection8 } from "@tiptap/pm/state";
@@ -3332,10 +3436,10 @@ var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3332
3436
  return false;
3333
3437
  }
3334
3438
  if (dispatch) {
3335
- let wrap = Fragment3.empty;
3439
+ let wrap = Fragment6.empty;
3336
3440
  const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
3337
3441
  for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {
3338
- wrap = Fragment3.from($from.node(d).copy(wrap));
3442
+ wrap = Fragment6.from($from.node(d).copy(wrap));
3339
3443
  }
3340
3444
  const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
3341
3445
  const newNextTypeAttributes2 = {
@@ -3347,7 +3451,7 @@ var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3347
3451
  ...overrideAttrs
3348
3452
  };
3349
3453
  const nextType2 = ((_a = type.contentMatch.defaultType) == null ? void 0 : _a.createAndFill(newNextTypeAttributes2)) || void 0;
3350
- wrap = wrap.append(Fragment3.from(type.createAndFill(null, nextType2) || void 0));
3454
+ wrap = wrap.append(Fragment6.from(type.createAndFill(null, nextType2) || void 0));
3351
3455
  const start = $from.before($from.depth - (depthBefore - 1));
3352
3456
  tr.replace(start, $from.after(-depthAfter), new Slice(wrap, 4 - depthBefore, 0));
3353
3457
  let sel = -1;
@@ -3508,10 +3612,14 @@ var toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, co
3508
3612
  const type = getNodeType(typeOrName, state.schema);
3509
3613
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3510
3614
  const isActive2 = isNodeActive(state, type, attributes);
3615
+ let attributesToCopy;
3616
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3617
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3618
+ }
3511
3619
  if (isActive2) {
3512
- return commands.setNode(toggleType);
3620
+ return commands.setNode(toggleType, attributesToCopy);
3513
3621
  }
3514
- return commands.setNode(type, attributes);
3622
+ return commands.setNode(type, { ...attributesToCopy, ...attributes });
3515
3623
  };
3516
3624
 
3517
3625
  // src/commands/toggleWrap.ts
@@ -3614,18 +3722,63 @@ var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }
3614
3722
  tr.selection.ranges.forEach((range) => {
3615
3723
  const from = range.$from.pos;
3616
3724
  const to = range.$to.pos;
3617
- state.doc.nodesBetween(from, to, (node, pos) => {
3618
- if (nodeType && nodeType === node.type) {
3619
- tr.setNodeMarkup(pos, void 0, {
3620
- ...node.attrs,
3725
+ let lastPos;
3726
+ let lastNode;
3727
+ let trimmedFrom;
3728
+ let trimmedTo;
3729
+ if (tr.selection.empty) {
3730
+ state.doc.nodesBetween(from, to, (node, pos) => {
3731
+ if (nodeType && nodeType === node.type) {
3732
+ trimmedFrom = Math.max(pos, from);
3733
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3734
+ lastPos = pos;
3735
+ lastNode = node;
3736
+ }
3737
+ });
3738
+ } else {
3739
+ state.doc.nodesBetween(from, to, (node, pos) => {
3740
+ if (pos < from && nodeType && nodeType === node.type) {
3741
+ trimmedFrom = Math.max(pos, from);
3742
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3743
+ lastPos = pos;
3744
+ lastNode = node;
3745
+ }
3746
+ if (pos >= from && pos <= to) {
3747
+ if (nodeType && nodeType === node.type) {
3748
+ tr.setNodeMarkup(pos, void 0, {
3749
+ ...node.attrs,
3750
+ ...attributes
3751
+ });
3752
+ }
3753
+ if (markType && node.marks.length) {
3754
+ node.marks.forEach((mark) => {
3755
+ if (markType === mark.type) {
3756
+ const trimmedFrom2 = Math.max(pos, from);
3757
+ const trimmedTo2 = Math.min(pos + node.nodeSize, to);
3758
+ tr.addMark(
3759
+ trimmedFrom2,
3760
+ trimmedTo2,
3761
+ markType.create({
3762
+ ...mark.attrs,
3763
+ ...attributes
3764
+ })
3765
+ );
3766
+ }
3767
+ });
3768
+ }
3769
+ }
3770
+ });
3771
+ }
3772
+ if (lastNode) {
3773
+ if (lastPos !== void 0) {
3774
+ tr.setNodeMarkup(lastPos, void 0, {
3775
+ ...lastNode.attrs,
3621
3776
  ...attributes
3622
3777
  });
3623
3778
  }
3624
- if (markType && node.marks.length) {
3625
- node.marks.forEach((mark) => {
3779
+ if (markType && lastNode.marks.length) {
3780
+ lastNode.marks.forEach((mark) => {
3626
3781
  if (markType === mark.type) {
3627
- const trimmedFrom = Math.max(pos, from);
3628
- const trimmedTo = Math.min(pos + node.nodeSize, to);
3629
3782
  tr.addMark(
3630
3783
  trimmedFrom,
3631
3784
  trimmedTo,
@@ -3637,7 +3790,7 @@ var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }
3637
3790
  }
3638
3791
  });
3639
3792
  }
3640
- });
3793
+ }
3641
3794
  });
3642
3795
  }
3643
3796
  return true;
@@ -3667,14 +3820,37 @@ var Commands = Extension.create({
3667
3820
  }
3668
3821
  });
3669
3822
 
3670
- // src/extensions/editable.ts
3823
+ // src/extensions/drop.ts
3671
3824
  import { Plugin as Plugin4, PluginKey as PluginKey2 } from "@tiptap/pm/state";
3825
+ var Drop = Extension.create({
3826
+ name: "drop",
3827
+ addProseMirrorPlugins() {
3828
+ return [
3829
+ new Plugin4({
3830
+ key: new PluginKey2("tiptapDrop"),
3831
+ props: {
3832
+ handleDrop: (_, e, slice, moved) => {
3833
+ this.editor.emit("drop", {
3834
+ editor: this.editor,
3835
+ event: e,
3836
+ slice,
3837
+ moved
3838
+ });
3839
+ }
3840
+ }
3841
+ })
3842
+ ];
3843
+ }
3844
+ });
3845
+
3846
+ // src/extensions/editable.ts
3847
+ import { Plugin as Plugin5, PluginKey as PluginKey3 } from "@tiptap/pm/state";
3672
3848
  var Editable = Extension.create({
3673
3849
  name: "editable",
3674
3850
  addProseMirrorPlugins() {
3675
3851
  return [
3676
- new Plugin4({
3677
- key: new PluginKey2("editable"),
3852
+ new Plugin5({
3853
+ key: new PluginKey3("editable"),
3678
3854
  props: {
3679
3855
  editable: () => this.editor.options.editable
3680
3856
  }
@@ -3684,14 +3860,14 @@ var Editable = Extension.create({
3684
3860
  });
3685
3861
 
3686
3862
  // src/extensions/focusEvents.ts
3687
- import { Plugin as Plugin5, PluginKey as PluginKey3 } from "@tiptap/pm/state";
3863
+ import { Plugin as Plugin6, PluginKey as PluginKey4 } from "@tiptap/pm/state";
3688
3864
  var FocusEvents = Extension.create({
3689
3865
  name: "focusEvents",
3690
3866
  addProseMirrorPlugins() {
3691
3867
  const { editor } = this;
3692
3868
  return [
3693
- new Plugin5({
3694
- key: new PluginKey3("focusEvents"),
3869
+ new Plugin6({
3870
+ key: new PluginKey4("focusEvents"),
3695
3871
  props: {
3696
3872
  handleDOMEvents: {
3697
3873
  focus: (view, event) => {
@@ -3714,7 +3890,7 @@ var FocusEvents = Extension.create({
3714
3890
  });
3715
3891
 
3716
3892
  // src/extensions/keymap.ts
3717
- import { Plugin as Plugin6, PluginKey as PluginKey4, Selection as Selection3 } from "@tiptap/pm/state";
3893
+ import { Plugin as Plugin7, PluginKey as PluginKey5, Selection as Selection3 } from "@tiptap/pm/state";
3718
3894
  var Keymap = Extension.create({
3719
3895
  name: "keymap",
3720
3896
  addKeyboardShortcuts() {
@@ -3786,11 +3962,12 @@ var Keymap = Extension.create({
3786
3962
  // to a paragraph if necessary.
3787
3963
  // This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
3788
3964
  // with many other commands.
3789
- new Plugin6({
3790
- key: new PluginKey4("clearDocument"),
3965
+ new Plugin7({
3966
+ key: new PluginKey5("clearDocument"),
3791
3967
  appendTransaction: (transactions, oldState, newState) => {
3792
3968
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
3793
- if (!docChanges) {
3969
+ const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
3970
+ if (!docChanges || ignoreTr) {
3794
3971
  return;
3795
3972
  }
3796
3973
  const { empty, from, to } = oldState.selection;
@@ -3800,7 +3977,7 @@ var Keymap = Extension.create({
3800
3977
  if (empty || !allWasSelected) {
3801
3978
  return;
3802
3979
  }
3803
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, " ", " ").length === 0;
3980
+ const isEmpty = isNodeEmpty(newState.doc);
3804
3981
  if (!isEmpty) {
3805
3982
  return;
3806
3983
  }
@@ -3824,14 +4001,36 @@ var Keymap = Extension.create({
3824
4001
  }
3825
4002
  });
3826
4003
 
4004
+ // src/extensions/paste.ts
4005
+ import { Plugin as Plugin8, PluginKey as PluginKey6 } from "@tiptap/pm/state";
4006
+ var Paste = Extension.create({
4007
+ name: "paste",
4008
+ addProseMirrorPlugins() {
4009
+ return [
4010
+ new Plugin8({
4011
+ key: new PluginKey6("tiptapPaste"),
4012
+ props: {
4013
+ handlePaste: (_view, e, slice) => {
4014
+ this.editor.emit("paste", {
4015
+ editor: this.editor,
4016
+ event: e,
4017
+ slice
4018
+ });
4019
+ }
4020
+ }
4021
+ })
4022
+ ];
4023
+ }
4024
+ });
4025
+
3827
4026
  // src/extensions/tabindex.ts
3828
- import { Plugin as Plugin7, PluginKey as PluginKey5 } from "@tiptap/pm/state";
4027
+ import { Plugin as Plugin9, PluginKey as PluginKey7 } from "@tiptap/pm/state";
3829
4028
  var Tabindex = Extension.create({
3830
4029
  name: "tabindex",
3831
4030
  addProseMirrorPlugins() {
3832
4031
  return [
3833
- new Plugin7({
3834
- key: new PluginKey5("tabindex"),
4032
+ new Plugin9({
4033
+ key: new PluginKey7("tabindex"),
3835
4034
  props: {
3836
4035
  attributes: () => this.editor.isEditable ? { tabindex: "0" } : {}
3837
4036
  }
@@ -3935,7 +4134,8 @@ var NodePos = class _NodePos {
3935
4134
  const children = [];
3936
4135
  this.node.content.forEach((node, offset) => {
3937
4136
  const isBlock = node.isBlock && !node.isTextblock;
3938
- const targetPos = this.pos + offset + 1;
4137
+ const isNonTextAtom = node.isAtom && !node.isText;
4138
+ const targetPos = this.pos + offset + (isNonTextAtom ? 0 : 1);
3939
4139
  const $pos = this.resolvedPos.doc.resolve(targetPos);
3940
4140
  if (!isBlock && $pos.depth <= this.depth) {
3941
4141
  return;
@@ -4004,8 +4204,12 @@ var NodePos = class _NodePos {
4004
4204
  return nodes;
4005
4205
  }
4006
4206
  setAttribute(attributes) {
4007
- const oldSelection = this.editor.state.selection;
4008
- this.editor.chain().setTextSelection(this.from).updateAttributes(this.node.type.name, attributes).setTextSelection(oldSelection.from).run();
4207
+ const { tr } = this.editor.state;
4208
+ tr.setNodeMarkup(this.from, void 0, {
4209
+ ...this.node.attrs,
4210
+ ...attributes
4211
+ });
4212
+ this.editor.view.dispatch(tr);
4009
4213
  }
4010
4214
  };
4011
4215
 
@@ -4108,6 +4312,10 @@ var Editor = class extends EventEmitter {
4108
4312
  */
4109
4313
  this.isInitialized = false;
4110
4314
  this.extensionStorage = {};
4315
+ /**
4316
+ * A unique ID for this editor instance.
4317
+ */
4318
+ this.instanceId = Math.random().toString(36).slice(2, 9);
4111
4319
  this.options = {
4112
4320
  element: document.createElement("div"),
4113
4321
  content: "",
@@ -4133,7 +4341,9 @@ var Editor = class extends EventEmitter {
4133
4341
  onDestroy: () => null,
4134
4342
  onContentError: ({ error }) => {
4135
4343
  throw error;
4136
- }
4344
+ },
4345
+ onPaste: () => null,
4346
+ onDrop: () => null
4137
4347
  };
4138
4348
  this.isCapturingTransaction = false;
4139
4349
  this.capturedTransaction = null;
@@ -4153,6 +4363,8 @@ var Editor = class extends EventEmitter {
4153
4363
  this.on("focus", this.options.onFocus);
4154
4364
  this.on("blur", this.options.onBlur);
4155
4365
  this.on("destroy", this.options.onDestroy);
4366
+ this.on("drop", ({ event, slice, moved }) => this.options.onDrop(event, slice, moved));
4367
+ this.on("paste", ({ event, slice }) => this.options.onPaste(event, slice));
4156
4368
  window.setTimeout(() => {
4157
4369
  if (this.isDestroyed) {
4158
4370
  return;
@@ -4238,27 +4450,38 @@ var Editor = class extends EventEmitter {
4238
4450
  *
4239
4451
  * @param plugin A ProseMirror plugin
4240
4452
  * @param handlePlugins Control how to merge the plugin into the existing plugins.
4453
+ * @returns The new editor state
4241
4454
  */
4242
4455
  registerPlugin(plugin, handlePlugins) {
4243
4456
  const plugins = isFunction(handlePlugins) ? handlePlugins(plugin, [...this.state.plugins]) : [...this.state.plugins, plugin];
4244
4457
  const state = this.state.reconfigure({ plugins });
4245
4458
  this.view.updateState(state);
4459
+ return state;
4246
4460
  }
4247
4461
  /**
4248
4462
  * Unregister a ProseMirror plugin.
4249
4463
  *
4250
- * @param nameOrPluginKey The plugins name
4464
+ * @param nameOrPluginKeyToRemove The plugins name
4465
+ * @returns The new editor state or undefined if the editor is destroyed
4251
4466
  */
4252
- unregisterPlugin(nameOrPluginKey) {
4467
+ unregisterPlugin(nameOrPluginKeyToRemove) {
4253
4468
  if (this.isDestroyed) {
4254
- return;
4469
+ return void 0;
4470
+ }
4471
+ const prevPlugins = this.state.plugins;
4472
+ let plugins = prevPlugins;
4473
+ [].concat(nameOrPluginKeyToRemove).forEach((nameOrPluginKey) => {
4474
+ const name = typeof nameOrPluginKey === "string" ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
4475
+ plugins = prevPlugins.filter((plugin) => !plugin.key.startsWith(name));
4476
+ });
4477
+ if (prevPlugins.length === plugins.length) {
4478
+ return void 0;
4255
4479
  }
4256
- const name = typeof nameOrPluginKey === "string" ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
4257
4480
  const state = this.state.reconfigure({
4258
- // @ts-ignore
4259
- plugins: this.state.plugins.filter((plugin) => !plugin.key.startsWith(name))
4481
+ plugins
4260
4482
  });
4261
4483
  this.view.updateState(state);
4484
+ return state;
4262
4485
  }
4263
4486
  /**
4264
4487
  * Creates an extension manager.
@@ -4273,8 +4496,15 @@ var Editor = class extends EventEmitter {
4273
4496
  Commands,
4274
4497
  FocusEvents,
4275
4498
  Keymap,
4276
- Tabindex
4277
- ] : [];
4499
+ Tabindex,
4500
+ Drop,
4501
+ Paste
4502
+ ].filter((ext) => {
4503
+ if (typeof this.options.enableCoreExtensions === "object") {
4504
+ return this.options.enableCoreExtensions[ext.name] !== false;
4505
+ }
4506
+ return true;
4507
+ }) : [];
4278
4508
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter((extension) => {
4279
4509
  return ["extension", "node", "mark"].includes(extension == null ? void 0 : extension.type);
4280
4510
  });
@@ -4298,6 +4528,7 @@ var Editor = class extends EventEmitter {
4298
4528
  * Creates a ProseMirror view.
4299
4529
  */
4300
4530
  createView() {
4531
+ var _a;
4301
4532
  let doc;
4302
4533
  try {
4303
4534
  doc = createDocument(
@@ -4314,6 +4545,9 @@ var Editor = class extends EventEmitter {
4314
4545
  editor: this,
4315
4546
  error: e,
4316
4547
  disableCollaboration: () => {
4548
+ if (this.storage.collaboration) {
4549
+ this.storage.collaboration.isDisabled = true;
4550
+ }
4317
4551
  this.options.extensions = this.options.extensions.filter((extension) => extension.name !== "collaboration");
4318
4552
  this.createExtensionManager();
4319
4553
  }
@@ -4328,6 +4562,11 @@ var Editor = class extends EventEmitter {
4328
4562
  const selection = resolveFocusPosition(doc, this.options.autofocus);
4329
4563
  this.view = new EditorView(this.options.element, {
4330
4564
  ...this.options.editorProps,
4565
+ attributes: {
4566
+ // add `role="textbox"` to the editor element
4567
+ role: "textbox",
4568
+ ...(_a = this.options.editorProps) == null ? void 0 : _a.attributes
4569
+ },
4331
4570
  dispatchTransaction: this.dispatchTransaction.bind(this),
4332
4571
  state: EditorState4.create({
4333
4572
  doc,
@@ -4489,6 +4728,10 @@ var Editor = class extends EventEmitter {
4489
4728
  destroy() {
4490
4729
  this.emit("destroy");
4491
4730
  if (this.view) {
4731
+ const dom = this.view.dom;
4732
+ if (dom && dom.editor) {
4733
+ delete dom.editor;
4734
+ }
4492
4735
  this.view.destroy();
4493
4736
  }
4494
4737
  this.removeAllListeners();
@@ -4763,6 +5006,9 @@ var NodeView = class {
4763
5006
  this.extension = props.extension;
4764
5007
  this.node = props.node;
4765
5008
  this.decorations = props.decorations;
5009
+ this.innerDecorations = props.innerDecorations;
5010
+ this.view = props.view;
5011
+ this.HTMLAttributes = props.HTMLAttributes;
4766
5012
  this.getPos = props.getPos;
4767
5013
  this.mount();
4768
5014
  }
@@ -4794,7 +5040,11 @@ var NodeView = class {
4794
5040
  y = handleBox.y - domBox.y + offsetY;
4795
5041
  }
4796
5042
  (_g = event.dataTransfer) == null ? void 0 : _g.setDragImage(this.dom, x, y);
4797
- const selection = NodeSelection4.create(view.state.doc, this.getPos());
5043
+ const pos = this.getPos();
5044
+ if (typeof pos !== "number") {
5045
+ return;
5046
+ }
5047
+ const selection = NodeSelection4.create(view.state.doc, pos);
4798
5048
  const transaction = view.state.tr.setSelection(selection);
4799
5049
  view.dispatch(transaction);
4800
5050
  }
@@ -4825,10 +5075,10 @@ var NodeView = class {
4825
5075
  const isPasteEvent = event.type === "paste";
4826
5076
  const isCutEvent = event.type === "cut";
4827
5077
  const isClickEvent = event.type === "mousedown";
4828
- if (!isDraggable && isSelectable && isDragEvent) {
5078
+ if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
4829
5079
  event.preventDefault();
4830
5080
  }
4831
- if (isDraggable && isDragEvent && !isDragging) {
5081
+ if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
4832
5082
  event.preventDefault();
4833
5083
  return false;
4834
5084
  }
@@ -4865,6 +5115,11 @@ var NodeView = class {
4865
5115
  }
4866
5116
  return true;
4867
5117
  }
5118
+ /**
5119
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
5120
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
5121
+ * @return `true` if it can safely be ignored.
5122
+ */
4868
5123
  ignoreMutation(mutation) {
4869
5124
  if (!this.dom || !this.contentDOM) {
4870
5125
  return true;
@@ -4895,9 +5150,15 @@ var NodeView = class {
4895
5150
  }
4896
5151
  return true;
4897
5152
  }
5153
+ /**
5154
+ * Update the attributes of the prosemirror node.
5155
+ */
4898
5156
  updateAttributes(attributes) {
4899
5157
  this.editor.commands.command(({ tr }) => {
4900
5158
  const pos = this.getPos();
5159
+ if (typeof pos !== "number") {
5160
+ return false;
5161
+ }
4901
5162
  tr.setNodeMarkup(pos, void 0, {
4902
5163
  ...this.node.attrs,
4903
5164
  ...attributes
@@ -4905,8 +5166,14 @@ var NodeView = class {
4905
5166
  return true;
4906
5167
  });
4907
5168
  }
5169
+ /**
5170
+ * Delete the node.
5171
+ */
4908
5172
  deleteNode() {
4909
5173
  const from = this.getPos();
5174
+ if (typeof from !== "number") {
5175
+ return;
5176
+ }
4910
5177
  const to = from + this.node.nodeSize;
4911
5178
  this.editor.commands.deleteRange({ from, to });
4912
5179
  }