Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 53 additions & 57 deletions docs/pages/docs/advanced/vanilla-js.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { Callout } from "nextra/components";
BlockNote is mainly designed as a quick and easy drop-in block-based editor for React apps, but can also be used in vanilla JavaScript apps. However, this does involve writing your own UI elements.

<Callout type={"warning"}>
We recommend using BlockNote with React so you can use the built-in UI components. This document will explain how you can use BlockNote without React, and write your own components, but this is not recommended as you'll lose the great out-of-the-box experience that BlockNote offers.
We recommend using BlockNote with React so you can use the built-in UI
components. This document will explain how you can use BlockNote without
React, and write your own components, but this is not recommended as you'll
lose the great out-of-the-box experience that BlockNote offers.
</Callout>

## Installing with NPM
Expand All @@ -25,19 +28,14 @@ npm install @blocknote/core

## Creating an editor

TODO: AFAIK there is actually just no way of doing this anymore

This is how to create a new BlockNote editor:

``` typescript
```typescript
import { BlockNoteEditor } from "@blocknote/core";

const editor = BlockNoteEditor.create({
element: document.getElementById("root")!, // element to append the editor to
onEditorContentChange: ({) => {
console.log(editor.getJSON());
}
});
const editor = BlockNoteEditor.create();

editor.mount(document.getElementById("root")); // element to append the editor to
```

Now, you'll have a plain BlockNote instance on your page. However, it's missing some menus and other UI elements.
Expand Down Expand Up @@ -70,60 +68,58 @@ Let's look at how you could add the [Side Menu]() to your editor:
import { BlockNoteEditor } from "@blocknote/core";

const editor = BlockNoteEditor.create({
element: document.getElementById("root")!
element: document.getElementById("root")!,
});

export function createButton(text: string, onClick?: () => void) {
const element = document.createElement("a");
element.href = "#";
element.text = text;
element.style.margin = "10px";

if (onClick) {
element.addEventListener("click", (e) => {
onClick();
e.preventDefault();
});
}

return element;
const element = document.createElement("a");
element.href = "#";
element.text = text;
element.style.margin = "10px";

if (onClick) {
element.addEventListener("click", (e) => {
onClick();
e.preventDefault();
});
}

return element;
}

let element: HTMLElement;

editor.sideMenu.onUpdate((sideMenuState) => {
if (!element) {
element = document.createElement("div");
element.style.background = "gray";
element.style.position = "absolute";
element.style.padding = "10px";
element.style.opacity = "0.8";
const addBtn = createButton("+", () => {
editor.sideMenu.addBlock();
});
element.appendChild(addBtn);

const dragBtn = createButton("::", () => {});

dragBtn.addEventListener("dragstart", editor.sideMenu.blockDragStart);
dragBtn.addEventListener("dragend", editor.sideMenu.blockDragEnd);
dragBtn.draggable = true;
element.style.display = "none";
element.appendChild(dragBtn);

document.getElementById("root")!.appendChild(element);
}

if (sideMenuState.show) {
element.style.display = "block";

element.style.top = sideMenuState.referencePos.top + "px";
element.style.left =
sideMenuState.referencePos.x - element.offsetWidth + "px";
} else {
element.style.display = "none";
}
if (!element) {
element = document.createElement("div");
element.style.background = "gray";
element.style.position = "absolute";
element.style.padding = "10px";
element.style.opacity = "0.8";
const addBtn = createButton("+", () => {
editor.sideMenu.addBlock();
});
element.appendChild(addBtn);

const dragBtn = createButton("::", () => {});

dragBtn.addEventListener("dragstart", editor.sideMenu.blockDragStart);
dragBtn.addEventListener("dragend", editor.sideMenu.blockDragEnd);
dragBtn.draggable = true;
element.style.display = "none";
element.appendChild(dragBtn);

document.getElementById("root")!.appendChild(element);
}

if (sideMenuState.show) {
element.style.display = "block";

element.style.top = sideMenuState.referencePos.top + "px";
element.style.left =
sideMenuState.referencePos.x - element.offsetWidth + "px";
} else {
element.style.display = "none";
}
});
```

TODO: Bring back vanilla example?
2 changes: 1 addition & 1 deletion docs/pages/docs/custom-schemas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn how to create custom schemas for your BlockNote editor

# Custom Schemas (advanced)

By default, BlockNote documents support different kind of blocks, inline content and text styles. See xxxx.
By default, BlockNote documents support different kind of blocks, inline content and text styles (see [default schema](/docs/editor-basics/default-schema)).
However, you can extend BlockNote and create custom schemas to support your own blocks, inline content and text styles.

## Custom Blocks
Expand Down
21 changes: 8 additions & 13 deletions docs/pages/docs/custom-schemas/custom-styles.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,14 @@ function createReactStyleSpec(
Let's look at our custom font style from the demo, and go over each field to explain how it works:

```typescript
const Mention = createReactStyleSpec(
export const Font = createReactStyleSpec(
{
type: "mention",
propSchema: {
user: {
default: "Unknown",
},
},
content: "none",
} as const,
type: "font",
propSchema: "string",
},
{
render: (props) => (
...
<span style={{ fontFamily: props.value }} ref={props.contentRef} />
),
}
);
Expand All @@ -57,7 +52,7 @@ Defines the identifier of the custom style.

The `PropSchema` specifies whether the style can only be toggled (`"boolean"`), or whether it can take a string value (`"string"`). Having a string value is useful for e.g. setting a color on the style.

_In the font style demo, we set this to `"string"` so we can store the font name._
_In the font style demo, we set this to `"string"` so we can store the font family._

#### Style Implementation (`ReactCustomStyleImplementation`)

Expand All @@ -78,9 +73,9 @@ This is your React component which defines how your custom style should be rende

`value:` The string value of the style, this is only available if your style config contains `propSchema: "string"`.

`contentRef:` A React `ref` you can use to mark which element in your style is editable.
`contentRef:` A React `ref` to mark the editable element.

_Note that since styles are applied to text, you must set `contentRef` somewhere in you component, and should also return an HTML inline element._
_Note that in contrast to Custom Blocks and Inline Content, the `render` function of Custom Styles cannot access React Context or other state. They should be plain React functions analogous to the example._

### Adding Custom Style to the Editor

Expand Down
10 changes: 9 additions & 1 deletion docs/pages/docs/editor-api.mdx
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
hello
# Editor API

BlockNote exposes an API to interact with the editor and its contents from code.
These methods are directly available on the `BlockNoteEditor` object you created when instantiating your editor.

- [Manipulating Blocks](/docs/editor-api/manipulating-blocks.md) explains how to read / update Blocks in the document.
- [Manipulating Inline Content](/docs/editor-api/manipulating-inline-content.md) explains how to update / read data from selected text.
- [Cursors & Selections](/docs/editor-api/cursor-selections) explains methods related to cursor positions and selections.
- [Markdown & HTML](/docs/converting-blocks) explains how to convert the document to and from Markdown and HTML.
6 changes: 2 additions & 4 deletions docs/pages/docs/editor-api/converting-blocks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import { Callout } from "nextra/components";

# Markdown & HTML

TODO: use hooks in examples
TODO: use examples with content

It's possible to export or import Blocks to and from Markdown and HTML.

<Callout type={"warning"}>
The functions to import/export to and from Markdown/HTML are considered "lossy"; some information might be dropped when you export Blocks to those formats.

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.topLevelBlocks)`.
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.document)`.

</Callout>

## Markdown
Expand Down
47 changes: 23 additions & 24 deletions docs/pages/docs/editor-api/manipulating-blocks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,25 @@ path: /docs/manipulating-blocks

Below, we explain the methods on `editor` you can use to read Blocks from the editor, and how to create / remove / update Blocks:

- [topLevelBlocks](/docs/editor-api/manipulating-blocks#getting-all-top-level-blocks)
- [getBlock](/docs/editor-api/manipulating-blocks#getting-a-specific-block)
- [forEachBlock](/docs/editor-api/manipulating-blocks#traversing-all-blocks)
- [insertBlocks](/docs/editor-api/manipulating-blocks#inserting-new-blocks)
- [updateBlock](/docs/editor-api/manipulating-blocks#updating-blocks)
- [removeBlocks](/docs/editor-api/manipulating-blocks#removing-blocks)
- [replaceBlocks](/docs/editor-api/manipulating-blocks#replacing-blocks)
- [canNestBlock](/docs/editor-api/manipulating-blocks#nesting-blocks)
- [nestBlock](/docs/editor-api/manipulating-blocks#nesting-blocks)
- [canUnnestBlock](/docs/editor-api/manipulating-blocks#un-nesting-blocks)
- [unnestBlock](/docs/editor-api/manipulating-blocks#un-nesting-blocks)
- [`get document`](/docs/editor-api/manipulating-blocks#getting-the-document)
- [`getBlock`](/docs/editor-api/manipulating-blocks#getting-a-specific-block)
- [`forEachBlock`](/docs/editor-api/manipulating-blocks#traversing-all-blocks)
- [`insertBlocks`](/docs/editor-api/manipulating-blocks#inserting-new-blocks)
- [`updateBlock`](/docs/editor-api/manipulating-blocks#updating-blocks)
- [`removeBlocks`](/docs/editor-api/manipulating-blocks#removing-blocks)
- [`replaceBlocks`](/docs/editor-api/manipulating-blocks#replacing-blocks)
- [`canNestBlock`](/docs/editor-api/manipulating-blocks#nesting-blocks)
- [`nestBlock`](/docs/editor-api/manipulating-blocks#nesting-blocks)
- [`canUnnestBlock`](/docs/editor-api/manipulating-blocks#un-nesting-blocks)
- [`unnestBlock`](/docs/editor-api/manipulating-blocks#un-nesting-blocks)

## Common types

Before we dive into the methods, let's discuss some common types used in parameters:

### Block Identifiers

The methods to access, insert, update, remove, or replace blocks, can require a `BlockIdentifier` as reference to an existing block in the document.
The methods to access, insert, update, remove, or replace blocks, can require a `BlockIdentifier` as reference to an existing block in the document.
This is either a `string` representing the block ID, or a `Block` object from which the ID is taken:

```typescript
Expand All @@ -36,7 +36,7 @@ type BlockIdentifier = string | Block;

### Partial Blocks

When retrieving blocks from the editor, you always receive complete `Block` objects.
When retrieving blocks from the editor, you always receive complete `Block` objects.
For updating or creating blocks, you don't need to pass all properties and you can use a `PartialBlock` type instead:

```typescript
Expand All @@ -51,25 +51,24 @@ type PartialBlock = {

`PartialBlock` objects are almost the same as regular `Block` objects, but with all members optional and partial `props`. This makes updating or creating simpler blocks much easier. We'll see this below.


## Accessing Blocks

There are a few different ways to retrieve Blocks from the editor:

### Getting All Top-Level Blocks
### Getting the Document

Retrieve a snapshot of all top-level (non-nested) blocks in the editor using the following call:
Retrieve a snapshot of the document (all top-level, non-nested blocks) in the editor using the following call:

```typescript
topLevelBlocks: Block[];
document: Block[];

// Usage
const blocks = editor.topLevelBlocks;
const blocks = editor.document;
```

`returns:` The document; a snapshot of all top-level (non-nested) blocks in the editor.

We already used this for the [Editor Content in JSON](/docs/editor-basics/content-structure#editor-content-in-json) demo.
We already used this for the [Editor Content in JSON](/docs/editor-basics/content-structure#editor-content-in-json) demo.

### Getting a Specific Block

Expand Down Expand Up @@ -129,7 +128,7 @@ editor.insertBlocks([{type: "paragraph", text: "Hello World"}], referenceBlock,

`placement:` Whether the blocks should be inserted just before, just after, or nested inside the `referenceBlock`. Inserts the blocks at the start of the existing block's children if `"nested"` is used.

If a block's `id` is undefined, BlockNote generates one automatically.
If a block's `id` is undefined, BlockNote generates one automatically.

The method throws an error if the reference block could not be found.

Expand All @@ -151,7 +150,7 @@ editor.updateBlock(blockToUpdate, { type: "paragraph" });

`update:` A [partial blocks](/docs/editor-api/manipulating-blocks#partial-blocks) which defines how the existing block should be changed.

Since `blockToUpdate` is a `PartialBlock` object, some fields might not be defined. These undefined fields are kept as-is from the existing block.
Since `blockToUpdate` is a `PartialBlock` object, some fields might not be defined. These undefined fields are kept as-is from the existing block.

Throws an error if the block to update could not be found.

Expand Down Expand Up @@ -190,7 +189,7 @@ editor.replaceBlocks(blocksToRemove, blocksToInsert)

`blocksToInsert:` An array of [partial blocks](/docs/editor-api/manipulating-blocks#partial-blocks) that the existing ones should be replaced with.

If the blocks that should be removed are not adjacent or are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in `blocksToRemove`.
If the blocks that should be removed are not adjacent or are at different nesting levels, `blocksToInsert` will be inserted at the position of the first block in `blocksToRemove`.

Throws an error if any of the blocks to remove could not be found.

Expand All @@ -200,7 +199,7 @@ BlockNote also provides functions to nest & un-nest the block containing the [Te

### Nesting Blocks

TODO: this API seems different as it doesn't require a block id. should we make it possible to pass an identifier?
{/* TODO: this API seems different as it doesn't require a block id. should we make it possible to pass an identifier? */}

Use `canNestBlock` to check whether the block containing the [Text Cursor](/docs/editor-api/cursor-selections#text-cursor) can be nested (i.e. if there is a block above it at the same nesting level):

Expand Down Expand Up @@ -238,4 +237,4 @@ unnestBlock(): void;

// Usage
editor.unnestBlock();
```
```
2 changes: 1 addition & 1 deletion docs/pages/docs/editor-api/manipulating-inline-content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ path: /docs/block-content

# Manipulating Inline Content

While `InlineContent` objects are used to describe a block's content, they can be cumbersome to work with directly. Therefore, BlockNote exposes functions which make it easier to edit block contents.
`BlockNoteEditor` exposes a number of functions to interact with the currently selected content.

## Accessing Styles

Expand Down
5 changes: 5 additions & 0 deletions docs/pages/docs/editor-basics.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Editor basics

In this section, we first explore the [methods to setup your editor](/docs/editor-basics/setup).
Then, we'll dive into the structure of documents, Blocks and rich text content in BlockNote ([document structure](/docs/editor-basics/document-structure)).
We'll also go over the blocks and content types that are part of BlockNote's [default built-in schema](/docs/editor-basics/default-schema).
6 changes: 3 additions & 3 deletions docs/pages/docs/editor-basics/_meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"content-structure": "Content Structure",
"default-content-types": "Default Content Types",
"editor": "Editor Setup"
"setup": "Editor Setup",
"document-structure": "Document Structure",
"default-schema": "Default Schema"
}
Loading