@blocknote/core 0.4.6-alpha.3 → 0.5.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 +46 -34
- package/dist/blocknote.js +331 -308
- package/dist/blocknote.js.map +1 -1
- package/dist/blocknote.umd.cjs +2 -2
- package/dist/blocknote.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/BlockNoteEditor.ts +76 -14
- package/src/editor.module.css +19 -6
- package/src/extensions/Blocks/nodes/Block.module.css +1 -23
- package/src/extensions/DraggableBlocks/DraggableBlocksPlugin.ts +25 -1
- package/types/src/BlockNoteEditor.d.ts +38 -4
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocknote/core",
|
|
3
|
-
"homepage": "https://github.com/
|
|
3
|
+
"homepage": "https://github.com/TypeCellOS/BlockNote",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.5.0",
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
9
|
"types",
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"access": "public",
|
|
110
110
|
"registry": "https://registry.npmjs.org/"
|
|
111
111
|
},
|
|
112
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "31e2f4516ba88cb1a6439fbf464f8bcab5dffd1b"
|
|
113
113
|
}
|
package/src/BlockNoteEditor.ts
CHANGED
|
@@ -34,13 +34,49 @@ export type BlockNoteEditorOptions = {
|
|
|
34
34
|
// TODO: Figure out if enableBlockNoteExtensions/disableHistoryExtension are needed and document them.
|
|
35
35
|
enableBlockNoteExtensions: boolean;
|
|
36
36
|
disableHistoryExtension: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Factories used to create a custom UI for BlockNote
|
|
39
|
+
*/
|
|
37
40
|
uiFactories: UiFactories;
|
|
41
|
+
/**
|
|
42
|
+
* TODO: why is this called slashCommands and not slashMenuItems?
|
|
43
|
+
*
|
|
44
|
+
* @default defaultSlashMenuItems from `./extensions/SlashMenu`
|
|
45
|
+
*/
|
|
38
46
|
slashCommands: BaseSlashMenuItem[];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The HTML element that should be used as the parent element for the editor.
|
|
50
|
+
*
|
|
51
|
+
* @default: undefined, the editor is not attached to the DOM
|
|
52
|
+
*/
|
|
39
53
|
parentElement: HTMLElement;
|
|
54
|
+
/**
|
|
55
|
+
* An object containing attributes that should be added to the editor's HTML element.
|
|
56
|
+
*
|
|
57
|
+
* @example { class: "my-editor-class" }
|
|
58
|
+
*/
|
|
40
59
|
editorDOMAttributes: Record<string, string>;
|
|
60
|
+
/**
|
|
61
|
+
* A callback function that runs when the editor is ready to be used.
|
|
62
|
+
*/
|
|
41
63
|
onEditorReady: (editor: BlockNoteEditor) => void;
|
|
64
|
+
/**
|
|
65
|
+
* A callback function that runs whenever the editor's contents change.
|
|
66
|
+
*/
|
|
42
67
|
onEditorContentChange: (editor: BlockNoteEditor) => void;
|
|
68
|
+
/**
|
|
69
|
+
* A callback function that runs whenever the text cursor position changes.
|
|
70
|
+
*/
|
|
43
71
|
onTextCursorPositionChange: (editor: BlockNoteEditor) => void;
|
|
72
|
+
initialContent: PartialBlock[];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
|
|
76
|
+
*
|
|
77
|
+
* @default true
|
|
78
|
+
*/
|
|
79
|
+
defaultStyles: boolean;
|
|
44
80
|
|
|
45
81
|
// tiptap options, undocumented
|
|
46
82
|
_tiptapOptions: any;
|
|
@@ -61,6 +97,12 @@ export class BlockNoteEditor {
|
|
|
61
97
|
}
|
|
62
98
|
|
|
63
99
|
constructor(options: Partial<BlockNoteEditorOptions> = {}) {
|
|
100
|
+
// apply defaults
|
|
101
|
+
options = {
|
|
102
|
+
defaultStyles: true,
|
|
103
|
+
...options,
|
|
104
|
+
};
|
|
105
|
+
|
|
64
106
|
const blockNoteExtensions = getBlockNoteExtensions({
|
|
65
107
|
editor: this,
|
|
66
108
|
uiFactories: options.uiFactories || {},
|
|
@@ -72,10 +114,19 @@ export class BlockNoteEditor {
|
|
|
72
114
|
: blockNoteExtensions;
|
|
73
115
|
|
|
74
116
|
const tiptapOptions: EditorOptions = {
|
|
117
|
+
// TODO: This approach to setting initial content is "cleaner" but requires the PM editor schema, which is only
|
|
118
|
+
// created after initializing the TipTap editor. Not sure it's feasible.
|
|
119
|
+
// content:
|
|
120
|
+
// options.initialContent &&
|
|
121
|
+
// options.initialContent.map((block) =>
|
|
122
|
+
// blockToNode(block, this._tiptapEditor.schema).toJSON()
|
|
123
|
+
// ),
|
|
75
124
|
...blockNoteTipTapOptions,
|
|
76
125
|
...options._tiptapOptions,
|
|
77
126
|
onCreate: () => {
|
|
78
127
|
options.onEditorReady?.(this);
|
|
128
|
+
options.initialContent &&
|
|
129
|
+
this.replaceBlocks(this.topLevelBlocks, options.initialContent);
|
|
79
130
|
},
|
|
80
131
|
onUpdate: () => {
|
|
81
132
|
options.onEditorContentChange?.(this);
|
|
@@ -93,6 +144,7 @@ export class BlockNoteEditor {
|
|
|
93
144
|
class: [
|
|
94
145
|
styles.bnEditor,
|
|
95
146
|
styles.bnRoot,
|
|
147
|
+
options.defaultStyles ? styles.defaultStyles : "",
|
|
96
148
|
options.editorDOMAttributes?.class || "",
|
|
97
149
|
].join(" "),
|
|
98
150
|
},
|
|
@@ -159,24 +211,34 @@ export class BlockNoteEditor {
|
|
|
159
211
|
* @param reverse Whether the blocks should be traversed in reverse order.
|
|
160
212
|
*/
|
|
161
213
|
public forEachBlock(
|
|
162
|
-
callback: (block: Block) =>
|
|
214
|
+
callback: (block: Block) => boolean,
|
|
163
215
|
reverse: boolean = false
|
|
164
216
|
): void {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
217
|
+
const blocks = this.topLevelBlocks.slice();
|
|
218
|
+
|
|
219
|
+
if (reverse) {
|
|
220
|
+
blocks.reverse();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function traverseBlockArray(blockArray: Block[]): boolean {
|
|
224
|
+
for (const block of blockArray) {
|
|
225
|
+
if (callback(block) === false) {
|
|
226
|
+
return false;
|
|
170
227
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
228
|
+
|
|
229
|
+
const children = reverse
|
|
230
|
+
? block.children.slice().reverse()
|
|
231
|
+
: block.children;
|
|
232
|
+
|
|
233
|
+
if (traverseBlockArray(children) === false) {
|
|
234
|
+
return false;
|
|
175
235
|
}
|
|
176
236
|
}
|
|
237
|
+
|
|
238
|
+
return true;
|
|
177
239
|
}
|
|
178
240
|
|
|
179
|
-
|
|
241
|
+
traverseBlockArray(blocks);
|
|
180
242
|
}
|
|
181
243
|
|
|
182
244
|
/**
|
|
@@ -273,7 +335,7 @@ export class BlockNoteEditor {
|
|
|
273
335
|
* @param blockToUpdate The block that should be updated.
|
|
274
336
|
* @param update A partial block which defines how the existing block should be changed.
|
|
275
337
|
*/
|
|
276
|
-
public updateBlock(blockToUpdate:
|
|
338
|
+
public updateBlock(blockToUpdate: BlockIdentifier, update: PartialBlock) {
|
|
277
339
|
updateBlock(blockToUpdate, update, this._tiptapEditor);
|
|
278
340
|
}
|
|
279
341
|
|
|
@@ -281,7 +343,7 @@ export class BlockNoteEditor {
|
|
|
281
343
|
* Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.
|
|
282
344
|
* @param blocksToRemove An array of identifiers for existing blocks that should be removed.
|
|
283
345
|
*/
|
|
284
|
-
public removeBlocks(blocksToRemove:
|
|
346
|
+
public removeBlocks(blocksToRemove: BlockIdentifier[]) {
|
|
285
347
|
removeBlocks(blocksToRemove, this._tiptapEditor);
|
|
286
348
|
}
|
|
287
349
|
|
|
@@ -293,7 +355,7 @@ export class BlockNoteEditor {
|
|
|
293
355
|
* @param blocksToInsert An array of partial blocks to replace the old ones with.
|
|
294
356
|
*/
|
|
295
357
|
public replaceBlocks(
|
|
296
|
-
blocksToRemove:
|
|
358
|
+
blocksToRemove: BlockIdentifier[],
|
|
297
359
|
blocksToInsert: PartialBlock[]
|
|
298
360
|
) {
|
|
299
361
|
replaceBlocks(blocksToRemove, blocksToInsert, this._tiptapEditor);
|
package/src/editor.module.css
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
.bnEditor {
|
|
4
4
|
outline: none;
|
|
5
5
|
margin-left: 50px;
|
|
6
|
+
|
|
7
|
+
/* Define a set of colors to be used throughout the app for consistency
|
|
8
|
+
see https://atlassian.design/foundations/color for more info */
|
|
9
|
+
--N800: #172b4d; /* Dark neutral used for tooltips and text on light background */
|
|
10
|
+
--N40: #dfe1e6; /* Light neutral used for subtle borders and text on dark background */
|
|
6
11
|
}
|
|
7
12
|
|
|
8
13
|
/*
|
|
@@ -25,13 +30,21 @@ Tippy popups that are appended to document.body directly
|
|
|
25
30
|
box-sizing: inherit;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
/* reset styles, they will be set on blockContent */
|
|
34
|
+
.defaultStyles p,
|
|
35
|
+
.defaultStyles h1,
|
|
36
|
+
.defaultStyles h2,
|
|
37
|
+
.defaultStyles h3,
|
|
38
|
+
.defaultStyles li {
|
|
39
|
+
all: unset;
|
|
40
|
+
margin: 0;
|
|
41
|
+
padding: 0;
|
|
42
|
+
font-size: inherit;
|
|
43
|
+
}
|
|
34
44
|
|
|
45
|
+
.defaultStyles {
|
|
46
|
+
font-size: 16px;
|
|
47
|
+
font-weight: normal;
|
|
35
48
|
font-family: "Inter", "SF Pro Display", -apple-system, BlinkMacSystemFont,
|
|
36
49
|
"Open Sans", "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
|
|
37
50
|
"Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
@@ -3,21 +3,11 @@ BASIC STYLES
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
.blockOuter {
|
|
6
|
-
/* padding-bottom: 15px; */
|
|
7
|
-
font-size: 16px;
|
|
8
6
|
line-height: 1.5;
|
|
9
|
-
transition:
|
|
10
|
-
font-weight: normal;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
.block {
|
|
14
|
-
/* content: ""; */
|
|
15
|
-
transition: all 0.2s;
|
|
16
|
-
margin: 0px;
|
|
7
|
+
transition: margin 0.2s;
|
|
17
8
|
}
|
|
18
9
|
|
|
19
10
|
.blockContent {
|
|
20
|
-
font-size: 1em;
|
|
21
11
|
padding: 3px 0;
|
|
22
12
|
transition: font-size 0.2s;
|
|
23
13
|
/* display: inline-block; */
|
|
@@ -29,18 +19,6 @@ BASIC STYLES
|
|
|
29
19
|
/*margin: 0px;*/
|
|
30
20
|
}
|
|
31
21
|
|
|
32
|
-
/* reset styles, they will be set on blockContent */
|
|
33
|
-
.blockContent p,
|
|
34
|
-
.blockContent h1,
|
|
35
|
-
.blockContent h2,
|
|
36
|
-
.blockContent h3,
|
|
37
|
-
.blockContent li {
|
|
38
|
-
all: unset;
|
|
39
|
-
margin: 0;
|
|
40
|
-
padding: 0;
|
|
41
|
-
font-size: inherit;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
22
|
/*
|
|
45
23
|
NESTED BLOCKS
|
|
46
24
|
*/
|
|
@@ -38,6 +38,12 @@ function getDraggableBlockFromCoords(
|
|
|
38
38
|
coords: { left: number; top: number },
|
|
39
39
|
view: EditorView
|
|
40
40
|
) {
|
|
41
|
+
if (!view.dom.isConnected) {
|
|
42
|
+
// view is not connected to the DOM, this can cause posAtCoords to fail
|
|
43
|
+
// (Cannot read properties of null (reading 'nearestDesc'), https://github.com/TypeCellOS/BlockNote/issues/123)
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
let pos = view.posAtCoords(coords);
|
|
42
48
|
if (!pos) {
|
|
43
49
|
return undefined;
|
|
@@ -152,8 +158,26 @@ function setDragImage(view: EditorView, from: number, to = from) {
|
|
|
152
158
|
// dataTransfer.setDragImage(element) only works if element is attached to the DOM.
|
|
153
159
|
unsetDragImage();
|
|
154
160
|
dragImageElement = parentClone;
|
|
161
|
+
|
|
162
|
+
// TODO: This is hacky, need a better way of assigning classes to the editor so that they can also be applied to the
|
|
163
|
+
// drag preview.
|
|
164
|
+
const classes = view.dom.className.split(" ");
|
|
165
|
+
const inheritedClasses = classes
|
|
166
|
+
.filter(
|
|
167
|
+
(className) =>
|
|
168
|
+
!className.includes("bn") &&
|
|
169
|
+
!className.includes("ProseMirror") &&
|
|
170
|
+
!className.includes("editor")
|
|
171
|
+
)
|
|
172
|
+
.join(" ");
|
|
173
|
+
|
|
155
174
|
dragImageElement.className =
|
|
156
|
-
dragImageElement.className +
|
|
175
|
+
dragImageElement.className +
|
|
176
|
+
" " +
|
|
177
|
+
styles.dragPreview +
|
|
178
|
+
" " +
|
|
179
|
+
inheritedClasses;
|
|
180
|
+
|
|
157
181
|
document.body.appendChild(dragImageElement);
|
|
158
182
|
}
|
|
159
183
|
|
|
@@ -6,13 +6,47 @@ import { BaseSlashMenuItem } from "./extensions/SlashMenu";
|
|
|
6
6
|
export type BlockNoteEditorOptions = {
|
|
7
7
|
enableBlockNoteExtensions: boolean;
|
|
8
8
|
disableHistoryExtension: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Factories used to create a custom UI for BlockNote
|
|
11
|
+
*/
|
|
9
12
|
uiFactories: UiFactories;
|
|
13
|
+
/**
|
|
14
|
+
* TODO: why is this called slashCommands and not slashMenuItems?
|
|
15
|
+
*
|
|
16
|
+
* @default defaultSlashMenuItems from `./extensions/SlashMenu`
|
|
17
|
+
*/
|
|
10
18
|
slashCommands: BaseSlashMenuItem[];
|
|
19
|
+
/**
|
|
20
|
+
* The HTML element that should be used as the parent element for the editor.
|
|
21
|
+
*
|
|
22
|
+
* @default: undefined, the editor is not attached to the DOM
|
|
23
|
+
*/
|
|
11
24
|
parentElement: HTMLElement;
|
|
25
|
+
/**
|
|
26
|
+
* An object containing attributes that should be added to the editor's HTML element.
|
|
27
|
+
*
|
|
28
|
+
* @example { class: "my-editor-class" }
|
|
29
|
+
*/
|
|
12
30
|
editorDOMAttributes: Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* A callback function that runs when the editor is ready to be used.
|
|
33
|
+
*/
|
|
13
34
|
onEditorReady: (editor: BlockNoteEditor) => void;
|
|
35
|
+
/**
|
|
36
|
+
* A callback function that runs whenever the editor's contents change.
|
|
37
|
+
*/
|
|
14
38
|
onEditorContentChange: (editor: BlockNoteEditor) => void;
|
|
39
|
+
/**
|
|
40
|
+
* A callback function that runs whenever the text cursor position changes.
|
|
41
|
+
*/
|
|
15
42
|
onTextCursorPositionChange: (editor: BlockNoteEditor) => void;
|
|
43
|
+
initialContent: PartialBlock[];
|
|
44
|
+
/**
|
|
45
|
+
* Use default BlockNote font and reset the styles of <p> <li> <h1> elements etc., that are used in BlockNote.
|
|
46
|
+
*
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
defaultStyles: boolean;
|
|
16
50
|
_tiptapOptions: any;
|
|
17
51
|
};
|
|
18
52
|
export declare class BlockNoteEditor {
|
|
@@ -38,7 +72,7 @@ export declare class BlockNoteEditor {
|
|
|
38
72
|
* @param callback The callback to execute for each block. Returning `false` stops the traversal.
|
|
39
73
|
* @param reverse Whether the blocks should be traversed in reverse order.
|
|
40
74
|
*/
|
|
41
|
-
forEachBlock(callback: (block: Block) =>
|
|
75
|
+
forEachBlock(callback: (block: Block) => boolean, reverse?: boolean): void;
|
|
42
76
|
/**
|
|
43
77
|
* Gets a snapshot of the current text cursor position.
|
|
44
78
|
* @returns A snapshot of the current text cursor position.
|
|
@@ -67,12 +101,12 @@ export declare class BlockNoteEditor {
|
|
|
67
101
|
* @param blockToUpdate The block that should be updated.
|
|
68
102
|
* @param update A partial block which defines how the existing block should be changed.
|
|
69
103
|
*/
|
|
70
|
-
updateBlock(blockToUpdate:
|
|
104
|
+
updateBlock(blockToUpdate: BlockIdentifier, update: PartialBlock): void;
|
|
71
105
|
/**
|
|
72
106
|
* Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.
|
|
73
107
|
* @param blocksToRemove An array of identifiers for existing blocks that should be removed.
|
|
74
108
|
*/
|
|
75
|
-
removeBlocks(blocksToRemove:
|
|
109
|
+
removeBlocks(blocksToRemove: BlockIdentifier[]): void;
|
|
76
110
|
/**
|
|
77
111
|
* Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or
|
|
78
112
|
* are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in
|
|
@@ -80,7 +114,7 @@ export declare class BlockNoteEditor {
|
|
|
80
114
|
* @param blocksToRemove An array of blocks that should be replaced.
|
|
81
115
|
* @param blocksToInsert An array of partial blocks to replace the old ones with.
|
|
82
116
|
*/
|
|
83
|
-
replaceBlocks(blocksToRemove:
|
|
117
|
+
replaceBlocks(blocksToRemove: BlockIdentifier[], blocksToInsert: PartialBlock[]): void;
|
|
84
118
|
/**
|
|
85
119
|
* Serializes blocks into an HTML string. To better conform to HTML standards, children of blocks which aren't list
|
|
86
120
|
* items are un-nested in the output HTML.
|