@tiptap/core 2.0.0-beta.99 → 2.0.0-rc.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 (297) hide show
  1. package/README.md +3 -3
  2. package/dist/index.cjs +4360 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/{tiptap-core.esm.js → index.js} +2349 -1447
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.umd.js +4358 -0
  7. package/dist/index.umd.js.map +1 -0
  8. package/dist/packages/core/src/CommandManager.d.ts +14 -7
  9. package/dist/packages/core/src/Editor.d.ts +25 -11
  10. package/dist/packages/core/src/EventEmitter.d.ts +8 -4
  11. package/dist/packages/core/src/Extension.d.ts +63 -29
  12. package/dist/packages/core/src/ExtensionManager.d.ts +3 -4
  13. package/dist/packages/core/src/InputRule.d.ts +42 -0
  14. package/dist/packages/core/src/Mark.d.ts +94 -36
  15. package/dist/packages/core/src/Node.d.ts +104 -45
  16. package/dist/packages/core/src/NodeView.d.ts +8 -8
  17. package/dist/packages/core/src/PasteRule.d.ts +42 -0
  18. package/dist/packages/core/src/Tracker.d.ts +1 -1
  19. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +12 -0
  20. package/dist/packages/core/src/commands/deleteNode.d.ts +1 -1
  21. package/dist/packages/core/src/commands/deleteRange.d.ts +1 -1
  22. package/dist/packages/core/src/commands/extendMarkRange.d.ts +1 -1
  23. package/dist/packages/core/src/commands/focus.d.ts +4 -2
  24. package/dist/packages/core/src/commands/index.d.ts +50 -0
  25. package/dist/packages/core/src/commands/insertContent.d.ts +6 -3
  26. package/dist/packages/core/src/commands/insertContentAt.d.ts +6 -3
  27. package/dist/packages/core/src/commands/join.d.ts +33 -0
  28. package/dist/packages/core/src/commands/lift.d.ts +1 -1
  29. package/dist/packages/core/src/commands/liftListItem.d.ts +1 -1
  30. package/dist/packages/core/src/commands/resetAttributes.d.ts +1 -1
  31. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +12 -0
  32. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +12 -0
  33. package/dist/packages/core/src/commands/setContent.d.ts +2 -2
  34. package/dist/packages/core/src/commands/setMark.d.ts +1 -1
  35. package/dist/packages/core/src/commands/setNode.d.ts +1 -1
  36. package/dist/packages/core/src/commands/setTextSelection.d.ts +1 -1
  37. package/dist/packages/core/src/commands/sinkListItem.d.ts +1 -1
  38. package/dist/packages/core/src/commands/splitListItem.d.ts +1 -1
  39. package/dist/packages/core/src/commands/toggleList.d.ts +2 -2
  40. package/dist/packages/core/src/commands/toggleMark.d.ts +7 -2
  41. package/dist/packages/core/src/commands/toggleNode.d.ts +1 -1
  42. package/dist/packages/core/src/commands/toggleWrap.d.ts +1 -1
  43. package/dist/packages/core/src/commands/unsetMark.d.ts +7 -2
  44. package/dist/packages/core/src/commands/updateAttributes.d.ts +1 -1
  45. package/dist/packages/core/src/commands/wrapIn.d.ts +1 -1
  46. package/dist/packages/core/src/commands/wrapInList.d.ts +1 -1
  47. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +1 -1
  48. package/dist/packages/core/src/extensions/commands.d.ts +2 -97
  49. package/dist/packages/core/src/extensions/editable.d.ts +1 -1
  50. package/dist/packages/core/src/extensions/focusEvents.d.ts +1 -1
  51. package/dist/packages/core/src/extensions/index.d.ts +1 -0
  52. package/dist/packages/core/src/extensions/keymap.d.ts +1 -1
  53. package/dist/packages/core/src/extensions/tabindex.d.ts +2 -0
  54. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +7 -0
  55. package/dist/packages/core/src/helpers/createChainableState.d.ts +5 -0
  56. package/dist/packages/core/src/helpers/createDocument.d.ts +2 -2
  57. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +2 -2
  58. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +2 -0
  59. package/dist/packages/core/src/helpers/findChildren.d.ts +3 -3
  60. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +3 -3
  61. package/dist/packages/core/src/helpers/findParentNode.d.ts +3 -4
  62. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +3 -3
  63. package/dist/packages/core/src/helpers/generateHTML.d.ts +1 -1
  64. package/dist/packages/core/src/helpers/generateJSON.d.ts +1 -1
  65. package/dist/packages/core/src/helpers/generateText.d.ts +5 -0
  66. package/dist/packages/core/src/helpers/getAttributes.d.ts +3 -3
  67. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +2 -2
  68. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +11 -0
  69. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +2 -5
  70. package/dist/packages/core/src/helpers/getExtensionField.d.ts +2 -2
  71. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +2 -2
  72. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +3 -3
  73. package/dist/packages/core/src/helpers/getMarkRange.d.ts +2 -2
  74. package/dist/packages/core/src/helpers/getMarkType.d.ts +2 -2
  75. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +2 -2
  76. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +3 -3
  77. package/dist/packages/core/src/helpers/getNodeType.d.ts +2 -2
  78. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +2 -2
  79. package/dist/packages/core/src/helpers/getSchema.d.ts +2 -2
  80. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +2 -2
  81. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +2 -2
  82. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +2 -2
  83. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +1 -1
  84. package/dist/packages/core/src/helpers/getText.d.ts +6 -0
  85. package/dist/packages/core/src/helpers/getTextBetween.d.ts +6 -0
  86. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +2 -0
  87. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +3 -0
  88. package/dist/packages/core/src/helpers/index.d.ts +47 -0
  89. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +2 -2
  90. package/dist/packages/core/src/helpers/isActive.d.ts +2 -2
  91. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +2 -0
  92. package/dist/packages/core/src/helpers/isList.d.ts +1 -1
  93. package/dist/packages/core/src/helpers/isMarkActive.d.ts +3 -3
  94. package/dist/packages/core/src/helpers/isNodeActive.d.ts +3 -3
  95. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +2 -2
  96. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +2 -2
  97. package/dist/packages/core/src/helpers/isTextSelection.d.ts +2 -2
  98. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +2 -2
  99. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +4 -0
  100. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +2 -2
  101. package/dist/packages/core/src/helpers/splitExtensions.d.ts +6 -6
  102. package/dist/packages/core/src/index.d.ts +12 -34
  103. package/dist/packages/core/src/inputRules/index.d.ts +5 -0
  104. package/dist/packages/core/src/inputRules/markInputRule.d.ts +12 -3
  105. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +12 -3
  106. package/dist/packages/core/src/inputRules/textInputRule.d.ts +9 -0
  107. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +14 -0
  108. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +27 -0
  109. package/dist/packages/core/src/pasteRules/index.d.ts +3 -0
  110. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +12 -3
  111. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +12 -0
  112. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +9 -0
  113. package/dist/packages/core/src/style.d.ts +1 -2
  114. package/dist/packages/core/src/types.d.ts +70 -40
  115. package/dist/packages/core/src/utilities/callOrReturn.d.ts +1 -1
  116. package/dist/packages/core/src/utilities/createStyleTag.d.ts +1 -1
  117. package/dist/packages/core/src/utilities/deleteProps.d.ts +1 -1
  118. package/dist/packages/core/src/utilities/elementFromString.d.ts +1 -1
  119. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +1 -0
  120. package/dist/packages/core/src/utilities/findDuplicates.d.ts +1 -0
  121. package/dist/packages/core/src/utilities/fromString.d.ts +1 -1
  122. package/dist/packages/core/src/utilities/index.d.ts +20 -0
  123. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +1 -1
  124. package/dist/packages/core/src/utilities/isFunction.d.ts +1 -0
  125. package/dist/packages/core/src/utilities/isMacOS.d.ts +1 -0
  126. package/dist/packages/core/src/utilities/isNumber.d.ts +1 -0
  127. package/dist/packages/core/src/utilities/isPlainObject.d.ts +1 -1
  128. package/dist/packages/core/src/utilities/isRegExp.d.ts +1 -0
  129. package/dist/packages/core/src/utilities/isString.d.ts +1 -0
  130. package/dist/packages/core/src/utilities/isiOS.d.ts +1 -1
  131. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +1 -1
  132. package/dist/packages/core/src/utilities/mergeDeep.d.ts +1 -1
  133. package/dist/packages/core/src/utilities/minMax.d.ts +1 -1
  134. package/dist/packages/core/src/utilities/objectIncludes.d.ts +3 -1
  135. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +8 -0
  136. package/package.json +25 -24
  137. package/src/CommandManager.ts +73 -83
  138. package/src/Editor.ts +101 -53
  139. package/src/EventEmitter.ts +14 -4
  140. package/src/Extension.ts +244 -138
  141. package/src/ExtensionManager.ts +153 -152
  142. package/src/InputRule.ts +260 -0
  143. package/src/Mark.ts +365 -204
  144. package/src/Node.ts +406 -253
  145. package/src/NodeView.ts +59 -38
  146. package/src/PasteRule.ts +240 -0
  147. package/src/Tracker.ts +4 -8
  148. package/src/commands/blur.ts +4 -0
  149. package/src/commands/clearNodes.ts +15 -9
  150. package/src/commands/createParagraphNear.ts +3 -2
  151. package/src/commands/deleteCurrentNode.ts +41 -0
  152. package/src/commands/deleteNode.ts +3 -2
  153. package/src/commands/deleteRange.ts +1 -1
  154. package/src/commands/deleteSelection.ts +3 -2
  155. package/src/commands/exitCode.ts +3 -2
  156. package/src/commands/extendMarkRange.ts +9 -5
  157. package/src/commands/focus.ts +31 -42
  158. package/src/commands/index.ts +50 -0
  159. package/src/commands/insertContent.ts +15 -4
  160. package/src/commands/insertContentAt.ts +71 -14
  161. package/src/commands/join.ts +53 -0
  162. package/src/commands/keyboardShortcut.ts +3 -3
  163. package/src/commands/lift.ts +6 -5
  164. package/src/commands/liftEmptyBlock.ts +2 -1
  165. package/src/commands/liftListItem.ts +5 -4
  166. package/src/commands/newlineInCode.ts +3 -2
  167. package/src/commands/resetAttributes.ts +16 -10
  168. package/src/commands/selectAll.ts +5 -3
  169. package/src/commands/selectNodeBackward.ts +3 -2
  170. package/src/commands/selectNodeForward.ts +3 -2
  171. package/src/commands/selectParentNode.ts +3 -2
  172. package/src/commands/selectTextblockEnd.ts +20 -0
  173. package/src/commands/selectTextblockStart.ts +20 -0
  174. package/src/commands/setContent.ts +6 -9
  175. package/src/commands/setMark.ts +66 -13
  176. package/src/commands/setNode.ts +30 -6
  177. package/src/commands/setNodeSelection.ts +6 -7
  178. package/src/commands/setTextSelection.ts +8 -9
  179. package/src/commands/sinkListItem.ts +5 -4
  180. package/src/commands/splitBlock.ts +23 -38
  181. package/src/commands/splitListItem.ts +30 -27
  182. package/src/commands/toggleList.ts +108 -19
  183. package/src/commands/toggleMark.ts +17 -6
  184. package/src/commands/toggleNode.ts +9 -4
  185. package/src/commands/toggleWrap.ts +8 -8
  186. package/src/commands/undoInputRule.ts +31 -2
  187. package/src/commands/unsetAllMarks.ts +4 -8
  188. package/src/commands/unsetMark.ts +34 -21
  189. package/src/commands/updateAttributes.ts +18 -12
  190. package/src/commands/wrapIn.ts +5 -10
  191. package/src/commands/wrapInList.ts +5 -4
  192. package/src/extensions/clipboardTextSerializer.ts +15 -36
  193. package/src/extensions/commands.ts +3 -144
  194. package/src/extensions/editable.ts +2 -1
  195. package/src/extensions/focusEvents.ts +4 -6
  196. package/src/extensions/index.ts +1 -0
  197. package/src/extensions/keymap.ts +111 -13
  198. package/src/extensions/tabindex.ts +18 -0
  199. package/src/helpers/combineTransactionSteps.ts +21 -0
  200. package/src/helpers/createChainableState.ts +38 -0
  201. package/src/helpers/createDocument.ts +4 -3
  202. package/src/helpers/createNodeFromContent.ts +10 -15
  203. package/src/helpers/defaultBlockAt.ts +13 -0
  204. package/src/helpers/findChildren.ts +4 -3
  205. package/src/helpers/findChildrenInRange.ts +8 -3
  206. package/src/helpers/findParentNode.ts +4 -3
  207. package/src/helpers/findParentNodeClosestToPos.ts +13 -7
  208. package/src/helpers/generateHTML.ts +6 -5
  209. package/src/helpers/generateJSON.ts +6 -7
  210. package/src/helpers/generateText.ts +27 -0
  211. package/src/helpers/getAttributes.ts +8 -9
  212. package/src/helpers/getAttributesFromExtensions.ts +25 -12
  213. package/src/helpers/getChangedRanges.ts +83 -0
  214. package/src/helpers/getDebugJSON.ts +42 -38
  215. package/src/helpers/getExtensionField.ts +3 -3
  216. package/src/helpers/getHTMLFromFragment.ts +5 -6
  217. package/src/helpers/getMarkAttributes.ts +18 -10
  218. package/src/helpers/getMarkRange.ts +13 -8
  219. package/src/helpers/getMarkType.ts +5 -3
  220. package/src/helpers/getMarksBetween.ts +34 -10
  221. package/src/helpers/getNodeAttributes.ts +14 -12
  222. package/src/helpers/getNodeType.ts +5 -3
  223. package/src/helpers/getRenderedAttributes.ts +8 -6
  224. package/src/helpers/getSchema.ts +5 -4
  225. package/src/helpers/getSchemaByResolvedExtensions.ts +165 -111
  226. package/src/helpers/getSchemaTypeByName.ts +3 -11
  227. package/src/helpers/getSchemaTypeNameByName.ts +2 -2
  228. package/src/helpers/getSplittedAttributes.ts +1 -1
  229. package/src/helpers/getText.ts +19 -0
  230. package/src/helpers/getTextBetween.ts +46 -0
  231. package/src/helpers/getTextContentFromNodes.ts +26 -0
  232. package/src/helpers/getTextSerializersFromSchema.ts +11 -0
  233. package/src/helpers/index.ts +47 -0
  234. package/src/helpers/injectExtensionAttributesToParseRule.ts +22 -23
  235. package/src/helpers/isActive.ts +10 -5
  236. package/src/helpers/isExtensionRulesEnabled.ts +15 -0
  237. package/src/helpers/isList.ts +6 -5
  238. package/src/helpers/isMarkActive.ts +32 -35
  239. package/src/helpers/isNodeActive.ts +27 -37
  240. package/src/helpers/isNodeEmpty.ts +2 -2
  241. package/src/helpers/isNodeSelection.ts +3 -4
  242. package/src/helpers/isTextSelection.ts +3 -4
  243. package/src/helpers/posToDOMRect.ts +10 -4
  244. package/src/helpers/resolveFocusPosition.ts +42 -0
  245. package/src/helpers/selectionToInsertionEnd.ts +3 -3
  246. package/src/helpers/splitExtensions.ts +3 -3
  247. package/src/index.ts +12 -37
  248. package/src/inputRules/index.ts +5 -0
  249. package/src/inputRules/markInputRule.ts +59 -40
  250. package/src/inputRules/nodeInputRule.ts +45 -12
  251. package/src/inputRules/textInputRule.ts +35 -0
  252. package/src/inputRules/textblockTypeInputRule.ts +37 -0
  253. package/src/inputRules/wrappingInputRule.ts +84 -0
  254. package/src/pasteRules/index.ts +3 -0
  255. package/src/pasteRules/markPasteRule.ts +49 -56
  256. package/src/pasteRules/nodePasteRule.ts +37 -0
  257. package/src/pasteRules/textPasteRule.ts +35 -0
  258. package/src/style.ts +12 -3
  259. package/src/types.ts +140 -106
  260. package/src/utilities/callOrReturn.ts +3 -2
  261. package/src/utilities/createStyleTag.ts +8 -4
  262. package/src/utilities/deleteProps.ts +1 -1
  263. package/src/utilities/elementFromString.ts +1 -1
  264. package/src/utilities/escapeForRegEx.ts +4 -0
  265. package/src/utilities/findDuplicates.ts +5 -0
  266. package/src/utilities/fromString.ts +2 -2
  267. package/src/utilities/index.ts +20 -0
  268. package/src/utilities/isEmptyObject.ts +2 -2
  269. package/src/utilities/isFunction.ts +3 -0
  270. package/src/utilities/isMacOS.ts +5 -0
  271. package/src/utilities/isNumber.ts +3 -0
  272. package/src/utilities/isPlainObject.ts +8 -5
  273. package/src/utilities/isRegExp.ts +3 -0
  274. package/src/utilities/isString.ts +3 -0
  275. package/src/utilities/isiOS.ts +1 -1
  276. package/src/utilities/mergeAttributes.ts +2 -1
  277. package/src/utilities/mergeDeep.ts +2 -2
  278. package/src/utilities/minMax.ts +1 -1
  279. package/src/utilities/objectIncludes.ts +18 -4
  280. package/src/utilities/removeDuplicates.ts +15 -0
  281. package/CHANGELOG.md +0 -1190
  282. package/LICENSE.md +0 -21
  283. package/dist/packages/core/src/commands/joinBackward.d.ts +0 -12
  284. package/dist/packages/core/src/commands/joinForward.d.ts +0 -12
  285. package/dist/packages/core/src/utilities/isClass.d.ts +0 -1
  286. package/dist/packages/core/src/utilities/isObject.d.ts +0 -1
  287. package/dist/packages/core/src/utilities/removeElement.d.ts +0 -1
  288. package/dist/tiptap-core.cjs.js +0 -3408
  289. package/dist/tiptap-core.cjs.js.map +0 -1
  290. package/dist/tiptap-core.esm.js.map +0 -1
  291. package/dist/tiptap-core.umd.js +0 -3405
  292. package/dist/tiptap-core.umd.js.map +0 -1
  293. package/src/commands/joinBackward.ts +0 -17
  294. package/src/commands/joinForward.ts +0 -17
  295. package/src/utilities/isClass.ts +0 -7
  296. package/src/utilities/isObject.ts +0 -10
  297. package/src/utilities/removeElement.ts +0 -5
@@ -1,22 +1,25 @@
1
- import { keymap } from 'prosemirror-keymap'
2
- import { Schema, Node as ProsemirrorNode } from 'prosemirror-model'
3
- import { inputRules as inputRulesPlugin } from 'prosemirror-inputrules'
4
- import { EditorView, Decoration } from 'prosemirror-view'
5
- import { Plugin } from 'prosemirror-state'
6
- import { Editor } from './Editor'
7
- import { Extensions, RawCommands, AnyConfig } from './types'
8
- import getExtensionField from './helpers/getExtensionField'
9
- import getSchemaByResolvedExtensions from './helpers/getSchemaByResolvedExtensions'
10
- import getSchemaTypeByName from './helpers/getSchemaTypeByName'
11
- import getNodeType from './helpers/getNodeType'
12
- import splitExtensions from './helpers/splitExtensions'
13
- import getAttributesFromExtensions from './helpers/getAttributesFromExtensions'
14
- import getRenderedAttributes from './helpers/getRenderedAttributes'
15
- import callOrReturn from './utilities/callOrReturn'
16
- import { NodeConfig } from '.'
17
-
18
- export default class ExtensionManager {
1
+ import { keymap } from '@tiptap/pm/keymap'
2
+ import { Node as ProsemirrorNode, Schema } from '@tiptap/pm/model'
3
+ import { Plugin } from '@tiptap/pm/state'
4
+ import { Decoration, EditorView } from '@tiptap/pm/view'
19
5
 
6
+ import { Mark, NodeConfig } from '.'
7
+ import { Editor } from './Editor'
8
+ import { getAttributesFromExtensions } from './helpers/getAttributesFromExtensions'
9
+ import { getExtensionField } from './helpers/getExtensionField'
10
+ import { getNodeType } from './helpers/getNodeType'
11
+ import { getRenderedAttributes } from './helpers/getRenderedAttributes'
12
+ import { getSchemaByResolvedExtensions } from './helpers/getSchemaByResolvedExtensions'
13
+ import { getSchemaTypeByName } from './helpers/getSchemaTypeByName'
14
+ import { isExtensionRulesEnabled } from './helpers/isExtensionRulesEnabled'
15
+ import { splitExtensions } from './helpers/splitExtensions'
16
+ import { inputRulesPlugin } from './InputRule'
17
+ import { pasteRulesPlugin } from './PasteRule'
18
+ import { AnyConfig, Extensions, RawCommands } from './types'
19
+ import { callOrReturn } from './utilities/callOrReturn'
20
+ import { findDuplicates } from './utilities/findDuplicates'
21
+
22
+ export class ExtensionManager {
20
23
  editor: Editor
21
24
 
22
25
  schema: Schema
@@ -31,9 +34,13 @@ export default class ExtensionManager {
31
34
  this.schema = getSchemaByResolvedExtensions(this.extensions)
32
35
 
33
36
  this.extensions.forEach(extension => {
37
+ // store extension storage in editor
38
+ this.editor.extensionStorage[extension.name] = extension.storage
39
+
34
40
  const context = {
35
41
  name: extension.name,
36
42
  options: extension.options,
43
+ storage: extension.storage,
37
44
  editor: this.editor,
38
45
  type: getSchemaTypeByName(extension.name, this.schema),
39
46
  }
@@ -56,21 +63,13 @@ export default class ExtensionManager {
56
63
  this.editor.on('beforeCreate', onBeforeCreate)
57
64
  }
58
65
 
59
- const onCreate = getExtensionField<AnyConfig['onCreate']>(
60
- extension,
61
- 'onCreate',
62
- context,
63
- )
66
+ const onCreate = getExtensionField<AnyConfig['onCreate']>(extension, 'onCreate', context)
64
67
 
65
68
  if (onCreate) {
66
69
  this.editor.on('create', onCreate)
67
70
  }
68
71
 
69
- const onUpdate = getExtensionField<AnyConfig['onUpdate']>(
70
- extension,
71
- 'onUpdate',
72
- context,
73
- )
72
+ const onUpdate = getExtensionField<AnyConfig['onUpdate']>(extension, 'onUpdate', context)
74
73
 
75
74
  if (onUpdate) {
76
75
  this.editor.on('update', onUpdate)
@@ -96,31 +95,19 @@ export default class ExtensionManager {
96
95
  this.editor.on('transaction', onTransaction)
97
96
  }
98
97
 
99
- const onFocus = getExtensionField<AnyConfig['onFocus']>(
100
- extension,
101
- 'onFocus',
102
- context,
103
- )
98
+ const onFocus = getExtensionField<AnyConfig['onFocus']>(extension, 'onFocus', context)
104
99
 
105
100
  if (onFocus) {
106
101
  this.editor.on('focus', onFocus)
107
102
  }
108
103
 
109
- const onBlur = getExtensionField<AnyConfig['onBlur']>(
110
- extension,
111
- 'onBlur',
112
- context,
113
- )
104
+ const onBlur = getExtensionField<AnyConfig['onBlur']>(extension, 'onBlur', context)
114
105
 
115
106
  if (onBlur) {
116
107
  this.editor.on('blur', onBlur)
117
108
  }
118
109
 
119
- const onDestroy = getExtensionField<AnyConfig['onDestroy']>(
120
- extension,
121
- 'onDestroy',
122
- context,
123
- )
110
+ const onDestroy = getExtensionField<AnyConfig['onDestroy']>(extension, 'onDestroy', context)
124
111
 
125
112
  if (onDestroy) {
126
113
  this.editor.on('destroy', onDestroy)
@@ -129,34 +116,45 @@ export default class ExtensionManager {
129
116
  }
130
117
 
131
118
  static resolve(extensions: Extensions): Extensions {
132
- return ExtensionManager.sort(ExtensionManager.flatten(extensions))
119
+ const resolvedExtensions = ExtensionManager.sort(ExtensionManager.flatten(extensions))
120
+ const duplicatedNames = findDuplicates(resolvedExtensions.map(extension => extension.name))
121
+
122
+ if (duplicatedNames.length) {
123
+ console.warn(
124
+ `[tiptap warn]: Duplicate extension names found: [${duplicatedNames
125
+ .map(item => `'${item}'`)
126
+ .join(', ')}]. This can lead to issues.`,
127
+ )
128
+ }
129
+
130
+ return resolvedExtensions
133
131
  }
134
132
 
135
133
  static flatten(extensions: Extensions): Extensions {
136
- return extensions
137
- .map(extension => {
138
- const context = {
139
- name: extension.name,
140
- options: extension.options,
141
- }
142
-
143
- const addExtensions = getExtensionField<AnyConfig['addExtensions']>(
144
- extension,
145
- 'addExtensions',
146
- context,
147
- )
148
-
149
- if (addExtensions) {
150
- return [
134
+ return (
135
+ extensions
136
+ .map(extension => {
137
+ const context = {
138
+ name: extension.name,
139
+ options: extension.options,
140
+ storage: extension.storage,
141
+ }
142
+
143
+ const addExtensions = getExtensionField<AnyConfig['addExtensions']>(
151
144
  extension,
152
- ...this.flatten(addExtensions()),
153
- ]
154
- }
145
+ 'addExtensions',
146
+ context,
147
+ )
155
148
 
156
- return extension
157
- })
158
- // `Infinity` will break TypeScript so we set a number that is probably high enough
159
- .flat(10)
149
+ if (addExtensions) {
150
+ return [extension, ...this.flatten(addExtensions())]
151
+ }
152
+
153
+ return extension
154
+ })
155
+ // `Infinity` will break TypeScript so we set a number that is probably high enough
156
+ .flat(10)
157
+ )
160
158
  }
161
159
 
162
160
  static sort(extensions: Extensions): Extensions {
@@ -183,6 +181,7 @@ export default class ExtensionManager {
183
181
  const context = {
184
182
  name: extension.name,
185
183
  options: extension.options,
184
+ storage: extension.storage,
186
185
  editor: this.editor,
187
186
  type: getSchemaTypeByName(extension.name, this.schema),
188
187
  }
@@ -205,13 +204,25 @@ export default class ExtensionManager {
205
204
  }
206
205
 
207
206
  get plugins(): Plugin[] {
208
- return [...this.extensions]
209
- .reverse()
207
+ const { editor } = this
208
+
209
+ // With ProseMirror, first plugins within an array are executed first.
210
+ // In Tiptap, we provide the ability to override plugins,
211
+ // so it feels more natural to run plugins at the end of an array first.
212
+ // That’s why we have to reverse the `extensions` array and sort again
213
+ // based on the `priority` option.
214
+ const extensions = ExtensionManager.sort([...this.extensions].reverse())
215
+
216
+ const inputRules: any[] = []
217
+ const pasteRules: any[] = []
218
+
219
+ const allPlugins = extensions
210
220
  .map(extension => {
211
221
  const context = {
212
222
  name: extension.name,
213
223
  options: extension.options,
214
- editor: this.editor,
224
+ storage: extension.storage,
225
+ editor,
215
226
  type: getSchemaTypeByName(extension.name, this.schema),
216
227
  }
217
228
 
@@ -223,33 +234,35 @@ export default class ExtensionManager {
223
234
  context,
224
235
  )
225
236
 
237
+ let defaultBindings: Record<string, () => boolean> = {}
238
+
239
+ // bind exit handling
240
+ if (extension.type === 'mark' && extension.config.exitable) {
241
+ defaultBindings.ArrowRight = () => Mark.handleExit({ editor, mark: extension as Mark })
242
+ }
243
+
226
244
  if (addKeyboardShortcuts) {
227
245
  const bindings = Object.fromEntries(
228
- Object
229
- .entries(addKeyboardShortcuts())
230
- .map(([shortcut, method]) => {
231
- return [shortcut, () => method({ editor: this.editor })]
232
- }),
246
+ Object.entries(addKeyboardShortcuts()).map(([shortcut, method]) => {
247
+ return [shortcut, () => method({ editor })]
248
+ }),
233
249
  )
234
250
 
235
- const keyMapPlugin = keymap(bindings)
236
-
237
- plugins.push(keyMapPlugin)
251
+ defaultBindings = { ...defaultBindings, ...bindings }
238
252
  }
239
253
 
254
+ const keyMapPlugin = keymap(defaultBindings)
255
+
256
+ plugins.push(keyMapPlugin)
257
+
240
258
  const addInputRules = getExtensionField<AnyConfig['addInputRules']>(
241
259
  extension,
242
260
  'addInputRules',
243
261
  context,
244
262
  )
245
263
 
246
- if (this.editor.options.enableInputRules && addInputRules) {
247
- const inputRules = addInputRules()
248
- const inputRulePlugins = inputRules.length
249
- ? [inputRulesPlugin({ rules: inputRules })]
250
- : []
251
-
252
- plugins.push(...inputRulePlugins)
264
+ if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
265
+ inputRules.push(...addInputRules())
253
266
  }
254
267
 
255
268
  const addPasteRules = getExtensionField<AnyConfig['addPasteRules']>(
@@ -258,10 +271,8 @@ export default class ExtensionManager {
258
271
  context,
259
272
  )
260
273
 
261
- if (this.editor.options.enablePasteRules && addPasteRules) {
262
- const pasteRulePlugins = addPasteRules()
263
-
264
- plugins.push(...pasteRulePlugins)
274
+ if (isExtensionRulesEnabled(extension, editor.options.enablePasteRules) && addPasteRules) {
275
+ pasteRules.push(...addPasteRules())
265
276
  }
266
277
 
267
278
  const addProseMirrorPlugins = getExtensionField<AnyConfig['addProseMirrorPlugins']>(
@@ -279,6 +290,18 @@ export default class ExtensionManager {
279
290
  return plugins
280
291
  })
281
292
  .flat()
293
+
294
+ return [
295
+ inputRulesPlugin({
296
+ editor,
297
+ rules: inputRules,
298
+ }),
299
+ ...pasteRulesPlugin({
300
+ editor,
301
+ rules: pasteRules,
302
+ }),
303
+ ...allPlugins,
304
+ ]
282
305
  }
283
306
 
284
307
  get attributes() {
@@ -289,72 +312,50 @@ export default class ExtensionManager {
289
312
  const { editor } = this
290
313
  const { nodeExtensions } = splitExtensions(this.extensions)
291
314
 
292
- return Object.fromEntries(nodeExtensions
293
- .filter(extension => !!getExtensionField(extension, 'addNodeView'))
294
- .map(extension => {
295
- const extensionAttributes = this.attributes.filter(attribute => attribute.type === extension.name)
296
- const context = {
297
- name: extension.name,
298
- options: extension.options,
299
- editor,
300
- type: getNodeType(extension.name, this.schema),
301
- }
302
- const addNodeView = getExtensionField<NodeConfig['addNodeView']>(
303
- extension,
304
- 'addNodeView',
305
- context,
306
- )
307
-
308
- if (!addNodeView) {
309
- return []
310
- }
311
-
312
- const nodeview = (
313
- node: ProsemirrorNode,
314
- view: EditorView,
315
- getPos: (() => number) | boolean,
316
- decorations: Decoration[],
317
- ) => {
318
- const HTMLAttributes = getRenderedAttributes(node, extensionAttributes)
319
-
320
- return addNodeView()({
315
+ return Object.fromEntries(
316
+ nodeExtensions
317
+ .filter(extension => !!getExtensionField(extension, 'addNodeView'))
318
+ .map(extension => {
319
+ const extensionAttributes = this.attributes.filter(
320
+ attribute => attribute.type === extension.name,
321
+ )
322
+ const context = {
323
+ name: extension.name,
324
+ options: extension.options,
325
+ storage: extension.storage,
321
326
  editor,
322
- node,
323
- getPos,
324
- decorations,
325
- HTMLAttributes,
327
+ type: getNodeType(extension.name, this.schema),
328
+ }
329
+ const addNodeView = getExtensionField<NodeConfig['addNodeView']>(
326
330
  extension,
327
- })
328
- }
329
-
330
- return [extension.name, nodeview]
331
- }))
332
- }
333
-
334
- get textSerializers() {
335
- const { editor } = this
336
- const { nodeExtensions } = splitExtensions(this.extensions)
337
-
338
- return Object.fromEntries(nodeExtensions
339
- .filter(extension => !!getExtensionField(extension, 'renderText'))
340
- .map(extension => {
341
- const context = {
342
- name: extension.name,
343
- options: extension.options,
344
- editor,
345
- type: getNodeType(extension.name, this.schema),
346
- }
347
-
348
- const renderText = getExtensionField<NodeConfig['renderText']>(extension, 'renderText', context)
349
-
350
- if (!renderText) {
351
- return []
352
- }
353
-
354
- const textSerializer = (props: { node: ProsemirrorNode }) => renderText(props)
331
+ 'addNodeView',
332
+ context,
333
+ )
355
334
 
356
- return [extension.name, textSerializer]
357
- }))
335
+ if (!addNodeView) {
336
+ return []
337
+ }
338
+
339
+ const nodeview = (
340
+ node: ProsemirrorNode,
341
+ view: EditorView,
342
+ getPos: (() => number) | boolean,
343
+ decorations: Decoration[],
344
+ ) => {
345
+ const HTMLAttributes = getRenderedAttributes(node, extensionAttributes)
346
+
347
+ return addNodeView()({
348
+ editor,
349
+ node,
350
+ getPos,
351
+ decorations,
352
+ HTMLAttributes,
353
+ extension,
354
+ })
355
+ }
356
+
357
+ return [extension.name, nodeview]
358
+ }),
359
+ )
358
360
  }
359
-
360
361
  }
@@ -0,0 +1,260 @@
1
+ import { EditorState, Plugin, TextSelection } from '@tiptap/pm/state'
2
+
3
+ import { CommandManager } from './CommandManager'
4
+ import { Editor } from './Editor'
5
+ import { createChainableState } from './helpers/createChainableState'
6
+ import { getTextContentFromNodes } from './helpers/getTextContentFromNodes'
7
+ import {
8
+ CanCommands,
9
+ ChainedCommands,
10
+ ExtendedRegExpMatchArray,
11
+ Range,
12
+ SingleCommands,
13
+ } from './types'
14
+ import { isRegExp } from './utilities/isRegExp'
15
+
16
+ export type InputRuleMatch = {
17
+ index: number
18
+ text: string
19
+ replaceWith?: string
20
+ match?: RegExpMatchArray
21
+ data?: Record<string, any>
22
+ }
23
+
24
+ export type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null)
25
+
26
+ export class InputRule {
27
+ find: InputRuleFinder
28
+
29
+ handler: (props: {
30
+ state: EditorState
31
+ range: Range
32
+ match: ExtendedRegExpMatchArray
33
+ commands: SingleCommands
34
+ chain: () => ChainedCommands
35
+ can: () => CanCommands
36
+ }) => void | null
37
+
38
+ constructor(config: {
39
+ find: InputRuleFinder
40
+ handler: (props: {
41
+ state: EditorState
42
+ range: Range
43
+ match: ExtendedRegExpMatchArray
44
+ commands: SingleCommands
45
+ chain: () => ChainedCommands
46
+ can: () => CanCommands
47
+ }) => void | null
48
+ }) {
49
+ this.find = config.find
50
+ this.handler = config.handler
51
+ }
52
+ }
53
+
54
+ const inputRuleMatcherHandler = (
55
+ text: string,
56
+ find: InputRuleFinder,
57
+ ): ExtendedRegExpMatchArray | null => {
58
+ if (isRegExp(find)) {
59
+ return find.exec(text)
60
+ }
61
+
62
+ const inputRuleMatch = find(text)
63
+
64
+ if (!inputRuleMatch) {
65
+ return null
66
+ }
67
+
68
+ const result: ExtendedRegExpMatchArray = [inputRuleMatch.text]
69
+
70
+ result.index = inputRuleMatch.index
71
+ result.input = text
72
+ result.data = inputRuleMatch.data
73
+
74
+ if (inputRuleMatch.replaceWith) {
75
+ if (!inputRuleMatch.text.includes(inputRuleMatch.replaceWith)) {
76
+ console.warn(
77
+ '[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".',
78
+ )
79
+ }
80
+
81
+ result.push(inputRuleMatch.replaceWith)
82
+ }
83
+
84
+ return result
85
+ }
86
+
87
+ function run(config: {
88
+ editor: Editor
89
+ from: number
90
+ to: number
91
+ text: string
92
+ rules: InputRule[]
93
+ plugin: Plugin
94
+ }): boolean {
95
+ const {
96
+ editor, from, to, text, rules, plugin,
97
+ } = config
98
+ const { view } = editor
99
+
100
+ if (view.composing) {
101
+ return false
102
+ }
103
+
104
+ const $from = view.state.doc.resolve(from)
105
+
106
+ if (
107
+ // check for code node
108
+ $from.parent.type.spec.code
109
+ // check for code mark
110
+ || !!($from.nodeBefore || $from.nodeAfter)?.marks.find(mark => mark.type.spec.code)
111
+ ) {
112
+ return false
113
+ }
114
+
115
+ let matched = false
116
+
117
+ const textBefore = getTextContentFromNodes($from) + text
118
+
119
+ rules.forEach(rule => {
120
+ if (matched) {
121
+ return
122
+ }
123
+
124
+ const match = inputRuleMatcherHandler(textBefore, rule.find)
125
+
126
+ if (!match) {
127
+ return
128
+ }
129
+
130
+ const tr = view.state.tr
131
+ const state = createChainableState({
132
+ state: view.state,
133
+ transaction: tr,
134
+ })
135
+ const range = {
136
+ from: from - (match[0].length - text.length),
137
+ to,
138
+ }
139
+
140
+ const { commands, chain, can } = new CommandManager({
141
+ editor,
142
+ state,
143
+ })
144
+
145
+ const handler = rule.handler({
146
+ state,
147
+ range,
148
+ match,
149
+ commands,
150
+ chain,
151
+ can,
152
+ })
153
+
154
+ // stop if there are no changes
155
+ if (handler === null || !tr.steps.length) {
156
+ return
157
+ }
158
+
159
+ // store transform as meta data
160
+ // so we can undo input rules within the `undoInputRules` command
161
+ tr.setMeta(plugin, {
162
+ transform: tr,
163
+ from,
164
+ to,
165
+ text,
166
+ })
167
+
168
+ view.dispatch(tr)
169
+ matched = true
170
+ })
171
+
172
+ return matched
173
+ }
174
+
175
+ /**
176
+ * Create an input rules plugin. When enabled, it will cause text
177
+ * input that matches any of the given rules to trigger the rule’s
178
+ * action.
179
+ */
180
+ export function inputRulesPlugin(props: { editor: Editor; rules: InputRule[] }): Plugin {
181
+ const { editor, rules } = props
182
+ const plugin = new Plugin({
183
+ state: {
184
+ init() {
185
+ return null
186
+ },
187
+ apply(tr, prev) {
188
+ const stored = tr.getMeta(plugin)
189
+
190
+ if (stored) {
191
+ return stored
192
+ }
193
+
194
+ return tr.selectionSet || tr.docChanged ? null : prev
195
+ },
196
+ },
197
+
198
+ props: {
199
+ handleTextInput(view, from, to, text) {
200
+ return run({
201
+ editor,
202
+ from,
203
+ to,
204
+ text,
205
+ rules,
206
+ plugin,
207
+ })
208
+ },
209
+
210
+ handleDOMEvents: {
211
+ compositionend: view => {
212
+ setTimeout(() => {
213
+ const { $cursor } = view.state.selection as TextSelection
214
+
215
+ if ($cursor) {
216
+ run({
217
+ editor,
218
+ from: $cursor.pos,
219
+ to: $cursor.pos,
220
+ text: '',
221
+ rules,
222
+ plugin,
223
+ })
224
+ }
225
+ })
226
+
227
+ return false
228
+ },
229
+ },
230
+
231
+ // add support for input rules to trigger on enter
232
+ // this is useful for example for code blocks
233
+ handleKeyDown(view, event) {
234
+ if (event.key !== 'Enter') {
235
+ return false
236
+ }
237
+
238
+ const { $cursor } = view.state.selection as TextSelection
239
+
240
+ if ($cursor) {
241
+ return run({
242
+ editor,
243
+ from: $cursor.pos,
244
+ to: $cursor.pos,
245
+ text: '\n',
246
+ rules,
247
+ plugin,
248
+ })
249
+ }
250
+
251
+ return false
252
+ },
253
+ },
254
+
255
+ // @ts-ignore
256
+ isInputRules: true,
257
+ }) as Plugin
258
+
259
+ return plugin
260
+ }