@blocknote/core 0.9.6 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/dist/blocknote.js +3697 -2609
  2. package/dist/blocknote.js.map +1 -1
  3. package/dist/blocknote.umd.cjs +7 -7
  4. package/dist/blocknote.umd.cjs.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/dist/webpack-stats.json +1 -0
  7. package/package.json +8 -4
  8. package/src/api/README.md +8 -0
  9. package/src/api/blockManipulation/blockManipulation.test.ts +72 -10
  10. package/src/api/blockManipulation/blockManipulation.ts +38 -18
  11. package/src/api/exporters/copyExtension.ts +68 -0
  12. package/src/api/exporters/html/__snapshots__/complex/misc/external.html +1 -0
  13. package/src/api/exporters/html/__snapshots__/complex/misc/internal.html +1 -0
  14. package/src/api/exporters/html/__snapshots__/customParagraph/basic/external.html +1 -0
  15. package/src/api/exporters/html/__snapshots__/customParagraph/basic/internal.html +1 -0
  16. package/src/api/exporters/html/__snapshots__/customParagraph/nested/external.html +1 -0
  17. package/src/api/exporters/html/__snapshots__/customParagraph/nested/internal.html +1 -0
  18. package/src/api/exporters/html/__snapshots__/customParagraph/styled/external.html +1 -0
  19. package/src/api/exporters/html/__snapshots__/customParagraph/styled/internal.html +1 -0
  20. package/src/api/exporters/html/__snapshots__/fontSize/basic/external.html +1 -0
  21. package/src/api/exporters/html/__snapshots__/fontSize/basic/internal.html +1 -0
  22. package/src/api/exporters/html/__snapshots__/hardbreak/basic/external.html +1 -0
  23. package/src/api/exporters/html/__snapshots__/hardbreak/basic/internal.html +1 -0
  24. package/src/api/exporters/html/__snapshots__/hardbreak/between-links/external.html +1 -0
  25. package/src/api/exporters/html/__snapshots__/hardbreak/between-links/internal.html +1 -0
  26. package/src/api/exporters/html/__snapshots__/hardbreak/end/external.html +1 -0
  27. package/src/api/exporters/html/__snapshots__/hardbreak/end/internal.html +1 -0
  28. package/src/api/exporters/html/__snapshots__/hardbreak/link/external.html +1 -0
  29. package/src/api/exporters/html/__snapshots__/hardbreak/link/internal.html +1 -0
  30. package/src/api/exporters/html/__snapshots__/hardbreak/multiple/external.html +1 -0
  31. package/src/api/exporters/html/__snapshots__/hardbreak/multiple/internal.html +1 -0
  32. package/src/api/exporters/html/__snapshots__/hardbreak/only/external.html +1 -0
  33. package/src/api/exporters/html/__snapshots__/hardbreak/only/internal.html +1 -0
  34. package/src/api/exporters/html/__snapshots__/hardbreak/start/external.html +1 -0
  35. package/src/api/exporters/html/__snapshots__/hardbreak/start/internal.html +1 -0
  36. package/src/api/exporters/html/__snapshots__/hardbreak/styles/external.html +1 -0
  37. package/src/api/exporters/html/__snapshots__/hardbreak/styles/internal.html +1 -0
  38. package/src/api/exporters/html/__snapshots__/image/basic/external.html +1 -0
  39. package/src/api/exporters/html/__snapshots__/image/basic/internal.html +1 -0
  40. package/src/api/exporters/html/__snapshots__/image/button/external.html +1 -0
  41. package/src/api/exporters/html/__snapshots__/image/button/internal.html +1 -0
  42. package/src/api/exporters/html/__snapshots__/image/nested/external.html +1 -0
  43. package/src/api/exporters/html/__snapshots__/image/nested/internal.html +1 -0
  44. package/src/api/exporters/html/__snapshots__/link/adjacent/external.html +1 -0
  45. package/src/api/exporters/html/__snapshots__/link/adjacent/internal.html +1 -0
  46. package/src/api/exporters/html/__snapshots__/link/basic/external.html +1 -0
  47. package/src/api/exporters/html/__snapshots__/link/basic/internal.html +1 -0
  48. package/src/api/exporters/html/__snapshots__/link/styled/external.html +1 -0
  49. package/src/api/exporters/html/__snapshots__/link/styled/internal.html +1 -0
  50. package/src/api/exporters/html/__snapshots__/mention/basic/external.html +1 -0
  51. package/src/api/exporters/html/__snapshots__/mention/basic/internal.html +1 -0
  52. package/src/api/exporters/html/__snapshots__/paragraph/basic/external.html +1 -0
  53. package/src/api/exporters/html/__snapshots__/paragraph/basic/internal.html +1 -0
  54. package/src/api/exporters/html/__snapshots__/paragraph/empty/external.html +1 -0
  55. package/src/api/exporters/html/__snapshots__/paragraph/empty/internal.html +1 -0
  56. package/src/api/exporters/html/__snapshots__/paragraph/nested/external.html +1 -0
  57. package/src/api/exporters/html/__snapshots__/paragraph/nested/internal.html +1 -0
  58. package/src/api/exporters/html/__snapshots__/paragraph/styled/external.html +1 -0
  59. package/src/api/exporters/html/__snapshots__/paragraph/styled/internal.html +1 -0
  60. package/src/api/exporters/html/__snapshots__/paste/parse-basic-block-types.json +140 -0
  61. package/src/api/exporters/html/__snapshots__/paste/parse-deep-nested-content.json +240 -0
  62. package/src/api/exporters/html/__snapshots__/paste/parse-div-with-inline-content.json +91 -0
  63. package/src/api/exporters/html/__snapshots__/paste/parse-divs.json +19 -0
  64. package/src/api/exporters/html/__snapshots__/paste/parse-fake-image-caption.json +31 -0
  65. package/src/api/exporters/html/__snapshots__/paste/parse-mixed-nested-lists.json +70 -0
  66. package/src/api/exporters/html/__snapshots__/paste/parse-nested-lists-with-paragraphs.json +70 -0
  67. package/src/api/exporters/html/__snapshots__/paste/parse-nested-lists.json +70 -0
  68. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/basic/external.html +1 -0
  69. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/basic/internal.html +1 -0
  70. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/nested/external.html +1 -0
  71. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/nested/internal.html +1 -0
  72. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/styled/external.html +1 -0
  73. package/src/api/exporters/html/__snapshots__/simpleCustomParagraph/styled/internal.html +1 -0
  74. package/src/api/exporters/html/__snapshots__/simpleImage/basic/external.html +1 -0
  75. package/src/api/exporters/html/__snapshots__/simpleImage/basic/internal.html +1 -0
  76. package/src/api/exporters/html/__snapshots__/simpleImage/button/external.html +1 -0
  77. package/src/api/exporters/html/__snapshots__/simpleImage/button/internal.html +1 -0
  78. package/src/api/exporters/html/__snapshots__/simpleImage/nested/external.html +1 -0
  79. package/src/api/exporters/html/__snapshots__/simpleImage/nested/internal.html +1 -0
  80. package/src/api/exporters/html/__snapshots__/small/basic/external.html +1 -0
  81. package/src/api/exporters/html/__snapshots__/small/basic/internal.html +1 -0
  82. package/src/api/exporters/html/__snapshots__/tag/basic/external.html +1 -0
  83. package/src/api/exporters/html/__snapshots__/tag/basic/internal.html +1 -0
  84. package/src/api/exporters/html/externalHTMLExporter.ts +98 -0
  85. package/src/api/exporters/html/htmlConversion.test.ts +100 -0
  86. package/src/api/exporters/html/internalHTMLSerializer.ts +80 -0
  87. package/src/api/exporters/html/util/sharedHTMLConversion.ts +128 -0
  88. package/src/api/{formatConversions → exporters/html/util}/simplifyBlocksRehypePlugin.ts +13 -0
  89. package/src/api/exporters/markdown/__snapshots__/complex/misc/markdown.md +5 -0
  90. package/src/api/exporters/markdown/__snapshots__/customParagraph/basic/markdown.md +1 -0
  91. package/src/api/exporters/markdown/__snapshots__/customParagraph/nested/markdown.md +5 -0
  92. package/src/api/exporters/markdown/__snapshots__/customParagraph/styled/markdown.md +1 -0
  93. package/src/api/exporters/markdown/__snapshots__/fontSize/basic/markdown.md +1 -0
  94. package/src/api/exporters/markdown/__snapshots__/hardbreak/basic/markdown.md +2 -0
  95. package/src/api/exporters/markdown/__snapshots__/hardbreak/between-links/markdown.md +2 -0
  96. package/src/api/exporters/markdown/__snapshots__/hardbreak/end/markdown.md +1 -0
  97. package/src/api/exporters/markdown/__snapshots__/hardbreak/link/markdown.md +2 -0
  98. package/src/api/exporters/markdown/__snapshots__/hardbreak/multiple/markdown.md +3 -0
  99. package/src/api/exporters/markdown/__snapshots__/hardbreak/start/markdown.md +1 -0
  100. package/src/api/exporters/markdown/__snapshots__/hardbreak/styles/markdown.md +2 -0
  101. package/src/api/exporters/markdown/__snapshots__/image/basic/markdown.md +3 -0
  102. package/src/api/exporters/markdown/__snapshots__/image/button/markdown.md +1 -0
  103. package/src/api/exporters/markdown/__snapshots__/image/nested/markdown.md +7 -0
  104. package/src/api/exporters/markdown/__snapshots__/link/adjacent/markdown.md +1 -0
  105. package/src/api/exporters/markdown/__snapshots__/link/basic/markdown.md +1 -0
  106. package/src/api/exporters/markdown/__snapshots__/link/styled/markdown.md +1 -0
  107. package/src/api/exporters/markdown/__snapshots__/mention/basic/markdown.md +1 -0
  108. package/src/api/exporters/markdown/__snapshots__/paragraph/basic/markdown.md +1 -0
  109. package/src/api/exporters/markdown/__snapshots__/paragraph/empty/markdown.md +0 -0
  110. package/src/api/exporters/markdown/__snapshots__/paragraph/nested/markdown.md +5 -0
  111. package/src/api/exporters/markdown/__snapshots__/paragraph/styled/markdown.md +1 -0
  112. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/basic/markdown.md +1 -0
  113. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/nested/markdown.md +5 -0
  114. package/src/api/exporters/markdown/__snapshots__/simpleCustomParagraph/styled/markdown.md +1 -0
  115. package/src/api/exporters/markdown/__snapshots__/simpleImage/basic/markdown.md +1 -0
  116. package/src/api/exporters/markdown/__snapshots__/simpleImage/button/markdown.md +1 -0
  117. package/src/api/exporters/markdown/__snapshots__/simpleImage/nested/markdown.md +3 -0
  118. package/src/api/exporters/markdown/__snapshots__/small/basic/markdown.md +1 -0
  119. package/src/api/exporters/markdown/__snapshots__/tag/basic/markdown.md +1 -0
  120. package/src/api/exporters/markdown/markdownExporter.test.ts +85 -0
  121. package/src/api/exporters/markdown/markdownExporter.ts +42 -0
  122. package/src/api/nodeConversions/__snapshots__/nodeConversions.test.ts.snap +486 -125
  123. package/src/api/nodeConversions/nodeConversions.test.ts +67 -498
  124. package/src/api/nodeConversions/nodeConversions.ts +311 -85
  125. package/src/api/parsers/html/__snapshots__/paste/list-test.json +105 -0
  126. package/src/api/parsers/html/__snapshots__/paste/parse-basic-block-types.json +140 -0
  127. package/src/api/parsers/html/__snapshots__/paste/parse-deep-nested-content.json +240 -0
  128. package/src/api/parsers/html/__snapshots__/paste/parse-div-with-inline-content.json +91 -0
  129. package/src/api/parsers/html/__snapshots__/paste/parse-divs.json +121 -0
  130. package/src/api/parsers/html/__snapshots__/paste/parse-fake-image-caption.json +31 -0
  131. package/src/api/parsers/html/__snapshots__/paste/parse-google-docs-html.json +476 -0
  132. package/src/api/parsers/html/__snapshots__/paste/parse-mixed-nested-lists.json +140 -0
  133. package/src/api/parsers/html/__snapshots__/paste/parse-nested-lists-with-paragraphs.json +140 -0
  134. package/src/api/parsers/html/__snapshots__/paste/parse-nested-lists.json +157 -0
  135. package/src/api/parsers/html/__snapshots__/paste/parse-notion-html.json +470 -0
  136. package/src/api/parsers/html/__snapshots__/paste/parse-two-divs.json +36 -0
  137. package/src/api/parsers/html/parseHTML.test.ts +440 -0
  138. package/src/api/parsers/html/parseHTML.ts +42 -0
  139. package/src/api/parsers/html/util/__snapshots__/nestedLists.test.ts.snap +129 -0
  140. package/src/api/parsers/html/util/nestedLists.test.ts +176 -0
  141. package/src/api/parsers/html/util/nestedLists.ts +113 -0
  142. package/src/api/parsers/markdown/__snapshots__/complex.json +353 -0
  143. package/src/api/parsers/markdown/__snapshots__/issue-226-1.json +71 -0
  144. package/src/api/parsers/markdown/__snapshots__/issue-226-2.json +144 -0
  145. package/src/api/parsers/markdown/__snapshots__/nested.json +72 -0
  146. package/src/api/parsers/markdown/__snapshots__/non-nested.json +71 -0
  147. package/src/api/parsers/markdown/__snapshots__/styled.json +58 -0
  148. package/src/api/parsers/markdown/parseMarkdown.test.ts +114 -0
  149. package/src/api/parsers/markdown/parseMarkdown.ts +84 -0
  150. package/src/api/parsers/pasteExtension.ts +59 -0
  151. package/src/api/testUtil/cases/customBlocks.ts +282 -0
  152. package/src/api/testUtil/cases/customInlineContent.ts +114 -0
  153. package/src/api/testUtil/cases/customStyles.ts +100 -0
  154. package/src/api/testUtil/cases/defaultSchema.ts +399 -0
  155. package/src/api/testUtil/index.ts +17 -0
  156. package/src/api/testUtil/partialBlockTestUtil.ts +127 -0
  157. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +136 -0
  158. package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ImageBlockContent/ImageBlockContent.ts +87 -31
  159. package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +34 -47
  160. package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ListItemBlockContent/ListItemKeyboardShortcuts.ts +1 -1
  161. package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +1 -1
  162. package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +34 -56
  163. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +43 -0
  164. package/src/blocks/README.md +3 -0
  165. package/src/blocks/TableBlockContent/TableBlockContent.ts +74 -0
  166. package/src/blocks/TableBlockContent/TableExtension.ts +63 -0
  167. package/src/blocks/defaultBlockHelpers.ts +95 -0
  168. package/src/blocks/defaultBlocks.ts +60 -0
  169. package/src/blocks/defaultProps.ts +24 -0
  170. package/src/{extensions/Blocks/nodes/Block.module.css → editor/Block.css} +69 -62
  171. package/src/{BlockNoteEditor.test.ts → editor/BlockNoteEditor.test.ts} +2 -2
  172. package/src/{BlockNoteEditor.ts → editor/BlockNoteEditor.ts} +364 -153
  173. package/src/{BlockNoteExtensions.ts → editor/BlockNoteExtensions.ts} +59 -40
  174. package/src/editor/README.md +3 -0
  175. package/src/editor/cursorPositionTypes.ts +16 -0
  176. package/src/{editor.module.css → editor/editor.css} +42 -15
  177. package/src/editor/selectionTypes.ts +14 -0
  178. package/src/editor/transformPasted.ts +58 -0
  179. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +1 -36
  180. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +12 -27
  181. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +16 -24
  182. package/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.ts +12 -10
  183. package/src/extensions/ImageToolbar/ImageToolbarPlugin.ts +35 -73
  184. package/src/extensions/Placeholder/PlaceholderExtension.ts +4 -4
  185. package/src/extensions/README.md +3 -0
  186. package/src/extensions/SideMenu/SideMenuPlugin.ts +66 -37
  187. package/src/extensions/SlashMenu/BaseSlashMenuItem.ts +7 -6
  188. package/src/extensions/SlashMenu/SlashMenuPlugin.ts +9 -7
  189. package/src/extensions/SlashMenu/defaultSlashMenuItems.ts +98 -35
  190. package/src/extensions/TableHandles/TableHandlesPlugin.ts +617 -0
  191. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +3 -51
  192. package/src/extensions/TextColor/TextColorExtension.ts +1 -29
  193. package/src/extensions/TextColor/TextColorMark.ts +7 -27
  194. package/src/extensions/UniqueID/UniqueID.ts +28 -2
  195. package/src/extensions-shared/README.md +3 -0
  196. package/src/{shared/plugins → extensions-shared}/suggestion/SuggestionPlugin.ts +19 -13
  197. package/src/index.ts +21 -15
  198. package/src/{extensions/Blocks/nodes → pm-nodes}/BlockContainer.ts +161 -96
  199. package/src/pm-nodes/BlockGroup.ts +54 -0
  200. package/src/pm-nodes/Doc.ts +7 -0
  201. package/src/pm-nodes/README.md +42 -0
  202. package/src/pm-nodes/index.ts +3 -0
  203. package/src/schema/README.md +3 -0
  204. package/src/schema/blocks/createSpec.ts +220 -0
  205. package/src/schema/blocks/internal.ts +253 -0
  206. package/src/schema/blocks/types.ts +252 -0
  207. package/src/schema/index.ts +10 -0
  208. package/src/schema/inlineContent/createSpec.ts +119 -0
  209. package/src/schema/inlineContent/internal.ts +105 -0
  210. package/src/schema/inlineContent/types.ts +144 -0
  211. package/src/schema/propTypes.ts +32 -0
  212. package/src/schema/styles/createSpec.ts +85 -0
  213. package/src/schema/styles/internal.ts +96 -0
  214. package/src/schema/styles/types.ts +42 -0
  215. package/src/util/README.md +3 -0
  216. package/src/{shared/utils.ts → util/browser.ts} +4 -8
  217. package/src/util/string.ts +3 -0
  218. package/src/util/typescript.ts +5 -0
  219. package/types/src/BlockNoteEditor.d.ts +49 -36
  220. package/types/src/BlockNoteExtensions.d.ts +8 -3
  221. package/types/src/api/blockManipulation/blockManipulation.d.ts +5 -4
  222. package/types/src/api/exporters/copyExtension.d.ts +6 -0
  223. package/types/src/api/exporters/html/externalHTMLExporter.d.ts +8 -0
  224. package/types/src/api/exporters/html/internalHTMLSerializer.d.ts +8 -0
  225. package/types/src/api/exporters/html/util/sharedHTMLConversion.d.ts +7 -0
  226. package/types/src/api/exporters/markdown/markdownExporter.d.ts +5 -0
  227. package/types/src/api/exporters/markdown/markdownExporter.test.d.ts +1 -0
  228. package/types/src/api/getBlockInfoFromPos.d.ts +27 -0
  229. package/types/src/api/nodeConversions/nodeConversions.d.ts +14 -6
  230. package/types/src/api/nodeConversions/testUtil.d.ts +7 -2
  231. package/types/src/api/nodeUtil.d.ts +8 -0
  232. package/types/src/api/parsers/html/parseHTML.d.ts +3 -0
  233. package/types/src/api/parsers/html/parseHTML.test.d.ts +1 -0
  234. package/types/src/api/parsers/html/util/nestedLists.d.ts +1 -0
  235. package/types/src/api/parsers/html/util/nestedLists.test.d.ts +1 -0
  236. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +3 -0
  237. package/types/src/api/parsers/markdown/parseMarkdown.test.d.ts +1 -0
  238. package/types/src/api/parsers/pasteExtension.d.ts +6 -0
  239. package/types/src/api/testCases/cases/customBlocks.d.ts +345 -0
  240. package/types/src/api/testCases/cases/customInlineContent.d.ts +29 -0
  241. package/types/src/api/testCases/cases/customStyles.d.ts +64 -0
  242. package/types/src/api/testCases/cases/defaultSchema.d.ts +3 -0
  243. package/types/src/api/testCases/index.d.ts +12 -0
  244. package/types/src/api/testUtil/cases/customBlocks.d.ts +345 -0
  245. package/types/src/api/testUtil/cases/customInlineContent.d.ts +29 -0
  246. package/types/src/api/testUtil/cases/customStyles.d.ts +64 -0
  247. package/types/src/api/testUtil/cases/defaultSchema.d.ts +3 -0
  248. package/types/src/api/testUtil/index.d.ts +12 -0
  249. package/types/src/api/testUtil/partialBlockTestUtil.d.ts +7 -0
  250. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +58 -0
  251. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +93 -0
  252. package/types/src/blocks/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +1 -0
  253. package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +46 -0
  254. package/types/src/blocks/ListItemBlockContent/ListItemKeyboardShortcuts.d.ts +2 -0
  255. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +2 -0
  256. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +46 -0
  257. package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +52 -0
  258. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +53 -0
  259. package/types/src/blocks/TableBlockContent/TableExtension.d.ts +2 -0
  260. package/types/src/blocks/defaultBlockHelpers.d.ts +10 -0
  261. package/types/src/blocks/defaultBlocks.d.ts +577 -0
  262. package/types/src/blocks/defaultProps.d.ts +15 -0
  263. package/types/src/editor/BlockNoteEditor.d.ts +299 -0
  264. package/types/src/editor/BlockNoteEditor.test.d.ts +1 -0
  265. package/types/src/editor/BlockNoteExtensions.d.ts +24 -0
  266. package/types/src/editor/cursorPositionTypes.d.ts +6 -0
  267. package/types/src/editor/selectionTypes.d.ts +4 -0
  268. package/types/src/editor/transformPasted.d.ts +12 -0
  269. package/types/src/extensions/BackgroundColor/BackgroundColorExtension.d.ts +0 -7
  270. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +7 -9
  271. package/types/src/extensions/Blocks/api/blocks/createSpec.d.ts +35 -0
  272. package/types/src/extensions/Blocks/api/blocks/internal.d.ts +45 -0
  273. package/types/src/extensions/Blocks/api/blocks/types.d.ts +114 -0
  274. package/types/src/extensions/Blocks/api/cursorPositionTypes.d.ts +7 -5
  275. package/types/src/extensions/Blocks/api/defaultBlocks.d.ts +573 -113
  276. package/types/src/extensions/Blocks/api/defaultProps.d.ts +2 -1
  277. package/types/src/extensions/Blocks/api/inlineContent/createSpec.d.ts +21 -0
  278. package/types/src/extensions/Blocks/api/inlineContent/internal.d.ts +25 -0
  279. package/types/src/extensions/Blocks/api/inlineContent/types.d.ts +62 -0
  280. package/types/src/extensions/Blocks/api/selectionTypes.d.ts +5 -3
  281. package/types/src/extensions/Blocks/api/styles/createSpec.d.ts +13 -0
  282. package/types/src/extensions/Blocks/api/styles/internal.d.ts +22 -0
  283. package/types/src/extensions/Blocks/api/styles/types.d.ts +21 -0
  284. package/types/src/extensions/Blocks/nodes/BlockContainer.d.ts +8 -4
  285. package/types/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.d.ts +38 -23
  286. package/types/src/extensions/Blocks/nodes/BlockContent/ImageBlockContent/ImageBlockContent.d.ts +75 -17
  287. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +30 -19
  288. package/types/src/extensions/Blocks/nodes/BlockContent/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +30 -19
  289. package/types/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.d.ts +36 -28
  290. package/types/src/extensions/Blocks/nodes/BlockContent/TableBlockContent/TableBlockContent.d.ts +53 -0
  291. package/types/src/extensions/Blocks/nodes/BlockContent/TableBlockContent/TableExtension.d.ts +2 -0
  292. package/types/src/extensions/Blocks/nodes/BlockContent/defaultBlockHelpers.d.ts +12 -0
  293. package/types/src/extensions/Blocks/nodes/BlockGroup.d.ts +1 -1
  294. package/types/src/extensions/FormattingToolbar/FormattingToolbarPlugin.d.ts +8 -6
  295. package/types/src/extensions/HyperlinkToolbar/HyperlinkToolbarPlugin.d.ts +6 -6
  296. package/types/src/extensions/ImageToolbar/ImageToolbarPlugin.d.ts +11 -16
  297. package/types/src/extensions/NonEditableBlocks/NonEditableBlockPlugin.d.ts +2 -0
  298. package/types/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.d.ts +14 -0
  299. package/types/src/extensions/SideMenu/SideMenuPlugin.d.ts +18 -11
  300. package/types/src/extensions/SlashMenu/BaseSlashMenuItem.d.ts +5 -6
  301. package/types/src/extensions/SlashMenu/SlashMenuPlugin.d.ts +6 -6
  302. package/types/src/extensions/SlashMenu/defaultSlashMenuItems.d.ts +2 -1
  303. package/types/src/extensions/TableHandles/TableHandlesPlugin.d.ts +74 -0
  304. package/types/src/extensions/TextAlignment/TextAlignmentExtension.d.ts +0 -7
  305. package/types/src/extensions/TextColor/TextColorExtension.d.ts +0 -7
  306. package/types/src/extensions/TextColor/TextColorMark.d.ts +7 -9
  307. package/types/src/extensions/UniqueID/UniqueID.d.ts +1 -1
  308. package/types/src/extensions-shared/BaseUiElementTypes.d.ts +7 -0
  309. package/types/src/extensions-shared/suggestion/SuggestionItem.d.ts +3 -0
  310. package/types/src/extensions-shared/suggestion/SuggestionPlugin.d.ts +36 -0
  311. package/types/src/index.d.ts +20 -15
  312. package/types/src/pm-nodes/BlockContainer.d.ts +28 -0
  313. package/types/src/pm-nodes/BlockGroup.d.ts +10 -0
  314. package/types/src/pm-nodes/Doc.d.ts +2 -0
  315. package/types/src/pm-nodes/index.d.ts +3 -0
  316. package/types/src/schema/blocks/createSpec.d.ts +35 -0
  317. package/types/src/schema/blocks/internal.d.ts +45 -0
  318. package/types/src/schema/blocks/types.d.ts +107 -0
  319. package/types/src/schema/index.d.ts +10 -0
  320. package/types/src/schema/inlineContent/createSpec.d.ts +21 -0
  321. package/types/src/schema/inlineContent/internal.d.ts +28 -0
  322. package/types/src/schema/inlineContent/types.d.ts +62 -0
  323. package/types/src/schema/propTypes.d.ts +8 -0
  324. package/types/src/schema/styles/createSpec.d.ts +13 -0
  325. package/types/src/schema/styles/internal.d.ts +22 -0
  326. package/types/src/schema/styles/types.d.ts +21 -0
  327. package/types/src/shared/plugins/suggestion/SuggestionPlugin.d.ts +4 -2
  328. package/types/src/util/EventEmitter.d.ts +11 -0
  329. package/types/src/util/browser.d.ts +3 -0
  330. package/types/src/util/string.d.ts +1 -0
  331. package/types/src/util/typescript.d.ts +3 -0
  332. package/src/api/formatConversions/__snapshots__/formatConversions.test.ts.snap +0 -346
  333. package/src/api/formatConversions/formatConversions.test.ts +0 -753
  334. package/src/api/formatConversions/formatConversions.ts +0 -133
  335. package/src/api/nodeConversions/testUtil.ts +0 -65
  336. package/src/extensions/Blocks/api/block.ts +0 -307
  337. package/src/extensions/Blocks/api/blockTypes.ts +0 -249
  338. package/src/extensions/Blocks/api/cursorPositionTypes.ts +0 -7
  339. package/src/extensions/Blocks/api/defaultBlocks.ts +0 -16
  340. package/src/extensions/Blocks/api/defaultProps.ts +0 -16
  341. package/src/extensions/Blocks/api/inlineContentTypes.ts +0 -36
  342. package/src/extensions/Blocks/api/selectionTypes.ts +0 -5
  343. package/src/extensions/Blocks/api/serialization.ts +0 -29
  344. package/src/extensions/Blocks/helpers/findBlock.ts +0 -5
  345. package/src/extensions/Blocks/index.ts +0 -8
  346. package/src/extensions/Blocks/nodes/BlockAttributes.ts +0 -10
  347. package/src/extensions/Blocks/nodes/BlockContent/HeadingBlockContent/HeadingBlockContent.ts +0 -142
  348. package/src/extensions/Blocks/nodes/BlockContent/ParagraphBlockContent/ParagraphBlockContent.ts +0 -62
  349. package/src/extensions/Blocks/nodes/BlockGroup.ts +0 -53
  350. package/types/src/api/formatConversions/formatConversions.d.ts +0 -6
  351. package/types/src/extensions/Blocks/api/block.d.ts +0 -20
  352. package/types/src/extensions/Blocks/api/blockTypes.d.ts +0 -103
  353. package/types/src/extensions/Blocks/api/inlineContentTypes.d.ts +0 -30
  354. package/types/src/extensions/Blocks/api/serialization.d.ts +0 -2
  355. /package/src/{shared/EditorElement.ts → api/exporters/markdown/__snapshots__/hardbreak/only/markdown.md} +0 -0
  356. /package/src/api/{formatConversions → exporters/markdown}/removeUnderlinesRehypePlugin.ts +0 -0
  357. /package/src/{extensions/Blocks/helpers → api}/getBlockInfoFromPos.ts +0 -0
  358. /package/src/api/{util/nodeUtil.ts → nodeUtil.ts} +0 -0
  359. /package/src/{extensions/Blocks/nodes/BlockContent → blocks}/ImageBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
  360. /package/src/extensions/{Blocks → NonEditableBlocks}/NonEditableBlockPlugin.ts +0 -0
  361. /package/src/extensions/{Blocks → PreviousBlockType}/PreviousBlockTypePlugin.ts +0 -0
  362. /package/src/{shared → extensions-shared}/BaseUiElementTypes.ts +0 -0
  363. /package/src/{shared/plugins → extensions-shared}/suggestion/SuggestionItem.ts +0 -0
  364. /package/src/{shared → util}/EventEmitter.ts +0 -0
  365. /package/types/src/api/{formatConversions/formatConversions.test.d.ts → exporters/html/htmlConversion.test.d.ts} +0 -0
  366. /package/types/src/api/{formatConversions → exporters/html/util}/simplifyBlocksRehypePlugin.d.ts +0 -0
  367. /package/types/src/api/{formatConversions → exporters/markdown}/removeUnderlinesRehypePlugin.d.ts +0 -0
@@ -0,0 +1,54 @@
1
+ import { Node } from "@tiptap/core";
2
+ import { BlockNoteDOMAttributes } from "../schema";
3
+ import { mergeCSSClasses } from "../util/browser";
4
+
5
+ export const BlockGroup = Node.create<{
6
+ domAttributes?: BlockNoteDOMAttributes;
7
+ }>({
8
+ name: "blockGroup",
9
+ group: "blockGroup",
10
+ content: "blockContainer+",
11
+
12
+ parseHTML() {
13
+ return [
14
+ {
15
+ tag: "div",
16
+ getAttrs: (element) => {
17
+ if (typeof element === "string") {
18
+ return false;
19
+ }
20
+
21
+ if (element.getAttribute("data-node-type") === "blockGroup") {
22
+ // Null means the element matches, but we don't want to add any attributes to the node.
23
+ return null;
24
+ }
25
+
26
+ return false;
27
+ },
28
+ },
29
+ ];
30
+ },
31
+
32
+ renderHTML({ HTMLAttributes }) {
33
+ const blockGroupHTMLAttributes = {
34
+ ...(this.options.domAttributes?.blockGroup || {}),
35
+ ...HTMLAttributes,
36
+ };
37
+ const blockGroup = document.createElement("div");
38
+ blockGroup.className = mergeCSSClasses(
39
+ "bn-block-group",
40
+ blockGroupHTMLAttributes.class
41
+ );
42
+ blockGroup.setAttribute("data-node-type", "blockGroup");
43
+ for (const [attribute, value] of Object.entries(blockGroupHTMLAttributes)) {
44
+ if (attribute !== "class") {
45
+ blockGroup.setAttribute(attribute, value);
46
+ }
47
+ }
48
+
49
+ return {
50
+ dom: blockGroup,
51
+ contentDOM: blockGroup,
52
+ };
53
+ },
54
+ });
@@ -0,0 +1,7 @@
1
+ import {Node} from "@tiptap/core";
2
+
3
+ export const Doc = Node.create({
4
+ name: "doc",
5
+ topNode: true,
6
+ content: "blockGroup",
7
+ });
@@ -0,0 +1,42 @@
1
+ ### @blocknote/core/src/pm-nodes
2
+
3
+ Defines the prosemirror nodes and base node structure. See below:
4
+
5
+
6
+ # Node structure
7
+
8
+ We use a Prosemirror document structure where every element is a `block` with 1 `content` element and one optional group of children (`blockgroup`).
9
+
10
+ - A `block` can only appear in a `blockgroup` (which is also the type of the root node)
11
+ - Every `block` element can have attributes (e.g.: is it a heading or a list item)
12
+ - Every `block` element can contain a `blockgroup` as second child. In this case the `blockgroup` is considered nested (indented in the UX)
13
+
14
+ This architecture is different from the "default" Prosemirror / Tiptap implementation which would use more semantic HTML node types (`p`, `li`, etc.). We have designed this block structure instead to more easily:
15
+
16
+ - support indentation of any node (without complex wrapping logic)
17
+ - supporting animations (nodes stay the same type, only attrs are changed)
18
+
19
+ ## Example
20
+
21
+ ```xml
22
+ <blockgroup>
23
+ <block>
24
+ <content>Parent element 1</content>
25
+ <blockgroup>
26
+ <block>
27
+ <content>Nested / child / indented item</content>
28
+ </block>
29
+ </blockgroup>
30
+ </block>
31
+ <block>
32
+ <content>Parent element 2</content>
33
+ <blockgroup>
34
+ <block>...</block>
35
+ <block>...</block>
36
+ </blockgroup>
37
+ </block>
38
+ <block>
39
+ <content>Element 3 without children</content>
40
+ </block>
41
+ </blockgroup>
42
+ ```
@@ -0,0 +1,3 @@
1
+ export { BlockContainer } from "./BlockContainer";
2
+ export { BlockGroup } from "./BlockGroup";
3
+ export { Doc } from "./Doc";
@@ -0,0 +1,3 @@
1
+ ### @blocknote/core/src/schema
2
+
3
+ The BlockNote Schema consists of Blocks, InlineContent and Styles.
@@ -0,0 +1,220 @@
1
+ import { ParseRule } from "@tiptap/pm/model";
2
+ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
3
+ import { InlineContentSchema } from "../inlineContent/types";
4
+ import { StyleSchema } from "../styles/types";
5
+ import {
6
+ createInternalBlockSpec,
7
+ createStronglyTypedTiptapNode,
8
+ getBlockFromPos,
9
+ propsToAttributes,
10
+ wrapInBlockStructure,
11
+ } from "./internal";
12
+ import {
13
+ BlockConfig,
14
+ BlockFromConfig,
15
+ BlockSchemaWithBlock,
16
+ PartialBlockFromConfig,
17
+ } from "./types";
18
+
19
+ // restrict content to "inline" and "none" only
20
+ export type CustomBlockConfig = BlockConfig & {
21
+ content: "inline" | "none";
22
+ };
23
+
24
+ export type CustomBlockImplementation<
25
+ T extends CustomBlockConfig,
26
+ I extends InlineContentSchema,
27
+ S extends StyleSchema
28
+ > = {
29
+ render: (
30
+ /**
31
+ * The custom block to render
32
+ */
33
+ block: BlockFromConfig<T, I, S>,
34
+ /**
35
+ * The BlockNote editor instance
36
+ * This is typed generically. If you want an editor with your custom schema, you need to
37
+ * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`
38
+ */
39
+ editor: BlockNoteEditor<BlockSchemaWithBlock<T["type"], T>, I, S>
40
+ // (note) if we want to fix the manual cast, we need to prevent circular references and separate block definition and render implementations
41
+ // or allow manually passing <BSchema>, but that's not possible without passing the other generics because Typescript doesn't support partial inferred generics
42
+ ) => {
43
+ dom: HTMLElement;
44
+ contentDOM?: HTMLElement;
45
+ destroy?: () => void;
46
+ };
47
+ // Exports block to external HTML. If not defined, the output will be the same
48
+ // as `render(...).dom`. Used to create clipboard data when pasting outside
49
+ // BlockNote.
50
+ // TODO: Maybe can return undefined to ignore when serializing?
51
+ toExternalHTML?: (
52
+ block: BlockFromConfig<T, I, S>,
53
+ editor: BlockNoteEditor<BlockSchemaWithBlock<T["type"], T>, I, S>
54
+ ) => {
55
+ dom: HTMLElement;
56
+ contentDOM?: HTMLElement;
57
+ };
58
+
59
+ parse?: (
60
+ el: HTMLElement
61
+ ) => PartialBlockFromConfig<T, I, S>["props"] | undefined;
62
+ };
63
+
64
+ // Function that uses the 'parse' function of a blockConfig to create a
65
+ // TipTap node's `parseHTML` property. This is only used for parsing content
66
+ // from the clipboard.
67
+ export function getParseRules(
68
+ config: BlockConfig,
69
+ customParseFunction: CustomBlockImplementation<any, any, any>["parse"]
70
+ ) {
71
+ const rules: ParseRule[] = [
72
+ {
73
+ tag: "[data-content-type=" + config.type + "]",
74
+ contentElement: "[data-editable]",
75
+ },
76
+ ];
77
+
78
+ if (customParseFunction) {
79
+ rules.push({
80
+ tag: "*",
81
+ getAttrs(node: string | HTMLElement) {
82
+ if (typeof node === "string") {
83
+ return false;
84
+ }
85
+
86
+ const props = customParseFunction?.(node);
87
+
88
+ if (props === undefined) {
89
+ return false;
90
+ }
91
+
92
+ return props;
93
+ },
94
+ });
95
+ }
96
+ // getContent(node, schema) {
97
+ // const block = blockConfig.parse?.(node as HTMLElement);
98
+ //
99
+ // if (block !== undefined && block.content !== undefined) {
100
+ // return Fragment.from(
101
+ // typeof block.content === "string"
102
+ // ? schema.text(block.content)
103
+ // : inlineContentToNodes(block.content, schema)
104
+ // );
105
+ // }
106
+ //
107
+ // return Fragment.empty;
108
+ // },
109
+ // });
110
+ // }
111
+
112
+ return rules;
113
+ }
114
+
115
+ // A function to create custom block for API consumers
116
+ // we want to hide the tiptap node from API consumers and provide a simpler API surface instead
117
+ export function createBlockSpec<
118
+ T extends CustomBlockConfig,
119
+ I extends InlineContentSchema,
120
+ S extends StyleSchema
121
+ >(blockConfig: T, blockImplementation: CustomBlockImplementation<T, I, S>) {
122
+ const node = createStronglyTypedTiptapNode({
123
+ name: blockConfig.type as T["type"],
124
+ content: (blockConfig.content === "inline"
125
+ ? "inline*"
126
+ : "") as T["content"] extends "inline" ? "inline*" : "",
127
+ group: "blockContent",
128
+ selectable: true,
129
+
130
+ addAttributes() {
131
+ return propsToAttributes(blockConfig.propSchema);
132
+ },
133
+
134
+ parseHTML() {
135
+ return getParseRules(blockConfig, blockImplementation.parse);
136
+ },
137
+
138
+ renderHTML() {
139
+ // renderHTML is not really used, as we always use a nodeView, and we use toExternalHTML / toInternalHTML for serialization
140
+ // There's an edge case when this gets called nevertheless; before the nodeviews have been mounted
141
+ // this is why we implement it with a temporary placeholder
142
+ const div = document.createElement("div");
143
+ div.setAttribute("data-tmp-placeholder", "true");
144
+ return {
145
+ dom: div,
146
+ };
147
+ },
148
+
149
+ addNodeView() {
150
+ return ({ getPos }) => {
151
+ // Gets the BlockNote editor instance
152
+ const editor = this.options.editor;
153
+ // Gets the block
154
+ const block = getBlockFromPos(
155
+ getPos,
156
+ editor,
157
+ this.editor,
158
+ blockConfig.type
159
+ );
160
+ // Gets the custom HTML attributes for `blockContent` nodes
161
+ const blockContentDOMAttributes =
162
+ this.options.domAttributes?.blockContent || {};
163
+
164
+ const output = blockImplementation.render(block as any, editor);
165
+
166
+ return wrapInBlockStructure(
167
+ output,
168
+ block.type,
169
+ block.props,
170
+ blockConfig.propSchema,
171
+ blockContentDOMAttributes
172
+ );
173
+ };
174
+ },
175
+ });
176
+
177
+ if (node.name !== blockConfig.type) {
178
+ throw new Error(
179
+ "Node name does not match block type. This is a bug in BlockNote."
180
+ );
181
+ }
182
+
183
+ return createInternalBlockSpec(blockConfig, {
184
+ node,
185
+ toInternalHTML: (block, editor) => {
186
+ const blockContentDOMAttributes =
187
+ node.options.domAttributes?.blockContent || {};
188
+
189
+ const output = blockImplementation.render(block as any, editor as any);
190
+
191
+ return wrapInBlockStructure(
192
+ output,
193
+ block.type,
194
+ block.props,
195
+ blockConfig.propSchema,
196
+ blockContentDOMAttributes
197
+ );
198
+ },
199
+ toExternalHTML: (block, editor) => {
200
+ const blockContentDOMAttributes =
201
+ node.options.domAttributes?.blockContent || {};
202
+
203
+ let output = blockImplementation.toExternalHTML?.(
204
+ block as any,
205
+ editor as any
206
+ );
207
+ if (output === undefined) {
208
+ output = blockImplementation.render(block as any, editor as any);
209
+ }
210
+
211
+ return wrapInBlockStructure(
212
+ output,
213
+ block.type,
214
+ block.props,
215
+ blockConfig.propSchema,
216
+ blockContentDOMAttributes
217
+ );
218
+ },
219
+ });
220
+ }
@@ -0,0 +1,253 @@
1
+ import {
2
+ Attribute,
3
+ Attributes,
4
+ Editor,
5
+ Extension,
6
+ Node,
7
+ NodeConfig,
8
+ } from "@tiptap/core";
9
+ import { defaultBlockToHTML } from "../../blocks/defaultBlockHelpers";
10
+ import { inheritedProps } from "../../blocks/defaultProps";
11
+ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor";
12
+ import { mergeCSSClasses } from "../../util/browser";
13
+ import { camelToDataKebab } from "../../util/string";
14
+ import { InlineContentSchema } from "../inlineContent/types";
15
+ import { PropSchema, Props } from "../propTypes";
16
+ import { StyleSchema } from "../styles/types";
17
+ import {
18
+ BlockConfig,
19
+ BlockSchemaFromSpecs,
20
+ BlockSchemaWithBlock,
21
+ BlockSpec,
22
+ BlockSpecs,
23
+ SpecificBlock,
24
+ TiptapBlockImplementation,
25
+ } from "./types";
26
+
27
+ // Function that uses the 'propSchema' of a blockConfig to create a TipTap
28
+ // node's `addAttributes` property.
29
+ // TODO: extract function
30
+ export function propsToAttributes(propSchema: PropSchema): Attributes {
31
+ const tiptapAttributes: Record<string, Attribute> = {};
32
+
33
+ Object.entries(propSchema)
34
+ .filter(([name, _spec]) => !inheritedProps.includes(name))
35
+ .forEach(([name, spec]) => {
36
+ tiptapAttributes[name] = {
37
+ default: spec.default,
38
+ keepOnSplit: true,
39
+ // Props are displayed in kebab-case as HTML attributes. If a prop's
40
+ // value is the same as its default, we don't display an HTML
41
+ // attribute for it.
42
+ parseHTML: (element) => {
43
+ const value = element.getAttribute(camelToDataKebab(name));
44
+
45
+ if (value === null) {
46
+ return null;
47
+ }
48
+
49
+ if (typeof spec.default === "boolean") {
50
+ if (value === "true") {
51
+ return true;
52
+ }
53
+
54
+ if (value === "false") {
55
+ return false;
56
+ }
57
+
58
+ return null;
59
+ }
60
+
61
+ if (typeof spec.default === "number") {
62
+ const asNumber = parseFloat(value);
63
+ const isNumeric =
64
+ !Number.isNaN(asNumber) && Number.isFinite(asNumber);
65
+
66
+ if (isNumeric) {
67
+ return asNumber;
68
+ }
69
+
70
+ return null;
71
+ }
72
+
73
+ return value;
74
+ },
75
+ renderHTML: (attributes) =>
76
+ attributes[name] !== spec.default
77
+ ? {
78
+ [camelToDataKebab(name)]: attributes[name],
79
+ }
80
+ : {},
81
+ };
82
+ });
83
+
84
+ return tiptapAttributes;
85
+ }
86
+
87
+ // Used to figure out which block should be rendered. This block is then used to
88
+ // create the node view.
89
+ export function getBlockFromPos<
90
+ BType extends string,
91
+ Config extends BlockConfig,
92
+ BSchema extends BlockSchemaWithBlock<BType, Config>,
93
+ I extends InlineContentSchema,
94
+ S extends StyleSchema
95
+ >(
96
+ getPos: (() => number) | boolean,
97
+ editor: BlockNoteEditor<BSchema, I, S>,
98
+ tipTapEditor: Editor,
99
+ type: BType
100
+ ) {
101
+ // Gets position of the node
102
+ if (typeof getPos === "boolean") {
103
+ throw new Error(
104
+ "Cannot find node position as getPos is a boolean, not a function."
105
+ );
106
+ }
107
+ const pos = getPos();
108
+ // Gets parent blockContainer node
109
+ const blockContainer = tipTapEditor.state.doc.resolve(pos!).node();
110
+ // Gets block identifier
111
+ const blockIdentifier = blockContainer.attrs.id;
112
+ // Gets the block
113
+ const block = editor.getBlock(blockIdentifier)! as SpecificBlock<
114
+ BSchema,
115
+ BType,
116
+ I,
117
+ S
118
+ >;
119
+ if (block.type !== type) {
120
+ throw new Error("Block type does not match");
121
+ }
122
+
123
+ return block;
124
+ }
125
+
126
+ // Function that wraps the `dom` element returned from 'blockConfig.render' in a
127
+ // `blockContent` div, which contains the block type and props as HTML
128
+ // attributes. If `blockConfig.render` also returns a `contentDOM`, it also adds
129
+ // an `inlineContent` class to it.
130
+ export function wrapInBlockStructure<
131
+ BType extends string,
132
+ PSchema extends PropSchema
133
+ >(
134
+ element: {
135
+ dom: HTMLElement;
136
+ contentDOM?: HTMLElement;
137
+ destroy?: () => void;
138
+ },
139
+ blockType: BType,
140
+ blockProps: Props<PSchema>,
141
+ propSchema: PSchema,
142
+ domAttributes?: Record<string, string>
143
+ ): {
144
+ dom: HTMLElement;
145
+ contentDOM?: HTMLElement;
146
+ destroy?: () => void;
147
+ } {
148
+ // Creates `blockContent` element
149
+ const blockContent = document.createElement("div");
150
+
151
+ // Adds custom HTML attributes
152
+ if (domAttributes !== undefined) {
153
+ for (const [attr, value] of Object.entries(domAttributes)) {
154
+ if (attr !== "class") {
155
+ blockContent.setAttribute(attr, value);
156
+ }
157
+ }
158
+ }
159
+ // Sets blockContent class
160
+ blockContent.className = mergeCSSClasses(
161
+ "bn-block-content",
162
+ domAttributes?.class || ""
163
+ );
164
+ // Sets content type attribute
165
+ blockContent.setAttribute("data-content-type", blockType);
166
+ // Adds props as HTML attributes in kebab-case with "data-" prefix. Skips props
167
+ // which are already added as HTML attributes to the parent `blockContent`
168
+ // element (inheritedProps) and props set to their default values.
169
+ for (const [prop, value] of Object.entries(blockProps)) {
170
+ if (!inheritedProps.includes(prop) && value !== propSchema[prop].default) {
171
+ blockContent.setAttribute(camelToDataKebab(prop), value);
172
+ }
173
+ }
174
+
175
+ blockContent.appendChild(element.dom);
176
+
177
+ if (element.contentDOM !== undefined) {
178
+ element.contentDOM.className = mergeCSSClasses(
179
+ "bn-inline-content",
180
+ element.contentDOM.className
181
+ );
182
+ element.contentDOM.setAttribute("data-editable", "");
183
+ }
184
+
185
+ return {
186
+ ...element,
187
+ dom: blockContent,
188
+ };
189
+ }
190
+
191
+ // Helper type to keep track of the `name` and `content` properties after calling Node.create.
192
+ type StronglyTypedTipTapNode<
193
+ Name extends string,
194
+ Content extends "inline*" | "tableRow+" | ""
195
+ > = Node & { name: Name; config: { content: Content } };
196
+
197
+ export function createStronglyTypedTiptapNode<
198
+ Name extends string,
199
+ Content extends "inline*" | "tableRow+" | ""
200
+ >(config: NodeConfig & { name: Name; content: Content }) {
201
+ return Node.create(config) as StronglyTypedTipTapNode<Name, Content>; // force re-typing (should be safe as it's type-checked from the config)
202
+ }
203
+
204
+ // This helper function helps to instantiate a blockspec with a
205
+ // config and implementation that conform to the type of Config
206
+ export function createInternalBlockSpec<T extends BlockConfig>(
207
+ config: T,
208
+ implementation: TiptapBlockImplementation<
209
+ T,
210
+ any,
211
+ InlineContentSchema,
212
+ StyleSchema
213
+ >
214
+ ) {
215
+ return {
216
+ config,
217
+ implementation,
218
+ } satisfies BlockSpec<T, any, InlineContentSchema, StyleSchema>;
219
+ }
220
+
221
+ export function createBlockSpecFromStronglyTypedTiptapNode<
222
+ T extends Node,
223
+ P extends PropSchema
224
+ >(node: T, propSchema: P, requiredExtensions?: Array<Extension | Node>) {
225
+ return createInternalBlockSpec(
226
+ {
227
+ type: node.name as T["name"],
228
+ content: (node.config.content === "inline*"
229
+ ? "inline"
230
+ : node.config.content === "tableRow+"
231
+ ? "table"
232
+ : "none") as T["config"]["content"] extends "inline*"
233
+ ? "inline"
234
+ : T["config"]["content"] extends "tableRow+"
235
+ ? "table"
236
+ : "none",
237
+ propSchema,
238
+ },
239
+ {
240
+ node,
241
+ requiredExtensions,
242
+ toInternalHTML: defaultBlockToHTML,
243
+ toExternalHTML: defaultBlockToHTML,
244
+ // parse: () => undefined, // parse rules are in node already
245
+ }
246
+ );
247
+ }
248
+
249
+ export function getBlockSchemaFromSpecs<T extends BlockSpecs>(specs: T) {
250
+ return Object.fromEntries(
251
+ Object.entries(specs).map(([key, value]) => [key, value.config])
252
+ ) as BlockSchemaFromSpecs<T>;
253
+ }