Skip to main content

YjsExtension

Summary

The YJS extension is the recommended extension for creating a collaborative editor.

Usage

Installation

This extension is installed for you when you install the main remirror package.

You can use the imports in the following way:

import { YjsExtension } from 'remirror/extensions';

The yjs extension provides support for "undo"/"redo" commands, which conflicts with the default history extension. The history extension provides "undo"/"redo" for the changes done by the current user only, while the yjs extension provides "undo"/"redo" on the level of the underlying yjs transactions, which covers changes by all active users. Note however that a yjs "undo" replaces the complete document, which prevents other extensions (such as the annotations extension) from tracking positions.

You can select the yjs "undo"/"redo" implementation by disabling the history extension in the core preset configuration:

const { manager } = useRemirror({
extensions: () => [new YjsExtension({ getProvider })],
core: {
excludeExtensions: ['history'],
},
});

Alternatively you can also disable the "undo"/"redo" functionality of the yjs extension:

const { manager } = useRemirror({
extensions: () => [new YjsExtension({ getProvider, disableUndo: true })],
});

Note that using the history extension "undo"/"redo" requires additional support from the y-prosemirror library.

Examples

Source code
import 'remirror/styles/all.css';

import React from 'react';
import { AnnotationExtension, PlaceholderExtension, YjsExtension } from 'remirror/extensions';
import { WebrtcProvider } from 'y-webrtc';
import * as Y from 'yjs';
import {
Remirror,
ThemeProvider,
useCommands,
useCurrentSelection,
useHelpers,
useRemirror,
} from '@remirror/react';

const ydoc = new Y.Doc();
// clients connected to the same room-name share document updates
const provider = new WebrtcProvider('remirror-yjs-demo', ydoc);

const extensions = () => [
new AnnotationExtension(),
new PlaceholderExtension({ placeholder: 'Open second tab and start to type...' }),
new YjsExtension({ getProvider: () => provider }),
];

const Menu = () => {
const { removeAnnotations, addAnnotation, redrawAnnotations } = useCommands();
const { getAnnotationsAt, selectionHasAnnotation } = useHelpers();
const selection = useCurrentSelection();

return (
<>
<button
onClick={() => {
addAnnotation({ id: `${Date.now()}` });
focus();
}}
disabled={selection.empty}
>
Add annotation
</button>
<button
onClick={() => {
const annotations = getAnnotationsAt(selection.from);
removeAnnotations(annotations.map(({ id }) => id));
focus();
}}
disabled={!selectionHasAnnotation()}
>
Remove annotation(s)
</button>
<button
onClick={() => {
redrawAnnotations();
focus();
}}
>
Redraw annotation(s)
</button>
</>
);
};

const Basic = (): JSX.Element => {
const { manager } = useRemirror({ extensions, core: { excludeExtensions: ['history'] } });

return (
<ThemeProvider>
<Remirror manager={manager} autoFocus autoRender='end'>
<Menu />
</Remirror>
</ThemeProvider>
);
};

export default Basic;

API