@tiptap/core 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/dist/index.cjs +290 -79
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +290 -79
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.umd.js +290 -79
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/packages/core/src/Extension.d.ts +129 -14
  8. package/dist/packages/core/src/ExtensionManager.d.ts +37 -0
  9. package/dist/packages/core/src/Mark.d.ts +129 -14
  10. package/dist/packages/core/src/Node.d.ts +226 -30
  11. package/dist/packages/core/src/NodeView.d.ts +4 -0
  12. package/dist/packages/core/src/PasteRule.d.ts +4 -0
  13. package/dist/packages/core/src/commands/blur.d.ts +1 -0
  14. package/dist/packages/core/src/commands/clearContent.d.ts +2 -0
  15. package/dist/packages/core/src/commands/clearNodes.d.ts +1 -0
  16. package/dist/packages/core/src/commands/command.d.ts +6 -0
  17. package/dist/packages/core/src/commands/createParagraphNear.d.ts +1 -0
  18. package/dist/packages/core/src/commands/cut.d.ts +5 -0
  19. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +1 -0
  20. package/dist/packages/core/src/commands/deleteNode.d.ts +3 -1
  21. package/dist/packages/core/src/commands/deleteRange.d.ts +2 -0
  22. package/dist/packages/core/src/commands/deleteSelection.d.ts +1 -0
  23. package/dist/packages/core/src/commands/enter.d.ts +1 -0
  24. package/dist/packages/core/src/commands/exitCode.d.ts +1 -0
  25. package/dist/packages/core/src/commands/extendMarkRange.d.ts +14 -2
  26. package/dist/packages/core/src/commands/first.d.ts +2 -0
  27. package/dist/packages/core/src/commands/focus.d.ts +14 -1
  28. package/dist/packages/core/src/commands/insertContent.d.ts +17 -1
  29. package/dist/packages/core/src/commands/insertContentAt.d.ts +20 -1
  30. package/dist/packages/core/src/commands/join.d.ts +12 -4
  31. package/dist/packages/core/src/commands/joinItemBackward.d.ts +2 -1
  32. package/dist/packages/core/src/commands/joinItemForward.d.ts +2 -1
  33. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +2 -0
  34. package/dist/packages/core/src/commands/lift.d.ts +5 -1
  35. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +2 -1
  36. package/dist/packages/core/src/commands/liftListItem.d.ts +3 -1
  37. package/dist/packages/core/src/commands/newlineInCode.d.ts +1 -0
  38. package/dist/packages/core/src/commands/resetAttributes.d.ts +3 -0
  39. package/dist/packages/core/src/commands/scrollIntoView.d.ts +1 -0
  40. package/dist/packages/core/src/commands/selectAll.d.ts +1 -0
  41. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +1 -0
  42. package/dist/packages/core/src/commands/selectNodeForward.d.ts +1 -0
  43. package/dist/packages/core/src/commands/selectParentNode.d.ts +1 -0
  44. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +1 -0
  45. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +1 -0
  46. package/dist/packages/core/src/commands/setContent.d.ts +19 -1
  47. package/dist/packages/core/src/commands/setMark.d.ts +2 -0
  48. package/dist/packages/core/src/commands/setMeta.d.ts +3 -0
  49. package/dist/packages/core/src/commands/setNode.d.ts +3 -0
  50. package/dist/packages/core/src/commands/setNodeSelection.d.ts +2 -0
  51. package/dist/packages/core/src/commands/setTextSelection.d.ts +2 -0
  52. package/dist/packages/core/src/commands/sinkListItem.d.ts +2 -0
  53. package/dist/packages/core/src/commands/splitBlock.d.ts +3 -0
  54. package/dist/packages/core/src/commands/splitListItem.d.ts +2 -0
  55. package/dist/packages/core/src/commands/toggleList.d.ts +5 -0
  56. package/dist/packages/core/src/commands/toggleMark.d.ts +13 -1
  57. package/dist/packages/core/src/commands/toggleNode.d.ts +4 -0
  58. package/dist/packages/core/src/commands/toggleWrap.d.ts +3 -0
  59. package/dist/packages/core/src/commands/undoInputRule.d.ts +1 -0
  60. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +1 -0
  61. package/dist/packages/core/src/commands/unsetMark.d.ts +8 -1
  62. package/dist/packages/core/src/commands/updateAttributes.d.ts +12 -1
  63. package/dist/packages/core/src/commands/wrapIn.d.ts +3 -0
  64. package/dist/packages/core/src/commands/wrapInList.d.ts +3 -0
  65. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +3 -0
  66. package/dist/packages/core/src/helpers/createChainableState.d.ts +5 -0
  67. package/dist/packages/core/src/helpers/createDocument.d.ts +7 -0
  68. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +7 -0
  69. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +5 -0
  70. package/dist/packages/core/src/helpers/findChildren.d.ts +6 -0
  71. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +4 -0
  72. package/dist/packages/core/src/helpers/findParentNode.d.ts +8 -0
  73. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +9 -0
  74. package/dist/packages/core/src/helpers/generateHTML.d.ts +6 -0
  75. package/dist/packages/core/src/helpers/generateJSON.d.ts +6 -0
  76. package/dist/packages/core/src/helpers/generateText.d.ts +7 -0
  77. package/dist/packages/core/src/helpers/getAttributes.d.ts +6 -0
  78. package/dist/packages/core/src/helpers/getExtensionField.d.ts +7 -0
  79. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +6 -0
  80. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +6 -0
  81. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +6 -0
  82. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +7 -0
  83. package/dist/packages/core/src/helpers/getText.d.ts +9 -0
  84. package/dist/packages/core/src/helpers/getTextBetween.d.ts +8 -0
  85. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +6 -0
  86. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +5 -0
  87. package/dist/packages/core/src/inputRules/markInputRule.d.ts +1 -0
  88. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +1 -0
  89. package/dist/packages/core/src/inputRules/textInputRule.d.ts +1 -0
  90. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +1 -0
  91. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +1 -0
  92. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +1 -0
  93. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +1 -0
  94. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +1 -0
  95. package/package.json +2 -2
  96. package/src/Extension.ts +130 -14
  97. package/src/ExtensionManager.ts +117 -85
  98. package/src/Mark.ts +129 -14
  99. package/src/Node.ts +226 -30
  100. package/src/NodePos.ts +19 -18
  101. package/src/NodeView.ts +4 -0
  102. package/src/PasteRule.ts +4 -0
  103. package/src/commands/blur.ts +1 -0
  104. package/src/commands/clearContent.ts +2 -0
  105. package/src/commands/clearNodes.ts +1 -0
  106. package/src/commands/command.ts +6 -0
  107. package/src/commands/createParagraphNear.ts +1 -0
  108. package/src/commands/cut.ts +5 -0
  109. package/src/commands/deleteCurrentNode.ts +1 -0
  110. package/src/commands/deleteNode.ts +3 -1
  111. package/src/commands/deleteRange.ts +2 -0
  112. package/src/commands/deleteSelection.ts +1 -0
  113. package/src/commands/enter.ts +1 -0
  114. package/src/commands/exitCode.ts +1 -0
  115. package/src/commands/extendMarkRange.ts +12 -1
  116. package/src/commands/first.ts +2 -0
  117. package/src/commands/focus.ts +12 -0
  118. package/src/commands/insertContent.ts +16 -0
  119. package/src/commands/insertContentAt.ts +19 -0
  120. package/src/commands/join.ts +12 -4
  121. package/src/commands/joinItemBackward.ts +2 -1
  122. package/src/commands/joinItemForward.ts +2 -1
  123. package/src/commands/keyboardShortcut.ts +2 -0
  124. package/src/commands/lift.ts +5 -1
  125. package/src/commands/liftEmptyBlock.ts +2 -1
  126. package/src/commands/liftListItem.ts +3 -1
  127. package/src/commands/newlineInCode.ts +1 -0
  128. package/src/commands/resetAttributes.ts +3 -0
  129. package/src/commands/scrollIntoView.ts +1 -0
  130. package/src/commands/selectAll.ts +1 -0
  131. package/src/commands/selectNodeBackward.ts +1 -0
  132. package/src/commands/selectNodeForward.ts +1 -0
  133. package/src/commands/selectParentNode.ts +1 -0
  134. package/src/commands/selectTextblockEnd.ts +1 -0
  135. package/src/commands/selectTextblockStart.ts +1 -0
  136. package/src/commands/setContent.ts +17 -0
  137. package/src/commands/setMark.ts +2 -0
  138. package/src/commands/setMeta.ts +3 -0
  139. package/src/commands/setNode.ts +3 -0
  140. package/src/commands/setNodeSelection.ts +2 -0
  141. package/src/commands/setTextSelection.ts +2 -0
  142. package/src/commands/sinkListItem.ts +2 -0
  143. package/src/commands/splitBlock.ts +3 -0
  144. package/src/commands/splitListItem.ts +2 -0
  145. package/src/commands/toggleList.ts +5 -0
  146. package/src/commands/toggleMark.ts +12 -0
  147. package/src/commands/toggleNode.ts +4 -0
  148. package/src/commands/toggleWrap.ts +3 -0
  149. package/src/commands/undoInputRule.ts +1 -0
  150. package/src/commands/unsetAllMarks.ts +1 -0
  151. package/src/commands/unsetMark.ts +7 -0
  152. package/src/commands/updateAttributes.ts +10 -0
  153. package/src/commands/wrapIn.ts +3 -0
  154. package/src/commands/wrapInList.ts +3 -0
  155. package/src/extensions/keymap.ts +7 -1
  156. package/src/helpers/combineTransactionSteps.ts +3 -0
  157. package/src/helpers/createChainableState.ts +5 -0
  158. package/src/helpers/createDocument.ts +7 -0
  159. package/src/helpers/createNodeFromContent.ts +16 -3
  160. package/src/helpers/defaultBlockAt.ts +5 -0
  161. package/src/helpers/findChildren.ts +6 -0
  162. package/src/helpers/findChildrenInRange.ts +4 -0
  163. package/src/helpers/findParentNode.ts +8 -0
  164. package/src/helpers/findParentNodeClosestToPos.ts +9 -0
  165. package/src/helpers/generateHTML.ts +6 -0
  166. package/src/helpers/generateJSON.ts +6 -0
  167. package/src/helpers/generateText.ts +7 -0
  168. package/src/helpers/getAttributes.ts +6 -0
  169. package/src/helpers/getExtensionField.ts +7 -0
  170. package/src/helpers/getSchemaByResolvedExtensions.ts +6 -0
  171. package/src/helpers/getSchemaTypeByName.ts +6 -0
  172. package/src/helpers/getSchemaTypeNameByName.ts +6 -0
  173. package/src/helpers/getSplittedAttributes.ts +7 -0
  174. package/src/helpers/getText.ts +9 -0
  175. package/src/helpers/getTextBetween.ts +12 -10
  176. package/src/helpers/getTextContentFromNodes.ts +6 -0
  177. package/src/helpers/getTextSerializersFromSchema.ts +5 -0
  178. package/src/inputRules/markInputRule.ts +1 -0
  179. package/src/inputRules/nodeInputRule.ts +1 -0
  180. package/src/inputRules/textInputRule.ts +1 -0
  181. package/src/inputRules/textblockTypeInputRule.ts +1 -0
  182. package/src/inputRules/wrappingInputRule.ts +1 -0
  183. package/src/pasteRules/markPasteRule.ts +1 -0
  184. package/src/pasteRules/nodePasteRule.ts +1 -0
  185. package/src/pasteRules/textPasteRule.ts +1 -0
package/dist/index.js CHANGED
@@ -6,6 +6,11 @@ import { liftTarget, ReplaceStep, ReplaceAroundStep, joinPoint, Transform, canSp
6
6
  import { createParagraphNear as createParagraphNear$1, deleteSelection as deleteSelection$1, exitCode as exitCode$1, joinUp as joinUp$1, joinDown as joinDown$1, joinBackward as joinBackward$1, joinForward as joinForward$1, joinTextblockBackward as joinTextblockBackward$1, joinTextblockForward as joinTextblockForward$1, lift as lift$1, liftEmptyBlock as liftEmptyBlock$1, newlineInCode as newlineInCode$1, selectNodeBackward as selectNodeBackward$1, selectNodeForward as selectNodeForward$1, selectParentNode as selectParentNode$1, selectTextblockEnd as selectTextblockEnd$1, selectTextblockStart as selectTextblockStart$1, setBlockType, wrapIn as wrapIn$1 } from '@tiptap/pm/commands';
7
7
  import { liftListItem as liftListItem$1, sinkListItem as sinkListItem$1, wrapInList as wrapInList$1 } from '@tiptap/pm/schema-list';
8
8
 
9
+ /**
10
+ * Takes a Transaction & Editor State and turns it into a chainable state object
11
+ * @param config The transaction and state to create the chainable state from
12
+ * @returns A chainable Editor state object
13
+ */
9
14
  function createChainableState(config) {
10
15
  const { state, transaction } = config;
11
16
  let { selection } = transaction;
@@ -172,6 +177,13 @@ class EventEmitter {
172
177
  }
173
178
  }
174
179
 
180
+ /**
181
+ * Returns a field from an extension
182
+ * @param extension The Tiptap extension
183
+ * @param field The field, for example `renderHTML` or `priority`
184
+ * @param context The context object that should be passed as `this` into the function
185
+ * @returns The field value
186
+ */
175
187
  function getExtensionField(extension, field, context) {
176
188
  if (extension.config[field] === undefined && extension.parent) {
177
189
  return getExtensionField(extension.parent, field, context);
@@ -416,6 +428,12 @@ function cleanUpSchemaItem(data) {
416
428
  return value !== null && value !== undefined;
417
429
  }));
418
430
  }
431
+ /**
432
+ * Creates a new Prosemirror schema based on the given extensions.
433
+ * @param extensions An array of Tiptap extensions
434
+ * @param editor The editor instance
435
+ * @returns A Prosemirror schema
436
+ */
419
437
  function getSchemaByResolvedExtensions(extensions, editor) {
420
438
  var _a;
421
439
  const allAttributes = getAttributesFromExtensions(extensions);
@@ -517,6 +535,12 @@ function getSchemaByResolvedExtensions(extensions, editor) {
517
535
  });
518
536
  }
519
537
 
538
+ /**
539
+ * Tries to get a node or mark type by its name.
540
+ * @param name The name of the node or mark type
541
+ * @param schema The Prosemiror schema to search in
542
+ * @returns The node or mark type, or null if it doesn't exist
543
+ */
520
544
  function getSchemaTypeByName(name, schema) {
521
545
  return schema.nodes[name] || schema.marks[name] || null;
522
546
  }
@@ -533,6 +557,12 @@ function isExtensionRulesEnabled(extension, enabled) {
533
557
  return enabled;
534
558
  }
535
559
 
560
+ /**
561
+ * Returns the text content of a resolved prosemirror position
562
+ * @param $from The resolved position to get the text content from
563
+ * @param maxMatch The maximum number of characters to match
564
+ * @returns The text content
565
+ */
536
566
  const getTextContentFromNodes = ($from, maxMatch = 500) => {
537
567
  let textBefore = '';
538
568
  const sliceEndPos = $from.parentOffset;
@@ -740,6 +770,10 @@ function isNumber(value) {
740
770
  return typeof value === 'number';
741
771
  }
742
772
 
773
+ /**
774
+ * Paste rules are used to react to pasted content.
775
+ * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
776
+ */
743
777
  class PasteRule {
744
778
  constructor(config) {
745
779
  this.find = config.find;
@@ -938,57 +972,14 @@ class ExtensionManager {
938
972
  this.editor = editor;
939
973
  this.extensions = ExtensionManager.resolve(extensions);
940
974
  this.schema = getSchemaByResolvedExtensions(this.extensions, editor);
941
- this.extensions.forEach(extension => {
942
- var _a;
943
- // store extension storage in editor
944
- this.editor.extensionStorage[extension.name] = extension.storage;
945
- const context = {
946
- name: extension.name,
947
- options: extension.options,
948
- storage: extension.storage,
949
- editor: this.editor,
950
- type: getSchemaTypeByName(extension.name, this.schema),
951
- };
952
- if (extension.type === 'mark') {
953
- const keepOnSplit = (_a = callOrReturn(getExtensionField(extension, 'keepOnSplit', context))) !== null && _a !== void 0 ? _a : true;
954
- if (keepOnSplit) {
955
- this.splittableMarks.push(extension.name);
956
- }
957
- }
958
- const onBeforeCreate = getExtensionField(extension, 'onBeforeCreate', context);
959
- if (onBeforeCreate) {
960
- this.editor.on('beforeCreate', onBeforeCreate);
961
- }
962
- const onCreate = getExtensionField(extension, 'onCreate', context);
963
- if (onCreate) {
964
- this.editor.on('create', onCreate);
965
- }
966
- const onUpdate = getExtensionField(extension, 'onUpdate', context);
967
- if (onUpdate) {
968
- this.editor.on('update', onUpdate);
969
- }
970
- const onSelectionUpdate = getExtensionField(extension, 'onSelectionUpdate', context);
971
- if (onSelectionUpdate) {
972
- this.editor.on('selectionUpdate', onSelectionUpdate);
973
- }
974
- const onTransaction = getExtensionField(extension, 'onTransaction', context);
975
- if (onTransaction) {
976
- this.editor.on('transaction', onTransaction);
977
- }
978
- const onFocus = getExtensionField(extension, 'onFocus', context);
979
- if (onFocus) {
980
- this.editor.on('focus', onFocus);
981
- }
982
- const onBlur = getExtensionField(extension, 'onBlur', context);
983
- if (onBlur) {
984
- this.editor.on('blur', onBlur);
985
- }
986
- const onDestroy = getExtensionField(extension, 'onDestroy', context);
987
- if (onDestroy) {
988
- this.editor.on('destroy', onDestroy);
989
- }
990
- });
975
+ this.setupExtensions();
991
976
  }
977
+ /**
978
+ * Returns a flattened and sorted extension list while
979
+ * also checking for duplicated extensions and warns the user.
980
+ * @param extensions An array of Tiptap extensions
981
+ * @returns An flattened and sorted array of Tiptap extensions
982
+ */
992
983
  static resolve(extensions) {
993
984
  const resolvedExtensions = ExtensionManager.sort(ExtensionManager.flatten(extensions));
994
985
  const duplicatedNames = findDuplicates(resolvedExtensions.map(extension => extension.name));
@@ -999,6 +990,11 @@ class ExtensionManager {
999
990
  }
1000
991
  return resolvedExtensions;
1001
992
  }
993
+ /**
994
+ * Create a flattened array of extensions by traversing the `addExtensions` field.
995
+ * @param extensions An array of Tiptap extensions
996
+ * @returns A flattened array of Tiptap extensions
997
+ */
1002
998
  static flatten(extensions) {
1003
999
  return (extensions
1004
1000
  .map(extension => {
@@ -1016,6 +1012,11 @@ class ExtensionManager {
1016
1012
  // `Infinity` will break TypeScript so we set a number that is probably high enough
1017
1013
  .flat(10));
1018
1014
  }
1015
+ /**
1016
+ * Sort extensions by priority.
1017
+ * @param extensions An array of Tiptap extensions
1018
+ * @returns A sorted array of Tiptap extensions by priority
1019
+ */
1019
1020
  static sort(extensions) {
1020
1021
  const defaultPriority = 100;
1021
1022
  return extensions.sort((a, b) => {
@@ -1030,6 +1031,10 @@ class ExtensionManager {
1030
1031
  return 0;
1031
1032
  });
1032
1033
  }
1034
+ /**
1035
+ * Get all commands from the extensions.
1036
+ * @returns An object with all commands where the key is the command name and the value is the command function
1037
+ */
1033
1038
  get commands() {
1034
1039
  return this.extensions.reduce((commands, extension) => {
1035
1040
  const context = {
@@ -1049,6 +1054,10 @@ class ExtensionManager {
1049
1054
  };
1050
1055
  }, {});
1051
1056
  }
1057
+ /**
1058
+ * Get all registered Prosemirror plugins from the extensions.
1059
+ * @returns An array of Prosemirror plugins
1060
+ */
1052
1061
  get plugins() {
1053
1062
  const { editor } = this;
1054
1063
  // With ProseMirror, first plugins within an array are executed first.
@@ -1111,9 +1120,17 @@ class ExtensionManager {
1111
1120
  ...allPlugins,
1112
1121
  ];
1113
1122
  }
1123
+ /**
1124
+ * Get all attributes from the extensions.
1125
+ * @returns An array of attributes
1126
+ */
1114
1127
  get attributes() {
1115
1128
  return getAttributesFromExtensions(this.extensions);
1116
1129
  }
1130
+ /**
1131
+ * Get all node views from the extensions.
1132
+ * @returns An object with all node views where the key is the node name and the value is the node view function
1133
+ */
1117
1134
  get nodeViews() {
1118
1135
  const { editor } = this;
1119
1136
  const { nodeExtensions } = splitExtensions(this.extensions);
@@ -1146,6 +1163,62 @@ class ExtensionManager {
1146
1163
  return [extension.name, nodeview];
1147
1164
  }));
1148
1165
  }
1166
+ /**
1167
+ * Go through all extensions, create extension storages & setup marks
1168
+ * & bind editor event listener.
1169
+ */
1170
+ setupExtensions() {
1171
+ this.extensions.forEach(extension => {
1172
+ var _a;
1173
+ // store extension storage in editor
1174
+ this.editor.extensionStorage[extension.name] = extension.storage;
1175
+ const context = {
1176
+ name: extension.name,
1177
+ options: extension.options,
1178
+ storage: extension.storage,
1179
+ editor: this.editor,
1180
+ type: getSchemaTypeByName(extension.name, this.schema),
1181
+ };
1182
+ if (extension.type === 'mark') {
1183
+ const keepOnSplit = (_a = callOrReturn(getExtensionField(extension, 'keepOnSplit', context))) !== null && _a !== void 0 ? _a : true;
1184
+ if (keepOnSplit) {
1185
+ this.splittableMarks.push(extension.name);
1186
+ }
1187
+ }
1188
+ const onBeforeCreate = getExtensionField(extension, 'onBeforeCreate', context);
1189
+ const onCreate = getExtensionField(extension, 'onCreate', context);
1190
+ const onUpdate = getExtensionField(extension, 'onUpdate', context);
1191
+ const onSelectionUpdate = getExtensionField(extension, 'onSelectionUpdate', context);
1192
+ const onTransaction = getExtensionField(extension, 'onTransaction', context);
1193
+ const onFocus = getExtensionField(extension, 'onFocus', context);
1194
+ const onBlur = getExtensionField(extension, 'onBlur', context);
1195
+ const onDestroy = getExtensionField(extension, 'onDestroy', context);
1196
+ if (onBeforeCreate) {
1197
+ this.editor.on('beforeCreate', onBeforeCreate);
1198
+ }
1199
+ if (onCreate) {
1200
+ this.editor.on('create', onCreate);
1201
+ }
1202
+ if (onUpdate) {
1203
+ this.editor.on('update', onUpdate);
1204
+ }
1205
+ if (onSelectionUpdate) {
1206
+ this.editor.on('selectionUpdate', onSelectionUpdate);
1207
+ }
1208
+ if (onTransaction) {
1209
+ this.editor.on('transaction', onTransaction);
1210
+ }
1211
+ if (onFocus) {
1212
+ this.editor.on('focus', onFocus);
1213
+ }
1214
+ if (onBlur) {
1215
+ this.editor.on('blur', onBlur);
1216
+ }
1217
+ if (onDestroy) {
1218
+ this.editor.on('destroy', onDestroy);
1219
+ }
1220
+ });
1221
+ }
1149
1222
  }
1150
1223
 
1151
1224
  // see: https://github.com/mesqueeb/is-what/blob/88d6e4ca92fb2baab6003c54e02eedf4e729e5ab/src/index.ts
@@ -1179,6 +1252,10 @@ function mergeDeep(target, source) {
1179
1252
  return output;
1180
1253
  }
1181
1254
 
1255
+ /**
1256
+ * The Extension class is the base class for all extensions.
1257
+ * @see https://tiptap.dev/api/extensions#create-a-new-extension
1258
+ */
1182
1259
  class Extension {
1183
1260
  constructor(config = {}) {
1184
1261
  this.type = 'extension';
@@ -1216,6 +1293,7 @@ class Extension {
1216
1293
  // return a new instance so we can use the same extension
1217
1294
  // with different calls of `configure`
1218
1295
  const extension = this.extend();
1296
+ extension.parent = this.parent;
1219
1297
  extension.options = mergeDeep(this.options, options);
1220
1298
  extension.storage = callOrReturn(getExtensionField(extension, 'addStorage', {
1221
1299
  name: extension.name,
@@ -1242,19 +1320,25 @@ class Extension {
1242
1320
  }
1243
1321
  }
1244
1322
 
1323
+ /**
1324
+ * Gets the text between two positions in a Prosemirror node
1325
+ * and serializes it using the given text serializers and block separator (see getText)
1326
+ * @param startNode The Prosemirror node to start from
1327
+ * @param range The range of the text to get
1328
+ * @param options Options for the text serializer & block separator
1329
+ * @returns The text between the two positions
1330
+ */
1245
1331
  function getTextBetween(startNode, range, options) {
1246
1332
  const { from, to } = range;
1247
1333
  const { blockSeparator = '\n\n', textSerializers = {} } = options || {};
1248
1334
  let text = '';
1249
- let separated = true;
1250
1335
  startNode.nodesBetween(from, to, (node, pos, parent, index) => {
1251
1336
  var _a;
1337
+ if (node.isBlock && pos > from) {
1338
+ text += blockSeparator;
1339
+ }
1252
1340
  const textSerializer = textSerializers === null || textSerializers === void 0 ? void 0 : textSerializers[node.type.name];
1253
1341
  if (textSerializer) {
1254
- if (node.isBlock && !separated) {
1255
- text += blockSeparator;
1256
- separated = true;
1257
- }
1258
1342
  if (parent) {
1259
1343
  text += textSerializer({
1260
1344
  node,
@@ -1269,16 +1353,16 @@ function getTextBetween(startNode, range, options) {
1269
1353
  }
1270
1354
  if (node.isText) {
1271
1355
  text += (_a = node === null || node === void 0 ? void 0 : node.text) === null || _a === void 0 ? void 0 : _a.slice(Math.max(from, pos) - pos, to - pos); // eslint-disable-line
1272
- separated = false;
1273
- }
1274
- else if (node.isBlock && !separated) {
1275
- text += blockSeparator;
1276
- separated = true;
1277
1356
  }
1278
1357
  });
1279
1358
  return text;
1280
1359
  }
1281
1360
 
1361
+ /**
1362
+ * Find text serializers `toText` in a Prosemirror schema
1363
+ * @param schema The Prosemirror schema to search in
1364
+ * @returns A record of text serializers by node name
1365
+ */
1282
1366
  function getTextSerializersFromSchema(schema) {
1283
1367
  return Object.fromEntries(Object.entries(schema.nodes)
1284
1368
  .filter(([, node]) => node.spec.toText)
@@ -1661,15 +1745,26 @@ function elementFromString(value) {
1661
1745
  return removeWhitespaces(html);
1662
1746
  }
1663
1747
 
1748
+ /**
1749
+ * Takes a JSON or HTML content and creates a Prosemirror node or fragment from it.
1750
+ * @param content The JSON or HTML content to create the node from
1751
+ * @param schema The Prosemirror schema to use for the node
1752
+ * @param options Options for the parser
1753
+ * @returns The created Prosemirror node or fragment
1754
+ */
1664
1755
  function createNodeFromContent(content, schema, options) {
1665
1756
  options = {
1666
1757
  slice: true,
1667
1758
  parseOptions: {},
1668
1759
  ...options,
1669
1760
  };
1670
- if (typeof content === 'object' && content !== null) {
1761
+ const isJSONContent = typeof content === 'object' && content !== null;
1762
+ const isTextContent = typeof content === 'string';
1763
+ if (isJSONContent) {
1671
1764
  try {
1672
- if (Array.isArray(content) && content.length > 0) {
1765
+ const isArrayContent = Array.isArray(content) && content.length > 0;
1766
+ // if the JSON Content is an array of nodes, create a fragment for each node
1767
+ if (isArrayContent) {
1673
1768
  return Fragment.fromArray(content.map(item => schema.nodeFromJSON(item)));
1674
1769
  }
1675
1770
  return schema.nodeFromJSON(content);
@@ -1679,7 +1774,7 @@ function createNodeFromContent(content, schema, options) {
1679
1774
  return createNodeFromContent('', schema, options);
1680
1775
  }
1681
1776
  }
1682
- if (typeof content === 'string') {
1777
+ if (isTextContent) {
1683
1778
  const parser = DOMParser.fromSchema(schema);
1684
1779
  return options.slice
1685
1780
  ? parser.parseSlice(elementFromString(content), options.parseOptions).content
@@ -1979,6 +2074,12 @@ const newlineInCode = () => ({ state, dispatch }) => {
1979
2074
  return newlineInCode$1(state, dispatch);
1980
2075
  };
1981
2076
 
2077
+ /**
2078
+ * Get the type of a schema item by its name.
2079
+ * @param name The name of the schema item
2080
+ * @param schema The Prosemiror schema to search in
2081
+ * @returns The type of the schema item (`node` or `mark`), or null if it doesn't exist
2082
+ */
1982
2083
  function getSchemaTypeNameByName(name, schema) {
1983
2084
  if (schema.nodes[name]) {
1984
2085
  return 'node';
@@ -2076,6 +2177,13 @@ const selectTextblockStart = () => ({ state, dispatch }) => {
2076
2177
  return selectTextblockStart$1(state, dispatch);
2077
2178
  };
2078
2179
 
2180
+ /**
2181
+ * Create a new Prosemirror document node from content.
2182
+ * @param content The JSON or HTML content to create the document from
2183
+ * @param schema The Prosemirror schema to use for the document
2184
+ * @param parseOptions Options for the parser
2185
+ * @returns The created Prosemirror document node
2186
+ */
2079
2187
  function createDocument(content, schema, parseOptions = {}) {
2080
2188
  return createNodeFromContent(content, schema, { slice: false, parseOptions });
2081
2189
  }
@@ -2113,6 +2221,9 @@ function getMarkAttributes(state, typeOrName) {
2113
2221
 
2114
2222
  /**
2115
2223
  * Returns a new `Transform` based on all steps of the passed transactions.
2224
+ * @param oldDoc The Prosemirror node to start from
2225
+ * @param transactions The transactions to combine
2226
+ * @returns A new `Transform` with all steps of the passed transactions
2116
2227
  */
2117
2228
  function combineTransactionSteps(oldDoc, transactions) {
2118
2229
  const transform = new Transform(oldDoc);
@@ -2124,6 +2235,11 @@ function combineTransactionSteps(oldDoc, transactions) {
2124
2235
  return transform;
2125
2236
  }
2126
2237
 
2238
+ /**
2239
+ * Gets the default block type at a given match
2240
+ * @param match The content match to get the default block type from
2241
+ * @returns The default block type or null
2242
+ */
2127
2243
  function defaultBlockAt(match) {
2128
2244
  for (let i = 0; i < match.edgeCount; i += 1) {
2129
2245
  const { type } = match.edge(i);
@@ -2134,6 +2250,12 @@ function defaultBlockAt(match) {
2134
2250
  return null;
2135
2251
  }
2136
2252
 
2253
+ /**
2254
+ * Find children inside a Prosemirror node that match a predicate.
2255
+ * @param node The Prosemirror node to search in
2256
+ * @param predicate The predicate to match
2257
+ * @returns An array of nodes with their positions
2258
+ */
2137
2259
  function findChildren(node, predicate) {
2138
2260
  const nodesWithPos = [];
2139
2261
  node.descendants((child, pos) => {
@@ -2149,6 +2271,10 @@ function findChildren(node, predicate) {
2149
2271
 
2150
2272
  /**
2151
2273
  * Same as `findChildren` but searches only within a `range`.
2274
+ * @param node The Prosemirror node to search in
2275
+ * @param range The range to search in
2276
+ * @param predicate The predicate to match
2277
+ * @returns An array of nodes with their positions
2152
2278
  */
2153
2279
  function findChildrenInRange(node, range, predicate) {
2154
2280
  const nodesWithPos = [];
@@ -2172,6 +2298,15 @@ function findChildrenInRange(node, range, predicate) {
2172
2298
  return nodesWithPos;
2173
2299
  }
2174
2300
 
2301
+ /**
2302
+ * Finds the closest parent node to a resolved position that matches a predicate.
2303
+ * @param $pos The resolved position to search from
2304
+ * @param predicate The predicate to match
2305
+ * @returns The closest parent node to the resolved position that matches the predicate
2306
+ * @example ```js
2307
+ * findParentNodeClosestToPos($from, node => node.type.name === 'paragraph')
2308
+ * ```
2309
+ */
2175
2310
  function findParentNodeClosestToPos($pos, predicate) {
2176
2311
  for (let i = $pos.depth; i > 0; i -= 1) {
2177
2312
  const node = $pos.node(i);
@@ -2186,6 +2321,14 @@ function findParentNodeClosestToPos($pos, predicate) {
2186
2321
  }
2187
2322
  }
2188
2323
 
2324
+ /**
2325
+ * Finds the closest parent node to the current selection that matches a predicate.
2326
+ * @param predicate The predicate to match
2327
+ * @returns A command that finds the closest parent node to the current selection that matches the predicate
2328
+ * @example ```js
2329
+ * findParentNode(node => node.type.name === 'paragraph')
2330
+ * ```
2331
+ */
2189
2332
  function findParentNode(predicate) {
2190
2333
  return (selection) => findParentNodeClosestToPos(selection.$from, predicate);
2191
2334
  }
@@ -2203,18 +2346,39 @@ function getSchema(extensions, editor) {
2203
2346
  return getSchemaByResolvedExtensions(resolvedExtensions, editor);
2204
2347
  }
2205
2348
 
2349
+ /**
2350
+ * Generate HTML from a JSONContent
2351
+ * @param doc The JSONContent to generate HTML from
2352
+ * @param extensions The extensions to use for the schema
2353
+ * @returns The generated HTML
2354
+ */
2206
2355
  function generateHTML(doc, extensions) {
2207
2356
  const schema = getSchema(extensions);
2208
2357
  const contentNode = Node$1.fromJSON(schema, doc);
2209
2358
  return getHTMLFromFragment(contentNode.content, schema);
2210
2359
  }
2211
2360
 
2361
+ /**
2362
+ * Generate JSONContent from HTML
2363
+ * @param html The HTML to generate JSONContent from
2364
+ * @param extensions The extensions to use for the schema
2365
+ * @returns The generated JSONContent
2366
+ */
2212
2367
  function generateJSON(html, extensions) {
2213
2368
  const schema = getSchema(extensions);
2214
2369
  const dom = elementFromString(html);
2215
2370
  return DOMParser.fromSchema(schema).parse(dom).toJSON();
2216
2371
  }
2217
2372
 
2373
+ /**
2374
+ * Gets the text of a Prosemirror node
2375
+ * @param node The Prosemirror node
2376
+ * @param options Options for the text serializer & block separator
2377
+ * @returns The text of the node
2378
+ * @example ```js
2379
+ * const text = getText(node, { blockSeparator: '\n' })
2380
+ * ```
2381
+ */
2218
2382
  function getText(node, options) {
2219
2383
  const range = {
2220
2384
  from: 0,
@@ -2223,6 +2387,13 @@ function getText(node, options) {
2223
2387
  return getTextBetween(node, range, options);
2224
2388
  }
2225
2389
 
2390
+ /**
2391
+ * Generate raw text from a JSONContent
2392
+ * @param doc The JSONContent to generate text from
2393
+ * @param extensions The extensions to use for the schema
2394
+ * @param options Options for the text generation f.e. blockSeparator or textSerializers
2395
+ * @returns The generated text
2396
+ */
2226
2397
  function generateText(doc, extensions, options) {
2227
2398
  const { blockSeparator = '\n\n', textSerializers = {} } = options || {};
2228
2399
  const schema = getSchema(extensions);
@@ -2250,6 +2421,12 @@ function getNodeAttributes(state, typeOrName) {
2250
2421
  return { ...node.attrs };
2251
2422
  }
2252
2423
 
2424
+ /**
2425
+ * Get node or mark attributes by type or name on the current editor state
2426
+ * @param state The current editor state
2427
+ * @param typeOrName The node or mark type or name
2428
+ * @returns The attributes of the node or mark or an empty object
2429
+ */
2253
2430
  function getAttributes(state, typeOrName) {
2254
2431
  const schemaType = getSchemaTypeNameByName(typeof typeOrName === 'string' ? typeOrName : typeOrName.name, state.schema);
2255
2432
  if (schemaType === 'node') {
@@ -2434,6 +2611,13 @@ const getNodeAtPosition = (state, typeOrName, pos, maxDepth = 20) => {
2434
2611
  return [node, currentDepth];
2435
2612
  };
2436
2613
 
2614
+ /**
2615
+ * Return attributes of an extension that should be splitted by keepOnSplit flag
2616
+ * @param extensionAttributes Array of extension attributes
2617
+ * @param typeName The type of the extension
2618
+ * @param attributes The attributes of the extension
2619
+ * @returns The splitted attributes
2620
+ */
2437
2621
  function getSplittedAttributes(extensionAttributes, typeName, attributes) {
2438
2622
  return Object.fromEntries(Object
2439
2623
  .entries(attributes)
@@ -3284,7 +3468,12 @@ const Keymap = Extension.create({
3284
3468
  const isAtStart = (parentIsIsolating && $parentPos.parent.childCount === 1)
3285
3469
  ? parentPos === $anchor.pos
3286
3470
  : Selection.atStart(doc).from === pos;
3287
- if (!empty || !isAtStart || !parent.type.isTextblock || parent.textContent.length) {
3471
+ if (!empty
3472
+ || !parent.type.isTextblock
3473
+ || parent.textContent.length
3474
+ || !isAtStart
3475
+ || (isAtStart && $anchor.parent.type.name === 'paragraph') // prevent clearNodes when no nodes to clear, otherwise history stack is appended
3476
+ ) {
3288
3477
  return false;
3289
3478
  }
3290
3479
  return commands.clearNodes();
@@ -3546,28 +3735,30 @@ class NodePos {
3546
3735
  }
3547
3736
  querySelectorAll(selector, attributes = {}, firstItemOnly = false) {
3548
3737
  let nodes = [];
3549
- // iterate through children recursively finding all nodes which match the selector with the node name
3550
3738
  if (!this.children || this.children.length === 0) {
3551
3739
  return nodes;
3552
3740
  }
3741
+ const attrKeys = Object.keys(attributes);
3742
+ /**
3743
+ * Finds all children recursively that match the selector and attributes
3744
+ * If firstItemOnly is true, it will return the first item found
3745
+ */
3553
3746
  this.children.forEach(childPos => {
3747
+ // If we already found a node and we only want the first item, we dont need to keep going
3748
+ if (firstItemOnly && nodes.length > 0) {
3749
+ return;
3750
+ }
3554
3751
  if (childPos.node.type.name === selector) {
3555
- if (Object.keys(attributes).length > 0) {
3556
- const nodeAttributes = childPos.node.attrs;
3557
- const attrKeys = Object.keys(attributes);
3558
- for (let index = 0; index < attrKeys.length; index += 1) {
3559
- const key = attrKeys[index];
3560
- if (nodeAttributes[key] !== attributes[key]) {
3561
- return;
3562
- }
3563
- }
3564
- }
3565
- nodes.push(childPos);
3566
- if (firstItemOnly) {
3567
- return;
3752
+ const doesAllAttributesMatch = attrKeys.every(key => attributes[key] === childPos.node.attrs[key]);
3753
+ if (doesAllAttributesMatch) {
3754
+ nodes.push(childPos);
3568
3755
  }
3569
3756
  }
3570
- nodes = nodes.concat(childPos.querySelectorAll(selector));
3757
+ // If we already found a node and we only want the first item, we can stop here and skip the recursion
3758
+ if (firstItemOnly && nodes.length > 0) {
3759
+ return;
3760
+ }
3761
+ nodes = nodes.concat(childPos.querySelectorAll(selector, attributes, firstItemOnly));
3571
3762
  });
3572
3763
  return nodes;
3573
3764
  }
@@ -4054,6 +4245,7 @@ class Editor extends EventEmitter {
4054
4245
  /**
4055
4246
  * Build an input rule that adds a mark when the
4056
4247
  * matched text is typed into it.
4248
+ * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4057
4249
  */
4058
4250
  function markInputRule(config) {
4059
4251
  return new InputRule({
@@ -4097,6 +4289,7 @@ function markInputRule(config) {
4097
4289
  /**
4098
4290
  * Build an input rule that adds a node when the
4099
4291
  * matched text is typed into it.
4292
+ * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4100
4293
  */
4101
4294
  function nodeInputRule(config) {
4102
4295
  return new InputRule({
@@ -4135,6 +4328,7 @@ function nodeInputRule(config) {
4135
4328
  * matched text is typed into it. When using a regular expresion you’ll
4136
4329
  * probably want the regexp to start with `^`, so that the pattern can
4137
4330
  * only occur at the start of a textblock.
4331
+ * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4138
4332
  */
4139
4333
  function textblockTypeInputRule(config) {
4140
4334
  return new InputRule({
@@ -4155,6 +4349,7 @@ function textblockTypeInputRule(config) {
4155
4349
  /**
4156
4350
  * Build an input rule that replaces text when the
4157
4351
  * matched text is typed into it.
4352
+ * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4158
4353
  */
4159
4354
  function textInputRule(config) {
4160
4355
  return new InputRule({
@@ -4191,6 +4386,7 @@ function textInputRule(config) {
4191
4386
  * two nodes. You can pass a join predicate, which takes a regular
4192
4387
  * expression match and the node before the wrapped node, and can
4193
4388
  * return a boolean to indicate whether a join should happen.
4389
+ * @see https://tiptap.dev/guide/custom-extensions/#input-rules
4194
4390
  */
4195
4391
  function wrappingInputRule(config) {
4196
4392
  return new InputRule({
@@ -4230,6 +4426,10 @@ function wrappingInputRule(config) {
4230
4426
  });
4231
4427
  }
4232
4428
 
4429
+ /**
4430
+ * The Mark class is used to create custom mark extensions.
4431
+ * @see https://tiptap.dev/api/extensions#create-a-new-extension
4432
+ */
4233
4433
  class Mark {
4234
4434
  constructor(config = {}) {
4235
4435
  this.type = 'mark';
@@ -4313,6 +4513,10 @@ class Mark {
4313
4513
  }
4314
4514
  }
4315
4515
 
4516
+ /**
4517
+ * The Node class is used to create custom node extensions.
4518
+ * @see https://tiptap.dev/api/extensions#create-a-new-extension
4519
+ */
4316
4520
  class Node {
4317
4521
  constructor(config = {}) {
4318
4522
  this.type = 'node';
@@ -4380,6 +4584,10 @@ function isAndroid() {
4380
4584
  return navigator.platform === 'Android' || /android/i.test(navigator.userAgent);
4381
4585
  }
4382
4586
 
4587
+ /**
4588
+ * Node views are used to customize the rendered DOM structure of a node.
4589
+ * @see https://tiptap.dev/guide/node-views
4590
+ */
4383
4591
  class NodeView {
4384
4592
  constructor(component, props, options) {
4385
4593
  this.isDragging = false;
@@ -4570,6 +4778,7 @@ class NodeView {
4570
4778
  /**
4571
4779
  * Build an paste rule that adds a mark when the
4572
4780
  * matched text is pasted into it.
4781
+ * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
4573
4782
  */
4574
4783
  function markPasteRule(config) {
4575
4784
  return new PasteRule({
@@ -4623,6 +4832,7 @@ function isString(value) {
4623
4832
  /**
4624
4833
  * Build an paste rule that adds a node when the
4625
4834
  * matched text is pasted into it.
4835
+ * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
4626
4836
  */
4627
4837
  function nodePasteRule(config) {
4628
4838
  return new PasteRule({
@@ -4645,6 +4855,7 @@ function nodePasteRule(config) {
4645
4855
  /**
4646
4856
  * Build an paste rule that replaces text when the
4647
4857
  * matched text is pasted into it.
4858
+ * @see https://tiptap.dev/guide/custom-extensions/#paste-rules
4648
4859
  */
4649
4860
  function textPasteRule(config) {
4650
4861
  return new PasteRule({