YjsExtension
Summary
The YJS extension is the recommended extension for creating a collaborative editor.
Usage
Installation
This extension is NOT installed for you when you install the main remirror
package but need to be installed separately:
You can use the imports in the following way:
import { YjsExtension } from '@remirror/extension-yjs';
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 } from 'remirror/extensions';
import { WebrtcProvider } from 'y-webrtc';
import * as Y from 'yjs';
import { YjsExtension } from '@remirror/extension-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;