@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
@@ -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
+ );