0
# Core Plugins
1
2
Y-ProseMirror provides three essential ProseMirror plugins that enable collaborative editing: synchronization, cursor tracking, and collaborative undo/redo functionality.
3
4
## Capabilities
5
6
### Synchronization Plugin (ySyncPlugin)
7
8
Maintains bidirectional synchronization between a Yjs XML fragment and ProseMirror document, ensuring all users see consistent content.
9
10
```javascript { .api }
11
/**
12
* Creates a ProseMirror plugin that synchronizes with a Yjs XML fragment
13
* @param yXmlFragment - The Yjs XML fragment to bind to
14
* @param opts - Optional configuration object with destructured options
15
* @returns ProseMirror Plugin instance
16
*/
17
function ySyncPlugin(yXmlFragment: Y.XmlFragment, opts?: {
18
/** Array of color definitions for user highlighting */
19
colors?: Array<ColorDef>;
20
/** Mapping of users to specific colors */
21
colorMapping?: Map<string, ColorDef>;
22
/** Persistent user data for the session */
23
permanentUserData?: Y.PermanentUserData | null;
24
/** Pre-existing mapping between Yjs and ProseMirror nodes */
25
mapping?: ProsemirrorMapping;
26
/** Callback fired when content initially renders */
27
onFirstRender?: () => void;
28
}): Plugin;
29
30
interface ColorDef {
31
light: string;
32
dark: string;
33
}
34
```
35
36
**Usage Example:**
37
38
```javascript
39
import * as Y from "yjs";
40
import { ySyncPlugin } from "y-prosemirror";
41
42
const ydoc = new Y.Doc();
43
const yXmlFragment = ydoc.getXmlFragment("prosemirror");
44
45
const syncPlugin = ySyncPlugin(yXmlFragment, {
46
colors: [
47
{ light: "#ffeb3b", dark: "#f57f17" },
48
{ light: "#4caf50", dark: "#2e7d32" }
49
],
50
onFirstRender: () => console.log("Content rendered")
51
});
52
```
53
54
### Cursor Plugin (yCursorPlugin)
55
56
Displays collaborative cursors and selections from other editing users using Yjs awareness protocol.
57
58
```javascript { .api }
59
/**
60
* Creates a ProseMirror plugin for displaying collaborative cursors
61
* @param awareness - Yjs awareness instance for cursor tracking
62
* @param opts - Optional configuration object with destructured options
63
* @param cursorStateField - Awareness field name for cursor data (default: 'cursor')
64
* @returns ProseMirror Plugin instance
65
*/
66
function yCursorPlugin(
67
awareness: Awareness,
68
opts?: {
69
/** Filter function for awareness states */
70
awarenessStateFilter?: (currentClientId: number, userClientId: number, user: any) => boolean;
71
/** Custom cursor element builder */
72
cursorBuilder?: (user: any, clientId: number) => HTMLElement;
73
/** Custom selection attributes builder */
74
selectionBuilder?: (user: any, clientId: number) => DecorationAttrs;
75
/** Custom selection getter */
76
getSelection?: (state: EditorState) => Selection;
77
},
78
cursorStateField?: string
79
): Plugin;
80
```
81
82
**Usage Example:**
83
84
```javascript
85
import { Awareness } from "y-protocols/awareness";
86
import { yCursorPlugin } from "y-prosemirror";
87
88
const awareness = new Awareness(ydoc);
89
90
const cursorPlugin = yCursorPlugin(awareness, {
91
cursorBuilder: (user, clientId) => {
92
const cursor = document.createElement("div");
93
cursor.className = "user-cursor";
94
cursor.style.borderColor = user.color;
95
cursor.textContent = user.name;
96
return cursor;
97
},
98
awarenessStateFilter: (currentId, userId, user) => {
99
return currentId !== userId && user.cursor;
100
}
101
});
102
```
103
104
### Undo Plugin (yUndoPlugin)
105
106
Provides collaborative undo/redo functionality with per-user history tracking that respects collaborative document state.
107
108
```javascript { .api }
109
/**
110
* Creates a ProseMirror plugin for collaborative undo/redo operations
111
* @param options - Optional configuration object with destructured options
112
* @returns ProseMirror Plugin instance
113
*/
114
function yUndoPlugin(options?: {
115
/** Set of node types that cannot be deleted during undo */
116
protectedNodes?: Set<string>;
117
/** Origins to track for undo operations */
118
trackedOrigins?: any[];
119
/** Custom undo manager instance */
120
undoManager?: UndoManager | null;
121
}): Plugin;
122
```
123
124
**Usage Example:**
125
126
```javascript
127
import { yUndoPlugin } from "y-prosemirror";
128
129
const undoPlugin = yUndoPlugin({
130
protectedNodes: new Set(["doc", "paragraph"]),
131
trackedOrigins: ["user-input", "paste"]
132
});
133
```
134
135
### Plugin Keys
136
137
Unique identifiers for each plugin, useful for accessing plugin state or configuration.
138
139
```javascript { .api }
140
/** Plugin key for synchronization plugin */
141
const ySyncPluginKey: PluginKey;
142
143
/** Plugin key for cursor plugin */
144
const yCursorPluginKey: PluginKey;
145
146
/** Plugin key for undo plugin */
147
const yUndoPluginKey: PluginKey;
148
```
149
150
### Undo/Redo Commands
151
152
Direct command functions for implementing undo/redo in your editor interface.
153
154
```javascript { .api }
155
/**
156
* Perform undo operation on editor state
157
* @param state - Current editor state
158
* @returns true if undo was performed
159
*/
160
function undo(state: EditorState): boolean;
161
162
/**
163
* Perform redo operation on editor state
164
* @param state - Current editor state
165
* @returns true if redo was performed
166
*/
167
function redo(state: EditorState): boolean;
168
169
/**
170
* ProseMirror command for undo operation
171
* @param state - Current editor state
172
* @param dispatch - Dispatch function for state changes
173
* @returns true if command was handled
174
*/
175
function undoCommand(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
176
177
/**
178
* ProseMirror command for redo operation
179
* @param state - Current editor state
180
* @param dispatch - Dispatch function for state changes
181
* @returns true if command was handled
182
*/
183
function redoCommand(state: EditorState, dispatch?: (tr: Transaction) => void): boolean;
184
```
185
186
### ProseMirror Binding Class
187
188
Core binding class that manages the synchronization lifecycle between Yjs and ProseMirror.
189
190
```javascript { .api }
191
/**
192
* Main binding class managing synchronization between Yjs and ProseMirror
193
*/
194
class ProsemirrorBinding {
195
/** The bound Yjs XML fragment */
196
type: Y.XmlFragment;
197
/** The ProseMirror editor view */
198
prosemirrorView: EditorView | null;
199
/** Mapping between Yjs and ProseMirror nodes */
200
mapping: ProsemirrorMapping;
201
/** The Yjs document */
202
doc: Y.Doc;
203
/** Mutex for preventing concurrent operations */
204
mux: Mutex;
205
/** Map tracking overlapping marks */
206
isOMark: Map<MarkType, boolean>;
207
/** Whether this binding has been destroyed */
208
isDestroyed: boolean;
209
/** Current selection as relative positions in the Yjs model */
210
beforeTransactionSelection: any;
211
212
/**
213
* Create a new ProseMirror binding
214
* @param yXmlFragment - Yjs XML fragment to bind
215
* @param mapping - Optional initial mapping
216
*/
217
constructor(yXmlFragment: Y.XmlFragment, mapping?: Map);
218
219
/**
220
* Initialize the binding with a ProseMirror view
221
* @param prosemirrorView - ProseMirror editor view
222
*/
223
initView(prosemirrorView: EditorView): void;
224
225
/**
226
* Clean up the binding and remove event listeners
227
*/
228
destroy(): void;
229
230
/**
231
* Render a specific document snapshot
232
* @param snapshot - Document snapshot to render
233
* @param prevSnapshot - Previous snapshot for comparison
234
*/
235
renderSnapshot(snapshot: Snapshot, prevSnapshot?: Snapshot): void;
236
237
/**
238
* Remove snapshot rendering and return to current state
239
*/
240
unrenderSnapshot(): void;
241
242
/**
243
* Get current transaction with addToHistory set to false
244
* @returns Transaction for internal operations
245
*/
246
get _tr(): Transaction;
247
248
/**
249
* Check if local cursor is visible in view
250
* @returns true if local cursor is in viewport
251
*/
252
_isLocalCursorInView(): boolean;
253
254
/**
255
* Force re-render of the binding mapping
256
*/
257
_forceRerender(): void;
258
}
259
```
260
261
### Default Builders and Filters
262
263
Default implementations for cursor display and awareness filtering that can be used or customized.
264
265
```javascript { .api }
266
/**
267
* Default cursor element builder
268
* @param user - User information from awareness
269
* @param clientId - Client ID of the user
270
* @returns HTML element for cursor display
271
*/
272
function defaultCursorBuilder(user: any, clientId: number): HTMLElement;
273
274
/**
275
* Default selection attributes builder
276
* @param user - User information from awareness
277
* @param clientId - Client ID of the user
278
* @returns Decoration attributes for selection display
279
*/
280
function defaultSelectionBuilder(user: any, clientId: number): DecorationAttrs;
281
282
/**
283
* Default awareness state filter
284
* @param currentClientId - Current user's client ID
285
* @param userClientId - Other user's client ID
286
* @param user - User data from awareness
287
* @returns true if user should be displayed
288
*/
289
function defaultAwarenessStateFilter(
290
currentClientId: number,
291
userClientId: number,
292
user: any
293
): boolean;
294
295
/**
296
* Default filter for undo delete operations
297
* @param item - Yjs item being deleted
298
* @param protectedNodes - Set of protected node types
299
* @returns true if item should be deleted
300
*/
301
function defaultDeleteFilter(item: any, protectedNodes: Set<string>): boolean;
302
303
/** Default set of protected node types for undo operations */
304
const defaultProtectedNodes: Set<string>;
305
```
306
307
### Internal Utilities
308
309
Functions that are exported but primarily intended for internal use or advanced scenarios.
310
311
```javascript { .api }
312
/**
313
* Update Yjs fragment from ProseMirror node
314
* @param y - Yjs document
315
* @param yDomFragment - Yjs fragment to update
316
* @param pNode - ProseMirror node
317
* @param meta - Binding metadata
318
*/
319
function updateYFragment(y: Y.Doc, yDomFragment: Y.XmlFragment, pNode: Node, meta: BindingMetadata): void;
320
321
/**
322
* Create ProseMirror node from Yjs element
323
* @param yElement - Yjs element
324
* @param schema - ProseMirror schema
325
* @param meta - Binding metadata
326
* @returns ProseMirror node
327
*/
328
function createNodeFromYElement(yElement: Y.XmlElement, schema: Schema, meta: BindingMetadata): Node;
329
330
/**
331
* Check if Yjs item is visible in snapshot
332
* @param item - Yjs item to check
333
* @param snapshot - Snapshot to check against
334
* @returns true if item is visible
335
*/
336
function isVisible(item: any, snapshot?: Snapshot): boolean;
337
338
/**
339
* Create empty binding metadata
340
* @returns Empty binding metadata object
341
*/
342
function createEmptyMeta(): BindingMetadata;
343
344
/**
345
* Get current selection as relative positions for collaboration
346
* @param pmbinding - ProseMirror binding instance
347
* @param state - Current editor state
348
* @returns Selection object with relative positions
349
*/
350
function getRelativeSelection(pmbinding: ProsemirrorBinding, state: EditorState): {
351
type: string;
352
anchor: Y.RelativePosition;
353
head: Y.RelativePosition;
354
};
355
356
/**
357
* Convert Yjs attribute name to ProseMirror mark name
358
* @param attrName - Yjs attribute name
359
* @returns ProseMirror mark name
360
*/
361
function yattr2markname(attrName: string): string;
362
363
/**
364
* Convert attributes to ProseMirror marks
365
* @param attrs - Attribute object
366
* @param schema - ProseMirror schema
367
* @returns Array of ProseMirror marks
368
*/
369
function attributesToMarks(attrs: object, schema: Schema): Mark[];
370
371
/**
372
* Create cursor and selection decorations
373
* @param awarenessStates - Map of awareness states
374
* @param cursorBuilder - Function to build cursor elements
375
* @param selectionBuilder - Function to build selection attributes
376
* @param schema - ProseMirror schema
377
* @returns DecorationSet with cursor decorations
378
*/
379
function createDecorations(
380
awarenessStates: Map<number, any>,
381
cursorBuilder: (user: any, clientId: number) => HTMLElement,
382
selectionBuilder: (user: any, clientId: number) => DecorationAttrs,
383
schema: Schema
384
): DecorationSet;
385
```