A collaborative editing module for the Quill text editor used by the Reedsy team.
npm install quill-cursors --save
quill-cursors
is a Quill module that exposes a number of methods to help display other users' cursors for
collaborative editing.
First, set up a Quill editor.
Next, load quill-cursors
through any of the options presented by UMD.
Load script in HTML:
<script src="quill-cursors.js"></script>
Using ES6-style import
:
import QuillCursors from 'quill-cursors';
Using CommonJS-style require
:
const QuillCursors = require('quill-cursors');
Then, register the quill-cursors
module:
Quill.register('modules/cursors', QuillCursors);
const quill = new Quill('#editor', {
modules: {
cursors: true,
}
});
Finally, use the exposed quill-cursors
methods to update the cursors (see below). For an example setup, see the
example code, which can be run with:
npm start
The quill-cursors
module has the following optional configuration:
template
string: override the default HTML template used for a cursorcontainerClass
string (default:ql-cursors
): the CSS class to add to the cursors containerhideDelayMs
number (default:3000
): number of milliseconds to show the username flag before hiding ithideSpeedMs
number (default:400
): the duration of the flag hiding animation in millisecondsselectionChangeSource
string | null (default:api
): the event source to use when emittingselection-change
transformOnTextChange
boolean (default:false
): attempt to locally infer cursor positions whenever the editor contents change, without receiving an update from the other client. This can be useful for smoother performance on high-latency connections.boundsContainer
HTMLElement (default: Quill's bounds container): the element container used to determine flag positioningpositionFlag
(flag: HTMLElement, caretRectangle: ClientRect, container: ClientRect) => void
(default: flip horizontally): an optional function for positioning the caret flag according to its position relative to the bounds container. By default, the flag will flip horizontally when it reaches the right-hand edge of the bounds
Provide these options when setting up the Quill editor:
const editor = new Quill('#editor', {
modules: {
cursors: {
template: '<div class="custom-cursor">...</div>',
hideDelayMs: 5000,
hideSpeedMs: 0,
selectionChangeSource: null,
transformOnTextChange: true,
},
},
});
For the custom template to work correctly with the module, it should closely follow the classes in the original template.
By default, QuillJS will suppress selection-change
events when typing
to avoid noise.
However, you will probably want to update the quill-cursors
selection on both selection-change
and text-change
.
In order to aid this, quill-cursors
will automatically emit a selection-change
event on text-change
.
You can differentiate between user input and the quill-cursors
module by checking the source
argument for the
selection-change
event. By default, quill-cursors
will have source = 'api'
, but if you need to differentiate
between calls from quill-cursors
and other events, then you can change this source
using the selectionChangeSource
option.
If emitting an event is undesirable (eg you want selection-change
to act like the Quill default), then the
selectionChangeSource
can be set to null
, and an event will not be emitted. Note that in this case, you will need to
separately handle the text-change
event and update the cursor position.
The module instance can be retrieved through Quill's getModule
:
const cursors = editor.getModule('cursors');
createCursor(id: string, name: string, color: string): Cursor;
Creates a Cursor
instance with the given id
. If a cursor with this id
already exists, a new one is not created.
id
string: the unique ID for the cursorname
string: the name to display on the cursorcolor
string: the CSS color to use for the cursor
Returns a Cursor
object:
{
id: string;
name: string;
color: string;
range: Range; // See https://quilljs.com/docs/api/#selection-change
}
moveCursor(id: string, range: QuillRange): void;
Sets the selection range of the cursor with the given id
.
id
string: the ID of the cursor to moverange
Range: the selection range
removeCursor(id: string): void;
Removes the cursor with the given id
from the DOM.
id
string: the ID of the cursor to remove
update(): void;
Redraws all of the cursors in the DOM.
clearCursors(): void;
Removes all the cursors from the DOM.
toggleFlag(id: string, shouldShow?: boolean): void;
Toggles display of the flag for the cursor with the given id
.
id
string: the ID of the cursor whose flag should be toggledshouldShow
boolean (optional): if set totrue
, will display the flag. If set tofalse
, will hide it. If omitted, the flag's display state will be toggled.
cursors(): Cursor[];
Returns an array of all the Cursor
objects in the DOM in no particular order.
This code is available under the MIT license.