@blocknote/core 0.38.0 → 0.39.1

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 (228) 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 +3401 -7305
  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 +6 -10
  22. package/src/api/clipboard/fromClipboard/pasteExtension.ts +1 -1
  23. package/src/api/clipboard/toClipboard/copyExtension.ts +1 -1
  24. package/src/api/exporters/html/util/serializeBlocksExternalHTML.ts +128 -28
  25. package/src/api/exporters/html/util/serializeBlocksInternalHTML.ts +101 -41
  26. package/src/api/pmUtil.ts +1 -1
  27. package/src/api/positionMapping.test.ts +58 -15
  28. package/src/api/positionMapping.ts +2 -4
  29. package/src/blocks/Audio/block.ts +174 -0
  30. package/src/blocks/BlockNoteSchema.ts +59 -0
  31. package/src/blocks/Code/block.ts +303 -0
  32. package/src/blocks/Code/shiki.ts +73 -0
  33. package/src/blocks/File/block.ts +98 -0
  34. package/src/blocks/{FileBlockContent → File}/helpers/render/createAddFileButton.ts +5 -2
  35. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileBlockWrapper.ts +15 -6
  36. package/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.ts +15 -2
  37. package/src/blocks/{FileBlockContent → File}/helpers/render/createResizableFileBlockWrapper.ts +21 -2
  38. package/src/blocks/Heading/block.ts +138 -0
  39. package/src/blocks/Image/block.ts +190 -0
  40. package/src/blocks/ListItem/BulletListItem/block.ts +116 -0
  41. package/src/blocks/ListItem/CheckListItem/block.ts +175 -0
  42. package/src/blocks/ListItem/NumberedListItem/IndexingPlugin.ts +173 -0
  43. package/src/blocks/ListItem/NumberedListItem/block.ts +133 -0
  44. package/src/blocks/ListItem/ToggleListItem/block.ts +78 -0
  45. package/src/blocks/PageBreak/block.ts +72 -0
  46. package/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.ts +9 -7
  47. package/src/blocks/Paragraph/block.ts +80 -0
  48. package/src/blocks/Quote/block.ts +90 -0
  49. package/src/blocks/{TableBlockContent/TableBlockContent.ts → Table/block.ts} +169 -51
  50. package/src/blocks/ToggleWrapper/createToggleWrapper.ts +1 -1
  51. package/src/blocks/Video/block.ts +143 -0
  52. package/src/blocks/defaultBlockHelpers.ts +2 -2
  53. package/src/blocks/defaultBlockTypeGuards.ts +143 -174
  54. package/src/blocks/defaultBlocks.ts +107 -35
  55. package/src/blocks/defaultProps.ts +145 -4
  56. package/src/blocks/index.ts +26 -0
  57. package/src/blocks/utils/listItemEnterHandler.ts +42 -0
  58. package/src/editor/Block.css +54 -18
  59. package/src/editor/BlockNoteEditor.ts +256 -211
  60. package/src/editor/BlockNoteExtension.ts +92 -0
  61. package/src/editor/BlockNoteExtensions.ts +18 -17
  62. package/src/editor/defaultColors.ts +2 -2
  63. package/src/exporter/Exporter.ts +1 -1
  64. package/src/exporter/mapping.ts +1 -1
  65. package/src/extensions/BackgroundColor/BackgroundColorExtension.ts +3 -20
  66. package/src/extensions/BackgroundColor/BackgroundColorMark.ts +6 -8
  67. package/src/extensions/BlockChange/BlockChangePlugin.ts +2 -1
  68. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor-forked.json +2 -2
  69. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-editor.json +2 -2
  70. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap-forked.html +1 -1
  71. package/src/extensions/Collaboration/__snapshots__/fork-yjs-snap.html +1 -1
  72. package/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.ts +52 -0
  73. package/src/extensions/Collaboration/schemaMigration/migrationRules/index.ts +4 -0
  74. package/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.ts +4 -0
  75. package/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.ts +78 -0
  76. package/src/extensions/Comments/CommentsPlugin.ts +1 -1
  77. package/src/extensions/FilePanel/FilePanelPlugin.ts +5 -10
  78. package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +1 -1
  79. package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +4 -3
  80. package/src/extensions/Placeholder/PlaceholderPlugin.ts +6 -6
  81. package/src/extensions/PreviousBlockType/PreviousBlockTypePlugin.ts +1 -23
  82. package/src/extensions/SideMenu/SideMenuPlugin.ts +1 -3
  83. package/src/extensions/SideMenu/dragging.ts +2 -2
  84. package/src/extensions/SuggestionMenu/SuggestionPlugin.ts +4 -7
  85. package/src/extensions/SuggestionMenu/getDefaultEmojiPickerItems.ts +6 -2
  86. package/src/extensions/SuggestionMenu/getDefaultSlashMenuItems.ts +24 -17
  87. package/src/extensions/TableHandles/TableHandlesPlugin.ts +8 -8
  88. package/src/extensions/TextAlignment/TextAlignmentExtension.ts +5 -11
  89. package/src/extensions/TextColor/TextColorExtension.ts +3 -17
  90. package/src/extensions/TextColor/TextColorMark.ts +4 -9
  91. package/src/extensions/UniqueID/UniqueID.ts +6 -13
  92. package/src/index.ts +2 -28
  93. package/src/schema/blocks/createSpec.ts +342 -169
  94. package/src/schema/blocks/internal.ts +77 -138
  95. package/src/schema/blocks/types.ts +264 -94
  96. package/src/schema/index.ts +1 -0
  97. package/src/schema/inlineContent/createSpec.ts +99 -21
  98. package/src/schema/inlineContent/internal.ts +16 -7
  99. package/src/schema/inlineContent/types.ts +24 -2
  100. package/src/schema/propTypes.ts +15 -9
  101. package/src/schema/schema.ts +209 -0
  102. package/src/schema/styles/createSpec.ts +79 -31
  103. package/src/schema/styles/internal.ts +61 -2
  104. package/src/schema/styles/types.ts +17 -3
  105. package/src/util/topo-sort.test.ts +125 -0
  106. package/src/util/topo-sort.ts +160 -0
  107. package/types/src/api/blockManipulation/commands/splitBlock/splitBlock.d.ts +2 -1
  108. package/types/src/api/blockManipulation/selections/selection.d.ts +1 -1
  109. package/types/src/api/blockManipulation/setupTestEnv.d.ts +29 -543
  110. package/types/src/api/exporters/html/util/serializeBlocksExternalHTML.d.ts +1 -1
  111. package/types/src/api/exporters/html/util/serializeBlocksInternalHTML.d.ts +1 -1
  112. package/types/src/api/pmUtil.d.ts +1 -1
  113. package/types/src/blocks/Audio/block.d.ts +58 -0
  114. package/types/src/blocks/BlockNoteSchema.d.ts +18 -0
  115. package/types/src/blocks/{CodeBlockContent/CodeBlockContent.d.ts → Code/block.d.ts} +25 -26
  116. package/types/src/blocks/Code/shiki.d.ts +4 -0
  117. package/types/src/blocks/File/block.d.ts +37 -0
  118. package/types/src/blocks/File/helpers/render/createAddFileButton.d.ts +6 -0
  119. package/types/src/blocks/File/helpers/render/createFileBlockWrapper.d.ts +25 -0
  120. package/types/src/blocks/{FileBlockContent → File}/helpers/render/createFileNameWithIcon.d.ts +6 -2
  121. package/types/src/blocks/File/helpers/render/createResizableFileBlockWrapper.d.ts +31 -0
  122. package/types/src/blocks/Heading/block.d.ts +71 -0
  123. package/types/src/blocks/Image/block.d.ts +102 -0
  124. package/types/src/blocks/ListItem/BulletListItem/block.d.ts +25 -0
  125. package/types/src/blocks/ListItem/CheckListItem/block.d.ts +33 -0
  126. package/types/src/blocks/ListItem/NumberedListItem/IndexingPlugin.d.ts +8 -0
  127. package/types/src/blocks/ListItem/NumberedListItem/block.d.ts +33 -0
  128. package/types/src/blocks/ListItem/ToggleListItem/block.d.ts +25 -0
  129. package/types/src/blocks/PageBreak/block.d.ts +11 -0
  130. package/types/src/blocks/{PageBreakBlockContent → PageBreak}/getPageBreakSlashMenuItems.d.ts +4 -2
  131. package/types/src/blocks/Paragraph/block.d.ts +25 -0
  132. package/types/src/blocks/Quote/block.d.ts +17 -0
  133. package/types/src/blocks/Table/block.d.ts +21 -0
  134. package/types/src/blocks/Video/block.d.ts +67 -0
  135. package/types/src/blocks/defaultBlockHelpers.d.ts +1 -1
  136. package/types/src/blocks/defaultBlockTypeGuards.d.ts +15 -36
  137. package/types/src/blocks/defaultBlocks.d.ts +221 -1060
  138. package/types/src/blocks/defaultProps.d.ts +17 -1
  139. package/types/src/blocks/index.d.ts +24 -0
  140. package/types/src/blocks/utils/listItemEnterHandler.d.ts +2 -0
  141. package/types/src/editor/BlockNoteEditor.d.ts +36 -67
  142. package/types/src/editor/BlockNoteExtension.d.ts +67 -0
  143. package/types/src/editor/BlockNoteExtensions.d.ts +1 -1
  144. package/types/src/editor/defaultColors.d.ts +8 -76
  145. package/types/src/exporter/Exporter.d.ts +1 -1
  146. package/types/src/exporter/mapping.d.ts +1 -1
  147. package/types/src/extensions/BackgroundColor/BackgroundColorMark.d.ts +4 -1
  148. package/types/src/extensions/Collaboration/schemaMigration/SchemaMigrationPlugin.d.ts +7 -0
  149. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/index.d.ts +3 -0
  150. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/migrationRule.d.ts +3 -0
  151. package/types/src/extensions/Collaboration/schemaMigration/migrationRules/moveColorAttributes.d.ts +2 -0
  152. package/types/src/extensions/Comments/CommentsPlugin.d.ts +1 -1
  153. package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +4 -4
  154. package/types/src/extensions/TextColor/TextColorMark.d.ts +4 -1
  155. package/types/src/index.d.ts +2 -25
  156. package/types/src/schema/blocks/createSpec.d.ts +16 -36
  157. package/types/src/schema/blocks/internal.d.ts +11 -33
  158. package/types/src/schema/blocks/types.d.ts +181 -57
  159. package/types/src/schema/index.d.ts +1 -0
  160. package/types/src/schema/inlineContent/createSpec.d.ts +36 -2
  161. package/types/src/schema/inlineContent/internal.d.ts +7 -15
  162. package/types/src/schema/inlineContent/types.d.ts +15 -1
  163. package/types/src/schema/propTypes.d.ts +4 -4
  164. package/types/src/schema/schema.d.ts +40 -0
  165. package/types/src/schema/styles/createSpec.d.ts +6 -4
  166. package/types/src/schema/styles/internal.d.ts +6 -3
  167. package/types/src/schema/styles/types.d.ts +11 -2
  168. package/types/src/util/topo-sort.d.ts +18 -0
  169. package/types/src/util/topo-sort.test.d.ts +1 -0
  170. package/src/blocks/AudioBlockContent/AudioBlockContent.ts +0 -144
  171. package/src/blocks/CodeBlockContent/CodeBlockContent.ts +0 -445
  172. package/src/blocks/FileBlockContent/FileBlockContent.ts +0 -100
  173. package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +0 -159
  174. package/src/blocks/ImageBlockContent/ImageBlockContent.ts +0 -159
  175. package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +0 -134
  176. package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +0 -299
  177. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.ts +0 -86
  178. package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +0 -172
  179. package/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.ts +0 -104
  180. package/src/blocks/PageBreakBlockContent/PageBreakBlockContent.ts +0 -49
  181. package/src/blocks/PageBreakBlockContent/schema.ts +0 -40
  182. package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +0 -78
  183. package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +0 -121
  184. package/src/blocks/VideoBlockContent/VideoBlockContent.ts +0 -158
  185. package/src/editor/BlockNoteSchema.ts +0 -107
  186. package/src/editor/BlockNoteTipTapEditor.ts +0 -335
  187. package/types/src/blocks/AudioBlockContent/AudioBlockContent.d.ts +0 -99
  188. package/types/src/blocks/FileBlockContent/FileBlockContent.d.ts +0 -90
  189. package/types/src/blocks/FileBlockContent/helpers/render/createAddFileButton.d.ts +0 -6
  190. package/types/src/blocks/FileBlockContent/helpers/render/createFileBlockWrapper.d.ts +0 -9
  191. package/types/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.d.ts +0 -9
  192. package/types/src/blocks/HeadingBlockContent/HeadingBlockContent.d.ts +0 -67
  193. package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +0 -131
  194. package/types/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.d.ts +0 -46
  195. package/types/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.d.ts +0 -55
  196. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListIndexingPlugin.d.ts +0 -2
  197. package/types/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.d.ts +0 -58
  198. package/types/src/blocks/ListItemBlockContent/ToggleListItemBlockContent/ToggleListItemBlockContent.d.ts +0 -46
  199. package/types/src/blocks/PageBreakBlockContent/PageBreakBlockContent.d.ts +0 -31
  200. package/types/src/blocks/PageBreakBlockContent/schema.d.ts +0 -86
  201. package/types/src/blocks/ParagraphBlockContent/ParagraphBlockContent.d.ts +0 -52
  202. package/types/src/blocks/QuoteBlockContent/QuoteBlockContent.d.ts +0 -52
  203. package/types/src/blocks/TableBlockContent/TableBlockContent.d.ts +0 -39
  204. package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +0 -131
  205. package/types/src/editor/BlockNoteSchema.d.ts +0 -34
  206. package/types/src/editor/BlockNoteTipTapEditor.d.ts +0 -43
  207. /package/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.ts +0 -0
  208. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.ts +0 -0
  209. /package/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.ts +0 -0
  210. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.ts +0 -0
  211. /package/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.ts +0 -0
  212. /package/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.ts +0 -0
  213. /package/src/blocks/{ImageBlockContent → Image}/parseImageElement.ts +0 -0
  214. /package/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.ts +0 -0
  215. /package/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.ts +0 -0
  216. /package/src/blocks/{TableBlockContent → Table}/TableExtension.ts +0 -0
  217. /package/src/blocks/{VideoBlockContent → Video}/parseVideoElement.ts +0 -0
  218. /package/types/src/blocks/{AudioBlockContent → Audio}/parseAudioElement.d.ts +0 -0
  219. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseEmbedElement.d.ts +0 -0
  220. /package/types/src/blocks/{FileBlockContent → File}/helpers/parse/parseFigureElement.d.ts +0 -0
  221. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createFigureWithCaption.d.ts +0 -0
  222. /package/types/src/blocks/{FileBlockContent → File}/helpers/toExternalHTML/createLinkWithCaption.d.ts +0 -0
  223. /package/types/src/blocks/{FileBlockContent → File/helpers}/uploadToTmpFilesDotOrg_DEV_ONLY.d.ts +0 -0
  224. /package/types/src/blocks/{ImageBlockContent → Image}/parseImageElement.d.ts +0 -0
  225. /package/types/src/blocks/{ListItemBlockContent → ListItem}/ListItemKeyboardShortcuts.d.ts +0 -0
  226. /package/types/src/blocks/{ListItemBlockContent → ListItem}/getListItemContent.d.ts +0 -0
  227. /package/types/src/blocks/{TableBlockContent → Table}/TableExtension.d.ts +0 -0
  228. /package/types/src/blocks/{VideoBlockContent → Video}/parseVideoElement.d.ts +0 -0
@@ -0,0 +1,173 @@
1
+ import type { Node } from "@tiptap/pm/model";
2
+ import type { Transaction } from "@tiptap/pm/state";
3
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
4
+ import { Decoration, DecorationSet } from "@tiptap/pm/view";
5
+
6
+ import { getBlockInfo } from "../../../api/getBlockInfoFromPos.js";
7
+
8
+ // Loosely based on https://github.com/ueberdosis/tiptap/blob/7ac01ef0b816a535e903b5ca92492bff110a71ae/packages/extension-mathematics/src/MathematicsPlugin.ts (MIT)
9
+
10
+ type DecoSpec = {
11
+ index: number;
12
+ isFirst: boolean;
13
+ hasStart: boolean;
14
+ side: number;
15
+ };
16
+
17
+ type Deco = Omit<Decoration, "spec"> & { spec: DecoSpec };
18
+
19
+ /**
20
+ * Calculate the index for a numbered list item based on its position and previous siblings
21
+ */
22
+ function calculateListItemIndex(
23
+ node: Node,
24
+ pos: number,
25
+ tr: Transaction,
26
+ map: Map<Node, number>,
27
+ ): { index: number; isFirst: boolean; hasStart: boolean } {
28
+ let index: number = node.firstChild!.attrs["start"] || 1;
29
+ let isFirst = true;
30
+ const hasStart = !!node.firstChild!.attrs["start"];
31
+
32
+ const blockInfo = getBlockInfo({
33
+ posBeforeNode: pos,
34
+ node,
35
+ });
36
+
37
+ if (!blockInfo.isBlockContainer) {
38
+ throw new Error("impossible");
39
+ }
40
+
41
+ // Check if this block is the start of a new ordered list
42
+ const prevBlock = tr.doc.resolve(blockInfo.bnBlock.beforePos).nodeBefore;
43
+ const prevBlockIndex = prevBlock ? map.get(prevBlock) : undefined;
44
+
45
+ if (prevBlockIndex !== undefined) {
46
+ index = prevBlockIndex + 1;
47
+ isFirst = false;
48
+ } else if (prevBlock) {
49
+ // Because we only check the affected ranges, we may need to walk backwards to find the previous block's index
50
+ // We can't just rely on the map, because the map is reset every `apply` call
51
+ const prevBlockInfo = getBlockInfo({
52
+ posBeforeNode: blockInfo.bnBlock.beforePos - prevBlock.nodeSize,
53
+ node: prevBlock,
54
+ });
55
+
56
+ const isPrevBlockOrderedListItem =
57
+ prevBlockInfo.blockNoteType === "numberedListItem";
58
+ if (isPrevBlockOrderedListItem) {
59
+ // recurse to get the index of the previous block
60
+ const itemIndex = calculateListItemIndex(
61
+ prevBlock,
62
+ blockInfo.bnBlock.beforePos - prevBlock.nodeSize,
63
+ tr,
64
+ map,
65
+ );
66
+ index = itemIndex.index + 1;
67
+ isFirst = false;
68
+ }
69
+ }
70
+ // Note: we set the map late, so that when we recurse, we can rely on the map to get the previous block's index in one lookup
71
+ map.set(node, index);
72
+
73
+ return { index, isFirst, hasStart };
74
+ }
75
+
76
+ /**
77
+ * Get the decorations for the current state based on the previous state,
78
+ * and the transaction that was applied to get to the current state
79
+ */
80
+ function getDecorations(
81
+ tr: Transaction,
82
+ previousPluginState: { decorations: DecorationSet },
83
+ ) {
84
+ const map = new Map<Node, number>();
85
+
86
+ const nextDecorationSet = previousPluginState.decorations.map(
87
+ tr.mapping,
88
+ tr.doc,
89
+ );
90
+ const decorationsToAdd = [] as Deco[];
91
+
92
+ tr.doc.nodesBetween(0, tr.doc.nodeSize - 2, (node, pos) => {
93
+ if (
94
+ node.type.name === "blockContainer" &&
95
+ node.firstChild!.type.name === "numberedListItem"
96
+ ) {
97
+ const { index, isFirst, hasStart } = calculateListItemIndex(
98
+ node,
99
+ pos,
100
+ tr,
101
+ map,
102
+ );
103
+
104
+ // Check if decoration already exists with the same properties (for perf reasons)
105
+ const existingDecorations = nextDecorationSet.find(
106
+ pos,
107
+ pos + node.nodeSize,
108
+ (deco: DecoSpec) =>
109
+ deco.index === index &&
110
+ deco.isFirst === isFirst &&
111
+ deco.hasStart === hasStart,
112
+ );
113
+
114
+ if (existingDecorations.length === 0) {
115
+ // Create a widget decoration to display the index
116
+ decorationsToAdd.push(
117
+ // move in by 1 to account for the block container
118
+ Decoration.node(pos + 1, pos + node.nodeSize - 1, {
119
+ "data-index": index.toString(),
120
+ }),
121
+ );
122
+ }
123
+ }
124
+ });
125
+
126
+ // Remove any decorations that exist at the same position, they will be replaced by the new decorations
127
+ const decorationsToRemove = decorationsToAdd.flatMap((deco) =>
128
+ nextDecorationSet.find(deco.from, deco.to),
129
+ );
130
+
131
+ return {
132
+ decorations: nextDecorationSet
133
+ // Remove existing decorations that are going to be replaced
134
+ .remove(decorationsToRemove)
135
+ // Add any new decorations
136
+ .add(tr.doc, decorationsToAdd),
137
+ };
138
+ }
139
+
140
+ /**
141
+ * This plugin adds decorations to numbered list items to display their index.
142
+ */
143
+ export const NumberedListIndexingDecorationPlugin = () => {
144
+ return new Plugin<{ decorations: DecorationSet }>({
145
+ key: new PluginKey("numbered-list-indexing-decorations"),
146
+
147
+ state: {
148
+ init(_config, state) {
149
+ // We create an empty transaction to get the decorations for the initial state based on the initial content
150
+ return getDecorations(state.tr, {
151
+ decorations: DecorationSet.empty,
152
+ });
153
+ },
154
+ apply(tr, previousPluginState) {
155
+ if (
156
+ !tr.docChanged &&
157
+ !tr.selectionSet &&
158
+ previousPluginState.decorations
159
+ ) {
160
+ // Just reuse the existing decorations, since nothing should have changed
161
+ return previousPluginState;
162
+ }
163
+ return getDecorations(tr, previousPluginState);
164
+ },
165
+ },
166
+
167
+ props: {
168
+ decorations(state) {
169
+ return this.getState(state)?.decorations ?? DecorationSet.empty;
170
+ },
171
+ },
172
+ });
173
+ };
@@ -0,0 +1,133 @@
1
+ import { createBlockNoteExtension } from "../../../editor/BlockNoteExtension.js";
2
+ import { createBlockConfig, createBlockSpec } from "../../../schema/index.js";
3
+ import {
4
+ addDefaultPropsExternalHTML,
5
+ defaultProps,
6
+ parseDefaultProps,
7
+ } from "../../defaultProps.js";
8
+ import { handleEnter } from "../../utils/listItemEnterHandler.js";
9
+ import { getListItemContent } from "../getListItemContent.js";
10
+ import { NumberedListIndexingDecorationPlugin } from "./IndexingPlugin.js";
11
+
12
+ export type NumberedListItemBlockConfig = ReturnType<
13
+ typeof createNumberedListItemBlockConfig
14
+ >;
15
+
16
+ export const createNumberedListItemBlockConfig = createBlockConfig(
17
+ () =>
18
+ ({
19
+ type: "numberedListItem" as const,
20
+ propSchema: {
21
+ ...defaultProps,
22
+ start: { default: undefined, type: "number" } as const,
23
+ },
24
+ content: "inline",
25
+ }) as const,
26
+ );
27
+
28
+ export const createNumberedListItemBlockSpec = createBlockSpec(
29
+ createNumberedListItemBlockConfig,
30
+ {
31
+ meta: {
32
+ isolating: false,
33
+ },
34
+ parse(element) {
35
+ if (element.tagName !== "LI") {
36
+ return undefined;
37
+ }
38
+
39
+ const parent = element.parentElement;
40
+
41
+ if (parent === null) {
42
+ return undefined;
43
+ }
44
+
45
+ if (
46
+ parent.tagName === "OL" ||
47
+ (parent.tagName === "DIV" && parent.parentElement?.tagName === "OL")
48
+ ) {
49
+ const startIndex = parseInt(parent.getAttribute("start") || "1");
50
+
51
+ const defaultProps = parseDefaultProps(element);
52
+
53
+ if (element.previousElementSibling || startIndex === 1) {
54
+ return defaultProps;
55
+ }
56
+
57
+ return {
58
+ ...defaultProps,
59
+ start: startIndex,
60
+ };
61
+ }
62
+
63
+ return undefined;
64
+ },
65
+ // As `li` elements can contain multiple paragraphs, we need to merge their contents
66
+ // into a single one so that ProseMirror can parse everything correctly.
67
+ parseContent: ({ el, schema }) =>
68
+ getListItemContent(el, schema, "numberedListItem"),
69
+ render() {
70
+ // We use a <p> tag, because for <li> tags we'd need a <ul> element to put
71
+ // them in to be semantically correct, which we can't have due to the
72
+ // schema.
73
+ const dom = document.createElement("p");
74
+
75
+ return {
76
+ dom,
77
+ contentDOM: dom,
78
+ };
79
+ },
80
+ toExternalHTML(block) {
81
+ const li = document.createElement("li");
82
+ const p = document.createElement("p");
83
+ addDefaultPropsExternalHTML(block.props, li);
84
+ li.appendChild(p);
85
+
86
+ return {
87
+ dom: li,
88
+ contentDOM: p,
89
+ };
90
+ },
91
+ },
92
+ [
93
+ createBlockNoteExtension({
94
+ key: "numbered-list-item-shortcuts",
95
+ inputRules: [
96
+ {
97
+ find: new RegExp(`^(\\d+)\\.\\s$`),
98
+ replace({ match }) {
99
+ const start = parseInt(match[1]);
100
+ return {
101
+ type: "numberedListItem",
102
+ props: {
103
+ start: start !== 1 ? start : undefined,
104
+ },
105
+ };
106
+ },
107
+ },
108
+ ],
109
+ keyboardShortcuts: {
110
+ Enter: ({ editor }) => {
111
+ return handleEnter(editor, "numberedListItem");
112
+ },
113
+ "Mod-Shift-7": ({ editor }) => {
114
+ const cursorPosition = editor.getTextCursorPosition();
115
+
116
+ if (
117
+ editor.schema.blockSchema[cursorPosition.block.type].content !==
118
+ "inline"
119
+ ) {
120
+ return false;
121
+ }
122
+
123
+ editor.updateBlock(cursorPosition.block, {
124
+ type: "numberedListItem",
125
+ props: {},
126
+ });
127
+ return true;
128
+ },
129
+ },
130
+ plugins: [NumberedListIndexingDecorationPlugin()],
131
+ }),
132
+ ],
133
+ );
@@ -0,0 +1,78 @@
1
+ import { createBlockNoteExtension } from "../../../editor/BlockNoteExtension.js";
2
+ import { createBlockConfig, createBlockSpec } from "../../../schema/index.js";
3
+ import {
4
+ addDefaultPropsExternalHTML,
5
+ defaultProps,
6
+ } from "../../defaultProps.js";
7
+ import { createToggleWrapper } from "../../ToggleWrapper/createToggleWrapper.js";
8
+ import { handleEnter } from "../../utils/listItemEnterHandler.js";
9
+
10
+ export type ToggleListItemBlockConfig = ReturnType<
11
+ typeof createToggleListItemBlockConfig
12
+ >;
13
+
14
+ export const createToggleListItemBlockConfig = createBlockConfig(
15
+ () =>
16
+ ({
17
+ type: "toggleListItem" as const,
18
+ propSchema: {
19
+ ...defaultProps,
20
+ },
21
+ content: "inline" as const,
22
+ }) as const,
23
+ );
24
+
25
+ export const createToggleListItemBlockSpec = createBlockSpec(
26
+ createToggleListItemBlockConfig,
27
+ {
28
+ meta: {
29
+ isolating: false,
30
+ },
31
+ render(block, editor) {
32
+ const paragraphEl = document.createElement("p");
33
+ const toggleWrapper = createToggleWrapper(
34
+ block as any,
35
+ editor,
36
+ paragraphEl,
37
+ );
38
+ return { ...toggleWrapper, contentDOM: paragraphEl };
39
+ },
40
+ toExternalHTML(block) {
41
+ const li = document.createElement("li");
42
+ const p = document.createElement("p");
43
+ addDefaultPropsExternalHTML(block.props, li);
44
+ li.appendChild(p);
45
+
46
+ return {
47
+ dom: li,
48
+ contentDOM: p,
49
+ };
50
+ },
51
+ },
52
+ [
53
+ createBlockNoteExtension({
54
+ key: "toggle-list-item-shortcuts",
55
+ keyboardShortcuts: {
56
+ Enter: ({ editor }) => {
57
+ return handleEnter(editor, "toggleListItem");
58
+ },
59
+ "Mod-Shift-6": ({ editor }) => {
60
+ const cursorPosition = editor.getTextCursorPosition();
61
+
62
+ if (
63
+ editor.schema.blockSchema[cursorPosition.block.type].content !==
64
+ "inline"
65
+ ) {
66
+ return false;
67
+ }
68
+
69
+ editor.updateBlock(cursorPosition.block, {
70
+ type: "toggleListItem",
71
+ props: {},
72
+ });
73
+ return true;
74
+ },
75
+ },
76
+ }),
77
+ ],
78
+ );
@@ -0,0 +1,72 @@
1
+ import {
2
+ BlockSchema,
3
+ createBlockConfig,
4
+ createBlockSpec,
5
+ InlineContentSchema,
6
+ StyleSchema,
7
+ } from "../../schema/index.js";
8
+ import { BlockNoteSchema } from "../BlockNoteSchema.js";
9
+
10
+ export type PageBreakBlockConfig = ReturnType<
11
+ typeof createPageBreakBlockConfig
12
+ >;
13
+
14
+ export const createPageBreakBlockConfig = createBlockConfig(
15
+ () =>
16
+ ({
17
+ type: "pageBreak" as const,
18
+ propSchema: {},
19
+ content: "none",
20
+ }) as const,
21
+ );
22
+
23
+ export const createPageBreakBlockSpec = createBlockSpec(
24
+ createPageBreakBlockConfig,
25
+ {
26
+ parse(element) {
27
+ if (
28
+ element.tagName === "DIV" &&
29
+ element.hasAttribute("data-page-break")
30
+ ) {
31
+ return {};
32
+ }
33
+
34
+ return undefined;
35
+ },
36
+ render() {
37
+ const pageBreak = document.createElement("div");
38
+
39
+ pageBreak.setAttribute("data-page-break", "");
40
+
41
+ return {
42
+ dom: pageBreak,
43
+ };
44
+ },
45
+ toExternalHTML() {
46
+ const pageBreak = document.createElement("div");
47
+
48
+ pageBreak.setAttribute("data-page-break", "");
49
+
50
+ return {
51
+ dom: pageBreak,
52
+ };
53
+ },
54
+ },
55
+ );
56
+
57
+ /**
58
+ * Adds page break support to the given schema.
59
+ */
60
+ export const withPageBreak = <
61
+ B extends BlockSchema,
62
+ I extends InlineContentSchema,
63
+ S extends StyleSchema,
64
+ >(
65
+ schema: BlockNoteSchema<B, I, S>,
66
+ ) => {
67
+ return schema.extend({
68
+ blockSpecs: {
69
+ pageBreak: createPageBreakBlockSpec(),
70
+ },
71
+ });
72
+ };
@@ -6,19 +6,21 @@ import {
6
6
  InlineContentSchema,
7
7
  StyleSchema,
8
8
  } from "../../schema/index.js";
9
- import { pageBreakSchema } from "./schema.js";
9
+ import { createPageBreakBlockConfig } from "./block.js";
10
10
 
11
11
  export function checkPageBreakBlocksInSchema<
12
12
  I extends InlineContentSchema,
13
13
  S extends StyleSchema,
14
14
  >(
15
15
  editor: BlockNoteEditor<any, I, S>,
16
- ): editor is BlockNoteEditor<typeof pageBreakSchema.blockSchema, I, S> {
17
- return (
18
- "pageBreak" in editor.schema.blockSchema &&
19
- editor.schema.blockSchema["pageBreak"] ===
20
- pageBreakSchema.blockSchema["pageBreak"]
21
- );
16
+ ): editor is BlockNoteEditor<
17
+ {
18
+ pageBreak: ReturnType<typeof createPageBreakBlockConfig>;
19
+ },
20
+ I,
21
+ S
22
+ > {
23
+ return "pageBreak" in editor.schema.blockSchema;
22
24
  }
23
25
 
24
26
  export function getPageBreakSlashMenuItems<
@@ -0,0 +1,80 @@
1
+ import { createBlockNoteExtension } from "../../editor/BlockNoteExtension.js";
2
+ import { createBlockConfig, createBlockSpec } from "../../schema/index.js";
3
+ import {
4
+ addDefaultPropsExternalHTML,
5
+ defaultProps,
6
+ parseDefaultProps,
7
+ } from "../defaultProps.js";
8
+
9
+ export type ParagraphBlockConfig = ReturnType<
10
+ typeof createParagraphBlockConfig
11
+ >;
12
+
13
+ export const createParagraphBlockConfig = createBlockConfig(
14
+ () =>
15
+ ({
16
+ type: "paragraph" as const,
17
+ propSchema: defaultProps,
18
+ content: "inline" as const,
19
+ }) as const,
20
+ );
21
+
22
+ export const createParagraphBlockSpec = createBlockSpec(
23
+ createParagraphBlockConfig,
24
+ {
25
+ meta: {
26
+ isolating: false,
27
+ },
28
+ parse: (e) => {
29
+ if (e.tagName !== "P") {
30
+ return undefined;
31
+ }
32
+
33
+ // Edge case for things like images directly inside paragraph.
34
+ if (!e.textContent?.trim()) {
35
+ return undefined;
36
+ }
37
+
38
+ return parseDefaultProps(e);
39
+ },
40
+ render: () => {
41
+ const dom = document.createElement("p");
42
+ return {
43
+ dom,
44
+ contentDOM: dom,
45
+ };
46
+ },
47
+ toExternalHTML: (block) => {
48
+ const dom = document.createElement("p");
49
+ addDefaultPropsExternalHTML(block.props, dom);
50
+ return {
51
+ dom,
52
+ contentDOM: dom,
53
+ };
54
+ },
55
+ runsBefore: ["default"],
56
+ },
57
+ [
58
+ createBlockNoteExtension({
59
+ key: "paragraph-shortcuts",
60
+ keyboardShortcuts: {
61
+ "Mod-Alt-0": ({ editor }) => {
62
+ const cursorPosition = editor.getTextCursorPosition();
63
+
64
+ if (
65
+ editor.schema.blockSchema[cursorPosition.block.type].content !==
66
+ "inline"
67
+ ) {
68
+ return false;
69
+ }
70
+
71
+ editor.updateBlock(cursorPosition.block, {
72
+ type: "paragraph",
73
+ props: {},
74
+ });
75
+ return true;
76
+ },
77
+ },
78
+ }),
79
+ ],
80
+ );
@@ -0,0 +1,90 @@
1
+ import { createBlockNoteExtension } from "../../editor/BlockNoteExtension.js";
2
+ import { createBlockConfig, createBlockSpec } from "../../schema/index.js";
3
+ import {
4
+ addDefaultPropsExternalHTML,
5
+ defaultProps,
6
+ parseDefaultProps,
7
+ } from "../defaultProps.js";
8
+
9
+ export type QuoteBlockConfig = ReturnType<typeof createQuoteBlockConfig>;
10
+
11
+ export const createQuoteBlockConfig = createBlockConfig(
12
+ () =>
13
+ ({
14
+ type: "quote" as const,
15
+ propSchema: {
16
+ backgroundColor: defaultProps.backgroundColor,
17
+ textColor: defaultProps.textColor,
18
+ },
19
+ content: "inline" as const,
20
+ }) as const,
21
+ );
22
+
23
+ export const createQuoteBlockSpec = createBlockSpec(
24
+ createQuoteBlockConfig,
25
+ {
26
+ meta: {
27
+ isolating: false,
28
+ },
29
+ parse(element) {
30
+ if (element.tagName === "BLOCKQUOTE") {
31
+ const { backgroundColor, textColor } = parseDefaultProps(element);
32
+
33
+ return { backgroundColor, textColor };
34
+ }
35
+
36
+ return undefined;
37
+ },
38
+ render() {
39
+ const quote = document.createElement("blockquote");
40
+
41
+ return {
42
+ dom: quote,
43
+ contentDOM: quote,
44
+ };
45
+ },
46
+ toExternalHTML(block) {
47
+ const quote = document.createElement("blockquote");
48
+ addDefaultPropsExternalHTML(block.props, quote);
49
+
50
+ return {
51
+ dom: quote,
52
+ contentDOM: quote,
53
+ };
54
+ },
55
+ },
56
+ [
57
+ createBlockNoteExtension({
58
+ key: "quote-block-shortcuts",
59
+ keyboardShortcuts: {
60
+ "Mod-Alt-q": ({ editor }) => {
61
+ const cursorPosition = editor.getTextCursorPosition();
62
+
63
+ if (
64
+ editor.schema.blockSchema[cursorPosition.block.type].content !==
65
+ "inline"
66
+ ) {
67
+ return false;
68
+ }
69
+
70
+ editor.updateBlock(cursorPosition.block, {
71
+ type: "quote",
72
+ props: {},
73
+ });
74
+ return true;
75
+ },
76
+ },
77
+ inputRules: [
78
+ {
79
+ find: new RegExp(`^>\\s$`),
80
+ replace() {
81
+ return {
82
+ type: "quote",
83
+ props: {},
84
+ };
85
+ },
86
+ },
87
+ ],
88
+ }),
89
+ ],
90
+ );