@blocknote/core 0.29.0 → 0.30.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.
- package/README.md +125 -0
- package/dist/blocknote.cjs +9 -9
- package/dist/blocknote.cjs.map +1 -1
- package/dist/blocknote.js +1479 -1339
- package/dist/blocknote.js.map +1 -1
- package/dist/locales.cjs +1 -1
- package/dist/locales.cjs.map +1 -1
- package/dist/locales.js +751 -9
- package/dist/locales.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/webpack-stats.json +1 -1
- package/package.json +3 -6
- package/src/api/blockManipulation/commands/insertBlocks/__snapshots__/insertBlocks.test.ts.snap +0 -7
- package/src/api/blockManipulation/commands/mergeBlocks/__snapshots__/mergeBlocks.test.ts.snap +0 -5
- package/src/api/blockManipulation/commands/moveBlocks/__snapshots__/moveBlocks.test.ts.snap +0 -20
- package/src/api/blockManipulation/commands/replaceBlocks/__snapshots__/replaceBlocks.test.ts.snap +0 -12
- package/src/api/blockManipulation/commands/splitBlock/__snapshots__/splitBlock.test.ts.snap +0 -6
- package/src/api/blockManipulation/commands/updateBlock/__snapshots__/updateBlock.test.ts.snap +0 -17
- package/src/api/clipboard/fromClipboard/pasteExtension.ts +19 -1
- package/src/blocks/AudioBlockContent/AudioBlockContent.ts +5 -0
- package/src/blocks/CodeBlockContent/CodeBlockContent.ts +32 -18
- package/src/blocks/FileBlockContent/FileBlockContent.ts +5 -0
- package/src/blocks/FileBlockContent/helpers/render/createResizableFileBlockWrapper.ts +9 -2
- package/src/blocks/HeadingBlockContent/HeadingBlockContent.ts +3 -0
- package/src/blocks/ImageBlockContent/ImageBlockContent.ts +10 -2
- package/src/blocks/ListItemBlockContent/BulletListItemBlockContent/BulletListItemBlockContent.ts +9 -25
- package/src/blocks/ListItemBlockContent/CheckListItemBlockContent/CheckListItemBlockContent.ts +14 -3
- package/src/blocks/ListItemBlockContent/NumberedListItemBlockContent/NumberedListItemBlockContent.ts +9 -26
- package/src/blocks/ListItemBlockContent/getListItemContent.ts +115 -0
- package/src/blocks/ParagraphBlockContent/ParagraphBlockContent.ts +6 -2
- package/src/blocks/QuoteBlockContent/QuoteBlockContent.ts +6 -1
- package/src/blocks/TableBlockContent/TableBlockContent.ts +71 -14
- package/src/blocks/VideoBlockContent/VideoBlockContent.ts +10 -2
- package/src/blocks/defaultBlockHelpers.ts +16 -0
- package/src/editor/Block.css +2 -1
- package/src/editor/BlockNoteEditor.ts +103 -60
- package/src/editor/BlockNoteExtensions.ts +14 -5
- package/src/extensions/Collaboration/CursorPlugin.ts +152 -0
- package/src/extensions/Collaboration/SyncPlugin.ts +15 -0
- package/src/extensions/Collaboration/UndoPlugin.ts +14 -0
- package/src/extensions/FilePanel/FilePanelPlugin.ts +31 -22
- package/src/extensions/FormattingToolbar/FormattingToolbarPlugin.ts +2 -4
- package/src/extensions/KeyboardShortcuts/KeyboardShortcutsExtension.ts +3 -0
- package/src/i18n/locales/index.ts +2 -0
- package/src/i18n/locales/ru.ts +2 -2
- package/src/i18n/locales/sk.ts +355 -0
- package/src/i18n/locales/zh-tw.ts +390 -0
- package/src/pm-nodes/BlockContainer.ts +7 -6
- package/src/schema/blocks/createSpec.ts +1 -1
- package/src/schema/blocks/internal.ts +0 -1
- package/src/schema/blocks/types.ts +2 -1
- package/types/src/api/blockManipulation/setupTestEnv.d.ts +8 -4
- package/types/src/blocks/ImageBlockContent/ImageBlockContent.d.ts +8 -4
- package/types/src/blocks/ListItemBlockContent/getListItemContent.d.ts +28 -0
- package/types/src/blocks/VideoBlockContent/VideoBlockContent.d.ts +8 -4
- package/types/src/blocks/defaultBlockHelpers.d.ts +1 -0
- package/types/src/blocks/defaultBlocks.d.ts +16 -8
- package/types/src/editor/BlockNoteEditor.d.ts +18 -1
- package/types/src/extensions/Collaboration/CursorPlugin.d.ts +31 -0
- package/types/src/extensions/Collaboration/SyncPlugin.d.ts +7 -0
- package/types/src/extensions/Collaboration/UndoPlugin.d.ts +6 -0
- package/types/src/extensions/FilePanel/FilePanelPlugin.d.ts +1 -1
- package/types/src/i18n/locales/index.d.ts +2 -0
- package/types/src/i18n/locales/sk.d.ts +313 -0
- package/types/src/i18n/locales/zh-tw.d.ts +2 -0
- package/types/src/schema/blocks/types.d.ts +2 -1
- package/src/extensions/Collaboration/createCollaborationExtensions.ts +0 -147
- package/types/src/extensions/Collaboration/createCollaborationExtensions.d.ts +0 -17
|
@@ -39,10 +39,14 @@ export const ParagraphBlockContent = createStronglyTypedTiptapNode({
|
|
|
39
39
|
|
|
40
40
|
parseHTML() {
|
|
41
41
|
return [
|
|
42
|
-
|
|
42
|
+
// Parse from internal HTML.
|
|
43
|
+
{
|
|
44
|
+
tag: "div[data-content-type=" + this.name + "]",
|
|
45
|
+
contentElement: ".bn-inline-content",
|
|
46
|
+
},
|
|
47
|
+
// Parse from external HTML.
|
|
43
48
|
{
|
|
44
49
|
tag: "p",
|
|
45
|
-
priority: 200,
|
|
46
50
|
getAttrs: (element) => {
|
|
47
51
|
if (typeof element === "string" || !element.textContent?.trim()) {
|
|
48
52
|
return false;
|
|
@@ -67,7 +67,12 @@ export const QuoteBlockContent = createStronglyTypedTiptapNode({
|
|
|
67
67
|
|
|
68
68
|
parseHTML() {
|
|
69
69
|
return [
|
|
70
|
-
|
|
70
|
+
// Parse from internal HTML.
|
|
71
|
+
{
|
|
72
|
+
tag: "div[data-content-type=" + this.name + "]",
|
|
73
|
+
contentElement: ".bn-inline-content",
|
|
74
|
+
},
|
|
75
|
+
// Parse from external HTML.
|
|
71
76
|
{
|
|
72
77
|
tag: "blockquote",
|
|
73
78
|
node: "quote",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TableCell } from "@tiptap/extension-table-cell";
|
|
2
2
|
import { TableHeader } from "@tiptap/extension-table-header";
|
|
3
3
|
import { TableRow } from "@tiptap/extension-table-row";
|
|
4
|
-
import { Node as PMNode } from "prosemirror-model";
|
|
4
|
+
import { DOMParser, Fragment, Node as PMNode, Schema } from "prosemirror-model";
|
|
5
5
|
import { TableView } from "prosemirror-tables";
|
|
6
6
|
|
|
7
7
|
import { NodeView } from "prosemirror-view";
|
|
@@ -27,7 +27,11 @@ export const TableBlockContent = createStronglyTypedTiptapNode({
|
|
|
27
27
|
isolating: true,
|
|
28
28
|
|
|
29
29
|
parseHTML() {
|
|
30
|
-
return [
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
tag: "table",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
31
35
|
},
|
|
32
36
|
|
|
33
37
|
renderHTML({ HTMLAttributes }) {
|
|
@@ -113,17 +117,6 @@ const TableParagraph = createStronglyTypedTiptapNode({
|
|
|
113
117
|
|
|
114
118
|
parseHTML() {
|
|
115
119
|
return [
|
|
116
|
-
{
|
|
117
|
-
preserveWhitespace: "full",
|
|
118
|
-
// set this rule as high priority so it takes precedence over the default paragraph rule,
|
|
119
|
-
// but only if we're in the tableContent context
|
|
120
|
-
priority: 210,
|
|
121
|
-
context: "tableContent",
|
|
122
|
-
tag: "p",
|
|
123
|
-
getAttrs: (_element) => {
|
|
124
|
-
return {};
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
120
|
{
|
|
128
121
|
tag: "p",
|
|
129
122
|
getAttrs: (element) => {
|
|
@@ -131,18 +124,24 @@ const TableParagraph = createStronglyTypedTiptapNode({
|
|
|
131
124
|
return false;
|
|
132
125
|
}
|
|
133
126
|
|
|
127
|
+
// Only parse in internal HTML.
|
|
128
|
+
if (!element.closest("[data-content-type]")) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
|
|
134
132
|
const parent = element.parentElement;
|
|
135
133
|
|
|
136
134
|
if (parent === null) {
|
|
137
135
|
return false;
|
|
138
136
|
}
|
|
139
137
|
|
|
140
|
-
if (parent.tagName === "TD") {
|
|
138
|
+
if (parent.tagName === "TD" || parent.tagName === "TH") {
|
|
141
139
|
return {};
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
return false;
|
|
145
143
|
},
|
|
144
|
+
node: "tableParagraph",
|
|
146
145
|
},
|
|
147
146
|
];
|
|
148
147
|
},
|
|
@@ -152,6 +151,42 @@ const TableParagraph = createStronglyTypedTiptapNode({
|
|
|
152
151
|
},
|
|
153
152
|
});
|
|
154
153
|
|
|
154
|
+
/**
|
|
155
|
+
* This will flatten a node's content to fit into a table cell's paragraph.
|
|
156
|
+
*/
|
|
157
|
+
function parseTableContent(node: HTMLElement, schema: Schema) {
|
|
158
|
+
const parser = DOMParser.fromSchema(schema);
|
|
159
|
+
|
|
160
|
+
// This will parse the content of the table paragraph as though it were a blockGroup.
|
|
161
|
+
// Resulting in a structure like:
|
|
162
|
+
// <blockGroup>
|
|
163
|
+
// <blockContainer>
|
|
164
|
+
// <p>Hello</p>
|
|
165
|
+
// </blockContainer>
|
|
166
|
+
// <blockContainer>
|
|
167
|
+
// <p>Hello</p>
|
|
168
|
+
// </blockContainer>
|
|
169
|
+
// </blockGroup>
|
|
170
|
+
const parsedContent = parser.parse(node, {
|
|
171
|
+
topNode: schema.nodes.blockGroup.create(),
|
|
172
|
+
});
|
|
173
|
+
const extractedContent: PMNode[] = [];
|
|
174
|
+
|
|
175
|
+
// Try to extract any content within the blockContainer.
|
|
176
|
+
parsedContent.content.descendants((child) => {
|
|
177
|
+
// As long as the child is an inline node, we can append it to the fragment.
|
|
178
|
+
if (child.isInline) {
|
|
179
|
+
// And append it to the fragment
|
|
180
|
+
extractedContent.push(child);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return undefined;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return Fragment.fromArray(extractedContent);
|
|
188
|
+
}
|
|
189
|
+
|
|
155
190
|
export const Table = createBlockSpecFromStronglyTypedTiptapNode(
|
|
156
191
|
TableBlockContent,
|
|
157
192
|
tablePropSchema,
|
|
@@ -167,9 +202,31 @@ export const Table = createBlockSpecFromStronglyTypedTiptapNode(
|
|
|
167
202
|
* So, we manually fix this up when reading back in the `nodeToBlock` and only ever place a single tableContent back into the cell.
|
|
168
203
|
*/
|
|
169
204
|
content: "tableContent+",
|
|
205
|
+
parseHTML() {
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
tag: "th",
|
|
209
|
+
// As `th` elements can contain multiple paragraphs, we need to merge their contents
|
|
210
|
+
// into a single one so that ProseMirror can parse everything correctly.
|
|
211
|
+
getContent: (node, schema) =>
|
|
212
|
+
parseTableContent(node as HTMLElement, schema),
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
},
|
|
170
216
|
}),
|
|
171
217
|
TableCell.extend({
|
|
172
218
|
content: "tableContent+",
|
|
219
|
+
parseHTML() {
|
|
220
|
+
return [
|
|
221
|
+
{
|
|
222
|
+
tag: "td",
|
|
223
|
+
// As `td` elements can contain multiple paragraphs, we need to merge their contents
|
|
224
|
+
// into a single one so that ProseMirror can parse everything correctly.
|
|
225
|
+
getContent: (node, schema) =>
|
|
226
|
+
parseTableContent(node as HTMLElement, schema),
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
},
|
|
173
230
|
}),
|
|
174
231
|
TableRow,
|
|
175
232
|
]
|
|
@@ -37,7 +37,8 @@ export const videoPropSchema = {
|
|
|
37
37
|
},
|
|
38
38
|
// File preview width in px.
|
|
39
39
|
previewWidth: {
|
|
40
|
-
default:
|
|
40
|
+
default: undefined,
|
|
41
|
+
type: "number",
|
|
41
42
|
},
|
|
42
43
|
} satisfies PropSchema;
|
|
43
44
|
|
|
@@ -88,6 +89,11 @@ export const videoParse = (
|
|
|
88
89
|
element: HTMLElement
|
|
89
90
|
): Partial<Props<typeof videoBlockConfig.propSchema>> | undefined => {
|
|
90
91
|
if (element.tagName === "VIDEO") {
|
|
92
|
+
// Ignore if parent figure has already been parsed.
|
|
93
|
+
if (element.closest("figure")) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
91
97
|
return parseVideoElement(element as HTMLVideoElement);
|
|
92
98
|
}
|
|
93
99
|
|
|
@@ -124,7 +130,9 @@ export const videoToExternalHTML = (
|
|
|
124
130
|
if (block.props.showPreview) {
|
|
125
131
|
video = document.createElement("video");
|
|
126
132
|
video.src = block.props.url;
|
|
127
|
-
|
|
133
|
+
if (block.props.previewWidth) {
|
|
134
|
+
video.width = block.props.previewWidth;
|
|
135
|
+
}
|
|
128
136
|
} else {
|
|
129
137
|
video = document.createElement("a");
|
|
130
138
|
video.href = block.props.url;
|
|
@@ -95,3 +95,19 @@ export const defaultBlockToHTML = <
|
|
|
95
95
|
contentDOM?: HTMLElement;
|
|
96
96
|
};
|
|
97
97
|
};
|
|
98
|
+
|
|
99
|
+
// Function that merges all paragraphs into a single one separated by line breaks.
|
|
100
|
+
// This is used when parsing blocks like list items and table cells, as they may
|
|
101
|
+
// contain multiple paragraphs that ProseMirror will not be able to handle
|
|
102
|
+
// properly.
|
|
103
|
+
export function mergeParagraphs(element: HTMLElement) {
|
|
104
|
+
const paragraphs = element.querySelectorAll("p");
|
|
105
|
+
if (paragraphs.length > 1) {
|
|
106
|
+
const firstParagraph = paragraphs[0];
|
|
107
|
+
for (let i = 1; i < paragraphs.length; i++) {
|
|
108
|
+
const paragraph = paragraphs[i];
|
|
109
|
+
firstParagraph.innerHTML += "<br>" + paragraph.innerHTML;
|
|
110
|
+
paragraph.remove();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
package/src/editor/Block.css
CHANGED
|
@@ -14,7 +14,6 @@ BASIC STYLES
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.bn-block-content {
|
|
17
|
-
display: flex;
|
|
18
17
|
padding: 3px 0;
|
|
19
18
|
transition: font-size 0.2s;
|
|
20
19
|
width: 100%;
|
|
@@ -163,6 +162,7 @@ NESTED BLOCKS
|
|
|
163
162
|
.bn-block-content::before {
|
|
164
163
|
margin-right: 0;
|
|
165
164
|
content: "";
|
|
165
|
+
display: inline;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
/* Ordered */
|
|
@@ -411,6 +411,7 @@ NESTED BLOCKS
|
|
|
411
411
|
display: flex;
|
|
412
412
|
align-items: center;
|
|
413
413
|
position: relative;
|
|
414
|
+
max-width: 100%;
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
[data-file-block] .bn-visual-media {
|