@tiptap/core 3.0.0-next.0 → 3.0.0-next.2

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 (214) hide show
  1. package/dist/index.cjs +4934 -4574
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +3576 -0
  4. package/dist/index.d.ts +3576 -0
  5. package/dist/index.js +4839 -4481
  6. package/dist/index.js.map +1 -1
  7. package/package.json +6 -8
  8. package/src/Editor.ts +66 -10
  9. package/src/EventEmitter.ts +9 -0
  10. package/src/Extension.ts +4 -3
  11. package/src/ExtensionManager.ts +18 -12
  12. package/src/InputRule.ts +45 -30
  13. package/src/Mark.ts +4 -3
  14. package/src/Node.ts +23 -3
  15. package/src/NodePos.ts +9 -4
  16. package/src/NodeView.ts +43 -12
  17. package/src/PasteRule.ts +96 -42
  18. package/src/commands/focus.ts +1 -6
  19. package/src/commands/insertContent.ts +9 -9
  20. package/src/commands/insertContentAt.ts +23 -3
  21. package/src/commands/selectAll.ts +10 -5
  22. package/src/commands/setContent.ts +10 -14
  23. package/src/commands/setMeta.ts +3 -1
  24. package/src/commands/setNode.ts +9 -2
  25. package/src/commands/splitListItem.ts +27 -17
  26. package/src/commands/toggleNode.ts +11 -2
  27. package/src/commands/updateAttributes.ts +72 -12
  28. package/src/extensions/drop.ts +26 -0
  29. package/src/extensions/index.ts +2 -0
  30. package/src/extensions/keymap.ts +5 -2
  31. package/src/extensions/paste.ts +26 -0
  32. package/src/helpers/createDocument.ts +4 -2
  33. package/src/helpers/createNodeFromContent.ts +11 -2
  34. package/src/helpers/getAttributesFromExtensions.ts +1 -1
  35. package/src/helpers/getMarkRange.ts +35 -8
  36. package/src/helpers/getMarksBetween.ts +1 -1
  37. package/src/helpers/getRenderedAttributes.ts +3 -0
  38. package/src/helpers/getSchemaByResolvedExtensions.ts +3 -2
  39. package/src/helpers/isList.ts +1 -1
  40. package/src/helpers/isNodeEmpty.ts +33 -12
  41. package/src/inputRules/markInputRule.ts +1 -1
  42. package/src/inputRules/nodeInputRule.ts +1 -1
  43. package/src/inputRules/textInputRule.ts +1 -1
  44. package/src/inputRules/textblockTypeInputRule.ts +1 -1
  45. package/src/inputRules/wrappingInputRule.ts +1 -1
  46. package/src/pasteRules/markPasteRule.ts +1 -1
  47. package/src/pasteRules/nodePasteRule.ts +15 -6
  48. package/src/pasteRules/textPasteRule.ts +1 -1
  49. package/src/style.ts +2 -2
  50. package/src/types.ts +107 -19
  51. package/src/utilities/mergeAttributes.ts +18 -1
  52. package/dist/index.umd.js +0 -5130
  53. package/dist/index.umd.js.map +0 -1
  54. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  55. package/dist/packages/core/src/Editor.d.ts +0 -159
  56. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  57. package/dist/packages/core/src/Extension.d.ts +0 -343
  58. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  59. package/dist/packages/core/src/InputRule.d.ts +0 -42
  60. package/dist/packages/core/src/Mark.d.ts +0 -451
  61. package/dist/packages/core/src/Node.d.ts +0 -611
  62. package/dist/packages/core/src/NodePos.d.ts +0 -44
  63. package/dist/packages/core/src/NodeView.d.ts +0 -31
  64. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  65. package/dist/packages/core/src/Tracker.d.ts +0 -11
  66. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  67. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  68. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  69. package/dist/packages/core/src/commands/command.d.ts +0 -18
  70. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  71. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  72. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  73. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  74. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  75. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  76. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  77. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  78. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  79. package/dist/packages/core/src/commands/first.d.ts +0 -14
  80. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  81. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  82. package/dist/packages/core/src/commands/index.d.ts +0 -55
  83. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  84. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  85. package/dist/packages/core/src/commands/join.d.ts +0 -41
  86. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  87. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  88. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  89. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  90. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  91. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  92. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  93. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  94. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  95. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  96. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  97. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  98. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  99. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  100. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  101. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  102. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  103. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  104. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  105. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  106. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  107. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  108. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  109. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  110. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  111. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  112. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  113. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  114. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  115. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  116. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  117. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  118. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  119. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  120. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  121. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  122. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  123. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  124. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  125. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  126. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  127. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  128. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  129. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  130. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  131. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  132. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  133. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  134. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  135. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  136. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  137. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  138. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  139. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  140. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  141. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  142. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  143. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  144. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  145. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  146. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  147. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  148. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  149. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  150. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  151. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  152. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  153. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  154. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  155. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  156. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  157. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  158. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  159. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  160. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  161. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  162. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  163. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  164. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  165. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  166. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  167. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  168. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  169. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  170. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  171. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  172. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  173. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -8
  174. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  175. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  176. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  177. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  178. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  179. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  180. package/dist/packages/core/src/index.d.ts +0 -24
  181. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  182. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  183. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  184. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  185. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  186. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  187. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  188. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  189. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  190. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  191. package/dist/packages/core/src/style.d.ts +0 -1
  192. package/dist/packages/core/src/types.d.ts +0 -253
  193. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  194. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  195. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  196. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  197. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  198. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  199. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  200. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  201. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  202. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  203. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  204. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  205. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  206. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  207. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  208. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  209. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  210. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  211. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  212. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  213. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  214. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/core",
3
3
  "description": "headless rich text editor",
4
- "version": "3.0.0-next.0",
4
+ "version": "3.0.0-next.2",
5
5
  "homepage": "https://tiptap.dev",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -18,24 +18,23 @@
18
18
  "type": "module",
19
19
  "exports": {
20
20
  ".": {
21
- "types": "./dist/packages/core/src/index.d.ts",
21
+ "types": "./dist/index.d.ts",
22
22
  "import": "./dist/index.js",
23
23
  "require": "./dist/index.cjs"
24
24
  }
25
25
  },
26
26
  "main": "dist/index.cjs",
27
27
  "module": "dist/index.js",
28
- "umd": "dist/index.umd.js",
29
- "types": "dist/packages/core/src/index.d.ts",
28
+ "types": "dist/index.d.ts",
30
29
  "files": [
31
30
  "src",
32
31
  "dist"
33
32
  ],
34
33
  "devDependencies": {
35
- "@tiptap/pm": "^3.0.0-next.0"
34
+ "@tiptap/pm": "^3.0.0-next.2"
36
35
  },
37
36
  "peerDependencies": {
38
- "@tiptap/pm": "^3.0.0-next.0"
37
+ "@tiptap/pm": "^3.0.0-next.1"
39
38
  },
40
39
  "repository": {
41
40
  "type": "git",
@@ -44,7 +43,6 @@
44
43
  },
45
44
  "sideEffects": false,
46
45
  "scripts": {
47
- "clean": "rm -rf dist",
48
- "build": "npm run clean && rollup -c"
46
+ "build": "tsup"
49
47
  }
50
48
  }
package/src/Editor.ts CHANGED
@@ -13,7 +13,8 @@ import { CommandManager } from './CommandManager.js'
13
13
  import { EventEmitter } from './EventEmitter.js'
14
14
  import { ExtensionManager } from './ExtensionManager.js'
15
15
  import {
16
- ClipboardTextSerializer, Commands, Editable, FocusEvents, Keymap, Tabindex,
16
+ ClipboardTextSerializer, Commands, Drop, Editable, FocusEvents, Keymap, Paste,
17
+ Tabindex,
17
18
  } from './extensions/index.js'
18
19
  import { createDocument } from './helpers/createDocument.js'
19
20
  import { getAttributes } from './helpers/getAttributes.js'
@@ -57,8 +58,18 @@ export class Editor extends EventEmitter<EditorEvents> {
57
58
 
58
59
  public isFocused = false
59
60
 
61
+ /**
62
+ * The editor is considered initialized after the `create` event has been emitted.
63
+ */
64
+ public isInitialized = false
65
+
60
66
  public extensionStorage: Record<string, any> = {}
61
67
 
68
+ /**
69
+ * A unique ID for this editor instance.
70
+ */
71
+ public instanceId = Math.random().toString(36).slice(2, 9)
72
+
62
73
  public options: EditorOptions = {
63
74
  element: document.createElement('div'),
64
75
  content: '',
@@ -83,6 +94,8 @@ export class Editor extends EventEmitter<EditorEvents> {
83
94
  onBlur: () => null,
84
95
  onDestroy: () => null,
85
96
  onContentError: ({ error }) => { throw error },
97
+ onPaste: () => null,
98
+ onDrop: () => null,
86
99
  }
87
100
 
88
101
  constructor(options: Partial<EditorOptions> = {}) {
@@ -103,6 +116,8 @@ export class Editor extends EventEmitter<EditorEvents> {
103
116
  this.on('focus', this.options.onFocus)
104
117
  this.on('blur', this.options.onBlur)
105
118
  this.on('destroy', this.options.onDestroy)
119
+ this.on('drop', ({ event, slice, moved }) => this.options.onDrop(event, slice, moved))
120
+ this.on('paste', ({ event, slice }) => this.options.onPaste(event, slice))
106
121
 
107
122
  window.setTimeout(() => {
108
123
  if (this.isDestroyed) {
@@ -111,6 +126,7 @@ export class Editor extends EventEmitter<EditorEvents> {
111
126
 
112
127
  this.commands.focus(this.options.autofocus)
113
128
  this.emit('create', { editor: this })
129
+ this.isInitialized = true
114
130
  }, 0)
115
131
  }
116
132
 
@@ -206,11 +222,12 @@ export class Editor extends EventEmitter<EditorEvents> {
206
222
  *
207
223
  * @param plugin A ProseMirror plugin
208
224
  * @param handlePlugins Control how to merge the plugin into the existing plugins.
225
+ * @returns The new editor state
209
226
  */
210
227
  public registerPlugin(
211
228
  plugin: Plugin,
212
229
  handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[],
213
- ): void {
230
+ ): EditorState {
214
231
  const plugins = isFunction(handlePlugins)
215
232
  ? handlePlugins(plugin, [...this.state.plugins])
216
233
  : [...this.state.plugins, plugin]
@@ -218,27 +235,44 @@ export class Editor extends EventEmitter<EditorEvents> {
218
235
  const state = this.state.reconfigure({ plugins })
219
236
 
220
237
  this.view.updateState(state)
238
+
239
+ return state
221
240
  }
222
241
 
223
242
  /**
224
243
  * Unregister a ProseMirror plugin.
225
244
  *
226
- * @param nameOrPluginKey The plugins name
245
+ * @param nameOrPluginKeyToRemove The plugins name
246
+ * @returns The new editor state or undefined if the editor is destroyed
227
247
  */
228
- public unregisterPlugin(nameOrPluginKey: string | PluginKey): void {
248
+ public unregisterPlugin(nameOrPluginKeyToRemove: string | PluginKey | (string | PluginKey)[]): EditorState | undefined {
229
249
  if (this.isDestroyed) {
230
- return
250
+ return undefined
231
251
  }
232
252
 
233
- // @ts-ignore
234
- const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key
253
+ const prevPlugins = this.state.plugins
254
+ let plugins = prevPlugins;
255
+
256
+ ([] as (string | PluginKey)[]).concat(nameOrPluginKeyToRemove).forEach(nameOrPluginKey => {
257
+ // @ts-ignore
258
+ const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key
235
259
 
236
- const state = this.state.reconfigure({
237
260
  // @ts-ignore
238
- plugins: this.state.plugins.filter(plugin => !plugin.key.startsWith(name)),
261
+ plugins = prevPlugins.filter(plugin => !plugin.key.startsWith(name))
262
+ })
263
+
264
+ if (prevPlugins.length === plugins.length) {
265
+ // No plugin was removed, so we don’t need to update the state
266
+ return undefined
267
+ }
268
+
269
+ const state = this.state.reconfigure({
270
+ plugins,
239
271
  })
240
272
 
241
273
  this.view.updateState(state)
274
+
275
+ return state
242
276
  }
243
277
 
244
278
  /**
@@ -255,7 +289,14 @@ export class Editor extends EventEmitter<EditorEvents> {
255
289
  FocusEvents,
256
290
  Keymap,
257
291
  Tabindex,
258
- ] : []
292
+ Drop,
293
+ Paste,
294
+ ].filter(ext => {
295
+ if (typeof this.options.enableCoreExtensions === 'object') {
296
+ return this.options.enableCoreExtensions[ext.name as keyof typeof this.options.enableCoreExtensions] !== false
297
+ }
298
+ return true
299
+ }) : []
259
300
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
260
301
  return ['extension', 'node', 'mark'].includes(extension?.type)
261
302
  })
@@ -301,6 +342,9 @@ export class Editor extends EventEmitter<EditorEvents> {
301
342
  editor: this,
302
343
  error: e as Error,
303
344
  disableCollaboration: () => {
345
+ if (this.storage.collaboration) {
346
+ this.storage.collaboration.isDisabled = true
347
+ }
304
348
  // To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
305
349
  this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration')
306
350
 
@@ -321,6 +365,11 @@ export class Editor extends EventEmitter<EditorEvents> {
321
365
 
322
366
  this.view = new EditorView(this.options.element, {
323
367
  ...this.options.editorProps,
368
+ attributes: {
369
+ // add `role="textbox"` to the editor element
370
+ role: 'textbox',
371
+ ...this.options.editorProps?.attributes,
372
+ },
324
373
  dispatchTransaction: this.dispatchTransaction.bind(this),
325
374
  state: EditorState.create({
326
375
  doc,
@@ -539,6 +588,13 @@ export class Editor extends EventEmitter<EditorEvents> {
539
588
  this.emit('destroy')
540
589
 
541
590
  if (this.view) {
591
+ // Cleanup our reference to prevent circular references which caused memory leaks
592
+ // @ts-ignore
593
+ const dom = this.view.dom as TiptapEditorHTMLElement
594
+
595
+ if (dom && dom.editor) {
596
+ delete dom.editor
597
+ }
542
598
  this.view.destroy()
543
599
  }
544
600
 
@@ -46,6 +46,15 @@ export class EventEmitter<T extends Record<string, any>> {
46
46
  return this
47
47
  }
48
48
 
49
+ public once<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this {
50
+ const onceFn = (...args: CallbackType<T, EventName>) => {
51
+ this.off(event, onceFn)
52
+ fn.apply(this, args)
53
+ }
54
+
55
+ return this.on(event, onceFn)
56
+ }
57
+
49
58
  public removeAllListeners(): void {
50
59
  this.callbacks = {}
51
60
  }
package/src/Extension.ts CHANGED
@@ -32,10 +32,10 @@ declare module '@tiptap/core' {
32
32
  name: string
33
33
 
34
34
  /**
35
- * The priority of your extension. The higher, the later it will be called
35
+ * The priority of your extension. The higher, the earlier it will be called
36
36
  * and will take precedence over other extensions with a lower priority.
37
- * @default 1000
38
- * @example 1001
37
+ * @default 100
38
+ * @example 101
39
39
  */
40
40
  priority?: number
41
41
 
@@ -339,6 +339,7 @@ declare module '@tiptap/core' {
339
339
  parent: ParentConfig<ExtensionConfig<Options, Storage>>['onTransaction']
340
340
  },
341
341
  props: {
342
+ editor: Editor
342
343
  transaction: Transaction
343
344
  },
344
345
  ) => void)
@@ -1,7 +1,7 @@
1
1
  import { keymap } from '@tiptap/pm/keymap'
2
- import { Node as ProsemirrorNode, Schema } from '@tiptap/pm/model'
2
+ import { Schema } from '@tiptap/pm/model'
3
3
  import { Plugin } from '@tiptap/pm/state'
4
- import { Decoration, EditorView } from '@tiptap/pm/view'
4
+ import { NodeViewConstructor } from '@tiptap/pm/view'
5
5
 
6
6
  import type { Editor } from './Editor.js'
7
7
  import { getAttributesFromExtensions } from './helpers/getAttributesFromExtensions.js'
@@ -12,8 +12,9 @@ import { getSchemaByResolvedExtensions } from './helpers/getSchemaByResolvedExte
12
12
  import { getSchemaTypeByName } from './helpers/getSchemaTypeByName.js'
13
13
  import { isExtensionRulesEnabled } from './helpers/isExtensionRulesEnabled.js'
14
14
  import { splitExtensions } from './helpers/splitExtensions.js'
15
- import { Mark, NodeConfig } from './index.js'
15
+ import type { NodeConfig } from './index.js'
16
16
  import { InputRule, inputRulesPlugin } from './InputRule.js'
17
+ import { Mark } from './Mark.js'
17
18
  import { PasteRule, pasteRulesPlugin } from './PasteRule.js'
18
19
  import { AnyConfig, Extensions, RawCommands } from './types.js'
19
20
  import { callOrReturn } from './utilities/callOrReturn.js'
@@ -260,7 +261,7 @@ export class ExtensionManager {
260
261
  * Get all node views from the extensions.
261
262
  * @returns An object with all node views where the key is the node name and the value is the node view function
262
263
  */
263
- get nodeViews() {
264
+ get nodeViews(): Record<string, NodeViewConstructor> {
264
265
  const { editor } = this
265
266
  const { nodeExtensions } = splitExtensions(this.extensions)
266
267
 
@@ -288,21 +289,26 @@ export class ExtensionManager {
288
289
  return []
289
290
  }
290
291
 
291
- const nodeview = (
292
- node: ProsemirrorNode,
293
- view: EditorView,
294
- getPos: (() => number) | boolean,
295
- decorations: Decoration[],
292
+ const nodeview: NodeViewConstructor = (
293
+ node,
294
+ view,
295
+ getPos,
296
+ decorations,
297
+ innerDecorations,
296
298
  ) => {
297
299
  const HTMLAttributes = getRenderedAttributes(node, extensionAttributes)
298
300
 
299
301
  return addNodeView()({
300
- editor,
302
+ // pass-through
301
303
  node,
302
- getPos,
304
+ view,
305
+ getPos: getPos as () => number,
303
306
  decorations,
304
- HTMLAttributes,
307
+ innerDecorations,
308
+ // tiptap-specific
309
+ editor,
305
310
  extension,
311
+ HTMLAttributes,
306
312
  })
307
313
  }
308
314
 
package/src/InputRule.ts CHANGED
@@ -1,8 +1,10 @@
1
+ import { Fragment, Node as ProseMirrorNode } from '@tiptap/pm/model'
1
2
  import { EditorState, Plugin, TextSelection } from '@tiptap/pm/state'
2
3
 
3
4
  import { CommandManager } from './CommandManager.js'
4
5
  import { Editor } from './Editor.js'
5
6
  import { createChainableState } from './helpers/createChainableState.js'
7
+ import { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js'
6
8
  import { getTextContentFromNodes } from './helpers/getTextContentFromNodes.js'
7
9
  import {
8
10
  CanCommands,
@@ -14,37 +16,37 @@ import {
14
16
  import { isRegExp } from './utilities/isRegExp.js'
15
17
 
16
18
  export type InputRuleMatch = {
17
- index: number
18
- text: string
19
- replaceWith?: string
20
- match?: RegExpMatchArray
21
- data?: Record<string, any>
22
- }
19
+ index: number;
20
+ text: string;
21
+ replaceWith?: string;
22
+ match?: RegExpMatchArray;
23
+ data?: Record<string, any>;
24
+ };
23
25
 
24
- export type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null)
26
+ export type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null);
25
27
 
26
28
  export class InputRule {
27
29
  find: InputRuleFinder
28
30
 
29
31
  handler: (props: {
30
- state: EditorState
31
- range: Range
32
- match: ExtendedRegExpMatchArray
33
- commands: SingleCommands
34
- chain: () => ChainedCommands
35
- can: () => CanCommands
32
+ state: EditorState;
33
+ range: Range;
34
+ match: ExtendedRegExpMatchArray;
35
+ commands: SingleCommands;
36
+ chain: () => ChainedCommands;
37
+ can: () => CanCommands;
36
38
  }) => void | null
37
39
 
38
40
  constructor(config: {
39
- find: InputRuleFinder
41
+ find: InputRuleFinder;
40
42
  handler: (props: {
41
- state: EditorState
42
- range: Range
43
- match: ExtendedRegExpMatchArray
44
- commands: SingleCommands
45
- chain: () => ChainedCommands
46
- can: () => CanCommands
47
- }) => void | null
43
+ state: EditorState;
44
+ range: Range;
45
+ match: ExtendedRegExpMatchArray;
46
+ commands: SingleCommands;
47
+ chain: () => ChainedCommands;
48
+ can: () => CanCommands;
49
+ }) => void | null;
48
50
  }) {
49
51
  this.find = config.find
50
52
  this.handler = config.handler
@@ -85,12 +87,12 @@ const inputRuleMatcherHandler = (
85
87
  }
86
88
 
87
89
  function run(config: {
88
- editor: Editor
89
- from: number
90
- to: number
91
- text: string
92
- rules: InputRule[]
93
- plugin: Plugin
90
+ editor: Editor;
91
+ from: number;
92
+ to: number;
93
+ text: string;
94
+ rules: InputRule[];
95
+ plugin: Plugin;
94
96
  }): boolean {
95
97
  const {
96
98
  editor, from, to, text, rules, plugin,
@@ -184,7 +186,7 @@ export function inputRulesPlugin(props: { editor: Editor; rules: InputRule[] }):
184
186
  init() {
185
187
  return null
186
188
  },
187
- apply(tr, prev) {
189
+ apply(tr, prev, state) {
188
190
  const stored = tr.getMeta(plugin)
189
191
 
190
192
  if (stored) {
@@ -192,12 +194,25 @@ export function inputRulesPlugin(props: { editor: Editor; rules: InputRule[] }):
192
194
  }
193
195
 
194
196
  // if InputRule is triggered by insertContent()
195
- const simulatedInputMeta = tr.getMeta('applyInputRules')
197
+ const simulatedInputMeta = tr.getMeta('applyInputRules') as
198
+ | undefined
199
+ | {
200
+ from: number;
201
+ text: string | ProseMirrorNode | Fragment;
202
+ }
196
203
  const isSimulatedInput = !!simulatedInputMeta
197
204
 
198
205
  if (isSimulatedInput) {
199
206
  setTimeout(() => {
200
- const { from, text } = simulatedInputMeta
207
+ let { text } = simulatedInputMeta
208
+
209
+ if (typeof text === 'string') {
210
+ text = text as string
211
+ } else {
212
+ text = getHTMLFromFragment(Fragment.from(text), state.schema)
213
+ }
214
+
215
+ const { from } = simulatedInputMeta
201
216
  const to = from + text.length
202
217
 
203
218
  run({
package/src/Mark.ts CHANGED
@@ -35,10 +35,10 @@ declare module '@tiptap/core' {
35
35
  name: string
36
36
 
37
37
  /**
38
- * The priority of your extension. The higher, the later it will be called
38
+ * The priority of your extension. The higher, the earlier it will be called
39
39
  * and will take precedence over other extensions with a lower priority.
40
- * @default 1000
41
- * @example 1001
40
+ * @default 100
41
+ * @example 101
42
42
  */
43
43
  priority?: number
44
44
 
@@ -352,6 +352,7 @@ declare module '@tiptap/core' {
352
352
  parent: ParentConfig<MarkConfig<Options, Storage>>['onTransaction']
353
353
  },
354
354
  props: {
355
+ editor: Editor
355
356
  transaction: Transaction
356
357
  },
357
358
  ) => void)
package/src/Node.ts CHANGED
@@ -36,10 +36,10 @@ declare module '@tiptap/core' {
36
36
  name: string
37
37
 
38
38
  /**
39
- * The priority of your extension. The higher, the later it will be called
39
+ * The priority of your extension. The higher, the earlier it will be called
40
40
  * and will take precedence over other extensions with a lower priority.
41
- * @default 1000
42
- * @example 1001
41
+ * @default 100
42
+ * @example 101
43
43
  */
44
44
  priority?: number
45
45
 
@@ -354,6 +354,7 @@ declare module '@tiptap/core' {
354
354
  parent: ParentConfig<NodeConfig<Options, Storage>>['onTransaction']
355
355
  },
356
356
  props: {
357
+ editor: Editor
357
358
  transaction: Transaction
358
359
  },
359
360
  ) => void)
@@ -594,6 +595,25 @@ declare module '@tiptap/core' {
594
595
  editor?: Editor
595
596
  }) => NodeSpec['whitespace'])
596
597
 
598
+ /**
599
+ * Allows a **single** node to be set as linebreak equivalent (e.g. hardBreak).
600
+ * When converting between block types that have whitespace set to "pre"
601
+ * and don't support the linebreak node (e.g. codeBlock) and other block types
602
+ * that do support the linebreak node (e.g. paragraphs) - this node will be used
603
+ * as the linebreak instead of stripping the newline.
604
+ *
605
+ * See [linebreakReplacement](https://prosemirror.net/docs/ref/#model.NodeSpec.linebreakReplacement).
606
+ */
607
+ linebreakReplacement?:
608
+ | NodeSpec['linebreakReplacement']
609
+ | ((this: {
610
+ name: string
611
+ options: Options
612
+ storage: Storage
613
+ parent: ParentConfig<NodeConfig<Options, Storage>>['linebreakReplacement']
614
+ editor?: Editor
615
+ }) => NodeSpec['linebreakReplacement'])
616
+
597
617
  /**
598
618
  * When enabled, enables both
599
619
  * [`definingAsContext`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext) and
package/src/NodePos.ts CHANGED
@@ -135,8 +135,9 @@ export class NodePos {
135
135
 
136
136
  this.node.content.forEach((node, offset) => {
137
137
  const isBlock = node.isBlock && !node.isTextblock
138
+ const isNonTextAtom = node.isAtom && !node.isText
138
139
 
139
- const targetPos = this.pos + offset + 1
140
+ const targetPos = this.pos + offset + (isNonTextAtom ? 0 : 1)
140
141
  const $pos = this.resolvedPos.doc.resolve(targetPos)
141
142
 
142
143
  if (!isBlock && $pos.depth <= this.depth) {
@@ -235,9 +236,13 @@ export class NodePos {
235
236
  }
236
237
 
237
238
  setAttribute(attributes: { [key: string]: any }) {
238
- const oldSelection = this.editor.state.selection
239
+ const { tr } = this.editor.state
239
240
 
240
- this.editor.chain().setTextSelection(this.from).updateAttributes(this.node.type.name, attributes).setTextSelection(oldSelection.from)
241
- .run()
241
+ tr.setNodeMarkup(this.from, undefined, {
242
+ ...this.node.attrs,
243
+ ...attributes,
244
+ })
245
+
246
+ this.editor.view.dispatch(tr)
242
247
  }
243
248
  }
package/src/NodeView.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { Node as ProseMirrorNode } from '@tiptap/pm/model'
2
1
  import { NodeSelection } from '@tiptap/pm/state'
3
- import { NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
2
+ import { NodeView as ProseMirrorNodeView, ViewMutationRecord } from '@tiptap/pm/view'
4
3
 
5
4
  import { Editor as CoreEditor } from './Editor.js'
6
- import { Node } from './Node.js'
7
5
  import { DecorationWithType, NodeViewRendererOptions, NodeViewRendererProps } from './types.js'
8
6
  import { isAndroid } from './utilities/isAndroid.js'
9
7
  import { isiOS } from './utilities/isiOS.js'
@@ -23,13 +21,19 @@ export class NodeView<
23
21
 
24
22
  options: Options
25
23
 
26
- extension: Node
24
+ extension: NodeViewRendererProps['extension']
27
25
 
28
- node: ProseMirrorNode
26
+ node: NodeViewRendererProps['node']
29
27
 
30
- decorations: DecorationWithType[]
28
+ decorations: NodeViewRendererProps['decorations']
31
29
 
32
- getPos: any
30
+ innerDecorations: NodeViewRendererProps['innerDecorations']
31
+
32
+ view: NodeViewRendererProps['view']
33
+
34
+ getPos: NodeViewRendererProps['getPos']
35
+
36
+ HTMLAttributes: NodeViewRendererProps['HTMLAttributes']
33
37
 
34
38
  isDragging = false
35
39
 
@@ -44,6 +48,9 @@ export class NodeView<
44
48
  this.extension = props.extension
45
49
  this.node = props.node
46
50
  this.decorations = props.decorations as DecorationWithType[]
51
+ this.innerDecorations = props.innerDecorations
52
+ this.view = props.view
53
+ this.HTMLAttributes = props.HTMLAttributes
47
54
  this.getPos = props.getPos
48
55
  this.mount()
49
56
  }
@@ -93,9 +100,14 @@ export class NodeView<
93
100
 
94
101
  event.dataTransfer?.setDragImage(this.dom, x, y)
95
102
 
103
+ const pos = this.getPos()
104
+
105
+ if (typeof pos !== 'number') {
106
+ return
107
+ }
96
108
  // we need to tell ProseMirror that we want to move the whole node
97
109
  // so we create a NodeSelection
98
- const selection = NodeSelection.create(view.state.doc, this.getPos())
110
+ const selection = NodeSelection.create(view.state.doc, pos)
99
111
  const transaction = view.state.tr.setSelection(selection)
100
112
 
101
113
  view.dispatch(transaction)
@@ -139,11 +151,11 @@ export class NodeView<
139
151
  // ProseMirror tries to drag selectable nodes
140
152
  // even if `draggable` is set to `false`
141
153
  // this fix prevents that
142
- if (!isDraggable && isSelectable && isDragEvent) {
154
+ if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
143
155
  event.preventDefault()
144
156
  }
145
157
 
146
- if (isDraggable && isDragEvent && !isDragging) {
158
+ if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
147
159
  event.preventDefault()
148
160
  return false
149
161
  }
@@ -197,7 +209,12 @@ export class NodeView<
197
209
  return true
198
210
  }
199
211
 
200
- ignoreMutation(mutation: MutationRecord | { type: 'selection'; target: Element }) {
212
+ /**
213
+ * Called when a DOM [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) or a selection change happens within the view.
214
+ * @return `false` if the editor should re-read the selection or re-parse the range around the mutation
215
+ * @return `true` if it can safely be ignored.
216
+ */
217
+ ignoreMutation(mutation: ViewMutationRecord) {
201
218
  if (!this.dom || !this.contentDOM) {
202
219
  return true
203
220
  }
@@ -254,10 +271,17 @@ export class NodeView<
254
271
  return true
255
272
  }
256
273
 
257
- updateAttributes(attributes: {}) {
274
+ /**
275
+ * Update the attributes of the prosemirror node.
276
+ */
277
+ updateAttributes(attributes: Record<string, any>): void {
258
278
  this.editor.commands.command(({ tr }) => {
259
279
  const pos = this.getPos()
260
280
 
281
+ if (typeof pos !== 'number') {
282
+ return false
283
+ }
284
+
261
285
  tr.setNodeMarkup(pos, undefined, {
262
286
  ...this.node.attrs,
263
287
  ...attributes,
@@ -267,8 +291,15 @@ export class NodeView<
267
291
  })
268
292
  }
269
293
 
294
+ /**
295
+ * Delete the node.
296
+ */
270
297
  deleteNode(): void {
271
298
  const from = this.getPos()
299
+
300
+ if (typeof from !== 'number') {
301
+ return
302
+ }
272
303
  const to = from + this.node.nodeSize
273
304
 
274
305
  this.editor.commands.deleteRange({ from, to })