Skip to content

Commit 8919d8b

Browse files
committed
docs: add docs for yjs utils
1 parent 4a8b176 commit 8919d8b

3 files changed

Lines changed: 357 additions & 1 deletion

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"title": "Editor",
3-
"pages": ["overview", "manipulating-content", "cursor-selections", "..."]
3+
"pages": ["overview", "manipulating-content", "cursor-selections", "yjs-utilities", "..."]
44
}

docs/content/docs/reference/editor/overview.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ The editor can be configured with the following options when using `BlockNoteEdi
118118
name="BlockNoteEditorOptions"
119119
/>
120120

121+
## YJS Utilities
122+
123+
BlockNote provides utilities for working with YJS collaborative documents. These utilities allow you to convert between BlockNote blocks and YJS documents programmatically.
124+
125+
To read more about YJS utilities, see the [YJS Utilities](/docs/reference/editor/yjs-utilities) reference.
126+
121127
## Related Documentation
122128

123129
For more detailed information about specific areas:
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
---
2+
title: YJS Utilities
3+
description: Utilities for converting between BlockNote blocks and YJS collaborative documents
4+
imageTitle: YJS Utilities
5+
---
6+
7+
# YJS Utilities
8+
9+
The `@blocknote/core/yjs` export provides utilities for converting between BlockNote blocks and YJS collaborative documents. These utilities are useful when you need to work with YJS documents outside of the standard collaboration setup, such as importing existing content or working with YJS documents programmatically.
10+
11+
## Import
12+
13+
```typescript
14+
import {
15+
blocksToYDoc,
16+
blocksToYXmlFragment,
17+
yDocToBlocks,
18+
yXmlFragmentToBlocks,
19+
_blocksToProsemirrorNode,
20+
_prosemirrorJSONToBlocks,
21+
} from "@blocknote/core/yjs";
22+
```
23+
24+
## Overview
25+
26+
YJS utilities enable bidirectional conversion between:
27+
28+
- **BlockNote blocks****Y.Doc** (YJS document)
29+
- **BlockNote blocks****Y.XmlFragment** (YJS XML fragment)
30+
- **BlockNote blocks****Prosemirror nodes** (intermediate format)
31+
32+
These conversions are essential for:
33+
34+
- Importing existing BlockNote content into a YJS document for collaboration
35+
- Exporting content from a YJS document back to BlockNote blocks
36+
- Working with YJS documents programmatically without an active editor instance
37+
38+
## Converting Blocks to YJS Documents
39+
40+
### `blocksToYDoc`
41+
42+
Converts BlockNote blocks into a Y.Doc. This is useful when importing existing content to a Y.Doc for the first time.
43+
44+
<Callout type="warning">
45+
**Important:** This should not be used to rehydrate a Y.Doc from a database once collaboration has begun, as all history will be lost.
46+
</Callout>
47+
48+
```typescript
49+
function blocksToYDoc<
50+
BSchema extends BlockSchema,
51+
ISchema extends InlineContentSchema,
52+
SSchema extends StyleSchema,
53+
>(
54+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
55+
blocks: PartialBlock<BSchema, ISchema, SSchema>[],
56+
xmlFragment?: string
57+
): Y.Doc
58+
```
59+
60+
**Parameters:**
61+
62+
- `editor` - The BlockNote editor instance
63+
- `blocks` - Array of blocks to convert
64+
- `xmlFragment` - Optional XML fragment name (defaults to `"prosemirror"`)
65+
66+
**Returns:** A new Y.Doc containing the converted blocks
67+
68+
**Example:**
69+
70+
```typescript
71+
import { BlockNoteEditor } from "@blocknote/core";
72+
import { blocksToYDoc } from "@blocknote/core/yjs";
73+
import * as Y from "yjs";
74+
75+
const editor = BlockNoteEditor.create();
76+
77+
const blocks = [
78+
{
79+
type: "paragraph",
80+
content: "Hello, world!",
81+
},
82+
{
83+
type: "heading",
84+
props: { level: 1 },
85+
content: "My Document",
86+
},
87+
];
88+
89+
// Convert blocks to Y.Doc
90+
const ydoc = blocksToYDoc(editor, blocks);
91+
92+
// Now you can use this Y.Doc with a YJS provider for collaboration
93+
const provider = new WebrtcProvider("my-room", ydoc);
94+
```
95+
96+
### `blocksToYXmlFragment`
97+
98+
Converts BlockNote blocks into a Y.XmlFragment. This is useful when you want to work with a specific XML fragment within a Y.Doc.
99+
100+
```typescript
101+
function blocksToYXmlFragment<
102+
BSchema extends BlockSchema,
103+
ISchema extends InlineContentSchema,
104+
SSchema extends StyleSchema,
105+
>(
106+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
107+
blocks: Block<BSchema, ISchema, SSchema>[],
108+
xmlFragment?: Y.XmlFragment
109+
): Y.XmlFragment
110+
```
111+
112+
**Parameters:**
113+
114+
- `editor` - The BlockNote editor instance
115+
- `blocks` - Array of blocks to convert
116+
- `xmlFragment` - Optional existing Y.XmlFragment to populate (creates new one if not provided)
117+
118+
**Returns:** A Y.XmlFragment containing the converted blocks
119+
120+
**Example:**
121+
122+
```typescript
123+
import { BlockNoteEditor } from "@blocknote/core";
124+
import { blocksToYXmlFragment } from "@blocknote/core/yjs";
125+
import * as Y from "yjs";
126+
127+
const editor = BlockNoteEditor.create();
128+
const doc = new Y.Doc();
129+
const fragment = doc.getXmlFragment("my-fragment");
130+
131+
const blocks = [
132+
{
133+
type: "paragraph",
134+
content: "Content for fragment",
135+
},
136+
];
137+
138+
// Convert blocks to the XML fragment
139+
blocksToYXmlFragment(editor, blocks, fragment);
140+
```
141+
142+
## Converting YJS Documents to Blocks
143+
144+
### `yDocToBlocks`
145+
146+
Converts a Y.Doc back into BlockNote blocks. This is useful for reading content from a YJS document.
147+
148+
```typescript
149+
function yDocToBlocks<
150+
BSchema extends BlockSchema,
151+
ISchema extends InlineContentSchema,
152+
SSchema extends StyleSchema,
153+
>(
154+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
155+
ydoc: Y.Doc,
156+
xmlFragment?: string
157+
): Block<BSchema, ISchema, SSchema>[]
158+
```
159+
160+
**Parameters:**
161+
162+
- `editor` - The BlockNote editor instance
163+
- `ydoc` - The Y.Doc to convert
164+
- `xmlFragment` - Optional XML fragment name (defaults to `"prosemirror"`)
165+
166+
**Returns:** Array of BlockNote blocks
167+
168+
**Example:**
169+
170+
```typescript
171+
import { BlockNoteEditor } from "@blocknote/core";
172+
import { yDocToBlocks } from "@blocknote/core/yjs";
173+
import * as Y from "yjs";
174+
175+
const editor = BlockNoteEditor.create();
176+
const ydoc = new Y.Doc();
177+
178+
// ... Y.Doc is populated through collaboration or other means ...
179+
180+
// Convert Y.Doc back to blocks
181+
const blocks = yDocToBlocks(editor, ydoc);
182+
183+
console.log(blocks); // Array of BlockNote blocks
184+
```
185+
186+
### `yXmlFragmentToBlocks`
187+
188+
Converts a Y.XmlFragment back into BlockNote blocks.
189+
190+
```typescript
191+
function yXmlFragmentToBlocks<
192+
BSchema extends BlockSchema,
193+
ISchema extends InlineContentSchema,
194+
SSchema extends StyleSchema,
195+
>(
196+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
197+
xmlFragment: Y.XmlFragment
198+
): Block<BSchema, ISchema, SSchema>[]
199+
```
200+
201+
**Parameters:**
202+
203+
- `editor` - The BlockNote editor instance
204+
- `xmlFragment` - The Y.XmlFragment to convert
205+
206+
**Returns:** Array of BlockNote blocks
207+
208+
**Example:**
209+
210+
```typescript
211+
import { BlockNoteEditor } from "@blocknote/core";
212+
import { yXmlFragmentToBlocks } from "@blocknote/core/yjs";
213+
import * as Y from "yjs";
214+
215+
const editor = BlockNoteEditor.create();
216+
const doc = new Y.Doc();
217+
const fragment = doc.getXmlFragment("my-fragment");
218+
219+
// ... Fragment is populated through collaboration or other means ...
220+
221+
// Convert fragment back to blocks
222+
const blocks = yXmlFragmentToBlocks(editor, fragment);
223+
```
224+
225+
## Prosemirror Conversions
226+
227+
### `_blocksToProsemirrorNode`
228+
229+
Converts BlockNote blocks to a Prosemirror node. This is an intermediate conversion step used internally.
230+
231+
```typescript
232+
function _blocksToProsemirrorNode<
233+
BSchema extends BlockSchema,
234+
ISchema extends InlineContentSchema,
235+
SSchema extends StyleSchema,
236+
>(
237+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
238+
blocks: PartialBlock<BSchema, ISchema, SSchema>[]
239+
): Node
240+
```
241+
242+
**Parameters:**
243+
244+
- `editor` - The BlockNote editor instance
245+
- `blocks` - Array of blocks to convert
246+
247+
**Returns:** Prosemirror root node
248+
249+
### `_prosemirrorJSONToBlocks`
250+
251+
Converts Prosemirror JSON to BlockNote blocks.
252+
253+
```typescript
254+
function _prosemirrorJSONToBlocks<
255+
BSchema extends BlockSchema,
256+
ISchema extends InlineContentSchema,
257+
SSchema extends StyleSchema,
258+
>(
259+
editor: BlockNoteEditor<BSchema, ISchema, SSchema>,
260+
json: any
261+
): Block<BSchema, ISchema, SSchema>[]
262+
```
263+
264+
**Parameters:**
265+
266+
- `editor` - The BlockNote editor instance
267+
- `json` - Prosemirror JSON object
268+
269+
**Returns:** Array of BlockNote blocks
270+
271+
## Complete Example: Importing Existing Content
272+
273+
Here's a complete example showing how to import existing BlockNote content into a YJS document for collaboration:
274+
275+
```typescript
276+
import { BlockNoteEditor } from "@blocknote/core";
277+
import { blocksToYDoc, yDocToBlocks } from "@blocknote/core/yjs";
278+
import { WebrtcProvider } from "y-webrtc";
279+
import * as Y from "yjs";
280+
281+
// Create editor
282+
const editor = BlockNoteEditor.create();
283+
284+
// Existing content you want to import
285+
const existingBlocks = [
286+
{
287+
type: "heading",
288+
props: { level: 1 },
289+
content: "Welcome to Collaboration",
290+
},
291+
{
292+
type: "paragraph",
293+
content: "This content will be synced across all users.",
294+
},
295+
];
296+
297+
// Convert blocks to Y.Doc
298+
const ydoc = blocksToYDoc(editor, existingBlocks);
299+
300+
// Set up collaboration provider
301+
const provider = new WebrtcProvider("my-room", ydoc);
302+
303+
// Create editor with collaboration
304+
const collaborativeEditor = BlockNoteEditor.create({
305+
collaboration: {
306+
provider,
307+
fragment: ydoc.getXmlFragment("prosemirror"),
308+
user: {
309+
name: "User 1",
310+
color: "#ff0000",
311+
},
312+
},
313+
});
314+
315+
// Later, you can read the content back
316+
const currentBlocks = yDocToBlocks(editor, ydoc);
317+
console.log("Current document:", currentBlocks);
318+
```
319+
320+
## Round-trip Conversion
321+
322+
All conversion functions support round-trip conversion, meaning you can convert blocksYJSblocks and get back the same content:
323+
324+
```typescript
325+
import { BlockNoteEditor } from "@blocknote/core";
326+
import { blocksToYDoc, yDocToBlocks } from "@blocknote/core/yjs";
327+
328+
const editor = BlockNoteEditor.create();
329+
330+
const originalBlocks = [
331+
{
332+
type: "paragraph",
333+
content: "Test content",
334+
},
335+
];
336+
337+
// Convert to Y.Doc and back
338+
const ydoc = blocksToYDoc(editor, originalBlocks);
339+
const convertedBlocks = yDocToBlocks(editor, ydoc);
340+
341+
// originalBlocks and convertedBlocks are equivalent
342+
console.log(originalBlocks); // Same structure as convertedBlocks
343+
```
344+
345+
## Related Documentation
346+
347+
- [Real-time Collaboration](/docs/features/collaboration) - Learn how to set up collaboration in BlockNote
348+
- [Manipulating Content](/docs/reference/editor/manipulating-content) - Working with blocks and inline content
349+
- [Server Utilities](/docs/reference/server-util) - Server-side utilities for BlockNote (uses these YJS utilities internally)
350+

0 commit comments

Comments
 (0)