@blocknote/core 0.4.6-alpha.4 → 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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://github.com/TypeCellOS/BlockNote",
4
4
  "private": false,
5
5
  "license": "MPL-2.0",
6
- "version": "0.4.6-alpha.4",
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": "4ec9f17bdaa504a53eb080909e0e6c22ba071b61"
112
+ "gitHead": "31e2f4516ba88cb1a6439fbf464f8bcab5dffd1b"
113
113
  }
@@ -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) => void,
214
+ callback: (block: Block) => boolean,
163
215
  reverse: boolean = false
164
216
  ): void {
165
- function helper(blocks: Block[]) {
166
- if (reverse) {
167
- for (const block of blocks.reverse()) {
168
- helper(block.children);
169
- callback(block);
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
- } else {
172
- for (const block of blocks) {
173
- callback(block);
174
- helper(block.children);
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
- helper(this.topLevelBlocks);
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: Block, update: PartialBlock) {
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: Block[]) {
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: Block[],
358
+ blocksToRemove: BlockIdentifier[],
297
359
  blocksToInsert: PartialBlock[]
298
360
  ) {
299
361
  replaceBlocks(blocksToRemove, blocksToInsert, this._tiptapEditor);
@@ -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
- .bnEditor,
29
- .dragPreview {
30
- /* Define a set of colors to be used throughout the app for consistency
31
- see https://atlassian.design/foundations/color for more info */
32
- --N800: #172b4d; /* Dark neutral used for tooltips and text on light background */
33
- --N40: #dfe1e6; /* Light neutral used for subtle borders and text on dark background */
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: all 0.2s;
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
  */
@@ -158,8 +158,26 @@ function setDragImage(view: EditorView, from: number, to = from) {
158
158
  // dataTransfer.setDragImage(element) only works if element is attached to the DOM.
159
159
  unsetDragImage();
160
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
+
161
174
  dragImageElement.className =
162
- dragImageElement.className + " " + styles.dragPreview;
175
+ dragImageElement.className +
176
+ " " +
177
+ styles.dragPreview +
178
+ " " +
179
+ inheritedClasses;
180
+
163
181
  document.body.appendChild(dragImageElement);
164
182
  }
165
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) => void, reverse?: boolean): void;
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: Block, update: PartialBlock): void;
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: Block[]): void;
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: Block[], blocksToInsert: PartialBlock[]): void;
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.