@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.cjs CHANGED
@@ -253,7 +253,7 @@ var CommandManager = class {
253
253
  };
254
254
 
255
255
  // src/Editor.ts
256
- var import_state18 = require("@tiptap/pm/state");
256
+ var import_state21 = require("@tiptap/pm/state");
257
257
  var import_view = require("@tiptap/pm/view");
258
258
 
259
259
  // src/EventEmitter.ts
@@ -286,6 +286,13 @@ var EventEmitter = class {
286
286
  }
287
287
  return this;
288
288
  }
289
+ once(event, fn) {
290
+ const onceFn = (...args) => {
291
+ this.off(event, onceFn);
292
+ fn.apply(this, args);
293
+ };
294
+ return this.on(event, onceFn);
295
+ }
289
296
  removeAllListeners() {
290
297
  this.callbacks = {};
291
298
  }
@@ -432,7 +439,18 @@ function mergeAttributes(...objects) {
432
439
  );
433
440
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
434
441
  } else if (key === "style") {
435
- mergedAttributes[key] = [mergedAttributes[key], value].join("; ");
442
+ const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
443
+ const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
444
+ const styleMap = /* @__PURE__ */ new Map();
445
+ existingStyles.forEach((style2) => {
446
+ const [property, val] = style2.split(":").map((part) => part.trim());
447
+ styleMap.set(property, val);
448
+ });
449
+ newStyles.forEach((style2) => {
450
+ const [property, val] = style2.split(":").map((part) => part.trim());
451
+ styleMap.set(property, val);
452
+ });
453
+ mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
436
454
  } else {
437
455
  mergedAttributes[key] = value;
438
456
  }
@@ -443,7 +461,9 @@ function mergeAttributes(...objects) {
443
461
 
444
462
  // src/helpers/getRenderedAttributes.ts
445
463
  function getRenderedAttributes(nodeOrMark, extensionAttributes) {
446
- return extensionAttributes.filter((item) => item.attribute.rendered).map((item) => {
464
+ return extensionAttributes.filter(
465
+ (attribute) => attribute.type === nodeOrMark.type.name
466
+ ).filter((item) => item.attribute.rendered).map((item) => {
447
467
  if (!item.attribute.renderHTML) {
448
468
  return {
449
469
  [item.name]: nodeOrMark.attrs[item.name]
@@ -577,6 +597,7 @@ function getSchemaByResolvedExtensions(extensions, editor) {
577
597
  ),
578
598
  code: callOrReturn(getExtensionField(extension, "code", context)),
579
599
  whitespace: callOrReturn(getExtensionField(extension, "whitespace", context)),
600
+ linebreakReplacement: callOrReturn(getExtensionField(extension, "linebreakReplacement", context)),
580
601
  defining: callOrReturn(
581
602
  getExtensionField(extension, "defining", context)
582
603
  ),
@@ -704,8 +725,19 @@ function isExtensionRulesEnabled(extension, enabled) {
704
725
  }
705
726
 
706
727
  // src/InputRule.ts
728
+ var import_model3 = require("@tiptap/pm/model");
707
729
  var import_state = require("@tiptap/pm/state");
708
730
 
731
+ // src/helpers/getHTMLFromFragment.ts
732
+ var import_model2 = require("@tiptap/pm/model");
733
+ function getHTMLFromFragment(fragment, schema) {
734
+ const documentFragment = import_model2.DOMSerializer.fromSchema(schema).serializeFragment(fragment);
735
+ const temporaryDocument = document.implementation.createHTMLDocument();
736
+ const container = temporaryDocument.createElement("div");
737
+ container.appendChild(documentFragment);
738
+ return container.innerHTML;
739
+ }
740
+
709
741
  // src/helpers/getTextContentFromNodes.ts
710
742
  var getTextContentFromNodes = ($from, maxMatch = 500) => {
711
743
  let textBefore = "";
@@ -834,7 +866,7 @@ function inputRulesPlugin(props) {
834
866
  init() {
835
867
  return null;
836
868
  },
837
- apply(tr, prev) {
869
+ apply(tr, prev, state) {
838
870
  const stored = tr.getMeta(plugin);
839
871
  if (stored) {
840
872
  return stored;
@@ -843,7 +875,13 @@ function inputRulesPlugin(props) {
843
875
  const isSimulatedInput = !!simulatedInputMeta;
844
876
  if (isSimulatedInput) {
845
877
  setTimeout(() => {
846
- const { from, text } = simulatedInputMeta;
878
+ let { text } = simulatedInputMeta;
879
+ if (typeof text === "string") {
880
+ text = text;
881
+ } else {
882
+ text = getHTMLFromFragment(import_model3.Fragment.from(text), state.schema);
883
+ }
884
+ const { from } = simulatedInputMeta;
847
885
  const to = from + text.length;
848
886
  run({
849
887
  editor,
@@ -1035,6 +1073,7 @@ var Mark = class _Mark {
1035
1073
  };
1036
1074
 
1037
1075
  // src/PasteRule.ts
1076
+ var import_model4 = require("@tiptap/pm/model");
1038
1077
  var import_state2 = require("@tiptap/pm/state");
1039
1078
 
1040
1079
  // src/utilities/isNumber.ts
@@ -1122,6 +1161,7 @@ function run2(config) {
1122
1161
  const success = handlers.every((handler) => handler !== null);
1123
1162
  return success;
1124
1163
  }
1164
+ var tiptapDragFromOtherEditor = null;
1125
1165
  var createClipboardPasteEvent = (text) => {
1126
1166
  var _a;
1127
1167
  const event = new ClipboardEvent("paste", {
@@ -1136,7 +1176,12 @@ function pasteRulesPlugin(props) {
1136
1176
  let isPastedFromProseMirror = false;
1137
1177
  let isDroppedFromProseMirror = false;
1138
1178
  let pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
1139
- let dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1179
+ let dropEvent;
1180
+ try {
1181
+ dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1182
+ } catch (e) {
1183
+ dropEvent = null;
1184
+ }
1140
1185
  const processEvent = ({
1141
1186
  state,
1142
1187
  from,
@@ -1161,7 +1206,11 @@ function pasteRulesPlugin(props) {
1161
1206
  if (!handler || !tr.steps.length) {
1162
1207
  return;
1163
1208
  }
1164
- dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1209
+ try {
1210
+ dropEvent = typeof DragEvent !== "undefined" ? new DragEvent("drop") : null;
1211
+ } catch (e) {
1212
+ dropEvent = null;
1213
+ }
1165
1214
  pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
1166
1215
  return tr;
1167
1216
  };
@@ -1172,11 +1221,21 @@ function pasteRulesPlugin(props) {
1172
1221
  const handleDragstart = (event) => {
1173
1222
  var _a;
1174
1223
  dragSourceElement = ((_a = view.dom.parentElement) == null ? void 0 : _a.contains(event.target)) ? view.dom.parentElement : null;
1224
+ if (dragSourceElement) {
1225
+ tiptapDragFromOtherEditor = editor;
1226
+ }
1227
+ };
1228
+ const handleDragend = () => {
1229
+ if (tiptapDragFromOtherEditor) {
1230
+ tiptapDragFromOtherEditor = null;
1231
+ }
1175
1232
  };
1176
1233
  window.addEventListener("dragstart", handleDragstart);
1234
+ window.addEventListener("dragend", handleDragend);
1177
1235
  return {
1178
1236
  destroy() {
1179
1237
  window.removeEventListener("dragstart", handleDragstart);
1238
+ window.removeEventListener("dragend", handleDragend);
1180
1239
  }
1181
1240
  };
1182
1241
  },
@@ -1185,6 +1244,17 @@ function pasteRulesPlugin(props) {
1185
1244
  drop: (view, event) => {
1186
1245
  isDroppedFromProseMirror = dragSourceElement === view.dom.parentElement;
1187
1246
  dropEvent = event;
1247
+ if (!isDroppedFromProseMirror) {
1248
+ const dragFromOtherEditor = tiptapDragFromOtherEditor;
1249
+ if (dragFromOtherEditor) {
1250
+ setTimeout(() => {
1251
+ const selection = dragFromOtherEditor.state.selection;
1252
+ if (selection) {
1253
+ dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to });
1254
+ }
1255
+ }, 10);
1256
+ }
1257
+ }
1188
1258
  return false;
1189
1259
  },
1190
1260
  paste: (_view, event) => {
@@ -1206,7 +1276,13 @@ function pasteRulesPlugin(props) {
1206
1276
  return;
1207
1277
  }
1208
1278
  if (isSimulatedPaste) {
1209
- const { from: from2, text } = simulatedPasteMeta;
1279
+ let { text } = simulatedPasteMeta;
1280
+ if (typeof text === "string") {
1281
+ text = text;
1282
+ } else {
1283
+ text = getHTMLFromFragment(import_model4.Fragment.from(text), state.schema);
1284
+ }
1285
+ const { from: from2 } = simulatedPasteMeta;
1210
1286
  const to2 = from2 + text.length;
1211
1287
  const pasteEvt = createClipboardPasteEvent(text);
1212
1288
  return processEvent({
@@ -1445,15 +1521,19 @@ var ExtensionManager = class _ExtensionManager {
1445
1521
  if (!addNodeView) {
1446
1522
  return [];
1447
1523
  }
1448
- const nodeview = (node, view, getPos, decorations) => {
1524
+ const nodeview = (node, view, getPos, decorations, innerDecorations) => {
1449
1525
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes);
1450
1526
  return addNodeView()({
1451
- editor,
1527
+ // pass-through
1452
1528
  node,
1529
+ view,
1453
1530
  getPos,
1454
1531
  decorations,
1455
- HTMLAttributes,
1456
- extension
1532
+ innerDecorations,
1533
+ // tiptap-specific
1534
+ editor,
1535
+ extension,
1536
+ HTMLAttributes
1457
1537
  });
1458
1538
  };
1459
1539
  return [extension.name, nodeview];
@@ -1534,9 +1614,11 @@ var extensions_exports = {};
1534
1614
  __export(extensions_exports, {
1535
1615
  ClipboardTextSerializer: () => ClipboardTextSerializer,
1536
1616
  Commands: () => Commands,
1617
+ Drop: () => Drop,
1537
1618
  Editable: () => Editable,
1538
1619
  FocusEvents: () => FocusEvents,
1539
1620
  Keymap: () => Keymap,
1621
+ Paste: () => Paste,
1540
1622
  Tabindex: () => Tabindex
1541
1623
  });
1542
1624
 
@@ -1913,23 +1995,29 @@ function objectIncludes(object1, object2, options = { strict: true }) {
1913
1995
  // src/helpers/getMarkRange.ts
1914
1996
  function findMarkInSet(marks, type, attributes = {}) {
1915
1997
  return marks.find((item) => {
1916
- return item.type === type && objectIncludes(item.attrs, attributes);
1998
+ return item.type === type && objectIncludes(
1999
+ // Only check equality for the attributes that are provided
2000
+ Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])),
2001
+ attributes
2002
+ );
1917
2003
  });
1918
2004
  }
1919
2005
  function isMarkInSet(marks, type, attributes = {}) {
1920
2006
  return !!findMarkInSet(marks, type, attributes);
1921
2007
  }
1922
- function getMarkRange($pos, type, attributes = {}) {
2008
+ function getMarkRange($pos, type, attributes) {
2009
+ var _a;
1923
2010
  if (!$pos || !type) {
1924
2011
  return;
1925
2012
  }
1926
2013
  let start = $pos.parent.childAfter($pos.parentOffset);
1927
- if ($pos.parentOffset === start.offset && start.offset !== 0) {
2014
+ if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
1928
2015
  start = $pos.parent.childBefore($pos.parentOffset);
1929
2016
  }
1930
- if (!start.node) {
2017
+ if (!start.node || !start.node.marks.some((mark2) => mark2.type === type)) {
1931
2018
  return;
1932
2019
  }
2020
+ attributes = attributes || ((_a = start.node.marks[0]) == null ? void 0 : _a.attrs);
1933
2021
  const mark = findMarkInSet([...start.node.marks], type, attributes);
1934
2022
  if (!mark) {
1935
2023
  return;
@@ -1938,8 +2026,7 @@ function getMarkRange($pos, type, attributes = {}) {
1938
2026
  let startPos = $pos.start() + start.offset;
1939
2027
  let endIndex = startIndex + 1;
1940
2028
  let endPos = startPos + start.node.nodeSize;
1941
- findMarkInSet([...start.node.marks], type, attributes);
1942
- while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) {
2029
+ while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
1943
2030
  startIndex -= 1;
1944
2031
  startPos -= $pos.parent.child(startIndex).nodeSize;
1945
2032
  }
@@ -2035,18 +2122,6 @@ function resolveFocusPosition(doc, position = null) {
2035
2122
  );
2036
2123
  }
2037
2124
 
2038
- // src/utilities/isiOS.ts
2039
- function isiOS() {
2040
- return [
2041
- "iPad Simulator",
2042
- "iPhone Simulator",
2043
- "iPod Simulator",
2044
- "iPad",
2045
- "iPhone",
2046
- "iPod"
2047
- ].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
2048
- }
2049
-
2050
2125
  // src/commands/focus.ts
2051
2126
  var focus = (position = null, options = {}) => ({
2052
2127
  editor,
@@ -2059,9 +2134,7 @@ var focus = (position = null, options = {}) => ({
2059
2134
  ...options
2060
2135
  };
2061
2136
  const delayedFocus = () => {
2062
- if (isiOS()) {
2063
- view.dom.focus();
2064
- }
2137
+ view.dom.focus();
2065
2138
  requestAnimationFrame(() => {
2066
2139
  if (!editor.isDestroyed) {
2067
2140
  view.focus();
@@ -2106,8 +2179,11 @@ var insertContent = (value, options) => ({ tr, commands }) => {
2106
2179
  );
2107
2180
  };
2108
2181
 
2182
+ // src/commands/insertContentAt.ts
2183
+ var import_model6 = require("@tiptap/pm/model");
2184
+
2109
2185
  // src/helpers/createNodeFromContent.ts
2110
- var import_model2 = require("@tiptap/pm/model");
2186
+ var import_model5 = require("@tiptap/pm/model");
2111
2187
 
2112
2188
  // src/utilities/elementFromString.ts
2113
2189
  var removeWhitespaces = (node) => {
@@ -2130,6 +2206,9 @@ function elementFromString(value) {
2130
2206
 
2131
2207
  // src/helpers/createNodeFromContent.ts
2132
2208
  function createNodeFromContent(content, schema, options) {
2209
+ if (content instanceof import_model5.Node || content instanceof import_model5.Fragment) {
2210
+ return content;
2211
+ }
2133
2212
  options = {
2134
2213
  slice: true,
2135
2214
  parseOptions: {},
@@ -2141,9 +2220,13 @@ function createNodeFromContent(content, schema, options) {
2141
2220
  try {
2142
2221
  const isArrayContent = Array.isArray(content) && content.length > 0;
2143
2222
  if (isArrayContent) {
2144
- return import_model2.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
2223
+ return import_model5.Fragment.fromArray(content.map((item) => schema.nodeFromJSON(item)));
2145
2224
  }
2146
- return schema.nodeFromJSON(content);
2225
+ const node = schema.nodeFromJSON(content);
2226
+ if (options.errorOnInvalidContent) {
2227
+ node.check();
2228
+ }
2229
+ return node;
2147
2230
  } catch (error) {
2148
2231
  if (options.errorOnInvalidContent) {
2149
2232
  throw new Error("[tiptap error]: Invalid JSON content", { cause: error });
@@ -2156,7 +2239,7 @@ function createNodeFromContent(content, schema, options) {
2156
2239
  if (options.errorOnInvalidContent) {
2157
2240
  let hasInvalidContent = false;
2158
2241
  let invalidContent = "";
2159
- const contentCheckSchema = new import_model2.Schema({
2242
+ const contentCheckSchema = new import_model5.Schema({
2160
2243
  topNode: schema.spec.topNode,
2161
2244
  marks: schema.spec.marks,
2162
2245
  // Prosemirror's schemas are executed such that: the last to execute, matches last
@@ -2179,15 +2262,15 @@ function createNodeFromContent(content, schema, options) {
2179
2262
  })
2180
2263
  });
2181
2264
  if (options.slice) {
2182
- import_model2.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
2265
+ import_model5.DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
2183
2266
  } else {
2184
- import_model2.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
2267
+ import_model5.DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
2185
2268
  }
2186
2269
  if (options.errorOnInvalidContent && hasInvalidContent) {
2187
2270
  throw new Error("[tiptap error]: Invalid HTML content", { cause: new Error(`Invalid element found: ${invalidContent}`) });
2188
2271
  }
2189
2272
  }
2190
- const parser = import_model2.DOMParser.fromSchema(schema);
2273
+ const parser = import_model5.DOMParser.fromSchema(schema);
2191
2274
  if (options.slice) {
2192
2275
  return parser.parseSlice(elementFromString(content), options.parseOptions).content;
2193
2276
  }
@@ -2226,13 +2309,14 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2226
2309
  var _a;
2227
2310
  if (dispatch) {
2228
2311
  options = {
2229
- parseOptions: {},
2312
+ parseOptions: editor.options.parseOptions,
2230
2313
  updateSelection: true,
2231
2314
  applyInputRules: false,
2232
2315
  applyPasteRules: false,
2233
2316
  ...options
2234
2317
  };
2235
2318
  let content;
2319
+ const { selection } = editor.state;
2236
2320
  try {
2237
2321
  content = createNodeFromContent(value, editor.schema, {
2238
2322
  parseOptions: {
@@ -2246,7 +2330,9 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2246
2330
  editor,
2247
2331
  error: e,
2248
2332
  disableCollaboration: () => {
2249
- console.error("[tiptap error]: Unable to disable collaboration at this point in time");
2333
+ if (editor.storage.collaboration) {
2334
+ editor.storage.collaboration.isDisabled = true;
2335
+ }
2250
2336
  }
2251
2337
  });
2252
2338
  return false;
@@ -2272,6 +2358,14 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2272
2358
  if (isOnlyTextContent) {
2273
2359
  if (Array.isArray(value)) {
2274
2360
  newContent = value.map((v) => v.text || "").join("");
2361
+ } else if (value instanceof import_model6.Fragment) {
2362
+ let text = "";
2363
+ value.forEach((node) => {
2364
+ if (node.text) {
2365
+ text += node.text;
2366
+ }
2367
+ });
2368
+ newContent = text;
2275
2369
  } else if (typeof value === "object" && !!value && !!value.text) {
2276
2370
  newContent = value.text;
2277
2371
  } else {
@@ -2280,6 +2374,11 @@ var insertContentAt = (position, value, options) => ({ tr, dispatch, editor }) =
2280
2374
  tr.insertText(newContent, from, to);
2281
2375
  } else {
2282
2376
  newContent = content;
2377
+ const fromSelectionAtStart = selection.$from.parentOffset === 0;
2378
+ const isTextSelection2 = selection.$from.node().isText || selection.$from.node().isTextblock;
2379
+ if (fromSelectionAtStart && isTextSelection2) {
2380
+ from = Math.max(0, from - 1);
2381
+ }
2283
2382
  tr.replaceWith(from, to, newContent);
2284
2383
  }
2285
2384
  if (options.updateSelection) {
@@ -2366,6 +2465,18 @@ var joinTextblockForward = () => ({ state, dispatch }) => {
2366
2465
  return (0, import_commands6.joinTextblockForward)(state, dispatch);
2367
2466
  };
2368
2467
 
2468
+ // src/utilities/isiOS.ts
2469
+ function isiOS() {
2470
+ return [
2471
+ "iPad Simulator",
2472
+ "iPhone Simulator",
2473
+ "iPod Simulator",
2474
+ "iPad",
2475
+ "iPhone",
2476
+ "iPod"
2477
+ ].includes(navigator.platform) || navigator.userAgent.includes("Mac") && "ontouchend" in document;
2478
+ }
2479
+
2369
2480
  // src/utilities/isMacOS.ts
2370
2481
  function isMacOS() {
2371
2482
  return typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
@@ -2579,11 +2690,13 @@ var scrollIntoView = () => ({ tr, dispatch }) => {
2579
2690
  };
2580
2691
 
2581
2692
  // src/commands/selectAll.ts
2582
- var selectAll = () => ({ tr, commands }) => {
2583
- return commands.setTextSelection({
2584
- from: 0,
2585
- to: tr.doc.content.size
2586
- });
2693
+ var import_state9 = require("@tiptap/pm/state");
2694
+ var selectAll = () => ({ tr, dispatch }) => {
2695
+ if (dispatch) {
2696
+ const selection = new import_state9.AllSelection(tr.doc);
2697
+ tr.setSelection(selection);
2698
+ }
2699
+ return true;
2587
2700
  };
2588
2701
 
2589
2702
  // src/commands/selectNodeBackward.ts
@@ -2646,14 +2759,10 @@ var setContent = (content, emitUpdate = false, parseOptions = {}, options = {})
2646
2759
  if (dispatch) {
2647
2760
  tr.setMeta("preventUpdate", !emitUpdate);
2648
2761
  }
2649
- return commands.insertContentAt(
2650
- { from: 0, to: doc.content.size },
2651
- content,
2652
- {
2653
- parseOptions,
2654
- errorOnInvalidContent: (_b = options.errorOnInvalidContent) != null ? _b : editor.options.enableContentCheck
2655
- }
2656
- );
2762
+ return commands.insertContentAt({ from: 0, to: doc.content.size }, content, {
2763
+ parseOptions,
2764
+ errorOnInvalidContent: (_b = options.errorOnInvalidContent) != null ? _b : editor.options.enableContentCheck
2765
+ });
2657
2766
  };
2658
2767
 
2659
2768
  // src/helpers/getMarkAttributes.ts
@@ -2750,17 +2859,7 @@ function findParentNode(predicate) {
2750
2859
  }
2751
2860
 
2752
2861
  // src/helpers/generateHTML.ts
2753
- var import_model4 = require("@tiptap/pm/model");
2754
-
2755
- // src/helpers/getHTMLFromFragment.ts
2756
- var import_model3 = require("@tiptap/pm/model");
2757
- function getHTMLFromFragment(fragment, schema) {
2758
- const documentFragment = import_model3.DOMSerializer.fromSchema(schema).serializeFragment(fragment);
2759
- const temporaryDocument = document.implementation.createHTMLDocument();
2760
- const container = temporaryDocument.createElement("div");
2761
- container.appendChild(documentFragment);
2762
- return container.innerHTML;
2763
- }
2862
+ var import_model7 = require("@tiptap/pm/model");
2764
2863
 
2765
2864
  // src/helpers/getSchema.ts
2766
2865
  function getSchema(extensions, editor) {
@@ -2771,20 +2870,20 @@ function getSchema(extensions, editor) {
2771
2870
  // src/helpers/generateHTML.ts
2772
2871
  function generateHTML(doc, extensions) {
2773
2872
  const schema = getSchema(extensions);
2774
- const contentNode = import_model4.Node.fromJSON(schema, doc);
2873
+ const contentNode = import_model7.Node.fromJSON(schema, doc);
2775
2874
  return getHTMLFromFragment(contentNode.content, schema);
2776
2875
  }
2777
2876
 
2778
2877
  // src/helpers/generateJSON.ts
2779
- var import_model5 = require("@tiptap/pm/model");
2878
+ var import_model8 = require("@tiptap/pm/model");
2780
2879
  function generateJSON(html, extensions) {
2781
2880
  const schema = getSchema(extensions);
2782
2881
  const dom = elementFromString(html);
2783
- return import_model5.DOMParser.fromSchema(schema).parse(dom).toJSON();
2882
+ return import_model8.DOMParser.fromSchema(schema).parse(dom).toJSON();
2784
2883
  }
2785
2884
 
2786
2885
  // src/helpers/generateText.ts
2787
- var import_model6 = require("@tiptap/pm/model");
2886
+ var import_model9 = require("@tiptap/pm/model");
2788
2887
 
2789
2888
  // src/helpers/getText.ts
2790
2889
  function getText(node, options) {
@@ -2799,7 +2898,7 @@ function getText(node, options) {
2799
2898
  function generateText(doc, extensions, options) {
2800
2899
  const { blockSeparator = "\n\n", textSerializers = {} } = options || {};
2801
2900
  const schema = getSchema(extensions);
2802
- const contentNode = import_model6.Node.fromJSON(schema, doc);
2901
+ const contentNode = import_model9.Node.fromJSON(schema, doc);
2803
2902
  return getText(contentNode, {
2804
2903
  blockSeparator,
2805
2904
  textSerializers: {
@@ -3150,9 +3249,9 @@ function isNodeEmpty(node, {
3150
3249
  }
3151
3250
 
3152
3251
  // src/helpers/isNodeSelection.ts
3153
- var import_state9 = require("@tiptap/pm/state");
3252
+ var import_state10 = require("@tiptap/pm/state");
3154
3253
  function isNodeSelection(value) {
3155
- return value instanceof import_state9.NodeSelection;
3254
+ return value instanceof import_state10.NodeSelection;
3156
3255
  }
3157
3256
 
3158
3257
  // src/helpers/posToDOMRect.ts
@@ -3270,44 +3369,48 @@ var setMeta = (key, value) => ({ tr }) => {
3270
3369
  var import_commands15 = require("@tiptap/pm/commands");
3271
3370
  var setNode = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
3272
3371
  const type = getNodeType(typeOrName, state.schema);
3372
+ let attributesToCopy;
3373
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3374
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3375
+ }
3273
3376
  if (!type.isTextblock) {
3274
3377
  console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.');
3275
3378
  return false;
3276
3379
  }
3277
3380
  return chain().command(({ commands }) => {
3278
- const canSetBlock = (0, import_commands15.setBlockType)(type, attributes)(state);
3381
+ const canSetBlock = (0, import_commands15.setBlockType)(type, { ...attributesToCopy, ...attributes })(state);
3279
3382
  if (canSetBlock) {
3280
3383
  return true;
3281
3384
  }
3282
3385
  return commands.clearNodes();
3283
3386
  }).command(({ state: updatedState }) => {
3284
- return (0, import_commands15.setBlockType)(type, attributes)(updatedState, dispatch);
3387
+ return (0, import_commands15.setBlockType)(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch);
3285
3388
  }).run();
3286
3389
  };
3287
3390
 
3288
3391
  // src/commands/setNodeSelection.ts
3289
- var import_state10 = require("@tiptap/pm/state");
3392
+ var import_state11 = require("@tiptap/pm/state");
3290
3393
  var setNodeSelection = (position) => ({ tr, dispatch }) => {
3291
3394
  if (dispatch) {
3292
3395
  const { doc } = tr;
3293
3396
  const from = minMax(position, 0, doc.content.size);
3294
- const selection = import_state10.NodeSelection.create(doc, from);
3397
+ const selection = import_state11.NodeSelection.create(doc, from);
3295
3398
  tr.setSelection(selection);
3296
3399
  }
3297
3400
  return true;
3298
3401
  };
3299
3402
 
3300
3403
  // src/commands/setTextSelection.ts
3301
- var import_state11 = require("@tiptap/pm/state");
3404
+ var import_state12 = require("@tiptap/pm/state");
3302
3405
  var setTextSelection = (position) => ({ tr, dispatch }) => {
3303
3406
  if (dispatch) {
3304
3407
  const { doc } = tr;
3305
3408
  const { from, to } = typeof position === "number" ? { from: position, to: position } : position;
3306
- const minPos = import_state11.TextSelection.atStart(doc).from;
3307
- const maxPos = import_state11.TextSelection.atEnd(doc).to;
3409
+ const minPos = import_state12.TextSelection.atStart(doc).from;
3410
+ const maxPos = import_state12.TextSelection.atEnd(doc).to;
3308
3411
  const resolvedFrom = minMax(from, minPos, maxPos);
3309
3412
  const resolvedEnd = minMax(to, minPos, maxPos);
3310
- const selection = import_state11.TextSelection.create(doc, resolvedFrom, resolvedEnd);
3413
+ const selection = import_state12.TextSelection.create(doc, resolvedFrom, resolvedEnd);
3311
3414
  tr.setSelection(selection);
3312
3415
  }
3313
3416
  return true;
@@ -3321,7 +3424,7 @@ var sinkListItem = (typeOrName) => ({ state, dispatch }) => {
3321
3424
  };
3322
3425
 
3323
3426
  // src/commands/splitBlock.ts
3324
- var import_state12 = require("@tiptap/pm/state");
3427
+ var import_state13 = require("@tiptap/pm/state");
3325
3428
  var import_transform6 = require("@tiptap/pm/transform");
3326
3429
  function ensureMarks(state, splittableMarks) {
3327
3430
  const marks = state.storedMarks || state.selection.$to.parentOffset && state.selection.$from.marks();
@@ -3344,7 +3447,7 @@ var splitBlock = ({ keepMarks = true } = {}) => ({
3344
3447
  $from.node().type.name,
3345
3448
  $from.node().attrs
3346
3449
  );
3347
- if (selection instanceof import_state12.NodeSelection && selection.node.isBlock) {
3450
+ if (selection instanceof import_state13.NodeSelection && selection.node.isBlock) {
3348
3451
  if (!$from.parentOffset || !(0, import_transform6.canSplit)(doc, $from.pos)) {
3349
3452
  return false;
3350
3453
  }
@@ -3379,7 +3482,7 @@ var splitBlock = ({ keepMarks = true } = {}) => ({
3379
3482
  }
3380
3483
  if (dispatch) {
3381
3484
  if (can) {
3382
- if (selection instanceof import_state12.TextSelection) {
3485
+ if (selection instanceof import_state13.TextSelection) {
3383
3486
  tr.deleteSelection();
3384
3487
  }
3385
3488
  tr.split(tr.mapping.map($from.pos), 1, types);
@@ -3400,8 +3503,8 @@ var splitBlock = ({ keepMarks = true } = {}) => ({
3400
3503
  };
3401
3504
 
3402
3505
  // src/commands/splitListItem.ts
3403
- var import_model7 = require("@tiptap/pm/model");
3404
- var import_state13 = require("@tiptap/pm/state");
3506
+ var import_model10 = require("@tiptap/pm/model");
3507
+ var import_state14 = require("@tiptap/pm/state");
3405
3508
  var import_transform7 = require("@tiptap/pm/transform");
3406
3509
  var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3407
3510
  tr,
@@ -3426,10 +3529,10 @@ var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3426
3529
  return false;
3427
3530
  }
3428
3531
  if (dispatch) {
3429
- let wrap = import_model7.Fragment.empty;
3532
+ let wrap = import_model10.Fragment.empty;
3430
3533
  const depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
3431
3534
  for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d -= 1) {
3432
- wrap = import_model7.Fragment.from($from.node(d).copy(wrap));
3535
+ wrap = import_model10.Fragment.from($from.node(d).copy(wrap));
3433
3536
  }
3434
3537
  const depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
3435
3538
  const newNextTypeAttributes2 = {
@@ -3441,9 +3544,9 @@ var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3441
3544
  ...overrideAttrs
3442
3545
  };
3443
3546
  const nextType2 = ((_a = type.contentMatch.defaultType) == null ? void 0 : _a.createAndFill(newNextTypeAttributes2)) || void 0;
3444
- wrap = wrap.append(import_model7.Fragment.from(type.createAndFill(null, nextType2) || void 0));
3547
+ wrap = wrap.append(import_model10.Fragment.from(type.createAndFill(null, nextType2) || void 0));
3445
3548
  const start = $from.before($from.depth - (depthBefore - 1));
3446
- tr.replace(start, $from.after(-depthAfter), new import_model7.Slice(wrap, 4 - depthBefore, 0));
3549
+ tr.replace(start, $from.after(-depthAfter), new import_model10.Slice(wrap, 4 - depthBefore, 0));
3447
3550
  let sel = -1;
3448
3551
  tr.doc.nodesBetween(start, tr.doc.content.size, (n, pos) => {
3449
3552
  if (sel > -1) {
@@ -3454,7 +3557,7 @@ var splitListItem = (typeOrName, overrideAttrs = {}) => ({
3454
3557
  }
3455
3558
  });
3456
3559
  if (sel > -1) {
3457
- tr.setSelection(import_state13.TextSelection.near(tr.doc.resolve(sel)));
3560
+ tr.setSelection(import_state14.TextSelection.near(tr.doc.resolve(sel)));
3458
3561
  }
3459
3562
  tr.scrollIntoView();
3460
3563
  }
@@ -3602,10 +3705,14 @@ var toggleNode = (typeOrName, toggleTypeOrName, attributes = {}) => ({ state, co
3602
3705
  const type = getNodeType(typeOrName, state.schema);
3603
3706
  const toggleType = getNodeType(toggleTypeOrName, state.schema);
3604
3707
  const isActive2 = isNodeActive(state, type, attributes);
3708
+ let attributesToCopy;
3709
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
3710
+ attributesToCopy = state.selection.$anchor.parent.attrs;
3711
+ }
3605
3712
  if (isActive2) {
3606
- return commands.setNode(toggleType);
3713
+ return commands.setNode(toggleType, attributesToCopy);
3607
3714
  }
3608
- return commands.setNode(type, attributes);
3715
+ return commands.setNode(type, { ...attributesToCopy, ...attributes });
3609
3716
  };
3610
3717
 
3611
3718
  // src/commands/toggleWrap.ts
@@ -3708,18 +3815,63 @@ var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }
3708
3815
  tr.selection.ranges.forEach((range) => {
3709
3816
  const from = range.$from.pos;
3710
3817
  const to = range.$to.pos;
3711
- state.doc.nodesBetween(from, to, (node, pos) => {
3712
- if (nodeType && nodeType === node.type) {
3713
- tr.setNodeMarkup(pos, void 0, {
3714
- ...node.attrs,
3818
+ let lastPos;
3819
+ let lastNode;
3820
+ let trimmedFrom;
3821
+ let trimmedTo;
3822
+ if (tr.selection.empty) {
3823
+ state.doc.nodesBetween(from, to, (node, pos) => {
3824
+ if (nodeType && nodeType === node.type) {
3825
+ trimmedFrom = Math.max(pos, from);
3826
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3827
+ lastPos = pos;
3828
+ lastNode = node;
3829
+ }
3830
+ });
3831
+ } else {
3832
+ state.doc.nodesBetween(from, to, (node, pos) => {
3833
+ if (pos < from && nodeType && nodeType === node.type) {
3834
+ trimmedFrom = Math.max(pos, from);
3835
+ trimmedTo = Math.min(pos + node.nodeSize, to);
3836
+ lastPos = pos;
3837
+ lastNode = node;
3838
+ }
3839
+ if (pos >= from && pos <= to) {
3840
+ if (nodeType && nodeType === node.type) {
3841
+ tr.setNodeMarkup(pos, void 0, {
3842
+ ...node.attrs,
3843
+ ...attributes
3844
+ });
3845
+ }
3846
+ if (markType && node.marks.length) {
3847
+ node.marks.forEach((mark) => {
3848
+ if (markType === mark.type) {
3849
+ const trimmedFrom2 = Math.max(pos, from);
3850
+ const trimmedTo2 = Math.min(pos + node.nodeSize, to);
3851
+ tr.addMark(
3852
+ trimmedFrom2,
3853
+ trimmedTo2,
3854
+ markType.create({
3855
+ ...mark.attrs,
3856
+ ...attributes
3857
+ })
3858
+ );
3859
+ }
3860
+ });
3861
+ }
3862
+ }
3863
+ });
3864
+ }
3865
+ if (lastNode) {
3866
+ if (lastPos !== void 0) {
3867
+ tr.setNodeMarkup(lastPos, void 0, {
3868
+ ...lastNode.attrs,
3715
3869
  ...attributes
3716
3870
  });
3717
3871
  }
3718
- if (markType && node.marks.length) {
3719
- node.marks.forEach((mark) => {
3872
+ if (markType && lastNode.marks.length) {
3873
+ lastNode.marks.forEach((mark) => {
3720
3874
  if (markType === mark.type) {
3721
- const trimmedFrom = Math.max(pos, from);
3722
- const trimmedTo = Math.min(pos + node.nodeSize, to);
3723
3875
  tr.addMark(
3724
3876
  trimmedFrom,
3725
3877
  trimmedTo,
@@ -3731,7 +3883,7 @@ var updateAttributes = (typeOrName, attributes = {}) => ({ tr, state, dispatch }
3731
3883
  }
3732
3884
  });
3733
3885
  }
3734
- });
3886
+ }
3735
3887
  });
3736
3888
  }
3737
3889
  return true;
@@ -3761,14 +3913,37 @@ var Commands = Extension.create({
3761
3913
  }
3762
3914
  });
3763
3915
 
3916
+ // src/extensions/drop.ts
3917
+ var import_state15 = require("@tiptap/pm/state");
3918
+ var Drop = Extension.create({
3919
+ name: "drop",
3920
+ addProseMirrorPlugins() {
3921
+ return [
3922
+ new import_state15.Plugin({
3923
+ key: new import_state15.PluginKey("tiptapDrop"),
3924
+ props: {
3925
+ handleDrop: (_, e, slice, moved) => {
3926
+ this.editor.emit("drop", {
3927
+ editor: this.editor,
3928
+ event: e,
3929
+ slice,
3930
+ moved
3931
+ });
3932
+ }
3933
+ }
3934
+ })
3935
+ ];
3936
+ }
3937
+ });
3938
+
3764
3939
  // src/extensions/editable.ts
3765
- var import_state14 = require("@tiptap/pm/state");
3940
+ var import_state16 = require("@tiptap/pm/state");
3766
3941
  var Editable = Extension.create({
3767
3942
  name: "editable",
3768
3943
  addProseMirrorPlugins() {
3769
3944
  return [
3770
- new import_state14.Plugin({
3771
- key: new import_state14.PluginKey("editable"),
3945
+ new import_state16.Plugin({
3946
+ key: new import_state16.PluginKey("editable"),
3772
3947
  props: {
3773
3948
  editable: () => this.editor.options.editable
3774
3949
  }
@@ -3778,14 +3953,14 @@ var Editable = Extension.create({
3778
3953
  });
3779
3954
 
3780
3955
  // src/extensions/focusEvents.ts
3781
- var import_state15 = require("@tiptap/pm/state");
3956
+ var import_state17 = require("@tiptap/pm/state");
3782
3957
  var FocusEvents = Extension.create({
3783
3958
  name: "focusEvents",
3784
3959
  addProseMirrorPlugins() {
3785
3960
  const { editor } = this;
3786
3961
  return [
3787
- new import_state15.Plugin({
3788
- key: new import_state15.PluginKey("focusEvents"),
3962
+ new import_state17.Plugin({
3963
+ key: new import_state17.PluginKey("focusEvents"),
3789
3964
  props: {
3790
3965
  handleDOMEvents: {
3791
3966
  focus: (view, event) => {
@@ -3808,7 +3983,7 @@ var FocusEvents = Extension.create({
3808
3983
  });
3809
3984
 
3810
3985
  // src/extensions/keymap.ts
3811
- var import_state16 = require("@tiptap/pm/state");
3986
+ var import_state18 = require("@tiptap/pm/state");
3812
3987
  var Keymap = Extension.create({
3813
3988
  name: "keymap",
3814
3989
  addKeyboardShortcuts() {
@@ -3822,7 +3997,7 @@ var Keymap = Extension.create({
3822
3997
  const $parentPos = $anchor.parent.isTextblock && pos > 0 ? tr.doc.resolve(pos - 1) : $anchor;
3823
3998
  const parentIsIsolating = $parentPos.parent.type.spec.isolating;
3824
3999
  const parentPos = $anchor.pos - $anchor.parentOffset;
3825
- const isAtStart = parentIsIsolating && $parentPos.parent.childCount === 1 ? parentPos === $anchor.pos : import_state16.Selection.atStart(doc).from === pos;
4000
+ const isAtStart = parentIsIsolating && $parentPos.parent.childCount === 1 ? parentPos === $anchor.pos : import_state18.Selection.atStart(doc).from === pos;
3826
4001
  if (!empty || !parent.type.isTextblock || parent.textContent.length || !isAtStart || isAtStart && $anchor.parent.type.name === "paragraph") {
3827
4002
  return false;
3828
4003
  }
@@ -3880,21 +4055,22 @@ var Keymap = Extension.create({
3880
4055
  // to a paragraph if necessary.
3881
4056
  // This is an alternative to ProseMirror's `AllSelection`, which doesn’t work well
3882
4057
  // with many other commands.
3883
- new import_state16.Plugin({
3884
- key: new import_state16.PluginKey("clearDocument"),
4058
+ new import_state18.Plugin({
4059
+ key: new import_state18.PluginKey("clearDocument"),
3885
4060
  appendTransaction: (transactions, oldState, newState) => {
3886
4061
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
3887
- if (!docChanges) {
4062
+ const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
4063
+ if (!docChanges || ignoreTr) {
3888
4064
  return;
3889
4065
  }
3890
4066
  const { empty, from, to } = oldState.selection;
3891
- const allFrom = import_state16.Selection.atStart(oldState.doc).from;
3892
- const allEnd = import_state16.Selection.atEnd(oldState.doc).to;
4067
+ const allFrom = import_state18.Selection.atStart(oldState.doc).from;
4068
+ const allEnd = import_state18.Selection.atEnd(oldState.doc).to;
3893
4069
  const allWasSelected = from === allFrom && to === allEnd;
3894
4070
  if (empty || !allWasSelected) {
3895
4071
  return;
3896
4072
  }
3897
- const isEmpty = newState.doc.textBetween(0, newState.doc.content.size, " ", " ").length === 0;
4073
+ const isEmpty = isNodeEmpty(newState.doc);
3898
4074
  if (!isEmpty) {
3899
4075
  return;
3900
4076
  }
@@ -3918,14 +4094,36 @@ var Keymap = Extension.create({
3918
4094
  }
3919
4095
  });
3920
4096
 
4097
+ // src/extensions/paste.ts
4098
+ var import_state19 = require("@tiptap/pm/state");
4099
+ var Paste = Extension.create({
4100
+ name: "paste",
4101
+ addProseMirrorPlugins() {
4102
+ return [
4103
+ new import_state19.Plugin({
4104
+ key: new import_state19.PluginKey("tiptapPaste"),
4105
+ props: {
4106
+ handlePaste: (_view, e, slice) => {
4107
+ this.editor.emit("paste", {
4108
+ editor: this.editor,
4109
+ event: e,
4110
+ slice
4111
+ });
4112
+ }
4113
+ }
4114
+ })
4115
+ ];
4116
+ }
4117
+ });
4118
+
3921
4119
  // src/extensions/tabindex.ts
3922
- var import_state17 = require("@tiptap/pm/state");
4120
+ var import_state20 = require("@tiptap/pm/state");
3923
4121
  var Tabindex = Extension.create({
3924
4122
  name: "tabindex",
3925
4123
  addProseMirrorPlugins() {
3926
4124
  return [
3927
- new import_state17.Plugin({
3928
- key: new import_state17.PluginKey("tabindex"),
4125
+ new import_state20.Plugin({
4126
+ key: new import_state20.PluginKey("tabindex"),
3929
4127
  props: {
3930
4128
  attributes: () => this.editor.isEditable ? { tabindex: "0" } : {}
3931
4129
  }
@@ -4029,7 +4227,8 @@ var NodePos = class _NodePos {
4029
4227
  const children = [];
4030
4228
  this.node.content.forEach((node, offset) => {
4031
4229
  const isBlock = node.isBlock && !node.isTextblock;
4032
- const targetPos = this.pos + offset + 1;
4230
+ const isNonTextAtom = node.isAtom && !node.isText;
4231
+ const targetPos = this.pos + offset + (isNonTextAtom ? 0 : 1);
4033
4232
  const $pos = this.resolvedPos.doc.resolve(targetPos);
4034
4233
  if (!isBlock && $pos.depth <= this.depth) {
4035
4234
  return;
@@ -4098,8 +4297,12 @@ var NodePos = class _NodePos {
4098
4297
  return nodes;
4099
4298
  }
4100
4299
  setAttribute(attributes) {
4101
- const oldSelection = this.editor.state.selection;
4102
- this.editor.chain().setTextSelection(this.from).updateAttributes(this.node.type.name, attributes).setTextSelection(oldSelection.from).run();
4300
+ const { tr } = this.editor.state;
4301
+ tr.setNodeMarkup(this.from, void 0, {
4302
+ ...this.node.attrs,
4303
+ ...attributes
4304
+ });
4305
+ this.editor.view.dispatch(tr);
4103
4306
  }
4104
4307
  };
4105
4308
 
@@ -4202,6 +4405,10 @@ var Editor = class extends EventEmitter {
4202
4405
  */
4203
4406
  this.isInitialized = false;
4204
4407
  this.extensionStorage = {};
4408
+ /**
4409
+ * A unique ID for this editor instance.
4410
+ */
4411
+ this.instanceId = Math.random().toString(36).slice(2, 9);
4205
4412
  this.options = {
4206
4413
  element: document.createElement("div"),
4207
4414
  content: "",
@@ -4227,7 +4434,9 @@ var Editor = class extends EventEmitter {
4227
4434
  onDestroy: () => null,
4228
4435
  onContentError: ({ error }) => {
4229
4436
  throw error;
4230
- }
4437
+ },
4438
+ onPaste: () => null,
4439
+ onDrop: () => null
4231
4440
  };
4232
4441
  this.isCapturingTransaction = false;
4233
4442
  this.capturedTransaction = null;
@@ -4247,6 +4456,8 @@ var Editor = class extends EventEmitter {
4247
4456
  this.on("focus", this.options.onFocus);
4248
4457
  this.on("blur", this.options.onBlur);
4249
4458
  this.on("destroy", this.options.onDestroy);
4459
+ this.on("drop", ({ event, slice, moved }) => this.options.onDrop(event, slice, moved));
4460
+ this.on("paste", ({ event, slice }) => this.options.onPaste(event, slice));
4250
4461
  window.setTimeout(() => {
4251
4462
  if (this.isDestroyed) {
4252
4463
  return;
@@ -4332,27 +4543,38 @@ var Editor = class extends EventEmitter {
4332
4543
  *
4333
4544
  * @param plugin A ProseMirror plugin
4334
4545
  * @param handlePlugins Control how to merge the plugin into the existing plugins.
4546
+ * @returns The new editor state
4335
4547
  */
4336
4548
  registerPlugin(plugin, handlePlugins) {
4337
4549
  const plugins = isFunction(handlePlugins) ? handlePlugins(plugin, [...this.state.plugins]) : [...this.state.plugins, plugin];
4338
4550
  const state = this.state.reconfigure({ plugins });
4339
4551
  this.view.updateState(state);
4552
+ return state;
4340
4553
  }
4341
4554
  /**
4342
4555
  * Unregister a ProseMirror plugin.
4343
4556
  *
4344
- * @param nameOrPluginKey The plugins name
4557
+ * @param nameOrPluginKeyToRemove The plugins name
4558
+ * @returns The new editor state or undefined if the editor is destroyed
4345
4559
  */
4346
- unregisterPlugin(nameOrPluginKey) {
4560
+ unregisterPlugin(nameOrPluginKeyToRemove) {
4347
4561
  if (this.isDestroyed) {
4348
- return;
4562
+ return void 0;
4563
+ }
4564
+ const prevPlugins = this.state.plugins;
4565
+ let plugins = prevPlugins;
4566
+ [].concat(nameOrPluginKeyToRemove).forEach((nameOrPluginKey) => {
4567
+ const name = typeof nameOrPluginKey === "string" ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
4568
+ plugins = prevPlugins.filter((plugin) => !plugin.key.startsWith(name));
4569
+ });
4570
+ if (prevPlugins.length === plugins.length) {
4571
+ return void 0;
4349
4572
  }
4350
- const name = typeof nameOrPluginKey === "string" ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
4351
4573
  const state = this.state.reconfigure({
4352
- // @ts-ignore
4353
- plugins: this.state.plugins.filter((plugin) => !plugin.key.startsWith(name))
4574
+ plugins
4354
4575
  });
4355
4576
  this.view.updateState(state);
4577
+ return state;
4356
4578
  }
4357
4579
  /**
4358
4580
  * Creates an extension manager.
@@ -4367,8 +4589,15 @@ var Editor = class extends EventEmitter {
4367
4589
  Commands,
4368
4590
  FocusEvents,
4369
4591
  Keymap,
4370
- Tabindex
4371
- ] : [];
4592
+ Tabindex,
4593
+ Drop,
4594
+ Paste
4595
+ ].filter((ext) => {
4596
+ if (typeof this.options.enableCoreExtensions === "object") {
4597
+ return this.options.enableCoreExtensions[ext.name] !== false;
4598
+ }
4599
+ return true;
4600
+ }) : [];
4372
4601
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter((extension) => {
4373
4602
  return ["extension", "node", "mark"].includes(extension == null ? void 0 : extension.type);
4374
4603
  });
@@ -4392,6 +4621,7 @@ var Editor = class extends EventEmitter {
4392
4621
  * Creates a ProseMirror view.
4393
4622
  */
4394
4623
  createView() {
4624
+ var _a;
4395
4625
  let doc;
4396
4626
  try {
4397
4627
  doc = createDocument(
@@ -4408,6 +4638,9 @@ var Editor = class extends EventEmitter {
4408
4638
  editor: this,
4409
4639
  error: e,
4410
4640
  disableCollaboration: () => {
4641
+ if (this.storage.collaboration) {
4642
+ this.storage.collaboration.isDisabled = true;
4643
+ }
4411
4644
  this.options.extensions = this.options.extensions.filter((extension) => extension.name !== "collaboration");
4412
4645
  this.createExtensionManager();
4413
4646
  }
@@ -4422,8 +4655,13 @@ var Editor = class extends EventEmitter {
4422
4655
  const selection = resolveFocusPosition(doc, this.options.autofocus);
4423
4656
  this.view = new import_view.EditorView(this.options.element, {
4424
4657
  ...this.options.editorProps,
4658
+ attributes: {
4659
+ // add `role="textbox"` to the editor element
4660
+ role: "textbox",
4661
+ ...(_a = this.options.editorProps) == null ? void 0 : _a.attributes
4662
+ },
4425
4663
  dispatchTransaction: this.dispatchTransaction.bind(this),
4426
- state: import_state18.EditorState.create({
4664
+ state: import_state21.EditorState.create({
4427
4665
  doc,
4428
4666
  selection: selection || void 0
4429
4667
  })
@@ -4583,6 +4821,10 @@ var Editor = class extends EventEmitter {
4583
4821
  destroy() {
4584
4822
  this.emit("destroy");
4585
4823
  if (this.view) {
4824
+ const dom = this.view.dom;
4825
+ if (dom && dom.editor) {
4826
+ delete dom.editor;
4827
+ }
4586
4828
  this.view.destroy();
4587
4829
  }
4588
4830
  this.removeAllListeners();
@@ -4836,7 +5078,7 @@ var Node3 = class _Node {
4836
5078
  };
4837
5079
 
4838
5080
  // src/NodeView.ts
4839
- var import_state19 = require("@tiptap/pm/state");
5081
+ var import_state22 = require("@tiptap/pm/state");
4840
5082
 
4841
5083
  // src/utilities/isAndroid.ts
4842
5084
  function isAndroid() {
@@ -4857,6 +5099,9 @@ var NodeView = class {
4857
5099
  this.extension = props.extension;
4858
5100
  this.node = props.node;
4859
5101
  this.decorations = props.decorations;
5102
+ this.innerDecorations = props.innerDecorations;
5103
+ this.view = props.view;
5104
+ this.HTMLAttributes = props.HTMLAttributes;
4860
5105
  this.getPos = props.getPos;
4861
5106
  this.mount();
4862
5107
  }
@@ -4888,7 +5133,11 @@ var NodeView = class {
4888
5133
  y = handleBox.y - domBox.y + offsetY;
4889
5134
  }
4890
5135
  (_g = event.dataTransfer) == null ? void 0 : _g.setDragImage(this.dom, x, y);
4891
- const selection = import_state19.NodeSelection.create(view.state.doc, this.getPos());
5136
+ const pos = this.getPos();
5137
+ if (typeof pos !== "number") {
5138
+ return;
5139
+ }
5140
+ const selection = import_state22.NodeSelection.create(view.state.doc, pos);
4892
5141
  const transaction = view.state.tr.setSelection(selection);
4893
5142
  view.dispatch(transaction);
4894
5143
  }
@@ -4914,15 +5163,15 @@ var NodeView = class {
4914
5163
  const { isEditable } = this.editor;
4915
5164
  const { isDragging } = this;
4916
5165
  const isDraggable = !!this.node.type.spec.draggable;
4917
- const isSelectable = import_state19.NodeSelection.isSelectable(this.node);
5166
+ const isSelectable = import_state22.NodeSelection.isSelectable(this.node);
4918
5167
  const isCopyEvent = event.type === "copy";
4919
5168
  const isPasteEvent = event.type === "paste";
4920
5169
  const isCutEvent = event.type === "cut";
4921
5170
  const isClickEvent = event.type === "mousedown";
4922
- if (!isDraggable && isSelectable && isDragEvent) {
5171
+ if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
4923
5172
  event.preventDefault();
4924
5173
  }
4925
- if (isDraggable && isDragEvent && !isDragging) {
5174
+ if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
4926
5175
  event.preventDefault();
4927
5176
  return false;
4928
5177
  }
@@ -4959,6 +5208,11 @@ var NodeView = class {
4959
5208
  }
4960
5209
  return true;
4961
5210
  }
5211
+ /**
5212
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
5213
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
5214
+ * @return `true` if it can safely be ignored.
5215
+ */
4962
5216
  ignoreMutation(mutation) {
4963
5217
  if (!this.dom || !this.contentDOM) {
4964
5218
  return true;
@@ -4989,9 +5243,15 @@ var NodeView = class {
4989
5243
  }
4990
5244
  return true;
4991
5245
  }
5246
+ /**
5247
+ * Update the attributes of the prosemirror node.
5248
+ */
4992
5249
  updateAttributes(attributes) {
4993
5250
  this.editor.commands.command(({ tr }) => {
4994
5251
  const pos = this.getPos();
5252
+ if (typeof pos !== "number") {
5253
+ return false;
5254
+ }
4995
5255
  tr.setNodeMarkup(pos, void 0, {
4996
5256
  ...this.node.attrs,
4997
5257
  ...attributes
@@ -4999,8 +5259,14 @@ var NodeView = class {
4999
5259
  return true;
5000
5260
  });
5001
5261
  }
5262
+ /**
5263
+ * Delete the node.
5264
+ */
5002
5265
  deleteNode() {
5003
5266
  const from = this.getPos();
5267
+ if (typeof from !== "number") {
5268
+ return;
5269
+ }
5004
5270
  const to = from + this.node.nodeSize;
5005
5271
  this.editor.commands.deleteRange({ from, to });
5006
5272
  }