@blocknote/core 0.38.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 (225) 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 +3296 -7187
  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/style.css +1 -1
  14. package/dist/tsconfig.tsbuildinfo +1 -1
  15. package/dist/webpack-stats.json +1 -1
  16. package/package.json +19 -16
  17. package/src/api/blockManipulation/commands/insertBlocks/insertBlocks.ts +1 -1
  18. package/src/api/blockManipulation/commands/replaceBlocks/replaceBlocks.ts +2 -2
  19. package/src/api/blockManipulation/commands/splitBlock/splitBlock.ts +34 -25
  20. package/src/api/blockManipulation/setupTestEnv.ts +0 -1
  21. package/src/api/clipboard/fromClipboard/handleFileInsertion.ts +4 -8
  22. package/src/api/clipboard/toClipboard/copyExtension.ts +1 -1
  23. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +128 -28
  24. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +101 -41
  25. package/src/api/pmUtil.ts +1 -1
  26. package/src/api/positionMapping.test.ts +58 -15
  27. package/src/api/positionMapping.ts +2 -4
  28. package/src/blocks/Audio/block.ts +174 -0
  29. package/src/blocks/BlockNoteSchema.ts +59 -0
  30. package/src/blocks/Code/block.ts +303 -0
  31. package/src/blocks/Code/shiki.ts +73 -0
  32. package/src/blocks/File/block.ts +98 -0
  33. package/src/blocks/{FileBlockContent → File}/helpers/render/createAddFileButton.ts +5 -2
  34. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileBlockWrapper.ts +15 -6
  35. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.ts +15 -2
  36. package/src/blocks/{FileBlockContent → File}/helpers/render/createResizableFileBlockWrapper.ts +21 -2
  37. package/src/blocks/Heading/block.ts +138 -0
  38. package/src/blocks/Image/block.ts +190 -0
  39. package/src/blocks/ListItem/BulletListItem/block.ts +116 -0
  40. package/src/blocks/ListItem/CheckListItem/block.ts +175 -0
  41. package/src/blocks/ListItem/NumberedListItem/IndexingPlugin.ts +173 -0
  42. package/src/blocks/ListItem/NumberedListItem/block.ts +133 -0
  43. package/src/blocks/ListItem/ToggleListItem/block.ts +78 -0
  44. package/src/blocks/PageBreak/block.ts +72 -0
  45. package/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.ts +9 -7
  46. package/src/blocks/Paragraph/block.ts +80 -0
  47. package/src/blocks/Quote/block.ts +90 -0
  48. package/src/blocks/{TableBlockContent/TableBlockContent.ts → Table/block.ts} +169 -51
  49. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +1 -1
  50. package/src/blocks/Video/block.ts +143 -0
  51. package/src/blocks/defaultBlockHelpers.ts +2 -2
  52. package/src/blocks/defaultBlockTypeGuards.ts +143 -174
  53. package/src/blocks/defaultBlocks.ts +107 -35
  54. package/src/blocks/defaultProps.ts +145 -4
  55. package/src/blocks/index.ts +26 -0
  56. package/src/blocks/utils/listItemEnterHandler.ts +42 -0
  57. package/src/editor/Block.css +54 -18
  58. package/src/editor/BlockNoteEditor.ts +251 -210
  59. package/src/editor/BlockNoteExtension.ts +92 -0
  60. package/src/editor/BlockNoteExtensions.ts +18 -17
  61. package/src/editor/defaultColors.ts +2 -2
  62. package/src/exporter/Exporter.ts +1 -1
  63. package/src/exporter/mapping.ts +1 -1
  64. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +3 -20
  65. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +6 -8
  66. package/src/extensions/BlockChange/BlockChangePlugin.ts +2 -1
  67. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +2 -2
  68. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +2 -2
  69. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -1
  70. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -1
  71. package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +52 -0
  72. package/src/extensions/Collaboration/schemaMigration/migrationRules/index.ts +4 -0
  73. package/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.ts +4 -0
  74. package/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts +78 -0
  75. package/src/extensions/Comments/CommentsPlugin.ts +1 -1
  76. package/src/extensions/FilePanel/FilePanelPlugin.ts +5 -10
  77. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +1 -1
  78. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +4 -3
  79. package/src/extensions/Placeholder/PlaceholderPlugin.ts +2 -2
  80. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +1 -23
  81. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +0 -5
  82. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +6 -2
  83. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +24 -17
  84. package/src/extensions/TableHandles/TableHandlesPlugin.ts +2 -2
  85. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +5 -11
  86. package/src/extensions/TextColor/TextColorExtension.ts +3 -17
  87. package/src/extensions/TextColor/TextColorMark.ts +4 -9
  88. package/src/extensions/UniqueID/UniqueID.ts +6 -13
  89. package/src/index.ts +2 -28
  90. package/src/schema/blocks/createSpec.ts +342 -169
  91. package/src/schema/blocks/internal.ts +77 -138
  92. package/src/schema/blocks/types.ts +264 -94
  93. package/src/schema/index.ts +1 -0
  94. package/src/schema/inlineContent/createSpec.ts +99 -21
  95. package/src/schema/inlineContent/internal.ts +16 -7
  96. package/src/schema/inlineContent/types.ts +24 -2
  97. package/src/schema/propTypes.ts +15 -9
  98. package/src/schema/schema.ts +209 -0
  99. package/src/schema/styles/createSpec.ts +79 -31
  100. package/src/schema/styles/internal.ts +61 -2
  101. package/src/schema/styles/types.ts +17 -3
  102. package/src/util/topo-sort.test.ts +125 -0
  103. package/src/util/topo-sort.ts +160 -0
  104. package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.d.ts +2 -1
  105. package/types/src/api/blockManipulation/selections/selection.d.ts +1 -1
  106. package/types/src/api/blockManipulation/setupTestEnv.d.ts +29 -543
  107. package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +1 -1
  108. package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
  109. package/types/src/api/pmUtil.d.ts +1 -1
  110. package/types/src/blocks/Audio/block.d.ts +58 -0
  111. package/types/src/blocks/BlockNoteSchema.d.ts +18 -0
  112. package/types/src/blocks/{CodeBlockContent/CodeBlockContent.d.ts → Code/block.d.ts} +25 -26
  113. package/types/src/blocks/Code/shiki.d.ts +4 -0
  114. package/types/src/blocks/File/block.d.ts +37 -0
  115. package/types/src/blocks/File/helpers/render/createAddFileButton.d.ts +6 -0
  116. package/types/src/blocks/File/helpers/render/createFileBlockWrapper.d.ts +25 -0
  117. package/types/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.d.ts +6 -2
  118. package/types/src/blocks/File/helpers/render/createResizableFileBlockWrapper.d.ts +31 -0
  119. package/types/src/blocks/Heading/block.d.ts +71 -0
  120. package/types/src/blocks/Image/block.d.ts +102 -0
  121. package/types/src/blocks/ListItem/BulletListItem/block.d.ts +25 -0
  122. package/types/src/blocks/ListItem/CheckListItem/block.d.ts +33 -0
  123. package/types/src/blocks/ListItem/NumberedListItem/IndexingPlugin.d.ts +8 -0
  124. package/types/src/blocks/ListItem/NumberedListItem/block.d.ts +33 -0
  125. package/types/src/blocks/ListItem/ToggleListItem/block.d.ts +25 -0
  126. package/types/src/blocks/PageBreak/block.d.ts +11 -0
  127. package/types/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.d.ts +4 -2
  128. package/types/src/blocks/Paragraph/block.d.ts +25 -0
  129. package/types/src/blocks/Quote/block.d.ts +17 -0
  130. package/types/src/blocks/Table/block.d.ts +21 -0
  131. package/types/src/blocks/Video/block.d.ts +67 -0
  132. package/types/src/blocks/defaultBlockHelpers.d.ts +1 -1
  133. package/types/src/blocks/defaultBlockTypeGuards.d.ts +15 -36
  134. package/types/src/blocks/defaultBlocks.d.ts +221 -1060
  135. package/types/src/blocks/defaultProps.d.ts +17 -1
  136. package/types/src/blocks/index.d.ts +24 -0
  137. package/types/src/blocks/utils/listItemEnterHandler.d.ts +2 -0
  138. package/types/src/editor/BlockNoteEditor.d.ts +33 -66
  139. package/types/src/editor/BlockNoteExtension.d.ts +67 -0
  140. package/types/src/editor/BlockNoteExtensions.d.ts +1 -1
  141. package/types/src/editor/defaultColors.d.ts +8 -76
  142. package/types/src/exporter/Exporter.d.ts +1 -1
  143. package/types/src/exporter/mapping.d.ts +1 -1
  144. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +4 -1
  145. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +7 -0
  146. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/index.d.ts +3 -0
  147. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.d.ts +3 -0
  148. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.d.ts +2 -0
  149. package/types/src/extensions/Comments/CommentsPlugin.d.ts +1 -1
  150. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +4 -4
  151. package/types/src/extensions/TextColor/TextColorMark.d.ts +4 -1
  152. package/types/src/index.d.ts +2 -25
  153. package/types/src/schema/blocks/createSpec.d.ts +16 -36
  154. package/types/src/schema/blocks/internal.d.ts +11 -33
  155. package/types/src/schema/blocks/types.d.ts +181 -57
  156. package/types/src/schema/index.d.ts +1 -0
  157. package/types/src/schema/inlineContent/createSpec.d.ts +36 -2
  158. package/types/src/schema/inlineContent/internal.d.ts +7 -15
  159. package/types/src/schema/inlineContent/types.d.ts +15 -1
  160. package/types/src/schema/propTypes.d.ts +4 -4
  161. package/types/src/schema/schema.d.ts +40 -0
  162. package/types/src/schema/styles/createSpec.d.ts +6 -4
  163. package/types/src/schema/styles/internal.d.ts +6 -3
  164. package/types/src/schema/styles/types.d.ts +11 -2
  165. package/types/src/util/topo-sort.d.ts +18 -0
  166. package/types/src/util/topo-sort.test.d.ts +1 -0
  167. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +0 -144
  168. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +0 -445
  169. package/src/blocks/FileBlockContent/FileBlockContent.ts +0 -100
  170. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +0 -159
  171. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +0 -159
  172. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +0 -134
  173. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +0 -299
  174. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +0 -86
  175. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +0 -172
  176. package/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.ts +0 -104
  177. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +0 -49
  178. package/src/blocks/PageBreakBlockContent/schema.ts +0 -40
  179. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +0 -78
  180. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +0 -121
  181. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -158
  182. package/src/editor/BlockNoteSchema.ts +0 -107
  183. package/src/editor/BlockNoteTipTapEditor.ts +0 -335
  184. package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +0 -99
  185. package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +0 -90
  186. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +0 -6
  187. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +0 -9
  188. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +0 -9
  189. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +0 -67
  190. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +0 -131
  191. package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +0 -46
  192. package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +0 -55
  193. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +0 -2
  194. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +0 -58
  195. package/types/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.d.ts +0 -46
  196. package/types/src/blocks/PageBreakBlockContent/PageBreakBlockContent.d.ts +0 -31
  197. package/types/src/blocks/PageBreakBlockContent/schema.d.ts +0 -86
  198. package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +0 -52
  199. package/types/src/blocks/QuoteBlockContent/QuoteBlockContent.d.ts +0 -52
  200. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +0 -39
  201. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +0 -131
  202. package/types/src/editor/BlockNoteSchema.d.ts +0 -34
  203. package/types/src/editor/BlockNoteTipTapEditor.d.ts +0 -43
  204. /package/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.ts +0 -0
  205. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.ts +0 -0
  206. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.ts +0 -0
  207. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.ts +0 -0
  208. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.ts +0 -0
  209. /package/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
  210. /package/src/blocks/{ImageBlockContent → Image}/parseImageElement.ts +0 -0
  211. /package/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.ts +0 -0
  212. /package/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.ts +0 -0
  213. /package/src/blocks/{TableBlockContent → Table}/TableExtension.ts +0 -0
  214. /package/src/blocks/{VideoBlockContent → Video}/parseVideoElement.ts +0 -0
  215. /package/types/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.d.ts +0 -0
  216. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.d.ts +0 -0
  217. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.d.ts +0 -0
  218. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.d.ts +0 -0
  219. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.d.ts +0 -0
  220. /package/types/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +0 -0
  221. /package/types/src/blocks/{ImageBlockContent → Image}/parseImageElement.d.ts +0 -0
  222. /package/types/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.d.ts +0 -0
  223. /package/types/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.d.ts +0 -0
  224. /package/types/src/blocks/{TableBlockContent → Table}/TableExtension.d.ts +0 -0
  225. /package/types/src/blocks/{VideoBlockContent → Video}/parseVideoElement.d.ts +0 -0
@@ -1,6 +1,15 @@
1
1
  import { Plugin } from "prosemirror-state";
2
2
  import { EventEmitter } from "../util/EventEmitter.js";
3
3
 
4
+ import { AnyExtension } from "@tiptap/core";
5
+ import {
6
+ BlockSchema,
7
+ InlineContentSchema,
8
+ PartialBlockNoDefaults,
9
+ StyleSchema,
10
+ } from "../schema/index.js";
11
+ import { BlockNoteEditor } from "./BlockNoteEditor.js";
12
+
4
13
  export abstract class BlockNoteExtension<
5
14
  TEvent extends Record<string, any> = any,
6
15
  > extends EventEmitter<TEvent> {
@@ -23,4 +32,87 @@ export abstract class BlockNoteExtension<
23
32
  // Allow subclasses to have constructors with parameters
24
33
  // without this, we can't easily implement BlockNoteEditor.extension(MyExtension) pattern
25
34
  }
35
+
36
+ /**
37
+ * Input rules for the block
38
+ */
39
+ public inputRules?: InputRule[];
40
+
41
+ /**
42
+ * A mapping of a keyboard shortcut to a function that will be called when the shortcut is pressed
43
+ *
44
+ * The keys are in the format:
45
+ * - Key names may be strings like `Shift-Ctrl-Enter`—a key identifier prefixed with zero or more modifiers
46
+ * - Key identifiers are based on the strings that can appear in KeyEvent.key
47
+ * - Use lowercase letters to refer to letter keys (or uppercase letters if you want shift to be held)
48
+ * - You may use `Space` as an alias for the " " name
49
+ * - Modifiers can be given in any order: `Shift-` (or `s-`), `Alt-` (or `a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or `Meta-`)
50
+ * - For characters that are created by holding shift, the Shift- prefix is implied, and should not be added explicitly
51
+ * - You can use Mod- as a shorthand for Cmd- on Mac and Ctrl- on other platforms
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * keyboardShortcuts: {
56
+ * "Mod-Enter": (ctx) => { return true; },
57
+ * "Shift-Ctrl-Space": (ctx) => { return true; },
58
+ * "a": (ctx) => { return true; },
59
+ * "Space": (ctx) => { return true; }
60
+ * }
61
+ * ```
62
+ */
63
+ public keyboardShortcuts?: Record<
64
+ string,
65
+ (ctx: {
66
+ editor: BlockNoteEditor<BlockSchema, InlineContentSchema, StyleSchema>;
67
+ }) => boolean
68
+ >;
69
+
70
+ public tiptapExtensions?: AnyExtension[];
71
+ }
72
+
73
+ export type InputRule = {
74
+ /**
75
+ * The regex to match when to trigger the input rule
76
+ */
77
+ find: RegExp;
78
+ /**
79
+ * The function to call when the input rule is matched
80
+ * @returns undefined if the input rule should not be triggered, or an object with the type and props to update the block
81
+ */
82
+ replace: (props: {
83
+ /**
84
+ * The result of the regex match
85
+ */
86
+ match: RegExpMatchArray;
87
+ // TODO this will be a Point, when we have the Location API
88
+ /**
89
+ * The range of the text that was matched
90
+ */
91
+ range: { from: number; to: number };
92
+ /**
93
+ * The editor instance
94
+ */
95
+ editor: BlockNoteEditor<any, any, any>;
96
+ }) => undefined | PartialBlockNoDefaults<any, any, any>;
97
+ };
98
+
99
+ /**
100
+ * This creates an instance of a BlockNoteExtension that can be used to add to a schema.
101
+ * It is a bit of a hack, but it works.
102
+ */
103
+ export function createBlockNoteExtension(
104
+ options: Partial<
105
+ Pick<
106
+ BlockNoteExtension,
107
+ "inputRules" | "keyboardShortcuts" | "plugins" | "tiptapExtensions"
108
+ >
109
+ > & { key: string },
110
+ ) {
111
+ const x = Object.create(BlockNoteExtension.prototype);
112
+ x.key = options.key;
113
+ x.inputRules = options.inputRules;
114
+ x.keyboardShortcuts = options.keyboardShortcuts;
115
+ x.plugins = options.plugins ?? [];
116
+ x.tiptapExtensions = options.tiptapExtensions;
117
+ return x as BlockNoteExtension;
26
118
  }
@@ -1,4 +1,4 @@
1
- import { AnyExtension, Extension, extensions } from "@tiptap/core";
1
+ import { AnyExtension, Extension, extensions, Node } from "@tiptap/core";
2
2
  import { Gapcursor } from "@tiptap/extension-gapcursor";
3
3
  import { History } from "@tiptap/extension-history";
4
4
  import { Link } from "@tiptap/extension-link";
@@ -13,8 +13,10 @@ import type { ThreadStore } from "../comments/index.js";
13
13
  import { BackgroundColorExtension } from "../extensions/BackgroundColor/BackgroundColorExtension.js";
14
14
  import { BlockChangePlugin } from "../extensions/BlockChange/BlockChangePlugin.js";
15
15
  import { CursorPlugin } from "../extensions/Collaboration/CursorPlugin.js";
16
+ import { ForkYDocPlugin } from "../extensions/Collaboration/ForkYDocPlugin.js";
16
17
  import { SyncPlugin } from "../extensions/Collaboration/SyncPlugin.js";
17
18
  import { UndoPlugin } from "../extensions/Collaboration/UndoPlugin.js";
19
+ import { SchemaMigrationPlugin } from "../extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.js";
18
20
  import { CommentMark } from "../extensions/Comments/CommentMark.js";
19
21
  import { CommentsPlugin } from "../extensions/Comments/CommentsPlugin.js";
20
22
  import { FilePanelProsemirrorPlugin } from "../extensions/FilePanel/FilePanelPlugin.js";
@@ -57,8 +59,7 @@ import type {
57
59
  BlockNoteEditorOptions,
58
60
  SupportedExtension,
59
61
  } from "./BlockNoteEditor.js";
60
- import { BlockNoteSchema } from "./BlockNoteSchema.js";
61
- import { ForkYDocPlugin } from "../extensions/Collaboration/ForkYDocPlugin.js";
62
+ import { BlockNoteSchema } from "../blocks/BlockNoteSchema.js";
62
63
 
63
64
  type ExtensionOptions<
64
65
  BSchema extends BlockSchema,
@@ -127,6 +128,9 @@ export const getBlockNoteExtensions = <
127
128
  editor: opts.editor,
128
129
  collaboration: opts.collaboration,
129
130
  });
131
+ ret["schemaMigrationPlugin"] = new SchemaMigrationPlugin(
132
+ opts.collaboration.fragment,
133
+ );
130
134
  }
131
135
 
132
136
  // Note: this is pretty hardcoded and will break when user provides plugins with same keys.
@@ -226,11 +230,11 @@ const getTipTapExtensions = <
226
230
  // only call this once if we have multiple editors installed. Or fix https://github.com/ueberdosis/tiptap/issues/5450
227
231
  protocols: LINKIFY_INITIALIZED ? [] : VALID_LINK_PROTOCOLS,
228
232
  }),
229
- ...Object.values(opts.styleSpecs).map((styleSpec) => {
233
+ ...(Object.values(opts.styleSpecs).map((styleSpec) => {
230
234
  return styleSpec.implementation.mark.configure({
231
235
  editor: opts.editor as any,
232
236
  });
233
- }),
237
+ }) as any[]),
234
238
 
235
239
  TextColorExtension,
236
240
 
@@ -276,18 +280,15 @@ const getTipTapExtensions = <
276
280
 
277
281
  ...Object.values(opts.blockSpecs).flatMap((blockSpec) => {
278
282
  return [
279
- // dependent nodes (e.g.: tablecell / row)
280
- ...(blockSpec.implementation.requiredExtensions || []).map((ext) =>
281
- ext.configure({
282
- editor: opts.editor,
283
- domAttributes: opts.domAttributes,
284
- }),
285
- ),
286
- // the actual node itself
287
- blockSpec.implementation.node.configure({
288
- editor: opts.editor,
289
- domAttributes: opts.domAttributes,
290
- }),
283
+ // the node extension implementations
284
+ ...("node" in blockSpec.implementation
285
+ ? [
286
+ (blockSpec.implementation.node as Node).configure({
287
+ editor: opts.editor,
288
+ domAttributes: opts.domAttributes,
289
+ }),
290
+ ]
291
+ : []),
291
292
  ];
292
293
  }),
293
294
  createCopyToClipboardExtension(opts.editor),
@@ -35,7 +35,7 @@ export const COLORS_DEFAULT = {
35
35
  text: "#ad1a72",
36
36
  background: "#f4dfeb",
37
37
  },
38
- };
38
+ } as Record<string, { text: string; background: string }>;
39
39
 
40
40
  export const COLORS_DARK_MODE_DEFAULT = {
41
41
  gray: {
@@ -74,4 +74,4 @@ export const COLORS_DARK_MODE_DEFAULT = {
74
74
  text: "#da208f",
75
75
  background: "#ad1a72",
76
76
  },
77
- };
77
+ } as Record<string, { text: string; background: string }>;
@@ -1,4 +1,4 @@
1
- import { BlockNoteSchema } from "../editor/BlockNoteSchema.js";
1
+ import { BlockNoteSchema } from "../blocks/BlockNoteSchema.js";
2
2
  import { COLORS_DEFAULT } from "../editor/defaultColors.js";
3
3
  import {
4
4
  BlockFromConfig,
@@ -1,4 +1,4 @@
1
- import { BlockNoteSchema } from "../editor/BlockNoteSchema.js";
1
+ import { BlockNoteSchema } from "../blocks/BlockNoteSchema.js";
2
2
  import {
3
3
  BlockFromConfigNoChildren,
4
4
  BlockSchema,
@@ -1,5 +1,5 @@
1
1
  import { Extension } from "@tiptap/core";
2
- import { defaultProps } from "../../blocks/defaultProps.js";
2
+ import { getBackgroundColorAttribute } from "../../blocks/defaultProps.js";
3
3
 
4
4
  export const BackgroundColorExtension = Extension.create({
5
5
  name: "blockBackgroundColor",
@@ -7,26 +7,9 @@ export const BackgroundColorExtension = Extension.create({
7
7
  addGlobalAttributes() {
8
8
  return [
9
9
  {
10
- types: ["blockContainer", "tableCell", "tableHeader"],
10
+ types: ["tableCell", "tableHeader"],
11
11
  attributes: {
12
- backgroundColor: {
13
- default: defaultProps.backgroundColor.default,
14
- parseHTML: (element) =>
15
- element.hasAttribute("data-background-color")
16
- ? element.getAttribute("data-background-color")
17
- : defaultProps.backgroundColor.default,
18
- renderHTML: (attributes) => {
19
- if (
20
- attributes.backgroundColor ===
21
- defaultProps.backgroundColor.default
22
- ) {
23
- return {};
24
- }
25
- return {
26
- "data-background-color": attributes.backgroundColor,
27
- };
28
- },
29
- },
12
+ backgroundColor: getBackgroundColorAttribute(),
30
13
  },
31
14
  },
32
15
  ];
@@ -1,18 +1,13 @@
1
1
  import { Mark } from "@tiptap/core";
2
2
  import { createStyleSpecFromTipTapMark } from "../../schema/index.js";
3
+ import { getBackgroundColorAttribute } from "../../blocks/defaultProps.js";
3
4
 
4
5
  const BackgroundColorMark = Mark.create({
5
6
  name: "backgroundColor",
6
7
 
7
8
  addAttributes() {
8
9
  return {
9
- stringValue: {
10
- default: undefined,
11
- parseHTML: (element) => element.getAttribute("data-background-color"),
12
- renderHTML: (attributes) => ({
13
- "data-background-color": attributes.stringValue,
14
- }),
15
- },
10
+ stringValue: getBackgroundColorAttribute("stringValue"),
16
11
  };
17
12
  },
18
13
 
@@ -25,7 +20,10 @@ const BackgroundColorMark = Mark.create({
25
20
  return false;
26
21
  }
27
22
 
28
- if (element.hasAttribute("data-background-color")) {
23
+ if (
24
+ element.hasAttribute("data-background-color") ||
25
+ element.style.backgroundColor
26
+ ) {
29
27
  return {
30
28
  stringValue: element.getAttribute("data-background-color"),
31
29
  };
@@ -1,4 +1,4 @@
1
- import { Plugin, Transaction } from "prosemirror-state";
1
+ import { Plugin, PluginKey, Transaction } from "prosemirror-state";
2
2
  import {
3
3
  BlocksChanged,
4
4
  getBlocksChangedByTransaction,
@@ -23,6 +23,7 @@ export class BlockChangePlugin extends BlockNoteExtension {
23
23
 
24
24
  this.addProsemirrorPlugin(
25
25
  new Plugin({
26
+ key: new PluginKey("blockChange"),
26
27
  filterTransaction: (tr) => {
27
28
  let changes:
28
29
  | ReturnType<typeof getBlocksChangedByTransaction>
@@ -8,7 +8,7 @@
8
8
  "type": "text",
9
9
  },
10
10
  ],
11
- "id": "2",
11
+ "id": "3",
12
12
  "props": {
13
13
  "backgroundColor": "default",
14
14
  "textAlignment": "left",
@@ -19,7 +19,7 @@
19
19
  {
20
20
  "children": [],
21
21
  "content": [],
22
- "id": "3",
22
+ "id": "4",
23
23
  "props": {
24
24
  "backgroundColor": "default",
25
25
  "textAlignment": "left",
@@ -8,7 +8,7 @@
8
8
  "type": "text",
9
9
  },
10
10
  ],
11
- "id": "0",
11
+ "id": "1",
12
12
  "props": {
13
13
  "backgroundColor": "default",
14
14
  "textAlignment": "left",
@@ -19,7 +19,7 @@
19
19
  {
20
20
  "children": [],
21
21
  "content": [],
22
- "id": "1",
22
+ "id": "2",
23
23
  "props": {
24
24
  "backgroundColor": "default",
25
25
  "textAlignment": "left",
@@ -1 +1 @@
1
- <blockgroup><blockcontainer backgroundColor="default" id="2" textColor="default"><paragraph textAlignment="left">Hello World</paragraph></blockcontainer><blockcontainer backgroundColor="default" id="3" textColor="default"><paragraph textAlignment="left"></paragraph></blockcontainer></blockgroup>
1
+ <blockgroup><blockcontainer id="3"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello World</paragraph></blockcontainer><blockcontainer id="4"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>
@@ -1 +1 @@
1
- <blockgroup><blockcontainer backgroundColor="default" id="0" textColor="default"><paragraph textAlignment="left">Hello</paragraph></blockcontainer><blockcontainer backgroundColor="default" id="1" textColor="default"><paragraph textAlignment="left"></paragraph></blockcontainer></blockgroup>
1
+ <blockgroup><blockcontainer id="1"><paragraph backgroundColor="default" textAlignment="left" textColor="default">Hello</paragraph></blockcontainer><blockcontainer id="2"><paragraph backgroundColor="default" textAlignment="left" textColor="default"></paragraph></blockcontainer></blockgroup>
@@ -0,0 +1,52 @@
1
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
2
+ import { ySyncPluginKey } from "y-prosemirror";
3
+ import * as Y from "yjs";
4
+
5
+ import { BlockNoteExtension } from "../../../editor/BlockNoteExtension.js";
6
+ import migrationRules from "./migrationRules/index.js";
7
+
8
+ // This plugin allows us to update collaboration YDocs whenever BlockNote's
9
+ // underlying ProseMirror schema changes. The plugin reads the current Yjs
10
+ // fragment and dispatches additional transactions to the ProseMirror state, in
11
+ // case things are found in the fragment that don't adhere to the editor schema
12
+ // and need to be fixed. These fixes are defined as `MigrationRule`s within the
13
+ // `migrationRules` directory.
14
+ export class SchemaMigrationPlugin extends BlockNoteExtension {
15
+ private migrationDone = false;
16
+
17
+ public static key() {
18
+ return "schemaMigrationPlugin";
19
+ }
20
+
21
+ constructor(fragment: Y.XmlFragment) {
22
+ const pluginKey = new PluginKey(SchemaMigrationPlugin.key());
23
+
24
+ super();
25
+ this.addProsemirrorPlugin(
26
+ new Plugin({
27
+ key: pluginKey,
28
+ appendTransaction: (transactions, _oldState, newState) => {
29
+ if (this.migrationDone) {
30
+ return undefined;
31
+ }
32
+
33
+ if (
34
+ transactions.length !== 1 ||
35
+ !transactions[0].getMeta(ySyncPluginKey)
36
+ ) {
37
+ return undefined;
38
+ }
39
+
40
+ const tr = newState.tr;
41
+ for (const migrationRule of migrationRules) {
42
+ migrationRule(fragment, tr);
43
+ }
44
+
45
+ this.migrationDone = true;
46
+
47
+ return tr;
48
+ },
49
+ }),
50
+ );
51
+ }
52
+ }
@@ -0,0 +1,4 @@
1
+ import { MigrationRule } from "./migrationRule.js";
2
+ import { moveColorAttributes } from "./moveColorAttributes.js";
3
+
4
+ export default [moveColorAttributes] as MigrationRule[];
@@ -0,0 +1,4 @@
1
+ import { Transaction } from "@tiptap/pm/state";
2
+ import * as Y from "yjs";
3
+
4
+ export type MigrationRule = (fragment: Y.XmlFragment, tr: Transaction) => void;
@@ -0,0 +1,78 @@
1
+ import * as Y from "yjs";
2
+
3
+ import { MigrationRule } from "./migrationRule.js";
4
+ import { defaultProps } from "../../../../blocks/defaultProps.js";
5
+
6
+ // Helper function to recursively traverse a `Y.XMLElement` and its descendant
7
+ // elements.
8
+ const traverseElement = (
9
+ rootElement: Y.XmlElement,
10
+ cb: (element: Y.XmlElement) => void,
11
+ ) => {
12
+ cb(rootElement);
13
+ rootElement.forEach((element) => {
14
+ if (element instanceof Y.XmlElement) {
15
+ traverseElement(element, cb);
16
+ }
17
+ });
18
+ };
19
+
20
+ // Moves `textColor` and `backgroundColor` attributes from `blockContainer`
21
+ // nodes to their child `blockContent` nodes. This is due to a schema change
22
+ // introduced in PR #TODO.
23
+ export const moveColorAttributes: MigrationRule = (fragment, tr) => {
24
+ // Stores necessary info for all `blockContainer` nodes which still have
25
+ // `textColor` or `backgroundColor` attributes that need to be moved.
26
+ const targetBlockContainers: Record<
27
+ string,
28
+ {
29
+ textColor?: string;
30
+ backgroundColor?: string;
31
+ }
32
+ > = {};
33
+
34
+ // Finds all elements which still have `textColor` or `backgroundColor`
35
+ // attributes in the current Yjs fragment.
36
+ fragment.forEach((element) => {
37
+ if (element instanceof Y.XmlElement) {
38
+ traverseElement(element, (element) => {
39
+ if (
40
+ element.nodeName === "blockContainer" &&
41
+ element.hasAttribute("id")
42
+ ) {
43
+ const colors = {
44
+ textColor: element.getAttribute("textColor"),
45
+ backgroundColor: element.getAttribute("backgroundColor"),
46
+ };
47
+
48
+ if (colors.textColor === defaultProps.textColor.default) {
49
+ colors.textColor = undefined;
50
+ }
51
+ if (colors.backgroundColor === defaultProps.backgroundColor.default) {
52
+ colors.backgroundColor = undefined;
53
+ }
54
+
55
+ if (colors.textColor || colors.backgroundColor) {
56
+ targetBlockContainers[element.getAttribute("id")!] = colors;
57
+ }
58
+ }
59
+ });
60
+ }
61
+ });
62
+
63
+ // Appends transactions to add the `textColor` and `backgroundColor`
64
+ // attributes found on each `blockContainer` node to move them to the child
65
+ // `blockContent` node.
66
+ tr.doc.descendants((node, pos) => {
67
+ if (
68
+ node.type.name === "blockContainer" &&
69
+ targetBlockContainers[node.attrs.id]
70
+ ) {
71
+ tr = tr.setNodeMarkup(
72
+ pos + 1,
73
+ undefined,
74
+ targetBlockContainers[node.attrs.id],
75
+ );
76
+ }
77
+ });
78
+ };
@@ -10,7 +10,7 @@ import type {
10
10
  } from "../../comments/index.js";
11
11
  import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
12
12
  import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
13
- import { BlockNoteSchema } from "../../editor/BlockNoteSchema.js";
13
+ import { BlockNoteSchema } from "../../blocks/BlockNoteSchema.js";
14
14
  import { UserStore } from "./userstore/UserStore.js";
15
15
 
16
16
  const PLUGIN_KEY = new PluginKey(`blocknote-comments`);
@@ -7,7 +7,6 @@ import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
7
7
  import { UiElementPosition } from "../../extensions-shared/UiElementPosition.js";
8
8
  import type {
9
9
  BlockFromConfig,
10
- FileBlockConfig,
11
10
  InlineContentSchema,
12
11
  StyleSchema,
13
12
  } from "../../schema/index.js";
@@ -17,7 +16,7 @@ export type FilePanelState<
17
16
  S extends StyleSchema,
18
17
  > = UiElementPosition & {
19
18
  // TODO: This typing is not quite right (children should be from BSchema)
20
- block: BlockFromConfig<FileBlockConfig, I, S>;
19
+ block: BlockFromConfig<any, I, S>;
21
20
  };
22
21
 
23
22
  export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
@@ -27,11 +26,7 @@ export class FilePanelView<I extends InlineContentSchema, S extends StyleSchema>
27
26
  public emitUpdate: () => void;
28
27
 
29
28
  constructor(
30
- private readonly editor: BlockNoteEditor<
31
- Record<string, FileBlockConfig>,
32
- I,
33
- S
34
- >,
29
+ private readonly editor: BlockNoteEditor<Record<string, any>, I, S>,
35
30
  private readonly pluginKey: PluginKey<FilePanelState<I, S>>,
36
31
  private readonly pmView: EditorView,
37
32
  emitUpdate: (state: FilePanelState<I, S>) => void,
@@ -145,17 +140,17 @@ export class FilePanelProsemirrorPlugin<
145
140
 
146
141
  private view: FilePanelView<I, S> | undefined;
147
142
 
148
- constructor(editor: BlockNoteEditor<Record<string, FileBlockConfig>, I, S>) {
143
+ constructor(editor: BlockNoteEditor<Record<string, any>, I, S>) {
149
144
  super();
150
145
  this.addProsemirrorPlugin(
151
146
  new Plugin<{
152
- block: BlockFromConfig<FileBlockConfig, I, S> | undefined;
147
+ block: BlockFromConfig<any, I, S> | undefined;
153
148
  }>({
154
149
  key: filePanelPluginKey,
155
150
  view: (editorView) => {
156
151
  this.view = new FilePanelView<I, S>(
157
152
  editor,
158
- filePanelPluginKey,
153
+ filePanelPluginKey as any,
159
154
  editorView,
160
155
  (state) => {
161
156
  this.emit("update", state);
@@ -127,7 +127,7 @@ export class FormattingToolbarView implements PluginView {
127
127
  if (!element) {
128
128
  return false;
129
129
  }
130
- const editorWrapper = this.pmView.dom.parentElement;
130
+ const editorWrapper = this.pmView.dom.parentElement!;
131
131
  if (!editorWrapper) {
132
132
  return false;
133
133
  }
@@ -470,9 +470,10 @@ export const KeyboardShortcutsExtension = Extension.create<{
470
470
  commands.command(({ state }) => {
471
471
  const blockInfo = getBlockInfoFromSelection(state);
472
472
 
473
- const blockHardBreakShortcut: "shift+enter" | "enter" | "none" =
474
- this.options.editor.schema.blockSchema[blockInfo.blockNoteType]
475
- .hardBreakShortcut ?? "shift+enter";
473
+ const blockHardBreakShortcut =
474
+ this.options.editor.schema.blockSchema[
475
+ blockInfo.blockNoteType as keyof typeof this.options.editor.schema.blockSchema
476
+ ].meta?.hardBreakShortcut ?? "shift+enter";
476
477
 
477
478
  if (blockHardBreakShortcut === "none") {
478
479
  return false;
@@ -32,7 +32,7 @@ export class PlaceholderPlugin extends BlockNoteExtension {
32
32
  styleEl.setAttribute("nonce", nonce);
33
33
  }
34
34
 
35
- if (editor.prosemirrorView?.root instanceof ShadowRoot) {
35
+ if (editor.prosemirrorView?.root instanceof window.ShadowRoot) {
36
36
  editor.prosemirrorView.root.append(styleEl);
37
37
  } else {
38
38
  editor.prosemirrorView?.root.head.appendChild(styleEl);
@@ -88,7 +88,7 @@ export class PlaceholderPlugin extends BlockNoteExtension {
88
88
 
89
89
  return {
90
90
  destroy: () => {
91
- if (editor.prosemirrorView?.root instanceof ShadowRoot) {
91
+ if (editor.prosemirrorView?.root instanceof window.ShadowRoot) {
92
92
  editor.prosemirrorView.root.removeChild(styleEl);
93
93
  } else {
94
94
  editor.prosemirrorView?.root.head.removeChild(styleEl);
@@ -124,7 +124,7 @@ export class PreviousBlockTypePlugin extends BlockNoteExtension {
124
124
  depth: newState.doc.resolve(node.pos).depth,
125
125
  };
126
126
 
127
- let oldAttrs = {
127
+ const oldAttrs = {
128
128
  index: oldContentNode.attrs.index,
129
129
  level: oldContentNode.attrs.level,
130
130
  type: oldContentNode.type.name,
@@ -134,28 +134,6 @@ export class PreviousBlockTypePlugin extends BlockNoteExtension {
134
134
  currentTransactionOriginalOldBlockAttrs[node.node.attrs.id] =
135
135
  oldAttrs;
136
136
 
137
- // Whenever a transaction is appended by the OrderedListItemIndexPlugin, it's given the metadata:
138
- // { "orderedListIndexing": true }
139
- // These appended transactions happen immediately after any transaction which causes ordered list item
140
- // indices to require updating, including those which trigger animations. Therefore, these animations are
141
- // immediately overridden when the PreviousBlockTypePlugin processes the appended transaction, despite only
142
- // the listItemIndex attribute changing. To solve this, oldAttrs must be edited for transactions with the
143
- // "orderedListIndexing" metadata, so the correct animation can be re-triggered.
144
- if (transaction.getMeta("numberedListIndexing")) {
145
- // If the block existed before the transaction, gets the attributes from before the previous transaction
146
- // (i.e. the transaction that caused list item indices to need updating).
147
- if (node.node.attrs.id in prev.prevTransactionOldBlockAttrs) {
148
- oldAttrs =
149
- prev.prevTransactionOldBlockAttrs[node.node.attrs.id];
150
- }
151
-
152
- // Stops list item indices themselves being animated (looks smoother), unless the block's content type is
153
- // changing from a numbered list item to something else.
154
- if (newAttrs.type === "numberedListItem") {
155
- oldAttrs.index = newAttrs.index;
156
- }
157
- }
158
-
159
137
  prev.currentTransactionOldBlockAttrs[node.node.attrs.id] =
160
138
  oldAttrs;
161
139
 
@@ -204,11 +204,6 @@ export class SuggestionMenuProseMirrorPlugin<
204
204
  _oldState,
205
205
  newState,
206
206
  ): SuggestionPluginState => {
207
- // TODO: More clearly define which transactions should be ignored.
208
- if (transaction.getMeta("orderedListIndexing") !== undefined) {
209
- return prev;
210
- }
211
-
212
207
  // Ignore transactions in code blocks.
213
208
  if (transaction.selection.$from.parent.type.spec.code) {
214
209
  return prev;