@blocknote/core 0.37.0 → 0.39.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 (271) hide show
  1. package/dist/BlockNoteSchema-DmZ6UQfY.cjs +11 -0
  2. package/dist/BlockNoteSchema-DmZ6UQfY.cjs.map +1 -0
  3. package/dist/BlockNoteSchema-oR047ACf.js +4275 -0
  4. package/dist/BlockNoteSchema-oR047ACf.js.map +1 -0
  5. package/dist/blocknote.cjs +4 -12
  6. package/dist/blocknote.cjs.map +1 -1
  7. package/dist/blocknote.js +3311 -7230
  8. package/dist/blocknote.js.map +1 -1
  9. package/dist/blocks.cjs +2 -0
  10. package/dist/blocks.cjs.map +1 -0
  11. package/dist/blocks.js +71 -0
  12. package/dist/blocks.js.map +1 -0
  13. package/dist/{en-CvDoFvhc.js → en-Bq3Es3Np.js} +6 -12
  14. package/dist/en-Bq3Es3Np.js.map +1 -0
  15. package/dist/en-D3B48eJ7.cjs +2 -0
  16. package/dist/en-D3B48eJ7.cjs.map +1 -0
  17. package/dist/locales.cjs +1 -1
  18. package/dist/locales.cjs.map +1 -1
  19. package/dist/locales.js +109 -229
  20. package/dist/locales.js.map +1 -1
  21. package/dist/style.css +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -0
  23. package/dist/webpack-stats.json +1 -1
  24. package/package.json +25 -22
  25. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +1 -1
  26. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +2 -2
  27. package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +34 -25
  28. package/src/api/blockManipulation/setupTestEnv.ts +0 -1
  29. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +4 -8
  30. package/src/api/clipboard/toClipboard/copyExtension.ts +1 -3
  31. package/src/api/exporters/html/externalHTMLExporter.ts +0 -1
  32. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +128 -28
  33. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +101 -41
  34. package/src/api/exporters/markdown/markdownExporter.ts +13 -22
  35. package/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +2 -12
  36. package/src/api/parsers/html/parseHTML.ts +3 -2
  37. package/src/api/parsers/html/util/nestedLists.test.ts +8 -8
  38. package/src/api/parsers/markdown/parseMarkdown.ts +17 -14
  39. package/src/api/pmUtil.ts +1 -1
  40. package/src/api/positionMapping.test.ts +197 -33
  41. package/src/api/positionMapping.ts +4 -6
  42. package/src/blocks/Audio/block.ts +174 -0
  43. package/src/blocks/BlockNoteSchema.ts +59 -0
  44. package/src/blocks/Code/block.ts +303 -0
  45. package/src/blocks/Code/shiki.ts +73 -0
  46. package/src/blocks/File/block.ts +98 -0
  47. package/src/blocks/{FileBlockContent → File}/helpers/render/createAddFileButton.ts +8 -4
  48. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileBlockWrapper.ts +16 -13
  49. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.ts +15 -2
  50. package/src/blocks/{FileBlockContent → File}/helpers/render/createResizableFileBlockWrapper.ts +63 -19
  51. package/src/blocks/Heading/block.ts +138 -0
  52. package/src/blocks/Image/block.ts +190 -0
  53. package/src/blocks/ListItem/BulletListItem/block.ts +116 -0
  54. package/src/blocks/ListItem/CheckListItem/block.ts +175 -0
  55. package/src/blocks/ListItem/NumberedListItem/IndexingPlugin.ts +173 -0
  56. package/src/blocks/ListItem/NumberedListItem/block.ts +133 -0
  57. package/src/blocks/ListItem/ToggleListItem/block.ts +78 -0
  58. package/src/blocks/PageBreak/block.ts +72 -0
  59. package/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.ts +9 -7
  60. package/src/blocks/Paragraph/block.ts +80 -0
  61. package/src/blocks/Quote/block.ts +90 -0
  62. package/src/blocks/{TableBlockContent/TableBlockContent.ts → Table/block.ts} +169 -51
  63. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +1 -1
  64. package/src/blocks/Video/block.ts +143 -0
  65. package/src/blocks/defaultBlockHelpers.ts +2 -2
  66. package/src/blocks/defaultBlockTypeGuards.ts +143 -174
  67. package/src/blocks/defaultBlocks.ts +107 -35
  68. package/src/blocks/defaultProps.ts +145 -4
  69. package/src/blocks/index.ts +26 -0
  70. package/src/blocks/utils/listItemEnterHandler.ts +42 -0
  71. package/src/editor/Block.css +54 -18
  72. package/src/editor/BlockNoteEditor.ts +265 -230
  73. package/src/editor/BlockNoteExtension.ts +92 -0
  74. package/src/editor/BlockNoteExtensions.ts +20 -16
  75. package/src/editor/defaultColors.ts +2 -2
  76. package/src/exporter/Exporter.ts +1 -1
  77. package/src/exporter/mapping.ts +1 -1
  78. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +3 -20
  79. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +6 -8
  80. package/src/extensions/BlockChange/BlockChangePlugin.ts +2 -1
  81. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +2 -2
  82. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +2 -2
  83. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -1
  84. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -1
  85. package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +52 -0
  86. package/src/extensions/Collaboration/schemaMigration/migrationRules/index.ts +4 -0
  87. package/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.ts +4 -0
  88. package/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts +78 -0
  89. package/src/extensions/Comments/CommentsPlugin.ts +2 -0
  90. package/src/extensions/FilePanel/FilePanelPlugin.ts +5 -10
  91. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +1 -1
  92. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +4 -3
  93. package/src/extensions/Placeholder/PlaceholderPlugin.ts +2 -2
  94. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +1 -23
  95. package/src/extensions/SideMenu/SideMenuPlugin.ts +0 -2
  96. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +0 -5
  97. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +6 -2
  98. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +24 -17
  99. package/src/extensions/TableHandles/TableHandlesPlugin.ts +2 -2
  100. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +5 -11
  101. package/src/extensions/TextColor/TextColorExtension.ts +3 -17
  102. package/src/extensions/TextColor/TextColorMark.ts +4 -9
  103. package/src/extensions/UniqueID/UniqueID.ts +6 -13
  104. package/src/i18n/locales/ar.ts +6 -12
  105. package/src/i18n/locales/de.ts +6 -12
  106. package/src/i18n/locales/en.ts +6 -12
  107. package/src/i18n/locales/es.ts +6 -12
  108. package/src/i18n/locales/fr.ts +6 -12
  109. package/src/i18n/locales/he.ts +6 -12
  110. package/src/i18n/locales/hr.ts +6 -12
  111. package/src/i18n/locales/is.ts +6 -12
  112. package/src/i18n/locales/it.ts +6 -12
  113. package/src/i18n/locales/ja.ts +6 -12
  114. package/src/i18n/locales/ko.ts +6 -12
  115. package/src/i18n/locales/nl.ts +6 -12
  116. package/src/i18n/locales/no.ts +6 -12
  117. package/src/i18n/locales/pl.ts +6 -12
  118. package/src/i18n/locales/pt.ts +6 -12
  119. package/src/i18n/locales/ru.ts +6 -12
  120. package/src/i18n/locales/sk.ts +6 -12
  121. package/src/i18n/locales/uk.ts +6 -12
  122. package/src/i18n/locales/vi.ts +6 -12
  123. package/src/i18n/locales/zh-tw.ts +6 -12
  124. package/src/i18n/locales/zh.ts +6 -12
  125. package/src/index.ts +2 -29
  126. package/src/schema/blocks/createSpec.ts +342 -169
  127. package/src/schema/blocks/internal.ts +77 -138
  128. package/src/schema/blocks/types.ts +264 -94
  129. package/src/schema/index.ts +1 -0
  130. package/src/schema/inlineContent/createSpec.ts +99 -21
  131. package/src/schema/inlineContent/internal.ts +16 -7
  132. package/src/schema/inlineContent/types.ts +24 -2
  133. package/src/schema/propTypes.ts +15 -9
  134. package/src/schema/schema.ts +209 -0
  135. package/src/schema/styles/createSpec.ts +79 -31
  136. package/src/schema/styles/internal.ts +61 -2
  137. package/src/schema/styles/types.ts +17 -3
  138. package/src/util/topo-sort.test.ts +125 -0
  139. package/src/util/topo-sort.ts +160 -0
  140. package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.d.ts +2 -1
  141. package/types/src/api/blockManipulation/selections/selection.d.ts +1 -1
  142. package/types/src/api/blockManipulation/setupTestEnv.d.ts +29 -543
  143. package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +1 -1
  144. package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
  145. package/types/src/api/exporters/markdown/markdownExporter.d.ts +1 -1
  146. package/types/src/api/parsers/html/parseHTML.d.ts +1 -1
  147. package/types/src/api/parsers/markdown/parseMarkdown.d.ts +2 -2
  148. package/types/src/api/pmUtil.d.ts +1 -1
  149. package/types/src/blocks/Audio/block.d.ts +58 -0
  150. package/types/src/blocks/BlockNoteSchema.d.ts +18 -0
  151. package/types/src/blocks/{CodeBlockContent/CodeBlockContent.d.ts → Code/block.d.ts} +25 -26
  152. package/types/src/blocks/Code/shiki.d.ts +4 -0
  153. package/types/src/blocks/File/block.d.ts +37 -0
  154. package/types/src/blocks/File/helpers/render/createAddFileButton.d.ts +6 -0
  155. package/types/src/blocks/File/helpers/render/createFileBlockWrapper.d.ts +25 -0
  156. package/types/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.d.ts +6 -2
  157. package/types/src/blocks/File/helpers/render/createResizableFileBlockWrapper.d.ts +31 -0
  158. package/types/src/blocks/Heading/block.d.ts +71 -0
  159. package/types/src/blocks/Image/block.d.ts +102 -0
  160. package/types/src/blocks/ListItem/BulletListItem/block.d.ts +25 -0
  161. package/types/src/blocks/ListItem/CheckListItem/block.d.ts +33 -0
  162. package/types/src/blocks/ListItem/NumberedListItem/IndexingPlugin.d.ts +8 -0
  163. package/types/src/blocks/ListItem/NumberedListItem/block.d.ts +33 -0
  164. package/types/src/blocks/ListItem/ToggleListItem/block.d.ts +25 -0
  165. package/types/src/blocks/PageBreak/block.d.ts +11 -0
  166. package/types/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.d.ts +4 -2
  167. package/types/src/blocks/Paragraph/block.d.ts +25 -0
  168. package/types/src/blocks/Quote/block.d.ts +17 -0
  169. package/types/src/blocks/Table/block.d.ts +21 -0
  170. package/types/src/blocks/Video/block.d.ts +67 -0
  171. package/types/src/blocks/defaultBlockHelpers.d.ts +1 -1
  172. package/types/src/blocks/defaultBlockTypeGuards.d.ts +15 -36
  173. package/types/src/blocks/defaultBlocks.d.ts +221 -1060
  174. package/types/src/blocks/defaultProps.d.ts +17 -1
  175. package/types/src/blocks/index.d.ts +24 -0
  176. package/types/src/blocks/utils/listItemEnterHandler.d.ts +2 -0
  177. package/types/src/editor/BlockNoteEditor.d.ts +39 -75
  178. package/types/src/editor/BlockNoteExtension.d.ts +67 -0
  179. package/types/src/editor/BlockNoteExtensions.d.ts +2 -0
  180. package/types/src/editor/defaultColors.d.ts +8 -76
  181. package/types/src/exporter/Exporter.d.ts +1 -1
  182. package/types/src/exporter/mapping.d.ts +1 -1
  183. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +4 -1
  184. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +7 -0
  185. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/index.d.ts +3 -0
  186. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.d.ts +3 -0
  187. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.d.ts +2 -0
  188. package/types/src/extensions/Comments/CommentsPlugin.d.ts +3 -1
  189. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +4 -4
  190. package/types/src/extensions/TextColor/TextColorMark.d.ts +4 -1
  191. package/types/src/i18n/locales/en.d.ts +1 -12
  192. package/types/src/i18n/locales/sk.d.ts +1 -12
  193. package/types/src/index.d.ts +2 -26
  194. package/types/src/schema/blocks/createSpec.d.ts +16 -36
  195. package/types/src/schema/blocks/internal.d.ts +11 -33
  196. package/types/src/schema/blocks/types.d.ts +181 -57
  197. package/types/src/schema/index.d.ts +1 -0
  198. package/types/src/schema/inlineContent/createSpec.d.ts +36 -2
  199. package/types/src/schema/inlineContent/internal.d.ts +7 -15
  200. package/types/src/schema/inlineContent/types.d.ts +15 -1
  201. package/types/src/schema/propTypes.d.ts +4 -4
  202. package/types/src/schema/schema.d.ts +40 -0
  203. package/types/src/schema/styles/createSpec.d.ts +6 -4
  204. package/types/src/schema/styles/internal.d.ts +6 -3
  205. package/types/src/schema/styles/types.d.ts +11 -2
  206. package/types/src/util/topo-sort.d.ts +18 -0
  207. package/types/src/util/topo-sort.test.d.ts +1 -0
  208. package/dist/en-CvDoFvhc.js.map +0 -1
  209. package/dist/en-ub2yVBX0.cjs +0 -2
  210. package/dist/en-ub2yVBX0.cjs.map +0 -1
  211. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +0 -145
  212. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +0 -445
  213. package/src/blocks/FileBlockContent/FileBlockContent.ts +0 -100
  214. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +0 -159
  215. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +0 -160
  216. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +0 -134
  217. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +0 -299
  218. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +0 -86
  219. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +0 -172
  220. package/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.ts +0 -104
  221. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +0 -49
  222. package/src/blocks/PageBreakBlockContent/schema.ts +0 -40
  223. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +0 -78
  224. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +0 -121
  225. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -159
  226. package/src/editor/BlockNoteSchema.ts +0 -107
  227. package/src/editor/BlockNoteTipTapEditor.ts +0 -335
  228. package/src/util/esmDependencies.ts +0 -51
  229. package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +0 -99
  230. package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +0 -90
  231. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +0 -6
  232. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +0 -9
  233. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +0 -9
  234. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +0 -67
  235. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +0 -131
  236. package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +0 -46
  237. package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +0 -55
  238. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +0 -2
  239. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +0 -58
  240. package/types/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.d.ts +0 -46
  241. package/types/src/blocks/PageBreakBlockContent/PageBreakBlockContent.d.ts +0 -31
  242. package/types/src/blocks/PageBreakBlockContent/schema.d.ts +0 -86
  243. package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +0 -52
  244. package/types/src/blocks/QuoteBlockContent/QuoteBlockContent.d.ts +0 -52
  245. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +0 -39
  246. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +0 -131
  247. package/types/src/editor/BlockNoteSchema.d.ts +0 -34
  248. package/types/src/editor/BlockNoteTipTapEditor.d.ts +0 -43
  249. package/types/src/util/esmDependencies.d.ts +0 -24
  250. /package/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.ts +0 -0
  251. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.ts +0 -0
  252. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.ts +0 -0
  253. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.ts +0 -0
  254. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.ts +0 -0
  255. /package/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
  256. /package/src/blocks/{ImageBlockContent → Image}/parseImageElement.ts +0 -0
  257. /package/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.ts +0 -0
  258. /package/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.ts +0 -0
  259. /package/src/blocks/{TableBlockContent → Table}/TableExtension.ts +0 -0
  260. /package/src/blocks/{VideoBlockContent → Video}/parseVideoElement.ts +0 -0
  261. /package/types/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.d.ts +0 -0
  262. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.d.ts +0 -0
  263. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.d.ts +0 -0
  264. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.d.ts +0 -0
  265. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.d.ts +0 -0
  266. /package/types/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +0 -0
  267. /package/types/src/blocks/{ImageBlockContent → Image}/parseImageElement.d.ts +0 -0
  268. /package/types/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.d.ts +0 -0
  269. /package/types/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.d.ts +0 -0
  270. /package/types/src/blocks/{TableBlockContent → Table}/TableExtension.d.ts +0 -0
  271. /package/types/src/blocks/{VideoBlockContent → Video}/parseVideoElement.d.ts +0 -0
@@ -0,0 +1,303 @@
1
+ import type { HighlighterGeneric } from "@shikijs/types";
2
+ import { createBlockNoteExtension } from "../../editor/BlockNoteExtension.js";
3
+ import { createBlockConfig, createBlockSpec } from "../../schema/index.js";
4
+ import { lazyShikiPlugin } from "./shiki.js";
5
+ import { DOMParser } from "@tiptap/pm/model";
6
+
7
+ export type CodeBlockOptions = {
8
+ /**
9
+ * Whether to indent lines with a tab when the user presses `Tab` in a code block.
10
+ *
11
+ * @default true
12
+ */
13
+ indentLineWithTab?: boolean;
14
+ /**
15
+ * The default language to use for code blocks.
16
+ *
17
+ * @default "text"
18
+ */
19
+ defaultLanguage?: string;
20
+ /**
21
+ * The languages that are supported in the editor.
22
+ *
23
+ * @example
24
+ * {
25
+ * javascript: {
26
+ * name: "JavaScript",
27
+ * aliases: ["js"],
28
+ * },
29
+ * typescript: {
30
+ * name: "TypeScript",
31
+ * aliases: ["ts"],
32
+ * },
33
+ * }
34
+ */
35
+ supportedLanguages?: Record<
36
+ string,
37
+ {
38
+ /**
39
+ * The display name of the language.
40
+ */
41
+ name: string;
42
+ /**
43
+ * Aliases for this language.
44
+ */
45
+ aliases?: string[];
46
+ }
47
+ >;
48
+ /**
49
+ * The highlighter to use for code blocks.
50
+ */
51
+ createHighlighter?: () => Promise<HighlighterGeneric<any, any>>;
52
+ };
53
+
54
+ export type CodeBlockConfig = ReturnType<typeof createCodeBlockConfig>;
55
+
56
+ export const createCodeBlockConfig = createBlockConfig(
57
+ ({ defaultLanguage = "text" }: CodeBlockOptions) =>
58
+ ({
59
+ type: "codeBlock" as const,
60
+ propSchema: {
61
+ language: {
62
+ default: defaultLanguage,
63
+ },
64
+ },
65
+ content: "inline",
66
+ }) as const,
67
+ );
68
+
69
+ export const createCodeBlockSpec = createBlockSpec(
70
+ createCodeBlockConfig,
71
+ (options) => ({
72
+ meta: {
73
+ code: true,
74
+ defining: true,
75
+ isolating: false,
76
+ },
77
+ parse: (e) => {
78
+ if (e.tagName !== "PRE") {
79
+ return undefined;
80
+ }
81
+
82
+ if (
83
+ e.childElementCount !== 1 ||
84
+ e.firstElementChild?.tagName !== "CODE"
85
+ ) {
86
+ return undefined;
87
+ }
88
+
89
+ const code = e.firstElementChild!;
90
+ const language =
91
+ code.getAttribute("data-language") ||
92
+ code.className
93
+ .split(" ")
94
+ .find((name) => name.includes("language-"))
95
+ ?.replace("language-", "");
96
+
97
+ return { language };
98
+ },
99
+
100
+ parseContent: ({ el, schema }) => {
101
+ const parser = DOMParser.fromSchema(schema);
102
+ const code = el.firstElementChild!;
103
+
104
+ return parser.parse(code, {
105
+ topNode: schema.nodes["codeBlock"].create(),
106
+ }).content;
107
+ },
108
+
109
+ render(block, editor) {
110
+ const wrapper = document.createDocumentFragment();
111
+ const pre = document.createElement("pre");
112
+ const code = document.createElement("code");
113
+ pre.appendChild(code);
114
+
115
+ let removeSelectChangeListener = undefined;
116
+
117
+ if (options.supportedLanguages) {
118
+ const select = document.createElement("select");
119
+
120
+ const handleLanguageChange = (event: Event) => {
121
+ const language = (event.target as HTMLSelectElement).value;
122
+
123
+ editor.updateBlock(block.id, { props: { language } });
124
+ };
125
+ select.addEventListener("change", handleLanguageChange);
126
+
127
+ const selectWrapper = document.createElement("div");
128
+ selectWrapper.contentEditable = "false";
129
+ select.value =
130
+ block.props.language || options.defaultLanguage || "text";
131
+
132
+ Object.entries(options.supportedLanguages ?? {}).forEach(
133
+ ([id, { name }]) => {
134
+ const option = document.createElement("option");
135
+
136
+ option.value = id;
137
+ option.text = name;
138
+ select.appendChild(option);
139
+ },
140
+ );
141
+ selectWrapper.appendChild(select);
142
+ wrapper.appendChild(selectWrapper);
143
+
144
+ removeSelectChangeListener = () =>
145
+ select.removeEventListener("change", handleLanguageChange);
146
+ }
147
+ wrapper.appendChild(pre);
148
+
149
+ return {
150
+ dom: wrapper,
151
+ contentDOM: code,
152
+ destroy: () => {
153
+ removeSelectChangeListener?.();
154
+ },
155
+ };
156
+ },
157
+ toExternalHTML(block) {
158
+ const pre = document.createElement("pre");
159
+ const code = document.createElement("code");
160
+ code.className = `language-${block.props.language}`;
161
+ code.dataset.language = block.props.language;
162
+ pre.appendChild(code);
163
+ return {
164
+ dom: pre,
165
+ contentDOM: code,
166
+ };
167
+ },
168
+ }),
169
+ (options) => {
170
+ return [
171
+ createBlockNoteExtension({
172
+ key: "code-block-highlighter",
173
+ plugins: [lazyShikiPlugin(options)],
174
+ }),
175
+ createBlockNoteExtension({
176
+ key: "code-block-keyboard-shortcuts",
177
+ keyboardShortcuts: {
178
+ Delete: ({ editor }) => {
179
+ return editor.transact((tr) => {
180
+ const { block } = editor.getTextCursorPosition();
181
+ if (block.type !== "codeBlock") {
182
+ return false;
183
+ }
184
+ const { $from } = tr.selection;
185
+
186
+ // When inside empty codeblock, on `DELETE` key press, delete the codeblock
187
+ if (!$from.parent.textContent) {
188
+ editor.removeBlocks([block]);
189
+
190
+ return true;
191
+ }
192
+
193
+ return false;
194
+ });
195
+ },
196
+ Tab: ({ editor }) => {
197
+ if (options.indentLineWithTab === false) {
198
+ return false;
199
+ }
200
+
201
+ return editor.transact((tr) => {
202
+ const { block } = editor.getTextCursorPosition();
203
+ if (block.type === "codeBlock") {
204
+ // TODO should probably only tab when at a line start or already tabbed in
205
+ tr.insertText(" ");
206
+ return true;
207
+ }
208
+
209
+ return false;
210
+ });
211
+ },
212
+ Enter: ({ editor }) => {
213
+ return editor.transact((tr) => {
214
+ const { block, nextBlock } = editor.getTextCursorPosition();
215
+ if (block.type !== "codeBlock") {
216
+ return false;
217
+ }
218
+ const { $from } = tr.selection;
219
+
220
+ const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2;
221
+ const endsWithDoubleNewline =
222
+ $from.parent.textContent.endsWith("\n\n");
223
+
224
+ // The user is trying to exit the code block by pressing enter at the end of the code block
225
+ if (isAtEnd && endsWithDoubleNewline) {
226
+ // Remove the double newline
227
+ tr.delete($from.pos - 2, $from.pos);
228
+
229
+ // If there is a next block, move the cursor to it
230
+ if (nextBlock) {
231
+ editor.setTextCursorPosition(nextBlock, "start");
232
+ return true;
233
+ }
234
+
235
+ // If there is no next block, insert a new paragraph
236
+ const [newBlock] = editor.insertBlocks(
237
+ [{ type: "paragraph" }],
238
+ block,
239
+ "after",
240
+ );
241
+ // Move the cursor to the new block
242
+ editor.setTextCursorPosition(newBlock, "start");
243
+
244
+ return true;
245
+ }
246
+
247
+ tr.insertText("\n");
248
+ return true;
249
+ });
250
+ },
251
+ "Shift-Enter": ({ editor }) => {
252
+ return editor.transact(() => {
253
+ const { block } = editor.getTextCursorPosition();
254
+ if (block.type !== "codeBlock") {
255
+ return false;
256
+ }
257
+
258
+ const [newBlock] = editor.insertBlocks(
259
+ // insert a new paragraph
260
+ [{ type: "paragraph" }],
261
+ block,
262
+ "after",
263
+ );
264
+ // move the cursor to the new block
265
+ editor.setTextCursorPosition(newBlock, "start");
266
+ return true;
267
+ });
268
+ },
269
+ },
270
+ inputRules: [
271
+ {
272
+ find: /^```(.*?)\s$/,
273
+ replace: ({ match }) => {
274
+ const languageName = match[1].trim();
275
+ const attributes = {
276
+ language: getLanguageId(options, languageName) ?? languageName,
277
+ };
278
+
279
+ return {
280
+ type: "codeBlock",
281
+ props: {
282
+ language: attributes.language,
283
+ },
284
+ content: [],
285
+ };
286
+ },
287
+ },
288
+ ],
289
+ }),
290
+ ];
291
+ },
292
+ );
293
+
294
+ export function getLanguageId(
295
+ options: CodeBlockOptions,
296
+ languageName: string,
297
+ ): string | undefined {
298
+ return Object.entries(options.supportedLanguages ?? {}).find(
299
+ ([id, { aliases }]) => {
300
+ return aliases?.includes(languageName) || id === languageName;
301
+ },
302
+ )?.[0];
303
+ }
@@ -0,0 +1,73 @@
1
+ import type { HighlighterGeneric } from "@shikijs/types";
2
+ import { Parser, createHighlightPlugin } from "prosemirror-highlight";
3
+ import { createParser } from "prosemirror-highlight/shiki";
4
+ import { CodeBlockOptions, getLanguageId } from "./block.js";
5
+
6
+ export const shikiParserSymbol = Symbol.for("blocknote.shikiParser");
7
+ export const shikiHighlighterPromiseSymbol = Symbol.for(
8
+ "blocknote.shikiHighlighterPromise",
9
+ );
10
+
11
+ export function lazyShikiPlugin(options: CodeBlockOptions) {
12
+ const globalThisForShiki = globalThis as {
13
+ [shikiHighlighterPromiseSymbol]?: Promise<HighlighterGeneric<any, any>>;
14
+ [shikiParserSymbol]?: Parser;
15
+ };
16
+
17
+ let highlighter: HighlighterGeneric<any, any> | undefined;
18
+ let parser: Parser | undefined;
19
+ let hasWarned = false;
20
+ const lazyParser: Parser = (parserOptions) => {
21
+ if (!options.createHighlighter) {
22
+ if (process.env.NODE_ENV === "development" && !hasWarned) {
23
+ // eslint-disable-next-line no-console
24
+ console.log(
25
+ "For syntax highlighting of code blocks, you must provide a `createCodeBlockSpec({ createHighlighter: () => ... })` function",
26
+ );
27
+ hasWarned = true;
28
+ }
29
+ return [];
30
+ }
31
+ if (!highlighter) {
32
+ globalThisForShiki[shikiHighlighterPromiseSymbol] =
33
+ globalThisForShiki[shikiHighlighterPromiseSymbol] ||
34
+ options.createHighlighter();
35
+
36
+ return globalThisForShiki[shikiHighlighterPromiseSymbol].then(
37
+ (createdHighlighter) => {
38
+ highlighter = createdHighlighter;
39
+ },
40
+ );
41
+ }
42
+ const language = getLanguageId(options, parserOptions.language!);
43
+
44
+ if (
45
+ !language ||
46
+ language === "text" ||
47
+ language === "none" ||
48
+ language === "plaintext" ||
49
+ language === "txt"
50
+ ) {
51
+ return [];
52
+ }
53
+
54
+ if (!highlighter.getLoadedLanguages().includes(language)) {
55
+ return highlighter.loadLanguage(language);
56
+ }
57
+
58
+ if (!parser) {
59
+ parser =
60
+ globalThisForShiki[shikiParserSymbol] ||
61
+ createParser(highlighter as any);
62
+ globalThisForShiki[shikiParserSymbol] = parser;
63
+ }
64
+
65
+ return parser(parserOptions);
66
+ };
67
+
68
+ return createHighlightPlugin({
69
+ parser: lazyParser,
70
+ languageExtractor: (node) => node.attrs.language,
71
+ nodeTypes: ["codeBlock"],
72
+ });
73
+ }
@@ -0,0 +1,98 @@
1
+ import { createBlockConfig, createBlockSpec } from "../../schema/index.js";
2
+ import { defaultProps, parseDefaultProps } from "../defaultProps.js";
3
+ import { parseEmbedElement } from "./helpers/parse/parseEmbedElement.js";
4
+ import { parseFigureElement } from "./helpers/parse/parseFigureElement.js";
5
+ import { createFileBlockWrapper } from "./helpers/render/createFileBlockWrapper.js";
6
+ import { createLinkWithCaption } from "./helpers/toExternalHTML/createLinkWithCaption.js";
7
+
8
+ export type FileBlockConfig = ReturnType<typeof createFileBlockConfig>;
9
+
10
+ export const createFileBlockConfig = createBlockConfig(
11
+ () =>
12
+ ({
13
+ type: "file" as const,
14
+ propSchema: {
15
+ backgroundColor: defaultProps.backgroundColor,
16
+ // File name.
17
+ name: {
18
+ default: "" as const,
19
+ },
20
+ // File url.
21
+ url: {
22
+ default: "" as const,
23
+ },
24
+ // File caption.
25
+ caption: {
26
+ default: "" as const,
27
+ },
28
+ },
29
+ content: "none" as const,
30
+ }) as const,
31
+ );
32
+
33
+ export const fileParse = () => (element: HTMLElement) => {
34
+ if (element.tagName === "EMBED") {
35
+ // Ignore if parent figure has already been parsed.
36
+ if (element.closest("figure")) {
37
+ return undefined;
38
+ }
39
+
40
+ const { backgroundColor } = parseDefaultProps(element);
41
+
42
+ return {
43
+ ...parseEmbedElement(element as HTMLEmbedElement),
44
+ backgroundColor,
45
+ };
46
+ }
47
+
48
+ if (element.tagName === "FIGURE") {
49
+ const parsedFigure = parseFigureElement(element, "embed");
50
+ if (!parsedFigure) {
51
+ return undefined;
52
+ }
53
+
54
+ const { targetElement, caption } = parsedFigure;
55
+
56
+ const { backgroundColor } = parseDefaultProps(element);
57
+
58
+ return {
59
+ ...parseEmbedElement(targetElement as HTMLEmbedElement),
60
+ backgroundColor,
61
+ caption,
62
+ };
63
+ }
64
+
65
+ return undefined;
66
+ };
67
+
68
+ export const createFileBlockSpec = createBlockSpec(createFileBlockConfig, {
69
+ meta: {
70
+ fileBlockAccept: ["*/*"],
71
+ },
72
+ parse: fileParse(),
73
+ render(block, editor) {
74
+ return createFileBlockWrapper(block, editor);
75
+ },
76
+ toExternalHTML(block) {
77
+ if (!block.props.url) {
78
+ const div = document.createElement("p");
79
+ div.textContent = "Add file";
80
+
81
+ return {
82
+ dom: div,
83
+ };
84
+ }
85
+
86
+ const fileSrcLink = document.createElement("a");
87
+ fileSrcLink.href = block.props.url;
88
+ fileSrcLink.textContent = block.props.name || block.props.url;
89
+
90
+ if (block.props.caption) {
91
+ return createLinkWithCaption(fileSrcLink, block.props.caption);
92
+ }
93
+
94
+ return {
95
+ dom: fileSrcLink,
96
+ };
97
+ },
98
+ });
@@ -1,10 +1,12 @@
1
1
  import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
2
- import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
2
+ import {
3
+ BlockConfig,
4
+ BlockFromConfigNoChildren,
5
+ } from "../../../../schema/index.js";
3
6
 
4
7
  export const createAddFileButton = (
5
- block: BlockFromConfig<FileBlockConfig, any, any>,
8
+ block: BlockFromConfigNoChildren<BlockConfig<string, any, "none">, any, any>,
6
9
  editor: BlockNoteEditor<any, any, any>,
7
- buttonText?: string,
8
10
  buttonIcon?: HTMLElement,
9
11
  ) => {
10
12
  const addFileButton = document.createElement("div");
@@ -23,7 +25,9 @@ export const createAddFileButton = (
23
25
  const addFileButtonText = document.createElement("p");
24
26
  addFileButtonText.className = "bn-add-file-button-text";
25
27
  addFileButtonText.innerHTML =
26
- buttonText || editor.dictionary.file_blocks.file.add_button_text;
28
+ block.type in editor.dictionary.file_blocks.add_button_text
29
+ ? editor.dictionary.file_blocks.add_button_text[block.type]
30
+ : editor.dictionary.file_blocks.add_button_text["file"];
27
31
  addFileButton.appendChild(addFileButtonText);
28
32
 
29
33
  // Prevents focus from moving to the button.
@@ -1,21 +1,29 @@
1
1
  import type { BlockNoteEditor } from "../../../../editor/BlockNoteEditor.js";
2
2
  import {
3
- BlockFromConfig,
4
- BlockSchemaWithBlock,
5
- FileBlockConfig,
3
+ BlockConfig,
4
+ BlockFromConfigNoChildren,
6
5
  } from "../../../../schema/index.js";
7
6
  import { createAddFileButton } from "./createAddFileButton.js";
8
7
  import { createFileNameWithIcon } from "./createFileNameWithIcon.js";
9
8
 
10
9
  export const createFileBlockWrapper = (
11
- block: BlockFromConfig<FileBlockConfig, any, any>,
12
- editor: BlockNoteEditor<
13
- BlockSchemaWithBlock<FileBlockConfig["type"], FileBlockConfig>,
10
+ block: BlockFromConfigNoChildren<
11
+ BlockConfig<
12
+ string,
13
+ {
14
+ backgroundColor: { default: "default" };
15
+ name: { default: "" };
16
+ url: { default: "" };
17
+ caption: { default: "" };
18
+ showPreview?: { default: true };
19
+ },
20
+ "none"
21
+ >,
14
22
  any,
15
23
  any
16
24
  >,
25
+ editor: BlockNoteEditor<any, any, any>,
17
26
  element?: { dom: HTMLElement; destroy?: () => void },
18
- buttonText?: string,
19
27
  buttonIcon?: HTMLElement,
20
28
  ) => {
21
29
  const wrapper = document.createElement("div");
@@ -24,12 +32,7 @@ export const createFileBlockWrapper = (
24
32
  // Show the add file button if the file has not been uploaded yet. Change to
25
33
  // show a loader if a file upload for the block begins.
26
34
  if (block.props.url === "") {
27
- const addFileButton = createAddFileButton(
28
- block,
29
- editor,
30
- buttonText,
31
- buttonIcon,
32
- );
35
+ const addFileButton = createAddFileButton(block, editor, buttonIcon);
33
36
  wrapper.appendChild(addFileButton.dom);
34
37
 
35
38
  const destroyUploadStartHandler = editor.onUploadStart((blockId) => {
@@ -1,9 +1,22 @@
1
- import { BlockFromConfig, FileBlockConfig } from "../../../../schema/index.js";
1
+ import {
2
+ BlockConfig,
3
+ BlockFromConfigNoChildren,
4
+ } from "../../../../schema/index.js";
2
5
 
3
6
  export const FILE_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 8L9.00319 2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8ZM10 4V9H5V20H19V4H10Z"></path></svg>`;
4
7
 
5
8
  export const createFileNameWithIcon = (
6
- block: BlockFromConfig<FileBlockConfig, any, any>,
9
+ block: BlockFromConfigNoChildren<
10
+ BlockConfig<
11
+ string,
12
+ {
13
+ name: { default: "" };
14
+ },
15
+ "none"
16
+ >,
17
+ any,
18
+ any
19
+ >,
7
20
  ): { dom: HTMLElement; destroy?: () => void } => {
8
21
  const file = document.createElement("div");
9
22
  file.className = "bn-file-name-with-icon";