Skip to content

Commit d4cd37a

Browse files
Docs Update (#116)
* Added new text cursor fields & functions docs * Made website and JS docs have same information + minor changes/fixes * More minor changes & fixes * More minor changes & fixes * Added block structure diagram * remove margin from editor (this is now built-in) * Added PR feedback and cleaned up links --------- Co-authored-by: yousefed <[email protected]>
1 parent e2a095d commit d4cd37a

File tree

12 files changed

+189
-118
lines changed

12 files changed

+189
-118
lines changed

packages/core/src/BlockNoteEditor.ts

Lines changed: 93 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { Editor, EditorOptions } from "@tiptap/core";
22
import { Node } from "prosemirror-model";
33
// import "./blocknote.css";
4-
import { Block, PartialBlock } from "./extensions/Blocks/api/blockTypes";
4+
import {
5+
Block,
6+
BlockIdentifier,
7+
PartialBlock,
8+
} from "./extensions/Blocks/api/blockTypes";
59
import { getBlockNoteExtensions, UiFactories } from "./BlockNoteExtensions";
610
import styles from "./editor.module.css";
711
import {
@@ -97,7 +101,8 @@ export class BlockNoteEditor {
97101
}
98102

99103
/**
100-
* Gets a list of all top-level blocks that are in the editor.
104+
* Gets a snapshot of all top-level (non-nested) blocks in the editor.
105+
* @returns A snapshot of all top-level (non-nested) blocks in the editor.
101106
*/
102107
public get topLevelBlocks(): Block[] {
103108
const blocks: Block[] = [];
@@ -112,12 +117,40 @@ export class BlockNoteEditor {
112117
}
113118

114119
/**
115-
* Traverses all blocks in the editor, including all nested blocks, and executes a callback for each. The traversal is
116-
* depth-first, which is the same order as blocks appear in the editor by y-coordinate.
117-
* @param callback The callback to execute for each block.
120+
* Gets a snapshot of an existing block from the editor.
121+
* @param blockIdentifier The identifier of an existing block that should be retrieved.
122+
* @returns The block that matches the identifier, or `undefined` if no matching block was found.
123+
*/
124+
public getBlock(blockIdentifier: BlockIdentifier): Block | undefined {
125+
const id =
126+
typeof blockIdentifier === "string"
127+
? blockIdentifier
128+
: blockIdentifier.id;
129+
let newBlock: Block | undefined = undefined;
130+
131+
this._tiptapEditor.state.doc.firstChild!.descendants((node) => {
132+
if (typeof newBlock !== "undefined") {
133+
return false;
134+
}
135+
136+
if (node.type.name !== "blockContainer" || node.attrs.id !== id) {
137+
return true;
138+
}
139+
140+
newBlock = nodeToBlock(node, this.blockCache);
141+
142+
return false;
143+
});
144+
145+
return newBlock;
146+
}
147+
148+
/**
149+
* Traverses all blocks in the editor depth-first, and executes a callback for each.
150+
* @param callback The callback to execute for each block. Returning `false` stops the traversal.
118151
* @param reverse Whether the blocks should be traversed in reverse order.
119152
*/
120-
public allBlocks(
153+
public forEachBlock(
121154
callback: (block: Block) => void,
122155
reverse: boolean = false
123156
): void {
@@ -139,7 +172,8 @@ export class BlockNoteEditor {
139172
}
140173

141174
/**
142-
* Gets information regarding the position of the text cursor in the editor.
175+
* Gets a snapshot of the current text cursor position.
176+
* @returns A snapshot of the current text cursor position.
143177
*/
144178
public getTextCursorPosition(): TextCursorPosition {
145179
const { node, depth, startPos, endPos } = getBlockInfoFromPos(
@@ -181,14 +215,19 @@ export class BlockNoteEditor {
181215
};
182216
}
183217

218+
/**
219+
* Sets the text cursor position to the start or end of an existing block. Throws an error if the target block could
220+
* not be found.
221+
* @param targetBlock The identifier of an existing block that the text cursor should be moved to.
222+
* @param placement Whether the text cursor should be placed at the start or end of the block.
223+
*/
184224
public setTextCursorPosition(
185-
block: Block,
225+
targetBlock: BlockIdentifier,
186226
placement: "start" | "end" = "start"
187227
) {
188-
const { posBeforeNode } = getNodeById(
189-
block.id,
190-
this._tiptapEditor.state.doc
191-
);
228+
const id = typeof targetBlock === "string" ? targetBlock : targetBlock.id;
229+
230+
const { posBeforeNode } = getNodeById(id, this._tiptapEditor.state.doc);
192231
const { startPos, contentNode } = getBlockInfoFromPos(
193232
this._tiptapEditor.state.doc,
194233
posBeforeNode + 2
@@ -204,48 +243,46 @@ export class BlockNoteEditor {
204243
}
205244

206245
/**
207-
* Inserts multiple blocks before, after, or nested inside an existing block in the editor.
208-
* @param blocksToInsert An array of blocks to insert.
209-
* @param blockToInsertAt An existing block, marking where the new blocks should be inserted at.
210-
* @param placement Determines whether the blocks should be inserted just before, just after, or nested inside the
211-
* existing block.
246+
* Inserts new blocks into the editor. If a block's `id` is undefined, BlockNote generates one automatically. Throws an
247+
* error if the reference block could not be found.
248+
* @param blocksToInsert An array of partial blocks that should be inserted.
249+
* @param referenceBlock An identifier for an existing block, at which the new blocks should be inserted.
250+
* @param placement Whether the blocks should be inserted just before, just after, or nested inside the
251+
* `referenceBlock`. Inserts the blocks at the start of the existing block's children if "nested" is used.
212252
*/
213253
public insertBlocks(
214254
blocksToInsert: PartialBlock[],
215-
blockToInsertAt: Block,
255+
referenceBlock: BlockIdentifier,
216256
placement: "before" | "after" | "nested" = "before"
217257
): void {
218-
insertBlocks(
219-
blocksToInsert,
220-
blockToInsertAt,
221-
placement,
222-
this._tiptapEditor
223-
);
258+
insertBlocks(blocksToInsert, referenceBlock, placement, this._tiptapEditor);
224259
}
225260

226261
/**
227-
* Updates a block in the editor to the given specification.
262+
* Updates an existing block in the editor. Since updatedBlock is a PartialBlock object, some fields might not be
263+
* defined. These undefined fields are kept as-is from the existing block. Throws an error if the block to update could
264+
* not be found.
228265
* @param blockToUpdate The block that should be updated.
229-
* @param updatedBlock The specification that the block should be updated to.
266+
* @param update A partial block which defines how the existing block should be changed.
230267
*/
231-
public updateBlock(blockToUpdate: Block, updatedBlock: PartialBlock) {
232-
updateBlock(blockToUpdate, updatedBlock, this._tiptapEditor);
268+
public updateBlock(blockToUpdate: Block, update: PartialBlock) {
269+
updateBlock(blockToUpdate, update, this._tiptapEditor);
233270
}
234271

235272
/**
236-
* Removes multiple blocks from the editor. Throws an error if any of the blocks could not be found.
237-
* @param blocksToRemove An array of blocks that should be removed.
273+
* Removes existing blocks from the editor. Throws an error if any of the blocks could not be found.
274+
* @param blocksToRemove An array of identifiers for existing blocks that should be removed.
238275
*/
239276
public removeBlocks(blocksToRemove: Block[]) {
240277
removeBlocks(blocksToRemove, this._tiptapEditor);
241278
}
242279

243280
/**
244-
* Replaces multiple blocks in the editor with several other blocks. If the provided blocks to remove are not adjacent
245-
* to each other, the new blocks are inserted at the position of the first block in the array. Throws an error if any
246-
* of the blocks could not be found.
281+
* Replaces existing blocks in the editor with new blocks. If the blocks that should be removed are not adjacent or
282+
* are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in
283+
* `blocksToRemove`. Throws an error if any of the blocks to remove could not be found.
247284
* @param blocksToRemove An array of blocks that should be replaced.
248-
* @param blocksToInsert An array of blocks to replace the old ones with.
285+
* @param blocksToInsert An array of partial blocks to replace the old ones with.
249286
*/
250287
public replaceBlocks(
251288
blocksToRemove: Block[],
@@ -263,38 +300,44 @@ export class BlockNoteEditor {
263300
}
264301

265302
/**
266-
* Serializes a list of blocks into an HTML string. The output is not the same as what's rendered by the editor, and
267-
* is simplified in order to better conform to HTML standards. Block structuring elements are removed, children of
268-
* blocks which aren't list items are lifted out of them, and list items blocks are wrapped in `ul`/`ol` tags.
269-
* @param blocks The list of blocks to serialize into HTML.
303+
* Serializes blocks into an HTML string. To better conform to HTML standards, children of blocks which aren't list
304+
* items are un-nested in the output HTML.
305+
* @param blocks An array of blocks that should be serialized into HTML.
306+
* @returns The blocks, serialized as an HTML string.
270307
*/
271308
public async blocksToHTML(blocks: Block[]): Promise<string> {
272309
return blocksToHTML(blocks, this._tiptapEditor.schema);
273310
}
274311

275312
/**
276-
* Creates a list of blocks from an HTML string.
277-
* @param htmlString The HTML string to create a list of blocks from.
313+
* Parses blocks from an HTML string. Tries to create `Block` objects out of any HTML block-level elements, and
314+
* `InlineNode` objects from any HTML inline elements, though not all element types are recognized. If BlockNote
315+
* doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.
316+
* @param html The HTML string to parse blocks from.
317+
* @returns The blocks parsed from the HTML string.
278318
*/
279-
public async HTMLToBlocks(htmlString: string): Promise<Block[]> {
280-
return HTMLToBlocks(htmlString, this._tiptapEditor.schema);
319+
public async HTMLToBlocks(html: string): Promise<Block[]> {
320+
return HTMLToBlocks(html, this._tiptapEditor.schema);
281321
}
282322

283323
/**
284-
* Serializes a list of blocks into a Markdown string. The output is simplified as Markdown does not support all
285-
* features of BlockNote. Block structuring elements are removed, children of blocks which aren't list items are
286-
* lifted out of them, and certain styles are removed.
287-
* @param blocks The list of blocks to serialize into Markdown.
324+
* Serializes blocks into a Markdown string. The output is simplified as Markdown does not support all features of
325+
* BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.
326+
* @param blocks An array of blocks that should be serialized into Markdown.
327+
* @returns The blocks, serialized as a Markdown string.
288328
*/
289329
public async blocksToMarkdown(blocks: Block[]): Promise<string> {
290330
return blocksToMarkdown(blocks, this._tiptapEditor.schema);
291331
}
292332

293333
/**
294-
* Creates a list of blocks from a Markdown string.
295-
* @param markdownString The Markdown string to create a list of blocks from.
334+
* Creates a list of blocks from a Markdown string. Tries to create `Block` and `InlineNode` objects based on
335+
* Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it
336+
* as text.
337+
* @param markdown The Markdown string to parse blocks from.
338+
* @returns The blocks parsed from the Markdown string.
296339
*/
297-
public async markdownToBlocks(markdownString: string): Promise<Block[]> {
298-
return markdownToBlocks(markdownString, this._tiptapEditor.schema);
340+
public async markdownToBlocks(markdown: string): Promise<Block[]> {
341+
return markdownToBlocks(markdown, this._tiptapEditor.schema);
299342
}
300343
}

packages/core/src/api/formatConversions/formatConversions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ export async function blocksToHTML(
3838
}
3939

4040
export async function HTMLToBlocks(
41-
htmlString: string,
41+
html: string,
4242
schema: Schema
4343
): Promise<Block[]> {
4444
const htmlNode = document.createElement("div");
45-
htmlNode.innerHTML = htmlString.trim();
45+
htmlNode.innerHTML = html.trim();
4646

4747
const parser = DOMParser.fromSchema(schema);
4848
const parentNode = parser.parse(htmlNode);
@@ -72,15 +72,15 @@ export async function blocksToMarkdown(
7272
}
7373

7474
export async function markdownToBlocks(
75-
markdownString: string,
75+
markdown: string,
7676
schema: Schema
7777
): Promise<Block[]> {
7878
const htmlString = await unified()
7979
.use(remarkParse)
8080
.use(remarkGfm)
8181
.use(remarkRehype)
8282
.use(rehypeStringify)
83-
.process(markdownString);
83+
.process(markdown);
8484

8585
return HTMLToBlocks(htmlString.value as string, schema);
8686
}

packages/website/docs/docs/blocks.md

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ function App() {
2929

3030
## Block Objects
3131

32-
So, BlockNote is centered around the idea of blocks. A block - like a Heading, Paragraph, or List item - contains a piece of content and optionally nested blocks. In code, the `Block` type is used to describe any given block in the editor:
32+
So, BlockNote is centered around the idea of blocks. A block - like a heading, paragraph, or list item - contains a piece of content and optionally nested blocks:
33+
34+
<img src="../public/img/screenshots/block_structure.png" alt="image" style="width: 100%">
35+
36+
In code, the `Block` type is used to describe any given block in the editor:
3337

3438
```typescript
3539
type Block = {
@@ -43,11 +47,11 @@ type Block = {
4347

4448
`id:` The block's ID. Multiple blocks cannot share a single ID, and a block will keep the same ID from when it's created until it's removed.
4549

46-
`type:` The block's type, such as a paragraph, heading, or list item. For an overview of built-in block types, see [Block Types & Properties](block-types).
50+
`type:` The block's type, such as a paragraph, heading, or list item. For an overview of built-in block types, see [Built-In Block Types](/docs/block-types#built-in-block-types).
4751

48-
`props:` The block's properties are stored in a set of key/value pairs and specify how the block looks and behaves. Different block types have different props - see [Block Types](block-types) for more.
52+
`props:` The block's properties, which are stored in a set of key/value pairs and specify how the block looks and behaves. Different block types have different props - see [Block Types & Properties](/docs/block-types) for more.
4953

50-
`content:` The block's content, represented as an array of `InlineNode` objects. This does not include content from any nested blocks. For more information on `InlineNode` objects, visit [Inline Content](inline-content.md).
54+
`content:` The block's content, represented as an array of `InlineContent` objects. This does not include content from any nested blocks. For more information on `InlineContent` objects, visit [Inline Content](/docs/inline-content).
5155

5256
`children:` Any blocks nested inside the block. The nested blocks are also represented using `Block` objects.
5357

@@ -85,11 +89,4 @@ export default function App() {
8589
}
8690
```
8791

88-
```css /styles.css [hidden]
89-
#root {
90-
margin-left: 45px;
91-
width: calc(100% - 90px);
92-
}
93-
```
94-
9592
:::

packages/website/docs/docs/converting-blocks.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ It's possible to export Blocks to other formats, or import Blocks from other for
55
::: warning
66
The functions to import / export to and from HTML / Markdown are considered "lossy"; some information might be dropped when you export Blocks to those formats.
77

8-
To serialize Blocks to a non-lossy format (for example, to store the contents of the editor in your backend), simply export the built in Block format using `JSON.stringify(editor.allBlocks)`.
8+
To serialize Blocks to a non-lossy format (for example, to store the contents of the editor in your backend), simply export the built-in Block format using `JSON.stringify(editor.allBlocks)`.
99
:::
1010

1111
## HTML
@@ -28,6 +28,10 @@ class BlockNoteEditor {
2828
const HTMLFromBlocks = editor.blocksToHTML(blocks);
2929
```
3030

31+
`returns:` The blocks, serialized as an HTML string.
32+
33+
To better conform to HTML standards, children of blocks which aren't list items are un-nested in the output HTML.
34+
3135
**Example**
3236

3337
TODO
@@ -48,7 +52,9 @@ class BlockNoteEditor {
4852
const blocksFromHTML = editor.HTMLToBlocks(html);
4953
```
5054

51-
This function will try to create `Block` objects out of any HTML block-level elements, and`InlineNode` objects from any HTML inline elements, though not all types of elements are recognized. If BlockNote doesn't recognize an HTML element's tag, it will parse it as a paragraph or plain text.
55+
`returns:` The blocks parsed from the HTML string.
56+
57+
Tries to create `Block` objects out of any HTML block-level elements, and `InlineNode` objects from any HTML inline elements, though not all HTML tags are recognized. If BlockNote doesn't recognize an element's tag, it will parse it as a paragraph or plain text.
5258

5359
**Example**
5460

@@ -74,10 +80,9 @@ class BlockNoteEditor {
7480
const markdownFromBlocks = editor.blocksToMarkdown(blocks);
7581
```
7682

77-
Some features of blocks can't be represented using Markdown, such as block color or text alignment, so some information is lost from the conversion:
83+
`returns:` The blocks, serialized as a Markdown string.
7884

79-
1. All blocks, except ones inside list items, are no longer nested since Markdown doesn't support nesting for them.
80-
2. Underline, text color, and background color styles are removed as Markdown doesn't support them.
85+
The output is simplified as Markdown does not support all features of BlockNote - children of blocks which aren't list items are un-nested and certain styles are removed.
8186

8287
**Example**
8388

@@ -99,7 +104,9 @@ class BlockNoteEditor {
99104
const blocksFromMarkdown = editor.markdownToBlocks(markdown);
100105
```
101106

102-
This function will try to create `Block` objects and `InlineNode` objects based on the Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it as text.
107+
`returns:` The blocks parsed from the Markdown string.
108+
109+
Tries to create `Block` and `InlineNode` objects based on Markdown syntax, though not all symbols are recognized. If BlockNote doesn't recognize a symbol, it will parse it as text.
103110

104111
**Example**
105112

0 commit comments

Comments
 (0)