@tiptap/core 3.0.0 → 3.0.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 (340) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +5169 -4654
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +3356 -0
  6. package/dist/index.d.ts +3356 -0
  7. package/dist/index.js +5051 -4561
  8. package/dist/index.js.map +1 -1
  9. package/dist/jsx-runtime/jsx-runtime.cjs +56 -0
  10. package/dist/jsx-runtime/jsx-runtime.cjs.map +1 -0
  11. package/dist/jsx-runtime/jsx-runtime.d.cts +22 -0
  12. package/dist/jsx-runtime/jsx-runtime.d.ts +22 -0
  13. package/dist/jsx-runtime/jsx-runtime.js +26 -0
  14. package/dist/jsx-runtime/jsx-runtime.js.map +1 -0
  15. package/jsx-dev-runtime/index.cjs +1 -0
  16. package/jsx-dev-runtime/index.d.cts +1 -0
  17. package/jsx-dev-runtime/index.d.ts +1 -0
  18. package/jsx-dev-runtime/index.js +1 -0
  19. package/jsx-runtime/index.cjs +1 -0
  20. package/jsx-runtime/index.d.cts +1 -0
  21. package/jsx-runtime/index.d.ts +1 -0
  22. package/jsx-runtime/index.js +1 -0
  23. package/package.json +30 -10
  24. package/src/CommandManager.ts +4 -11
  25. package/src/Editor.ts +273 -100
  26. package/src/EventEmitter.ts +16 -10
  27. package/src/Extendable.ts +484 -0
  28. package/src/Extension.ts +29 -493
  29. package/src/ExtensionManager.ts +100 -143
  30. package/src/InputRule.ts +28 -24
  31. package/src/Mark.ts +157 -624
  32. package/src/MarkView.ts +122 -0
  33. package/src/Node.ts +343 -807
  34. package/src/NodePos.ts +18 -9
  35. package/src/NodeView.ts +58 -35
  36. package/src/PasteRule.ts +68 -24
  37. package/src/Tracker.ts +8 -10
  38. package/src/commands/blur.ts +15 -13
  39. package/src/commands/clearContent.ts +13 -6
  40. package/src/commands/clearNodes.ts +33 -31
  41. package/src/commands/command.ts +2 -2
  42. package/src/commands/createParagraphNear.ts +6 -4
  43. package/src/commands/cut.ts +13 -11
  44. package/src/commands/deleteCurrentNode.ts +24 -22
  45. package/src/commands/deleteNode.ts +20 -18
  46. package/src/commands/deleteRange.ts +11 -9
  47. package/src/commands/deleteSelection.ts +6 -4
  48. package/src/commands/enter.ts +7 -5
  49. package/src/commands/exitCode.ts +6 -4
  50. package/src/commands/extendMarkRange.ts +16 -14
  51. package/src/commands/first.ts +3 -5
  52. package/src/commands/focus.ts +51 -53
  53. package/src/commands/forEach.ts +3 -3
  54. package/src/commands/insertContent.ts +8 -10
  55. package/src/commands/insertContentAt.ts +131 -76
  56. package/src/commands/join.ts +21 -13
  57. package/src/commands/joinItemBackward.ts +17 -19
  58. package/src/commands/joinItemForward.ts +17 -19
  59. package/src/commands/joinTextblockBackward.ts +6 -4
  60. package/src/commands/joinTextblockForward.ts +6 -4
  61. package/src/commands/keyboardShortcut.ts +30 -35
  62. package/src/commands/lift.ts +12 -10
  63. package/src/commands/liftEmptyBlock.ts +7 -5
  64. package/src/commands/liftListItem.ts +8 -6
  65. package/src/commands/newlineInCode.ts +6 -4
  66. package/src/commands/resetAttributes.ts +38 -43
  67. package/src/commands/scrollIntoView.ts +10 -8
  68. package/src/commands/selectAll.ts +15 -8
  69. package/src/commands/selectNodeBackward.ts +6 -4
  70. package/src/commands/selectNodeForward.ts +6 -4
  71. package/src/commands/selectParentNode.ts +6 -4
  72. package/src/commands/selectTextblockEnd.ts +6 -4
  73. package/src/commands/selectTextblockStart.ts +6 -4
  74. package/src/commands/setContent.ts +37 -40
  75. package/src/commands/setMark.ts +58 -60
  76. package/src/commands/setMeta.ts +10 -6
  77. package/src/commands/setNode.ts +36 -27
  78. package/src/commands/setNodeSelection.ts +12 -10
  79. package/src/commands/setTextSelection.ts +16 -14
  80. package/src/commands/sinkListItem.ts +8 -6
  81. package/src/commands/splitBlock.ts +60 -68
  82. package/src/commands/splitListItem.ts +99 -101
  83. package/src/commands/toggleList.ts +76 -74
  84. package/src/commands/toggleMark.ts +13 -11
  85. package/src/commands/toggleNode.ts +22 -11
  86. package/src/commands/toggleWrap.ts +12 -10
  87. package/src/commands/undoInputRule.ts +32 -30
  88. package/src/commands/unsetAllMarks.ts +17 -15
  89. package/src/commands/unsetMark.ts +29 -27
  90. package/src/commands/updateAttributes.ts +97 -45
  91. package/src/commands/wrapIn.ts +8 -6
  92. package/src/commands/wrapInList.ts +8 -6
  93. package/src/extensions/clipboardTextSerializer.ts +2 -4
  94. package/src/extensions/delete.ts +89 -0
  95. package/src/extensions/drop.ts +26 -0
  96. package/src/extensions/focusEvents.ts +5 -7
  97. package/src/extensions/index.ts +4 -1
  98. package/src/extensions/keymap.ts +63 -52
  99. package/src/extensions/paste.ts +25 -0
  100. package/src/extensions/tabindex.ts +1 -1
  101. package/src/helpers/combineTransactionSteps.ts +3 -6
  102. package/src/helpers/createChainableState.ts +2 -5
  103. package/src/helpers/createDocument.ts +3 -3
  104. package/src/helpers/createNodeFromContent.ts +37 -25
  105. package/src/helpers/defaultBlockAt.ts +1 -1
  106. package/src/helpers/findChildren.ts +2 -2
  107. package/src/helpers/findChildrenInRange.ts +3 -7
  108. package/src/helpers/findParentNode.ts +5 -3
  109. package/src/helpers/findParentNodeClosestToPos.ts +2 -2
  110. package/src/helpers/flattenExtensions.ts +30 -0
  111. package/src/helpers/generateHTML.ts +1 -1
  112. package/src/helpers/generateJSON.ts +1 -1
  113. package/src/helpers/generateText.ts +1 -1
  114. package/src/helpers/getAttributes.ts +3 -6
  115. package/src/helpers/getAttributesFromExtensions.ts +29 -38
  116. package/src/helpers/getChangedRanges.ts +15 -13
  117. package/src/helpers/getDebugJSON.ts +2 -2
  118. package/src/helpers/getExtensionField.ts +12 -12
  119. package/src/helpers/getHTMLFromFragment.ts +2 -1
  120. package/src/helpers/getMarkAttributes.ts +3 -6
  121. package/src/helpers/getMarkRange.ts +36 -19
  122. package/src/helpers/getMarkType.ts +2 -4
  123. package/src/helpers/getMarksBetween.ts +3 -3
  124. package/src/helpers/getNodeAtPosition.ts +2 -2
  125. package/src/helpers/getNodeAttributes.ts +3 -6
  126. package/src/helpers/getNodeType.ts +2 -4
  127. package/src/helpers/getRenderedAttributes.ts +3 -2
  128. package/src/helpers/getSchema.ts +5 -5
  129. package/src/helpers/getSchemaByResolvedExtensions.ts +49 -79
  130. package/src/helpers/getSchemaTypeByName.ts +1 -1
  131. package/src/helpers/getSchemaTypeNameByName.ts +1 -1
  132. package/src/helpers/getSplittedAttributes.ts +5 -5
  133. package/src/helpers/getText.ts +2 -2
  134. package/src/helpers/getTextBetween.ts +2 -2
  135. package/src/helpers/getTextContentFromNodes.ts +9 -12
  136. package/src/helpers/getTextSerializersFromSchema.ts +2 -2
  137. package/src/helpers/index.ts +4 -0
  138. package/src/helpers/injectExtensionAttributesToParseRule.ts +3 -3
  139. package/src/helpers/isActive.ts +2 -6
  140. package/src/helpers/isAtEndOfNode.ts +1 -1
  141. package/src/helpers/isAtStartOfNode.ts +1 -1
  142. package/src/helpers/isExtensionRulesEnabled.ts +2 -4
  143. package/src/helpers/isList.ts +2 -2
  144. package/src/helpers/isMarkActive.ts +3 -3
  145. package/src/helpers/isNodeActive.ts +3 -3
  146. package/src/helpers/isNodeEmpty.ts +56 -5
  147. package/src/helpers/posToDOMRect.ts +1 -1
  148. package/src/helpers/resolveExtensions.ts +25 -0
  149. package/src/helpers/resolveFocusPosition.ts +5 -16
  150. package/src/helpers/rewriteUnknownContent.ts +149 -0
  151. package/src/helpers/selectionToInsertionEnd.ts +2 -1
  152. package/src/helpers/sortExtensions.ts +26 -0
  153. package/src/helpers/splitExtensions.ts +4 -4
  154. package/src/index.ts +3 -7
  155. package/src/inputRules/markInputRule.ts +6 -9
  156. package/src/inputRules/nodeInputRule.ts +7 -13
  157. package/src/inputRules/textInputRule.ts +4 -6
  158. package/src/inputRules/textblockTypeInputRule.ts +7 -12
  159. package/src/inputRules/wrappingInputRule.ts +19 -24
  160. package/src/jsx-runtime.ts +64 -0
  161. package/src/pasteRules/markPasteRule.ts +6 -7
  162. package/src/pasteRules/nodePasteRule.ts +15 -11
  163. package/src/pasteRules/textPasteRule.ts +4 -6
  164. package/src/style.ts +2 -6
  165. package/src/types.ts +513 -58
  166. package/src/utilities/callOrReturn.ts +1 -1
  167. package/src/utilities/canInsertNode.ts +30 -0
  168. package/src/utilities/createStyleTag.ts +3 -1
  169. package/src/utilities/deleteProps.ts +7 -11
  170. package/src/utilities/elementFromString.ts +3 -0
  171. package/src/utilities/findDuplicates.ts +5 -2
  172. package/src/utilities/index.ts +2 -0
  173. package/src/utilities/isFunction.ts +1 -0
  174. package/src/utilities/isMacOS.ts +1 -3
  175. package/src/utilities/isiOS.ts +5 -10
  176. package/src/utilities/mergeAttributes.ts +32 -5
  177. package/src/utilities/removeDuplicates.ts +1 -3
  178. package/dist/index.umd.js +0 -5098
  179. package/dist/index.umd.js.map +0 -1
  180. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  181. package/dist/packages/core/src/Editor.d.ts +0 -161
  182. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  183. package/dist/packages/core/src/Extension.d.ts +0 -343
  184. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  185. package/dist/packages/core/src/InputRule.d.ts +0 -42
  186. package/dist/packages/core/src/Mark.d.ts +0 -451
  187. package/dist/packages/core/src/Node.d.ts +0 -611
  188. package/dist/packages/core/src/NodePos.d.ts +0 -44
  189. package/dist/packages/core/src/NodeView.d.ts +0 -31
  190. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  191. package/dist/packages/core/src/Tracker.d.ts +0 -11
  192. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  193. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  194. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  195. package/dist/packages/core/src/commands/command.d.ts +0 -18
  196. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  197. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  198. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  199. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  200. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  201. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  202. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  203. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  204. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  205. package/dist/packages/core/src/commands/first.d.ts +0 -14
  206. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  207. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  208. package/dist/packages/core/src/commands/index.d.ts +0 -55
  209. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  210. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  211. package/dist/packages/core/src/commands/join.d.ts +0 -41
  212. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  213. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  214. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  215. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  216. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  217. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  218. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  219. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  220. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  221. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  222. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  223. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  224. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  225. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  226. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  227. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  228. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  229. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  230. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  231. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  232. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  233. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  234. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  235. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  236. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  237. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  238. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  239. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  240. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  241. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  242. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  243. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  244. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  245. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  246. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  247. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  248. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  249. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  250. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  251. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  252. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  253. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  254. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  255. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  256. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  257. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  258. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  259. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  260. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  261. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  262. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  263. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  264. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  265. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  266. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  267. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  268. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  269. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  270. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  271. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  272. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  273. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  274. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  275. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  276. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  277. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  278. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  279. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  280. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  281. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  282. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  283. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  284. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  285. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  286. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  287. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  288. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  289. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  290. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  291. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  292. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  293. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  294. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  295. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  296. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  297. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  298. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  299. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
  300. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  301. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  302. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  303. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  304. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  305. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  306. package/dist/packages/core/src/index.d.ts +0 -24
  307. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  308. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  309. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  310. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  311. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  312. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  313. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  314. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  315. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  316. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  317. package/dist/packages/core/src/style.d.ts +0 -1
  318. package/dist/packages/core/src/types.d.ts +0 -255
  319. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  320. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  321. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  322. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  323. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  324. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  325. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  326. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  327. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  328. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  329. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  330. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  331. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  332. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  333. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  334. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  335. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  336. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  337. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  338. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  339. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  340. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
package/src/Editor.ts CHANGED
@@ -1,19 +1,22 @@
1
- import {
2
- MarkType,
3
- Node as ProseMirrorNode,
4
- NodeType,
5
- Schema,
6
- } from '@tiptap/pm/model'
7
- import {
8
- EditorState, Plugin, PluginKey, Transaction,
9
- } from '@tiptap/pm/state'
1
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
2
+ import type { MarkType, Node as ProseMirrorNode, NodeType, Schema } from '@tiptap/pm/model'
3
+ import type { Plugin, PluginKey, Transaction } from '@tiptap/pm/state'
4
+ import { EditorState } from '@tiptap/pm/state'
10
5
  import { EditorView } from '@tiptap/pm/view'
11
6
 
12
7
  import { CommandManager } from './CommandManager.js'
13
8
  import { EventEmitter } from './EventEmitter.js'
14
9
  import { ExtensionManager } from './ExtensionManager.js'
15
10
  import {
16
- ClipboardTextSerializer, Commands, Editable, FocusEvents, Keymap, Tabindex,
11
+ ClipboardTextSerializer,
12
+ Commands,
13
+ Delete,
14
+ Drop,
15
+ Editable,
16
+ FocusEvents,
17
+ Keymap,
18
+ Paste,
19
+ Tabindex,
17
20
  } from './extensions/index.js'
18
21
  import { createDocument } from './helpers/createDocument.js'
19
22
  import { getAttributes } from './helpers/getAttributes.js'
@@ -23,26 +26,28 @@ import { getTextSerializersFromSchema } from './helpers/getTextSerializersFromSc
23
26
  import { isActive } from './helpers/isActive.js'
24
27
  import { isNodeEmpty } from './helpers/isNodeEmpty.js'
25
28
  import { resolveFocusPosition } from './helpers/resolveFocusPosition.js'
29
+ import type { Storage } from './index.js'
26
30
  import { NodePos } from './NodePos.js'
27
31
  import { style } from './style.js'
28
- import {
32
+ import type {
29
33
  CanCommands,
30
34
  ChainedCommands,
35
+ DocumentType,
31
36
  EditorEvents,
32
37
  EditorOptions,
33
- JSONContent,
38
+ NodeType as TNodeType,
34
39
  SingleCommands,
35
40
  TextSerializer,
41
+ TextType as TTextType,
36
42
  } from './types.js'
37
43
  import { createStyleTag } from './utilities/createStyleTag.js'
38
44
  import { isFunction } from './utilities/isFunction.js'
39
45
 
40
46
  export * as extensions from './extensions/index.js'
41
47
 
42
- declare global {
43
- interface HTMLElement {
44
- editor?: Editor;
45
- }
48
+ // @ts-ignore
49
+ export interface TiptapEditorHTMLElement extends HTMLElement {
50
+ editor?: Editor
46
51
  }
47
52
 
48
53
  export class Editor extends EventEmitter<EditorEvents> {
@@ -50,18 +55,30 @@ export class Editor extends EventEmitter<EditorEvents> {
50
55
 
51
56
  public extensionManager!: ExtensionManager
52
57
 
53
- private css!: HTMLStyleElement
58
+ private css: HTMLStyleElement | null = null
54
59
 
55
60
  public schema!: Schema
56
61
 
57
- public view!: EditorView
62
+ private editorView: EditorView | null = null
58
63
 
59
64
  public isFocused = false
60
65
 
61
- public extensionStorage: Record<string, any> = {}
66
+ private editorState!: EditorState
67
+
68
+ /**
69
+ * The editor is considered initialized after the `create` event has been emitted.
70
+ */
71
+ public isInitialized = false
72
+
73
+ public extensionStorage: Storage = {} as Storage
74
+
75
+ /**
76
+ * A unique ID for this editor instance.
77
+ */
78
+ public instanceId = Math.random().toString(36).slice(2, 9)
62
79
 
63
80
  public options: EditorOptions = {
64
- element: document.createElement('div'),
81
+ element: typeof document !== 'undefined' ? document.createElement('div') : null,
65
82
  content: '',
66
83
  injectCSS: true,
67
84
  injectNonce: undefined,
@@ -75,6 +92,7 @@ export class Editor extends EventEmitter<EditorEvents> {
75
92
  enablePasteRules: true,
76
93
  enableCoreExtensions: true,
77
94
  enableContentCheck: false,
95
+ emitContentError: false,
78
96
  onBeforeCreate: () => null,
79
97
  onCreate: () => null,
80
98
  onUpdate: () => null,
@@ -83,7 +101,12 @@ export class Editor extends EventEmitter<EditorEvents> {
83
101
  onFocus: () => null,
84
102
  onBlur: () => null,
85
103
  onDestroy: () => null,
86
- onContentError: ({ error }) => { throw error },
104
+ onContentError: ({ error }) => {
105
+ throw error
106
+ },
107
+ onPaste: () => null,
108
+ onDrop: () => null,
109
+ onDelete: () => null,
87
110
  }
88
111
 
89
112
  constructor(options: Partial<EditorOptions> = {}) {
@@ -95,8 +118,6 @@ export class Editor extends EventEmitter<EditorEvents> {
95
118
  this.on('beforeCreate', this.options.onBeforeCreate)
96
119
  this.emit('beforeCreate', { editor: this })
97
120
  this.on('contentError', this.options.onContentError)
98
- this.createView()
99
- this.injectCSS()
100
121
  this.on('create', this.options.onCreate)
101
122
  this.on('update', this.options.onUpdate)
102
123
  this.on('selectionUpdate', this.options.onSelectionUpdate)
@@ -104,6 +125,35 @@ export class Editor extends EventEmitter<EditorEvents> {
104
125
  this.on('focus', this.options.onFocus)
105
126
  this.on('blur', this.options.onBlur)
106
127
  this.on('destroy', this.options.onDestroy)
128
+ this.on('drop', ({ event, slice, moved }) => this.options.onDrop(event, slice, moved))
129
+ this.on('paste', ({ event, slice }) => this.options.onPaste(event, slice))
130
+ this.on('delete', this.options.onDelete)
131
+
132
+ const initialDoc = this.createDoc()
133
+ const selection = resolveFocusPosition(initialDoc, this.options.autofocus)
134
+
135
+ // Set editor state immediately, so that it's available independently from the view
136
+ this.editorState = EditorState.create({
137
+ doc: initialDoc,
138
+ schema: this.schema,
139
+ selection: selection || undefined,
140
+ })
141
+
142
+ if (this.options.element) {
143
+ this.mount(this.options.element)
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Attach the editor to the DOM, creating a new editor view.
149
+ */
150
+ public mount(el: NonNullable<EditorOptions['element']> & {}) {
151
+ if (typeof document === 'undefined') {
152
+ throw new Error(
153
+ `[tiptap error]: The editor cannot be mounted because there is no 'document' defined in this environment.`,
154
+ )
155
+ }
156
+ this.createView(el)
107
157
 
108
158
  window.setTimeout(() => {
109
159
  if (this.isDestroyed) {
@@ -112,13 +162,34 @@ export class Editor extends EventEmitter<EditorEvents> {
112
162
 
113
163
  this.commands.focus(this.options.autofocus)
114
164
  this.emit('create', { editor: this })
165
+ this.isInitialized = true
115
166
  }, 0)
116
167
  }
117
168
 
169
+ /**
170
+ * Remove the editor from the DOM, but still allow remounting at a different point in time
171
+ */
172
+ public unmount() {
173
+ if (this.editorView) {
174
+ // Cleanup our reference to prevent circular references which caused memory leaks
175
+ // @ts-ignore
176
+ const dom = this.editorView.dom as TiptapEditorHTMLElement
177
+
178
+ if (dom?.editor) {
179
+ delete dom.editor
180
+ }
181
+ this.editorView.destroy()
182
+ }
183
+ this.editorView = null
184
+ this.isInitialized = false
185
+ this.css?.remove()
186
+ this.css = null
187
+ }
188
+
118
189
  /**
119
190
  * Returns the editor storage.
120
191
  */
121
- public get storage(): Record<string, any> {
192
+ public get storage(): Storage {
122
193
  return this.extensionStorage
123
194
  }
124
195
 
@@ -147,7 +218,7 @@ export class Editor extends EventEmitter<EditorEvents> {
147
218
  * Inject CSS styles.
148
219
  */
149
220
  private injectCSS(): void {
150
- if (this.options.injectCSS && document) {
221
+ if (this.options.injectCSS && typeof document !== 'undefined') {
151
222
  this.css = createStyleTag(style, this.options.injectNonce)
152
223
  }
153
224
  }
@@ -163,7 +234,7 @@ export class Editor extends EventEmitter<EditorEvents> {
163
234
  ...options,
164
235
  }
165
236
 
166
- if (!this.view || !this.state || this.isDestroyed) {
237
+ if (!this.editorView || !this.state || this.isDestroyed) {
167
238
  return
168
239
  }
169
240
 
@@ -181,7 +252,7 @@ export class Editor extends EventEmitter<EditorEvents> {
181
252
  this.setOptions({ editable })
182
253
 
183
254
  if (emitUpdate) {
184
- this.emit('update', { editor: this, transaction: this.state.tr })
255
+ this.emit('update', { editor: this, transaction: this.state.tr, appendedTransactions: [] })
185
256
  }
186
257
  }
187
258
 
@@ -195,11 +266,58 @@ export class Editor extends EventEmitter<EditorEvents> {
195
266
  return this.options.editable && this.view && this.view.editable
196
267
  }
197
268
 
269
+ /**
270
+ * Returns the editor state.
271
+ */
272
+ public get view(): EditorView {
273
+ if (this.editorView) {
274
+ return this.editorView
275
+ }
276
+
277
+ return new Proxy(
278
+ {
279
+ state: this.editorState,
280
+ updateState: (state: EditorState): ReturnType<EditorView['updateState']> => {
281
+ this.editorState = state
282
+ },
283
+ dispatch: (tr: Transaction): ReturnType<EditorView['dispatch']> => {
284
+ this.editorState = this.state.apply(tr)
285
+ },
286
+
287
+ // Stub some commonly accessed properties to prevent errors
288
+ composing: false,
289
+ dragging: null,
290
+ editable: true,
291
+ isDestroyed: false,
292
+ } as EditorView,
293
+ {
294
+ get: (obj, key) => {
295
+ // Specifically always return the most recent editorState
296
+ if (key === 'state') {
297
+ return this.editorState
298
+ }
299
+ if (key in obj) {
300
+ return Reflect.get(obj, key)
301
+ }
302
+
303
+ // We throw an error here, because we know the view is not available
304
+ throw new Error(
305
+ `[tiptap error]: The editor view is not available. Cannot access view['${key as string}']. The editor may not be mounted yet.`,
306
+ )
307
+ },
308
+ },
309
+ ) as EditorView
310
+ }
311
+
198
312
  /**
199
313
  * Returns the editor state.
200
314
  */
201
315
  public get state(): EditorState {
202
- return this.view.state
316
+ if (this.editorView) {
317
+ this.editorState = this.view.state
318
+ }
319
+
320
+ return this.editorState
203
321
  }
204
322
 
205
323
  /**
@@ -207,11 +325,12 @@ export class Editor extends EventEmitter<EditorEvents> {
207
325
  *
208
326
  * @param plugin A ProseMirror plugin
209
327
  * @param handlePlugins Control how to merge the plugin into the existing plugins.
328
+ * @returns The new editor state
210
329
  */
211
330
  public registerPlugin(
212
331
  plugin: Plugin,
213
332
  handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[],
214
- ): void {
333
+ ): EditorState {
215
334
  const plugins = isFunction(handlePlugins)
216
335
  ? handlePlugins(plugin, [...this.state.plugins])
217
336
  : [...this.state.plugins, plugin]
@@ -219,44 +338,74 @@ export class Editor extends EventEmitter<EditorEvents> {
219
338
  const state = this.state.reconfigure({ plugins })
220
339
 
221
340
  this.view.updateState(state)
341
+
342
+ return state
222
343
  }
223
344
 
224
345
  /**
225
346
  * Unregister a ProseMirror plugin.
226
347
  *
227
- * @param nameOrPluginKey The plugins name
348
+ * @param nameOrPluginKeyToRemove The plugins name
349
+ * @returns The new editor state or undefined if the editor is destroyed
228
350
  */
229
- public unregisterPlugin(nameOrPluginKey: string | PluginKey): void {
351
+ public unregisterPlugin(
352
+ nameOrPluginKeyToRemove: string | PluginKey | (string | PluginKey)[],
353
+ ): EditorState | undefined {
230
354
  if (this.isDestroyed) {
231
- return
355
+ return undefined
232
356
  }
233
357
 
234
- // @ts-ignore
235
- const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key
358
+ const prevPlugins = this.state.plugins
359
+ let plugins = prevPlugins
236
360
 
237
- const state = this.state.reconfigure({
361
+ ;([] as (string | PluginKey)[]).concat(nameOrPluginKeyToRemove).forEach(nameOrPluginKey => {
238
362
  // @ts-ignore
239
- plugins: this.state.plugins.filter(plugin => !plugin.key.startsWith(name)),
363
+ const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key
364
+
365
+ // @ts-ignore
366
+ plugins = plugins.filter(plugin => !plugin.key.startsWith(name))
367
+ })
368
+
369
+ if (prevPlugins.length === plugins.length) {
370
+ // No plugin was removed, so we don’t need to update the state
371
+ return undefined
372
+ }
373
+
374
+ const state = this.state.reconfigure({
375
+ plugins,
240
376
  })
241
377
 
242
378
  this.view.updateState(state)
379
+
380
+ return state
243
381
  }
244
382
 
245
383
  /**
246
384
  * Creates an extension manager.
247
385
  */
248
386
  private createExtensionManager(): void {
249
-
250
- const coreExtensions = this.options.enableCoreExtensions ? [
251
- Editable,
252
- ClipboardTextSerializer.configure({
253
- blockSeparator: this.options.coreExtensionOptions?.clipboardTextSerializer?.blockSeparator,
254
- }),
255
- Commands,
256
- FocusEvents,
257
- Keymap,
258
- Tabindex,
259
- ] : []
387
+ const coreExtensions = this.options.enableCoreExtensions
388
+ ? [
389
+ Editable,
390
+ ClipboardTextSerializer.configure({
391
+ blockSeparator: this.options.coreExtensionOptions?.clipboardTextSerializer?.blockSeparator,
392
+ }),
393
+ Commands,
394
+ FocusEvents,
395
+ Keymap,
396
+ Tabindex,
397
+ Drop,
398
+ Paste,
399
+ Delete,
400
+ ].filter(ext => {
401
+ if (typeof this.options.enableCoreExtensions === 'object') {
402
+ return (
403
+ this.options.enableCoreExtensions[ext.name as keyof typeof this.options.enableCoreExtensions] !== false
404
+ )
405
+ }
406
+ return true
407
+ })
408
+ : []
260
409
  const allExtensions = [...coreExtensions, ...this.options.extensions].filter(extension => {
261
410
  return ['extension', 'node', 'mark'].includes(extension?.type)
262
411
  })
@@ -281,20 +430,20 @@ export class Editor extends EventEmitter<EditorEvents> {
281
430
  }
282
431
 
283
432
  /**
284
- * Creates a ProseMirror view.
433
+ * Creates the initial document.
285
434
  */
286
- private createView(): void {
435
+ private createDoc(): ProseMirrorNode {
287
436
  let doc: ProseMirrorNode
288
437
 
289
438
  try {
290
- doc = createDocument(
291
- this.options.content,
292
- this.schema,
293
- this.options.parseOptions,
294
- { errorOnInvalidContent: this.options.enableContentCheck },
295
- )
439
+ doc = createDocument(this.options.content, this.schema, this.options.parseOptions, {
440
+ errorOnInvalidContent: this.options.enableContentCheck,
441
+ })
296
442
  } catch (e) {
297
- if (!(e instanceof Error) || !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)) {
443
+ if (
444
+ !(e instanceof Error) ||
445
+ !['[tiptap error]: Invalid JSON content', '[tiptap error]: Invalid HTML content'].includes(e.message)
446
+ ) {
298
447
  // Not the content error we were expecting
299
448
  throw e
300
449
  }
@@ -302,6 +451,13 @@ export class Editor extends EventEmitter<EditorEvents> {
302
451
  editor: this,
303
452
  error: e as Error,
304
453
  disableCollaboration: () => {
454
+ if (
455
+ 'collaboration' in this.storage &&
456
+ typeof this.storage.collaboration === 'object' &&
457
+ this.storage.collaboration
458
+ ) {
459
+ ;(this.storage.collaboration as any).isDisabled = true
460
+ }
305
461
  // To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
306
462
  this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration')
307
463
 
@@ -311,22 +467,26 @@ export class Editor extends EventEmitter<EditorEvents> {
311
467
  })
312
468
 
313
469
  // Content is invalid, but attempt to create it anyway, stripping out the invalid parts
314
- doc = createDocument(
315
- this.options.content,
316
- this.schema,
317
- this.options.parseOptions,
318
- { errorOnInvalidContent: false },
319
- )
470
+ doc = createDocument(this.options.content, this.schema, this.options.parseOptions, {
471
+ errorOnInvalidContent: false,
472
+ })
320
473
  }
321
- const selection = resolveFocusPosition(doc, this.options.autofocus)
474
+ return doc
475
+ }
322
476
 
323
- this.view = new EditorView(this.options.element, {
477
+ /**
478
+ * Creates a ProseMirror view.
479
+ */
480
+ private createView(element: NonNullable<EditorOptions['element']> & {}): void {
481
+ this.editorView = new EditorView(element, {
324
482
  ...this.options.editorProps,
483
+ attributes: {
484
+ // add `role="textbox"` to the editor element
485
+ role: 'textbox',
486
+ ...this.options.editorProps?.attributes,
487
+ },
325
488
  dispatchTransaction: this.dispatchTransaction.bind(this),
326
- state: EditorState.create({
327
- doc,
328
- selection: selection || undefined,
329
- }),
489
+ state: this.editorState,
330
490
  })
331
491
 
332
492
  // `editor.view` is not yet available at this time.
@@ -339,19 +499,26 @@ export class Editor extends EventEmitter<EditorEvents> {
339
499
 
340
500
  this.createNodeViews()
341
501
  this.prependClass()
502
+ this.injectCSS()
342
503
 
343
504
  // Let’s store the editor instance in the DOM element.
344
505
  // So we’ll have access to it for tests.
345
- const dom = this.view.dom as HTMLElement
506
+ // @ts-ignore
507
+ const dom = this.view.dom as TiptapEditorHTMLElement
346
508
 
347
509
  dom.editor = this
348
510
  }
349
511
 
350
512
  /**
351
- * Creates all node views.
513
+ * Creates all node and mark views.
352
514
  */
353
515
  public createNodeViews(): void {
516
+ if (this.view.isDestroyed) {
517
+ return
518
+ }
519
+
354
520
  this.view.setProps({
521
+ markViews: this.extensionManager.markViews,
355
522
  nodeViews: this.extensionManager.nodeViews,
356
523
  })
357
524
  }
@@ -367,7 +534,7 @@ export class Editor extends EventEmitter<EditorEvents> {
367
534
 
368
535
  private capturedTransaction: Transaction | null = null
369
536
 
370
- public captureTransaction(fn: Function) {
537
+ public captureTransaction(fn: () => void) {
371
538
  this.isCapturingTransaction = true
372
539
  fn()
373
540
  this.isCapturingTransaction = false
@@ -403,18 +570,30 @@ export class Editor extends EventEmitter<EditorEvents> {
403
570
  return
404
571
  }
405
572
 
406
- const state = this.state.apply(transaction)
573
+ // Apply transaction and get resulting state and transactions
574
+ const { state, transactions } = this.state.applyTransaction(transaction)
407
575
  const selectionHasChanged = !this.state.selection.eq(state.selection)
576
+ const rootTrWasApplied = transactions.includes(transaction)
577
+ const prevState = this.state
408
578
 
409
579
  this.emit('beforeTransaction', {
410
580
  editor: this,
411
581
  transaction,
412
582
  nextState: state,
413
583
  })
584
+
585
+ // If transaction was filtered out, we can return early
586
+ if (!rootTrWasApplied) {
587
+ return
588
+ }
589
+
414
590
  this.view.updateState(state)
591
+
592
+ // Emit transaction event with appended transactions info
415
593
  this.emit('transaction', {
416
594
  editor: this,
417
595
  transaction,
596
+ appendedTransactions: transactions.slice(1),
418
597
  })
419
598
 
420
599
  if (selectionHasChanged) {
@@ -424,14 +603,17 @@ export class Editor extends EventEmitter<EditorEvents> {
424
603
  })
425
604
  }
426
605
 
427
- const focus = transaction.getMeta('focus')
428
- const blur = transaction.getMeta('blur')
606
+ // Only emit the latest between focus and blur events
607
+ const mostRecentFocusTr = transactions.findLast(tr => tr.getMeta('focus') || tr.getMeta('blur'))
608
+ const focus = mostRecentFocusTr?.getMeta('focus')
609
+ const blur = mostRecentFocusTr?.getMeta('blur')
429
610
 
430
611
  if (focus) {
431
612
  this.emit('focus', {
432
613
  editor: this,
433
614
  event: focus.event,
434
- transaction,
615
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
616
+ transaction: mostRecentFocusTr!,
435
617
  })
436
618
  }
437
619
 
@@ -439,17 +621,24 @@ export class Editor extends EventEmitter<EditorEvents> {
439
621
  this.emit('blur', {
440
622
  editor: this,
441
623
  event: blur.event,
442
- transaction,
624
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
625
+ transaction: mostRecentFocusTr!,
443
626
  })
444
627
  }
445
628
 
446
- if (!transaction.docChanged || transaction.getMeta('preventUpdate')) {
629
+ // Compare states for update event
630
+ if (
631
+ transaction.getMeta('preventUpdate') ||
632
+ !transactions.some(tr => tr.docChanged) ||
633
+ prevState.doc.eq(state.doc)
634
+ ) {
447
635
  return
448
636
  }
449
637
 
450
638
  this.emit('update', {
451
639
  editor: this,
452
640
  transaction,
641
+ appendedTransactions: transactions.slice(1),
453
642
  })
454
643
  }
455
644
 
@@ -479,7 +668,10 @@ export class Editor extends EventEmitter<EditorEvents> {
479
668
  /**
480
669
  * Get the document as JSON.
481
670
  */
482
- public getJSON(): JSONContent {
671
+ public getJSON(): DocumentType<
672
+ Record<string, any> | undefined,
673
+ TNodeType<string, undefined | Record<string, any>, any, (TNodeType | TTextType)[]>[]
674
+ > {
483
675
  return this.state.doc.toJSON()
484
676
  }
485
677
 
@@ -493,10 +685,7 @@ export class Editor extends EventEmitter<EditorEvents> {
493
685
  /**
494
686
  * Get the document as text.
495
687
  */
496
- public getText(options?: {
497
- blockSeparator?: string
498
- textSerializers?: Record<string, TextSerializer>
499
- }): string {
688
+ public getText(options?: { blockSeparator?: string; textSerializers?: Record<string, TextSerializer> }): string {
500
689
  const { blockSeparator = '\n\n', textSerializers = {} } = options || {}
501
690
 
502
691
  return getText(this.state.doc, {
@@ -515,28 +704,13 @@ export class Editor extends EventEmitter<EditorEvents> {
515
704
  return isNodeEmpty(this.state.doc)
516
705
  }
517
706
 
518
- /**
519
- * Get the number of characters for the current document.
520
- *
521
- * @deprecated
522
- */
523
- public getCharacterCount(): number {
524
- console.warn(
525
- '[tiptap warn]: "editor.getCharacterCount()" is deprecated. Please use "editor.storage.characterCount.characters()" instead.',
526
- )
527
-
528
- return this.state.doc.content.size - 2
529
- }
530
-
531
707
  /**
532
708
  * Destroy the editor.
533
709
  */
534
710
  public destroy(): void {
535
711
  this.emit('destroy')
536
712
 
537
- if (this.view) {
538
- this.view.destroy()
539
- }
713
+ this.unmount()
540
714
 
541
715
  this.removeAllListeners()
542
716
  }
@@ -545,8 +719,7 @@ export class Editor extends EventEmitter<EditorEvents> {
545
719
  * Check if the editor is already destroyed.
546
720
  */
547
721
  public get isDestroyed(): boolean {
548
- // @ts-ignore
549
- return !this.view?.docView
722
+ return this.editorView?.isDestroyed ?? true
550
723
  }
551
724
 
552
725
  public $node(selector: string, attributes?: { [key: string]: any }): NodePos | null {
@@ -1,16 +1,13 @@
1
1
  type StringKeyOf<T> = Extract<keyof T, string>
2
- type CallbackType<
3
- T extends Record<string, any>,
4
- EventName extends StringKeyOf<T>,
5
- > = T[EventName] extends any[] ? T[EventName] : [T[EventName]]
6
- type CallbackFunction<
7
- T extends Record<string, any>,
8
- EventName extends StringKeyOf<T>,
9
- > = (...props: CallbackType<T, EventName>) => any
2
+ type CallbackType<T extends Record<string, any>, EventName extends StringKeyOf<T>> = T[EventName] extends any[]
3
+ ? T[EventName]
4
+ : [T[EventName]]
5
+ type CallbackFunction<T extends Record<string, any>, EventName extends StringKeyOf<T>> = (
6
+ ...props: CallbackType<T, EventName>
7
+ ) => any
10
8
 
11
9
  export class EventEmitter<T extends Record<string, any>> {
12
-
13
- private callbacks: { [key: string]: Function[] } = {}
10
+ private callbacks: { [key: string]: Array<(...args: any[]) => void> } = {}
14
11
 
15
12
  public on<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this {
16
13
  if (!this.callbacks[event]) {
@@ -46,6 +43,15 @@ export class EventEmitter<T extends Record<string, any>> {
46
43
  return this
47
44
  }
48
45
 
46
+ public once<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this {
47
+ const onceFn = (...args: CallbackType<T, EventName>) => {
48
+ this.off(event, onceFn)
49
+ fn.apply(this, args)
50
+ }
51
+
52
+ return this.on(event, onceFn)
53
+ }
54
+
49
55
  public removeAllListeners(): void {
50
56
  this.callbacks = {}
51
57
  }