@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,7 +1,10 @@
1
1
  /** Define the main block types **/
2
- import type { Extension, Node } from "@tiptap/core";
3
-
2
+ // import { Extension, Node } from "@tiptap/core";
3
+ import type { Node, NodeViewRendererProps } from "@tiptap/core";
4
+ import type { Fragment, Schema } from "prosemirror-model";
5
+ import type { ViewMutationRecord } from "prosemirror-view";
4
6
  import type { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
7
+ import type { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
5
8
  import type {
6
9
  InlineContent,
7
10
  InlineContentSchema,
@@ -21,92 +24,128 @@ export type BlockNoteDOMAttributes = Partial<{
21
24
  [DOMElement in BlockNoteDOMElement]: Record<string, string>;
22
25
  }>;
23
26
 
24
- export type FileBlockConfig = {
25
- type: string;
26
- readonly propSchema: PropSchema & {
27
- caption: {
28
- default: "";
29
- };
30
- name: {
31
- default: "";
32
- };
27
+ export interface BlockConfigMeta {
28
+ /**
29
+ * Defines which keyboard shortcut should be used to insert a hard break into the block's inline content.
30
+ * @default "shift+enter"
31
+ */
32
+ hardBreakShortcut?: "shift+enter" | "enter" | "none";
33
+
34
+ /**
35
+ * Whether the block is selectable
36
+ */
37
+ selectable?: boolean;
38
+
39
+ /**
40
+ * The accept mime types for the file block
41
+ */
42
+ fileBlockAccept?: string[];
33
43
 
34
- // URL is optional, as we also want to accept files with no URL, but for example ids
35
- // (ids can be used for files that are resolved on the backend)
36
- url?: {
37
- default: "";
38
- };
44
+ /**
45
+ * Whether the block is a {@link https://prosemirror.net/docs/ref/#model.NodeSpec.code} block
46
+ */
47
+ code?: boolean;
39
48
 
40
- // Whether to show the file preview or the name only.
41
- // This is useful for some file blocks, but not all
42
- // (e.g.: not relevant for default "file" block which doesn;'t show previews)
43
- showPreview?: {
44
- default: boolean;
45
- };
46
- // File preview width in px.
47
- previewWidth?: {
48
- default: undefined;
49
- type: "number";
50
- };
51
- };
52
- content: "none";
53
- isSelectable?: boolean;
54
- isFileBlock: true;
55
- fileBlockAccept?: string[];
56
- };
49
+ /**
50
+ * Whether the block is a {@link https://prosemirror.net/docs/ref/#model.NodeSpec.defining} block
51
+ */
52
+ defining?: boolean;
57
53
 
58
- // BlockConfig contains the "schema" info about a Block type
59
- // i.e. what props it supports, what content it supports, etc.
60
- export type BlockConfig =
61
- | {
62
- type: string;
63
- readonly propSchema: PropSchema;
64
- content: "inline" | "none" | "table";
65
- isSelectable?: boolean;
66
- isFileBlock?: false;
67
- hardBreakShortcut?: "shift+enter" | "enter" | "none";
68
- }
69
- | FileBlockConfig;
70
-
71
- // Block implementation contains the "implementation" info about a Block
72
- // such as the functions / Nodes required to render and / or serialize it
73
- export type TiptapBlockImplementation<
74
- T extends BlockConfig,
75
- B extends BlockSchema,
76
- I extends InlineContentSchema,
77
- S extends StyleSchema,
78
- > = {
79
- requiredExtensions?: Array<Extension | Node>;
80
- node: Node;
81
- toInternalHTML: (
82
- block: BlockFromConfigNoChildren<T, I, S> & {
83
- children: BlockNoDefaults<B, I, S>[];
84
- },
85
- editor: BlockNoteEditor<B, I, S>,
86
- ) => {
87
- dom: HTMLElement;
88
- contentDOM?: HTMLElement;
89
- };
90
- toExternalHTML: (
91
- block: BlockFromConfigNoChildren<T, I, S> & {
92
- children: BlockNoDefaults<B, I, S>[];
93
- },
94
- editor: BlockNoteEditor<B, I, S>,
95
- ) => {
96
- dom: HTMLElement;
97
- contentDOM?: HTMLElement;
98
- };
99
- };
54
+ /**
55
+ * Whether the block is a {@link https://prosemirror.net/docs/ref/#model.NodeSpec.isolating} block
56
+ */
57
+ isolating?: boolean;
58
+ }
59
+
60
+ /**
61
+ * BlockConfig contains the "schema" info about a Block type
62
+ * i.e. what props it supports, what content it supports, etc.
63
+ */
64
+ export interface BlockConfig<
65
+ T extends string = string,
66
+ PS extends PropSchema = PropSchema,
67
+ C extends "inline" | "none" | "table" = "inline" | "none" | "table",
68
+ > {
69
+ /**
70
+ * The type of the block (unique identifier within a schema)
71
+ */
72
+ type: T;
73
+ /**
74
+ * The properties that the block supports
75
+ * @todo will be zod schema in the future
76
+ */
77
+ readonly propSchema: PS;
78
+ /**
79
+ * The content that the block supports
80
+ */
81
+ content: C;
82
+ // TODO: how do you represent things that have nested content?
83
+ // e.g. tables, alerts (with title & content)
84
+ }
85
+
86
+ // restrict content to "inline" and "none" only
87
+ export type CustomBlockConfig<
88
+ T extends string = string,
89
+ PS extends PropSchema = PropSchema,
90
+ C extends "inline" | "none" = "inline" | "none",
91
+ > = BlockConfig<T, PS, C>;
100
92
 
101
93
  // A Spec contains both the Config and Implementation
102
94
  export type BlockSpec<
103
- T extends BlockConfig,
104
- B extends BlockSchema,
105
- I extends InlineContentSchema,
106
- S extends StyleSchema,
95
+ T extends string = string,
96
+ PS extends PropSchema = PropSchema,
97
+ C extends "inline" | "none" | "table" = "inline" | "none" | "table",
107
98
  > = {
108
- config: T;
109
- implementation: TiptapBlockImplementation<NoInfer<T>, B, I, S>;
99
+ config: BlockConfig<T, PS, C>;
100
+ implementation: BlockImplementation<T, PS, C>;
101
+ extensions?: BlockNoteExtension<any>[];
102
+ };
103
+
104
+ /**
105
+ * This allows de-coupling the types that we display to users versus the types we expose internally.
106
+ *
107
+ * This prevents issues with type-inference across parameters that Typescript cannot handle.
108
+ * Specifically, the blocks shape cannot be properly inferred to a specific type like we expose to the user.
109
+ */
110
+ export type LooseBlockSpec<
111
+ T extends string = string,
112
+ PS extends PropSchema = PropSchema,
113
+ C extends "inline" | "none" | "table" = "inline" | "none" | "table",
114
+ > = {
115
+ config: BlockConfig<T, PS, C>;
116
+ implementation: Omit<
117
+ BlockImplementation<T, PS, C>,
118
+ "render" | "toExternalHTML"
119
+ > & {
120
+ // purposefully stub the types for render and toExternalHTML since they reference the block
121
+ render: (
122
+ /**
123
+ * The custom block to render
124
+ */
125
+ block: any,
126
+ /**
127
+ * The BlockNote editor instance
128
+ */
129
+ editor: BlockNoteEditor<any>,
130
+ ) => {
131
+ dom: HTMLElement | DocumentFragment;
132
+ contentDOM?: HTMLElement;
133
+ ignoreMutation?: (mutation: ViewMutationRecord) => boolean;
134
+ destroy?: () => void;
135
+ };
136
+ toExternalHTML?: (
137
+ block: any,
138
+ editor: BlockNoteEditor<any>,
139
+ ) =>
140
+ | {
141
+ dom: HTMLElement | DocumentFragment;
142
+ contentDOM?: HTMLElement;
143
+ }
144
+ | undefined;
145
+
146
+ node: Node;
147
+ };
148
+ extensions?: BlockNoteExtension<any>[];
110
149
  };
111
150
 
112
151
  // Utility type. For a given object block schema, ensures that the key of each
@@ -125,25 +164,66 @@ type NamesMatch<Blocks extends Record<string, BlockConfig>> = Blocks extends {
125
164
  // The keys are the "type" of a block
126
165
  export type BlockSchema = NamesMatch<Record<string, BlockConfig>>;
127
166
 
128
- export type BlockSpecs = Record<
129
- string,
130
- BlockSpec<any, any, InlineContentSchema, StyleSchema>
131
- >;
167
+ export type BlockSpecs = {
168
+ [k in string]: {
169
+ config: BlockSpec<k>["config"];
170
+ implementation: Omit<
171
+ BlockSpec<k>["implementation"],
172
+ "render" | "toExternalHTML"
173
+ > & {
174
+ // purposefully stub the types for render and toExternalHTML since they reference the block
175
+ render: (
176
+ /**
177
+ * The custom block to render
178
+ */
179
+ block: any,
180
+ /**
181
+ * The BlockNote editor instance
182
+ */
183
+ editor: BlockNoteEditor<any>,
184
+ ) => {
185
+ dom: HTMLElement | DocumentFragment;
186
+ contentDOM?: HTMLElement;
187
+ ignoreMutation?: (mutation: ViewMutationRecord) => boolean;
188
+ destroy?: () => void;
189
+ };
190
+ toExternalHTML?: (
191
+ block: any,
192
+ editor: BlockNoteEditor<any>,
193
+ ) =>
194
+ | {
195
+ dom: HTMLElement | DocumentFragment;
196
+ contentDOM?: HTMLElement;
197
+ }
198
+ | undefined;
199
+ };
200
+ extensions?: BlockNoteExtension<any>[];
201
+ };
202
+ };
132
203
 
133
204
  export type BlockImplementations = Record<
134
205
  string,
135
- TiptapBlockImplementation<any, any, any, any>
206
+ BlockImplementation<any, any>
136
207
  >;
137
208
 
138
- export type BlockSchemaFromSpecs<T extends BlockSpecs> = {
139
- [K in keyof T]: T[K]["config"];
209
+ export type BlockSchemaFromSpecs<BS extends BlockSpecs> = {
210
+ [K in keyof BS]: BS[K]["config"];
140
211
  };
141
212
 
142
- export type BlockSchemaWithBlock<
143
- BType extends string,
144
- C extends BlockConfig,
145
- > = {
146
- [k in BType]: C;
213
+ export type BlockSpecsFromSchema<BS extends BlockSchema> = {
214
+ [K in keyof BS]: {
215
+ config: BlockConfig<BS[K]["type"], BS[K]["propSchema"], BS[K]["content"]>;
216
+ implementation: BlockImplementation<
217
+ BS[K]["type"],
218
+ BS[K]["propSchema"],
219
+ BS[K]["content"]
220
+ >;
221
+ extensions?: BlockNoteExtension<any>[];
222
+ };
223
+ };
224
+
225
+ export type BlockSchemaWithBlock<T extends string, C extends BlockConfig> = {
226
+ [k in T]: C;
147
227
  };
148
228
 
149
229
  export type TableCellProps = {
@@ -275,7 +355,9 @@ type PartialBlockFromConfigNoChildren<
275
355
  ? PartialInlineContent<I, S>
276
356
  : B["content"] extends "table"
277
357
  ? PartialTableContent<I, S>
278
- : undefined;
358
+ : B["content"] extends "none"
359
+ ? undefined
360
+ : never;
279
361
  };
280
362
 
281
363
  type PartialBlocksWithoutChildren<
@@ -321,3 +403,91 @@ export type PartialBlockFromConfig<
321
403
  };
322
404
 
323
405
  export type BlockIdentifier = { id: string } | string;
406
+
407
+ export type BlockImplementation<
408
+ TName extends string = string,
409
+ TProps extends PropSchema = PropSchema,
410
+ TContent extends "inline" | "none" | "table" = "inline" | "none" | "table",
411
+ > = {
412
+ /**
413
+ * Metadata
414
+ */
415
+ meta?: BlockConfigMeta;
416
+ /**
417
+ * A function that converts the block into a DOM element
418
+ */
419
+ render: (
420
+ this:
421
+ | Record<string, never>
422
+ | ({
423
+ blockContentDOMAttributes: Record<string, string>;
424
+ } & (
425
+ | {
426
+ renderType: "nodeView";
427
+ props: NodeViewRendererProps;
428
+ }
429
+ | {
430
+ renderType: "dom";
431
+ props: undefined;
432
+ }
433
+ )),
434
+ /**
435
+ * The custom block to render
436
+ */
437
+ block: BlockFromConfig<BlockConfig<TName, TProps, TContent>, any, any>,
438
+ /**
439
+ * The BlockNote editor instance
440
+ */
441
+ editor: BlockNoteEditor<
442
+ Record<TName, BlockConfig<TName, TProps, TContent>>
443
+ >,
444
+ ) => {
445
+ dom: HTMLElement | DocumentFragment;
446
+ contentDOM?: HTMLElement;
447
+ ignoreMutation?: (mutation: ViewMutationRecord) => boolean;
448
+ destroy?: () => void;
449
+ };
450
+
451
+ /**
452
+ * Exports block to external HTML. If not defined, the output will be the same
453
+ * as `render(...).dom`.
454
+ */
455
+ toExternalHTML?: (
456
+ this: Partial<{
457
+ blockContentDOMAttributes: Record<string, string>;
458
+ }>,
459
+ block: BlockFromConfig<BlockConfig<TName, TProps, TContent>, any, any>,
460
+ editor: BlockNoteEditor<
461
+ Record<TName, BlockConfig<TName, TProps, TContent>>
462
+ >,
463
+ ) =>
464
+ | {
465
+ dom: HTMLElement | DocumentFragment;
466
+ contentDOM?: HTMLElement;
467
+ }
468
+ | undefined;
469
+
470
+ /**
471
+ * Parses an external HTML element into a block of this type when it returns the block props object, otherwise undefined
472
+ */
473
+ parse?: (el: HTMLElement) => Partial<Props<TProps>> | undefined;
474
+
475
+ /**
476
+ * The blocks that this block should run before.
477
+ * This is used to determine the order in which blocks are parsed
478
+ */
479
+ runsBefore?: string[];
480
+
481
+ /**
482
+ * Advanced parsing function that controls how content within the block is parsed.
483
+ * This is not recommended to use, and is only useful for advanced use cases.
484
+ */
485
+ parseContent?: (options: { el: HTMLElement; schema: Schema }) => Fragment;
486
+ };
487
+
488
+ // restrict content to "inline" and "none" only
489
+ export type CustomBlockImplementation<
490
+ T extends string = string,
491
+ PS extends PropSchema = PropSchema,
492
+ C extends "inline" | "none" = "inline" | "none",
493
+ > = BlockImplementation<T, PS, C>;
@@ -8,3 +8,4 @@ export * from "./propTypes.js";
8
8
  export * from "./styles/createSpec.js";
9
9
  export * from "./styles/internal.js";
10
10
  export * from "./styles/types.js";
11
+ export * from "./schema.js";
@@ -19,19 +19,30 @@ import {
19
19
  PartialCustomInlineContentFromConfig,
20
20
  } from "./types.js";
21
21
 
22
- // TODO: support serialization
23
-
24
22
  export type CustomInlineContentImplementation<
25
23
  T extends CustomInlineContentConfig,
26
- // B extends BlockSchema,
27
- // I extends InlineContentSchema,
28
24
  S extends StyleSchema,
29
25
  > = {
26
+ meta?: {
27
+ draggable?: boolean;
28
+ };
29
+
30
+ /**
31
+ * Parses an external HTML element into a inline content of this type when it returns the block props object, otherwise undefined
32
+ */
33
+ parse?: (el: HTMLElement) => Partial<Props<T["propSchema"]>> | undefined;
34
+
35
+ /**
36
+ * Renders an inline content to DOM elements
37
+ */
30
38
  render: (
31
39
  /**
32
40
  * The custom inline content to render
33
41
  */
34
42
  inlineContent: InlineContentFromConfig<T, S>,
43
+ /**
44
+ * A callback that allows overriding the inline content element
45
+ */
35
46
  updateInlineContent: (
36
47
  update: PartialCustomInlineContentFromConfig<T, S>,
37
48
  ) => void,
@@ -46,14 +57,37 @@ export type CustomInlineContentImplementation<
46
57
  ) => {
47
58
  dom: HTMLElement;
48
59
  contentDOM?: HTMLElement;
49
- // destroy?: () => void;
60
+ destroy?: () => void;
50
61
  };
62
+
63
+ /**
64
+ * Renders an inline content to external HTML elements for use outside the editor
65
+ * If not provided, falls back to the render method
66
+ */
67
+ toExternalHTML?: (
68
+ /**
69
+ * The custom inline content to render
70
+ */
71
+ inlineContent: InlineContentFromConfig<T, S>,
72
+ /**
73
+ * The BlockNote editor instance
74
+ * This is typed generically. If you want an editor with your custom schema, you need to
75
+ * cast it manually, e.g.: `const e = editor as BlockNoteEditor<typeof mySchema>;`
76
+ */
77
+ editor: BlockNoteEditor<any, any, S>,
78
+ ) =>
79
+ | {
80
+ dom: HTMLElement | DocumentFragment;
81
+ contentDOM?: HTMLElement;
82
+ }
83
+ | undefined;
51
84
  };
52
85
 
53
- export function getInlineContentParseRules(
54
- config: CustomInlineContentConfig,
55
- ): TagParseRule[] {
56
- return [
86
+ export function getInlineContentParseRules<C extends CustomInlineContentConfig>(
87
+ config: C,
88
+ customParseFunction?: CustomInlineContentImplementation<C, any>["parse"],
89
+ ) {
90
+ const rules: TagParseRule[] = [
57
91
  {
58
92
  tag: `[data-inline-content-type="${config.type}"]`,
59
93
  contentElement: (element) => {
@@ -67,6 +101,26 @@ export function getInlineContentParseRules(
67
101
  },
68
102
  },
69
103
  ];
104
+
105
+ if (customParseFunction) {
106
+ rules.push({
107
+ tag: "*",
108
+ getAttrs(node: string | HTMLElement) {
109
+ if (typeof node === "string") {
110
+ return false;
111
+ }
112
+
113
+ const props = customParseFunction?.(node);
114
+
115
+ if (props === undefined) {
116
+ return false;
117
+ }
118
+
119
+ return props;
120
+ },
121
+ });
122
+ }
123
+ return rules;
70
124
  }
71
125
 
72
126
  export function createInlineContentSpec<
@@ -80,11 +134,10 @@ export function createInlineContentSpec<
80
134
  name: inlineContentConfig.type,
81
135
  inline: true,
82
136
  group: "inline",
137
+ draggable: inlineContentImplementation.meta?.draggable,
83
138
  selectable: inlineContentConfig.content === "styled",
84
139
  atom: inlineContentConfig.content === "none",
85
- content: (inlineContentConfig.content === "styled"
86
- ? "inline*"
87
- : "") as T["content"] extends "styled" ? "inline*" : "",
140
+ content: inlineContentConfig.content === "styled" ? "inline*" : "",
88
141
 
89
142
  addAttributes() {
90
143
  return propsToAttributes(inlineContentConfig.propSchema);
@@ -95,13 +148,17 @@ export function createInlineContentSpec<
95
148
  },
96
149
 
97
150
  parseHTML() {
98
- return getInlineContentParseRules(inlineContentConfig);
151
+ return getInlineContentParseRules(
152
+ inlineContentConfig,
153
+ inlineContentImplementation.parse,
154
+ );
99
155
  },
100
156
 
101
157
  renderHTML({ node }) {
102
158
  const editor = this.options.editor;
103
159
 
104
- const output = inlineContentImplementation.render(
160
+ const output = inlineContentImplementation.render.call(
161
+ { renderType: "dom", props: undefined },
105
162
  nodeToCustomInlineContent(
106
163
  node,
107
164
  editor.schema.inlineContentSchema,
@@ -122,24 +179,28 @@ export function createInlineContentSpec<
122
179
  },
123
180
 
124
181
  addNodeView() {
125
- return ({ node, getPos }) => {
182
+ return (props) => {
183
+ const { node, getPos } = props;
126
184
  const editor = this.options.editor as BlockNoteEditor<any, any, S>;
127
185
 
128
- const output = inlineContentImplementation.render(
186
+ const output = inlineContentImplementation.render.call(
187
+ { renderType: "nodeView", props },
129
188
  nodeToCustomInlineContent(
130
189
  node,
131
190
  editor.schema.inlineContentSchema,
132
191
  editor.schema.styleSchema,
133
192
  ) as any as InlineContentFromConfig<T, S>, // TODO: fix cast
134
193
  (update) => {
135
- if (typeof getPos === "boolean") {
194
+ const content = inlineContentToNodes([update], editor.pmSchema);
195
+
196
+ const pos = getPos();
197
+
198
+ if (!pos) {
136
199
  return;
137
200
  }
138
201
 
139
- const content = inlineContentToNodes([update], editor.pmSchema);
140
-
141
202
  editor.transact((tr) =>
142
- tr.replaceWith(getPos(), getPos() + node.nodeSize, content),
203
+ tr.replaceWith(pos, pos + node.nodeSize, content),
143
204
  );
144
205
  },
145
206
  editor,
@@ -158,5 +219,22 @@ export function createInlineContentSpec<
158
219
  return createInlineContentSpecFromTipTapNode(
159
220
  node,
160
221
  inlineContentConfig.propSchema,
161
- ) as InlineContentSpec<T>; // TODO: fix cast
222
+ {
223
+ toExternalHTML: inlineContentImplementation.toExternalHTML,
224
+ render(inlineContent, updateInlineContent, editor) {
225
+ const output = inlineContentImplementation.render(
226
+ inlineContent,
227
+ updateInlineContent,
228
+ editor,
229
+ );
230
+
231
+ return addInlineContentAttributes(
232
+ output,
233
+ inlineContentConfig.type,
234
+ inlineContent.props,
235
+ inlineContentConfig.propSchema,
236
+ );
237
+ },
238
+ },
239
+ ) as InlineContentSpec<T>;
162
240
  }
@@ -4,7 +4,6 @@ import { camelToDataKebab } from "../../util/string.js";
4
4
  import { PropSchema, Props } from "../propTypes.js";
5
5
  import {
6
6
  CustomInlineContentConfig,
7
- InlineContentConfig,
8
7
  InlineContentImplementation,
9
8
  InlineContentSchemaFromSpecs,
10
9
  InlineContentSpec,
@@ -43,7 +42,7 @@ export function addInlineContentAttributes<
43
42
  })
44
43
  .forEach(([prop, value]) => element.dom.setAttribute(prop, value));
45
44
 
46
- if (element.contentDOM !== undefined) {
45
+ if (element.contentDOM) {
47
46
  element.contentDOM.setAttribute("data-editable", "");
48
47
  }
49
48
 
@@ -73,20 +72,29 @@ export function addInlineContentKeyboardShortcuts<
73
72
 
74
73
  // This helper function helps to instantiate a InlineContentSpec with a
75
74
  // config and implementation that conform to the type of Config
76
- export function createInternalInlineContentSpec<T extends InlineContentConfig>(
75
+ export function createInternalInlineContentSpec<
76
+ const T extends CustomInlineContentConfig,
77
+ >(
77
78
  config: T,
78
- implementation: InlineContentImplementation<T>,
79
- ) {
79
+ implementation: InlineContentImplementation<NoInfer<T>>,
80
+ ): InlineContentSpec<T> {
80
81
  return {
81
82
  config,
82
83
  implementation,
83
- } satisfies InlineContentSpec<T>;
84
+ } as const;
84
85
  }
85
86
 
86
87
  export function createInlineContentSpecFromTipTapNode<
87
88
  T extends Node,
88
89
  P extends PropSchema,
89
- >(node: T, propSchema: P) {
90
+ >(
91
+ node: T,
92
+ propSchema: P,
93
+ implementation: Omit<
94
+ InlineContentImplementation<CustomInlineContentConfig>,
95
+ "node"
96
+ >,
97
+ ) {
90
98
  return createInternalInlineContentSpec(
91
99
  {
92
100
  type: node.name as T["name"],
@@ -94,6 +102,7 @@ export function createInlineContentSpecFromTipTapNode<
94
102
  content: node.config.content === "inline*" ? "styled" : "none",
95
103
  },
96
104
  {
105
+ ...implementation,
97
106
  node,
98
107
  },
99
108
  );