@veltdev/prosemirror-crdt-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/cjs/index.js +479 -0
- package/cjs/index.js.map +1 -0
- package/esm/index.js +465 -0
- package/esm/types/index.d.ts +6 -0
- package/esm/types/index.d.ts.map +1 -0
- package/esm/types/prosemirror-crdt-editor.d.ts +3 -0
- package/esm/types/prosemirror-crdt-editor.d.ts.map +1 -0
- package/esm/types/schema.d.ts +6 -0
- package/esm/types/schema.d.ts.map +1 -0
- package/esm/types/types.d.ts +74 -0
- package/esm/types/types.d.ts.map +1 -0
- package/esm/types/use-collaboration.d.ts +3 -0
- package/esm/types/use-collaboration.d.ts.map +1 -0
- package/esm/types/utils.d.ts +3 -0
- package/esm/types/utils.d.ts.map +1 -0
- package/index.d.ts +87 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Velt ProseMirror CRDT React Library
|
|
2
|
+
|
|
3
|
+
With Velt ProseMirror CRDT React Library, you can add powerful multiplayer editing and state synchronization features to any React application using ProseMirror.
|
|
4
|
+
|
|
5
|
+
The library provides **React-native realtime primitives**:
|
|
6
|
+
|
|
7
|
+
- `ProseMirrorCrdtEditor` drop-in collaborative ProseMirror React component
|
|
8
|
+
- `useCollaboration` hook for managing shared state, sync status, and versions
|
|
9
|
+
- `createDefaultProseMirrorSchema` ready-made schema with lists and highlight support
|
|
10
|
+
- Shared `undo`/`redo` commands powered by y-prosemirror
|
|
11
|
+
- Fully-managed on a scalable realtime backend
|
|
12
|
+
- Powered by Yjs for industry-standard conflict resolution
|
|
13
|
+
|
|
14
|
+
**Features include:**
|
|
15
|
+
|
|
16
|
+
- **Multiplayer Editing** with real-time synchronization
|
|
17
|
+
- **Collaboration** with presence and remote cursors
|
|
18
|
+
- **Conflict Resolution** ensuring document consistency across all clients
|
|
19
|
+
- **Offline Support** with automatic synchronization upon reconnection
|
|
20
|
+
- **Version History** with save and restore APIs
|
|
21
|
+
- **React Hooks** for seamless integration with React components
|
|
22
|
+
- ... and so much more
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @veltdev/prosemirror-crdt-react @veltdev/prosemirror-crdt @veltdev/react prosemirror-model prosemirror-schema-basic prosemirror-schema-list prosemirror-state prosemirror-view y-prosemirror yjs
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
|
|
32
|
+
* Read the [documentation](https://docs.velt.dev/realtime-collaboration/crdt/setup/prosemirror) for setup guides and API references.
|
|
33
|
+
|
|
34
|
+
## Use cases
|
|
35
|
+
|
|
36
|
+
The ProseMirror CRDT React library is used to power:
|
|
37
|
+
|
|
38
|
+
* Collaborative editing tools
|
|
39
|
+
* Real-time document editing
|
|
40
|
+
* Shared workspaces
|
|
41
|
+
* Any shared, mutable environment
|
|
42
|
+
|
|
43
|
+
## Resources
|
|
44
|
+
|
|
45
|
+
* Explore [multiplayer editing](https://velt.dev/libraries/prosemirror) to see features like collaborative text, whiteboards, and data grids.
|
|
46
|
+
* [Sample Apps](https://velt.dev/examples): Check out example implementations for various use cases.
|
|
47
|
+
|
|
48
|
+
## Releases
|
|
49
|
+
|
|
50
|
+
* See the [latest changes](https://docs.velt.dev/release-notes/).
|
|
51
|
+
|
|
52
|
+
## Security
|
|
53
|
+
|
|
54
|
+
* Velt is SOC2 Type 2 and HIPAA compliant. [Learn more](https://velt.dev/security)
|
|
55
|
+
|
|
56
|
+
## Community
|
|
57
|
+
|
|
58
|
+
* [X](https://x.com/veltjs): To receive updates, announcements,
|
|
59
|
+
and general Velt tips.
|
package/cjs/index.js
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react$1 = require('react');
|
|
4
|
+
var react = require('@veltdev/react');
|
|
5
|
+
var prosemirrorCrdt = require('@veltdev/prosemirror-crdt');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var prosemirrorModel = require('prosemirror-model');
|
|
8
|
+
var prosemirrorSchemaBasic = require('prosemirror-schema-basic');
|
|
9
|
+
var prosemirrorSchemaList = require('prosemirror-schema-list');
|
|
10
|
+
|
|
11
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
12
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
13
|
+
function logError(message, error) {
|
|
14
|
+
try {
|
|
15
|
+
if (typeof console !== 'undefined' && console.error) {
|
|
16
|
+
console.error(`[ProseMirrorCRDTReact] ${message}`, error);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Logging must never throw into consumer code.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function toError(error) {
|
|
24
|
+
try {
|
|
25
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return new Error('Unknown error');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
33
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
34
|
+
function getVeltUser(client) {
|
|
35
|
+
try {
|
|
36
|
+
return client.getUser?.();
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function useCollaboration(config) {
|
|
43
|
+
const { client } = react.useVeltClient();
|
|
44
|
+
const veltInitState = react.useVeltInitState();
|
|
45
|
+
const [mount, setMount] = react$1.useState(null);
|
|
46
|
+
const [editorView, setEditorView] = react$1.useState(config.editorView ?? null);
|
|
47
|
+
const [manager, setManager] = react$1.useState(null);
|
|
48
|
+
const [isLoading, setIsLoading] = react$1.useState(true);
|
|
49
|
+
const [synced, setSynced] = react$1.useState(false);
|
|
50
|
+
const [status, setStatus] = react$1.useState('connecting');
|
|
51
|
+
const [error, setError] = react$1.useState(null);
|
|
52
|
+
const [versions, setVersions] = react$1.useState([]);
|
|
53
|
+
const managerRef = react$1.useRef(null);
|
|
54
|
+
const createdViewRef = react$1.useRef(null);
|
|
55
|
+
const configRef = react$1.useRef(config);
|
|
56
|
+
const activeClientRef = react$1.useRef(null);
|
|
57
|
+
const activeEditorIdRef = react$1.useRef(null);
|
|
58
|
+
const activeMountRef = react$1.useRef(null);
|
|
59
|
+
const activeExternalViewRef = react$1.useRef(null);
|
|
60
|
+
const unsubscribersRef = react$1.useRef([]);
|
|
61
|
+
configRef.current = config;
|
|
62
|
+
const veltClient = config.veltClient ?? client;
|
|
63
|
+
const enabled = config.enabled ?? true;
|
|
64
|
+
const effectiveMount = config.mount ?? mount;
|
|
65
|
+
const externalView = config.editorView ?? null;
|
|
66
|
+
const cleanupActiveManager = react$1.useCallback(() => {
|
|
67
|
+
try {
|
|
68
|
+
for (const unsubscribe of unsubscribersRef.current) {
|
|
69
|
+
try {
|
|
70
|
+
unsubscribe();
|
|
71
|
+
}
|
|
72
|
+
catch { /* ignore */ }
|
|
73
|
+
}
|
|
74
|
+
unsubscribersRef.current = [];
|
|
75
|
+
try {
|
|
76
|
+
managerRef.current?.destroy();
|
|
77
|
+
}
|
|
78
|
+
catch { /* ignore */ }
|
|
79
|
+
managerRef.current = null;
|
|
80
|
+
const createdView = createdViewRef.current;
|
|
81
|
+
createdViewRef.current = null;
|
|
82
|
+
if (createdView && configRef.current.destroyViewOnUnmount !== false) {
|
|
83
|
+
try {
|
|
84
|
+
createdView.destroy();
|
|
85
|
+
}
|
|
86
|
+
catch { /* ignore */ }
|
|
87
|
+
}
|
|
88
|
+
activeClientRef.current = null;
|
|
89
|
+
activeEditorIdRef.current = null;
|
|
90
|
+
activeMountRef.current = null;
|
|
91
|
+
activeExternalViewRef.current = null;
|
|
92
|
+
setManager(null);
|
|
93
|
+
setEditorView(externalView);
|
|
94
|
+
setIsLoading(true);
|
|
95
|
+
setSynced(false);
|
|
96
|
+
setStatus('connecting');
|
|
97
|
+
setError(null);
|
|
98
|
+
setVersions([]);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
logError('Failed to cleanup ProseMirror collaboration manager', err);
|
|
102
|
+
}
|
|
103
|
+
}, [externalView]);
|
|
104
|
+
const mountRef = react$1.useCallback((element) => {
|
|
105
|
+
try {
|
|
106
|
+
setMount(element);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
logError('Failed to capture ProseMirror mount element', err);
|
|
110
|
+
}
|
|
111
|
+
}, []);
|
|
112
|
+
react$1.useEffect(() => {
|
|
113
|
+
try {
|
|
114
|
+
if (enabled)
|
|
115
|
+
return;
|
|
116
|
+
cleanupActiveManager();
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
logError('Failed to disable ProseMirror collaboration', err);
|
|
120
|
+
}
|
|
121
|
+
}, [enabled, cleanupActiveManager]);
|
|
122
|
+
react$1.useEffect(() => {
|
|
123
|
+
try {
|
|
124
|
+
if (!enabled || !veltClient || !veltInitState || !config.schema)
|
|
125
|
+
return;
|
|
126
|
+
if (!externalView && !effectiveMount)
|
|
127
|
+
return;
|
|
128
|
+
if (!getVeltUser(veltClient))
|
|
129
|
+
return;
|
|
130
|
+
if (managerRef.current
|
|
131
|
+
&& activeClientRef.current === veltClient
|
|
132
|
+
&& activeEditorIdRef.current === config.editorId
|
|
133
|
+
&& activeMountRef.current === effectiveMount
|
|
134
|
+
&& activeExternalViewRef.current === externalView) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
cleanupActiveManager();
|
|
138
|
+
let mounted = true;
|
|
139
|
+
const init = async () => {
|
|
140
|
+
try {
|
|
141
|
+
const latest = configRef.current;
|
|
142
|
+
const created = await prosemirrorCrdt.createCollaboration({
|
|
143
|
+
editorId: latest.editorId,
|
|
144
|
+
veltClient: veltClient,
|
|
145
|
+
schema: latest.schema,
|
|
146
|
+
initialContent: latest.initialContent,
|
|
147
|
+
cursorData: latest.cursorData,
|
|
148
|
+
debounceMs: latest.debounceMs,
|
|
149
|
+
forceResetInitialContent: latest.forceResetInitialContent,
|
|
150
|
+
editorView: externalView ?? undefined,
|
|
151
|
+
autoInitialize: false,
|
|
152
|
+
onError: (err) => {
|
|
153
|
+
try {
|
|
154
|
+
if (mounted)
|
|
155
|
+
setError(err);
|
|
156
|
+
configRef.current.onError?.(err);
|
|
157
|
+
}
|
|
158
|
+
catch { /* ignore */ }
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
if (!mounted) {
|
|
162
|
+
try {
|
|
163
|
+
created.destroy();
|
|
164
|
+
}
|
|
165
|
+
catch { /* ignore */ }
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
let view = externalView;
|
|
169
|
+
if (!view && effectiveMount) {
|
|
170
|
+
view = created.createEditorView(effectiveMount, {
|
|
171
|
+
schema: latest.schema,
|
|
172
|
+
state: latest.state,
|
|
173
|
+
plugins: latest.plugins,
|
|
174
|
+
keymap: latest.keymap,
|
|
175
|
+
disableCursors: latest.disableCursors,
|
|
176
|
+
viewProps: latest.viewProps,
|
|
177
|
+
});
|
|
178
|
+
createdViewRef.current = view;
|
|
179
|
+
}
|
|
180
|
+
else if (view) {
|
|
181
|
+
created.attachEditorView(view);
|
|
182
|
+
}
|
|
183
|
+
if (!view) {
|
|
184
|
+
throw new Error('Failed to create ProseMirror EditorView');
|
|
185
|
+
}
|
|
186
|
+
managerRef.current = created;
|
|
187
|
+
activeClientRef.current = veltClient;
|
|
188
|
+
activeEditorIdRef.current = latest.editorId;
|
|
189
|
+
activeMountRef.current = effectiveMount;
|
|
190
|
+
activeExternalViewRef.current = externalView;
|
|
191
|
+
setManager(created);
|
|
192
|
+
setEditorView(view);
|
|
193
|
+
const unsubscribeStatus = created.onStatusChange((nextStatus) => {
|
|
194
|
+
try {
|
|
195
|
+
if (mounted)
|
|
196
|
+
setStatus(nextStatus);
|
|
197
|
+
}
|
|
198
|
+
catch { /* ignore */ }
|
|
199
|
+
});
|
|
200
|
+
const unsubscribeSynced = created.onSynced((isSynced) => {
|
|
201
|
+
try {
|
|
202
|
+
if (mounted)
|
|
203
|
+
setSynced(isSynced);
|
|
204
|
+
}
|
|
205
|
+
catch { /* ignore */ }
|
|
206
|
+
});
|
|
207
|
+
unsubscribersRef.current = [unsubscribeStatus, unsubscribeSynced];
|
|
208
|
+
await created.initialize();
|
|
209
|
+
if (mounted && created.synced)
|
|
210
|
+
setSynced(true);
|
|
211
|
+
if (mounted && created.status !== 'connecting')
|
|
212
|
+
setStatus(created.status);
|
|
213
|
+
try {
|
|
214
|
+
const list = await created.getVersions();
|
|
215
|
+
if (mounted)
|
|
216
|
+
setVersions(list);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
logError('Failed to load initial ProseMirror versions', err);
|
|
220
|
+
}
|
|
221
|
+
if (mounted) {
|
|
222
|
+
setIsLoading(false);
|
|
223
|
+
setError(null);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
logError('Failed to initialize ProseMirror collaboration', err);
|
|
228
|
+
if (mounted) {
|
|
229
|
+
setError(toError(err));
|
|
230
|
+
setIsLoading(false);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
void init();
|
|
235
|
+
return () => {
|
|
236
|
+
try {
|
|
237
|
+
mounted = false;
|
|
238
|
+
cleanupActiveManager();
|
|
239
|
+
}
|
|
240
|
+
catch { /* ignore cleanup */ }
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
logError('Error in useCollaboration effect', err);
|
|
245
|
+
}
|
|
246
|
+
}, [
|
|
247
|
+
cleanupActiveManager,
|
|
248
|
+
effectiveMount,
|
|
249
|
+
enabled,
|
|
250
|
+
externalView,
|
|
251
|
+
veltClient,
|
|
252
|
+
veltInitState,
|
|
253
|
+
config.editorId,
|
|
254
|
+
config.schema,
|
|
255
|
+
]);
|
|
256
|
+
const refreshVersions = react$1.useCallback(async () => {
|
|
257
|
+
try {
|
|
258
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
259
|
+
setVersions(list);
|
|
260
|
+
return list;
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
logError('Failed to refresh ProseMirror versions', err);
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
}, []);
|
|
267
|
+
const saveVersion = react$1.useCallback(async (name) => {
|
|
268
|
+
try {
|
|
269
|
+
const id = (await managerRef.current?.saveVersion(name)) ?? '';
|
|
270
|
+
try {
|
|
271
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
272
|
+
setVersions(list);
|
|
273
|
+
}
|
|
274
|
+
catch { /* best-effort refresh */ }
|
|
275
|
+
return id;
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
logError('Failed to save ProseMirror version', err);
|
|
279
|
+
return '';
|
|
280
|
+
}
|
|
281
|
+
}, []);
|
|
282
|
+
const restoreVersion = react$1.useCallback(async (versionId) => {
|
|
283
|
+
try {
|
|
284
|
+
const restored = (await managerRef.current?.restoreVersion(versionId)) ?? false;
|
|
285
|
+
if (restored) {
|
|
286
|
+
try {
|
|
287
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
288
|
+
setVersions(list);
|
|
289
|
+
}
|
|
290
|
+
catch { /* best-effort refresh */ }
|
|
291
|
+
}
|
|
292
|
+
return restored;
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
logError('Failed to restore ProseMirror version', err);
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
}, []);
|
|
299
|
+
const destroy = react$1.useCallback(() => {
|
|
300
|
+
try {
|
|
301
|
+
cleanupActiveManager();
|
|
302
|
+
setStatus('disconnected');
|
|
303
|
+
setIsLoading(false);
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
logError('Failed to destroy ProseMirror collaboration', err);
|
|
307
|
+
}
|
|
308
|
+
}, [cleanupActiveManager]);
|
|
309
|
+
return {
|
|
310
|
+
mountRef,
|
|
311
|
+
editorView,
|
|
312
|
+
manager,
|
|
313
|
+
isLoading,
|
|
314
|
+
synced,
|
|
315
|
+
isSynced: synced,
|
|
316
|
+
status,
|
|
317
|
+
error,
|
|
318
|
+
versions,
|
|
319
|
+
refreshVersions,
|
|
320
|
+
saveVersion,
|
|
321
|
+
restoreVersion,
|
|
322
|
+
destroy,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
327
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
328
|
+
const DEFAULT_HIGHLIGHT_COLOR = '#fff59d';
|
|
329
|
+
function createHighlightMarkSpec(defaultColor = DEFAULT_HIGHLIGHT_COLOR) {
|
|
330
|
+
try {
|
|
331
|
+
return {
|
|
332
|
+
attrs: {
|
|
333
|
+
color: { default: defaultColor },
|
|
334
|
+
},
|
|
335
|
+
parseDOM: [
|
|
336
|
+
{
|
|
337
|
+
tag: 'span[data-highlight]',
|
|
338
|
+
getAttrs: (node) => {
|
|
339
|
+
try {
|
|
340
|
+
const element = node;
|
|
341
|
+
return {
|
|
342
|
+
color: element.getAttribute('data-highlight-color') || defaultColor,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
return { color: defaultColor };
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
style: 'background-color',
|
|
352
|
+
getAttrs: (value) => {
|
|
353
|
+
try {
|
|
354
|
+
return { color: String(value || defaultColor) };
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
return { color: defaultColor };
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
toDOM(mark) {
|
|
363
|
+
try {
|
|
364
|
+
const color = mark.attrs.color || defaultColor;
|
|
365
|
+
return [
|
|
366
|
+
'span',
|
|
367
|
+
{
|
|
368
|
+
'data-highlight': 'true',
|
|
369
|
+
'data-highlight-color': color,
|
|
370
|
+
style: `background-color: ${color}`,
|
|
371
|
+
},
|
|
372
|
+
0,
|
|
373
|
+
];
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
return ['span', { 'data-highlight': 'true' }, 0];
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
logError('Failed to create highlight mark spec', error);
|
|
383
|
+
return {};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function createDefaultProseMirrorSchema() {
|
|
387
|
+
try {
|
|
388
|
+
const nodes = prosemirrorSchemaList.addListNodes(prosemirrorSchemaBasic.schema.spec.nodes, 'paragraph block*', 'block');
|
|
389
|
+
return new prosemirrorModel.Schema({
|
|
390
|
+
nodes,
|
|
391
|
+
marks: prosemirrorSchemaBasic.schema.spec.marks.addToEnd('highlight', createHighlightMarkSpec(DEFAULT_HIGHLIGHT_COLOR)),
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
logError('Failed to create default ProseMirror schema', error);
|
|
396
|
+
return prosemirrorSchemaBasic.schema;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const defaultProseMirrorSchema = createDefaultProseMirrorSchema();
|
|
400
|
+
|
|
401
|
+
function ProseMirrorCrdtEditor(props) {
|
|
402
|
+
const { editorId, documentId, veltClient, schema = defaultProseMirrorSchema, initialContent, forceResetInitialContent, cursorData, debounceMs, enabled, state, plugins, keymap, disableCursors, viewProps, destroyViewOnUnmount, onError, onStatusChange, onManagerReady, onEditorReady, className, editorClassName, } = props;
|
|
403
|
+
const resolvedEditorId = editorId ?? documentId ?? 'velt-prosemirror-crdt-document';
|
|
404
|
+
const { mountRef, editorView, manager, status } = useCollaboration({
|
|
405
|
+
editorId: resolvedEditorId,
|
|
406
|
+
veltClient,
|
|
407
|
+
schema,
|
|
408
|
+
initialContent,
|
|
409
|
+
forceResetInitialContent,
|
|
410
|
+
cursorData,
|
|
411
|
+
debounceMs,
|
|
412
|
+
enabled,
|
|
413
|
+
state,
|
|
414
|
+
plugins,
|
|
415
|
+
keymap,
|
|
416
|
+
disableCursors,
|
|
417
|
+
viewProps,
|
|
418
|
+
destroyViewOnUnmount,
|
|
419
|
+
onError,
|
|
420
|
+
});
|
|
421
|
+
const lastStatusRef = react$1.useRef(null);
|
|
422
|
+
react$1.useEffect(() => {
|
|
423
|
+
try {
|
|
424
|
+
if (status !== lastStatusRef.current) {
|
|
425
|
+
lastStatusRef.current = status;
|
|
426
|
+
onStatusChange?.(status);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
logError('Error in onStatusChange callback', error);
|
|
431
|
+
}
|
|
432
|
+
}, [status, onStatusChange]);
|
|
433
|
+
const notifiedManagerRef = react$1.useRef(null);
|
|
434
|
+
react$1.useEffect(() => {
|
|
435
|
+
try {
|
|
436
|
+
if (manager && manager !== notifiedManagerRef.current) {
|
|
437
|
+
notifiedManagerRef.current = manager;
|
|
438
|
+
onManagerReady?.(manager);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
logError('Error in onManagerReady callback', error);
|
|
443
|
+
}
|
|
444
|
+
}, [manager, onManagerReady]);
|
|
445
|
+
const notifiedEditorRef = react$1.useRef(null);
|
|
446
|
+
react$1.useEffect(() => {
|
|
447
|
+
try {
|
|
448
|
+
if (editorView && editorView !== notifiedEditorRef.current) {
|
|
449
|
+
notifiedEditorRef.current = editorView;
|
|
450
|
+
onEditorReady?.(editorView);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
logError('Error in onEditorReady callback', error);
|
|
455
|
+
}
|
|
456
|
+
}, [editorView, onEditorReady]);
|
|
457
|
+
try {
|
|
458
|
+
return (jsxRuntime.jsx("div", { className: className, "data-velt-prosemirror-crdt": "true", children: jsxRuntime.jsx("div", { ref: mountRef, className: editorClassName, "data-prosemirror-crdt-mount": "true" }) }));
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
logError('Failed to render ProseMirrorCrdtEditor', error);
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
Object.defineProperty(exports, "redo", {
|
|
467
|
+
enumerable: true,
|
|
468
|
+
get: function () { return prosemirrorCrdt.redo; }
|
|
469
|
+
});
|
|
470
|
+
Object.defineProperty(exports, "undo", {
|
|
471
|
+
enumerable: true,
|
|
472
|
+
get: function () { return prosemirrorCrdt.undo; }
|
|
473
|
+
});
|
|
474
|
+
exports.ProseMirrorCrdtEditor = ProseMirrorCrdtEditor;
|
|
475
|
+
exports.createDefaultProseMirrorSchema = createDefaultProseMirrorSchema;
|
|
476
|
+
exports.createHighlightMarkSpec = createHighlightMarkSpec;
|
|
477
|
+
exports.defaultProseMirrorSchema = defaultProseMirrorSchema;
|
|
478
|
+
exports.useCollaboration = useCollaboration;
|
|
479
|
+
//# sourceMappingURL=index.js.map
|
package/cjs/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/utils.ts","../../../src/use-collaboration.ts","../../../src/schema.ts","../../../src/prosemirror-crdt-editor.tsx"],"sourcesContent":[null,null,null,null],"names":["useVeltClient","useVeltInitState","useState","useRef","useCallback","useEffect","createCollaboration","addListNodes","basicSchema","Schema","_jsx"],"mappings":"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"}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
+
import { useVeltClient, useVeltInitState } from '@veltdev/react';
|
|
3
|
+
import { createCollaboration } from '@veltdev/prosemirror-crdt';
|
|
4
|
+
export { redo, undo } from '@veltdev/prosemirror-crdt';
|
|
5
|
+
import { jsx } from 'react/jsx-runtime';
|
|
6
|
+
import { Schema } from 'prosemirror-model';
|
|
7
|
+
import { schema } from 'prosemirror-schema-basic';
|
|
8
|
+
import { addListNodes } from 'prosemirror-schema-list';
|
|
9
|
+
|
|
10
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
11
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
12
|
+
function logError(message, error) {
|
|
13
|
+
try {
|
|
14
|
+
if (typeof console !== 'undefined' && console.error) {
|
|
15
|
+
console.error(`[ProseMirrorCRDTReact] ${message}`, error);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Logging must never throw into consumer code.
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function toError(error) {
|
|
23
|
+
try {
|
|
24
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return new Error('Unknown error');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
32
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
33
|
+
function getVeltUser(client) {
|
|
34
|
+
try {
|
|
35
|
+
return client.getUser?.();
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function useCollaboration(config) {
|
|
42
|
+
const { client } = useVeltClient();
|
|
43
|
+
const veltInitState = useVeltInitState();
|
|
44
|
+
const [mount, setMount] = useState(null);
|
|
45
|
+
const [editorView, setEditorView] = useState(config.editorView ?? null);
|
|
46
|
+
const [manager, setManager] = useState(null);
|
|
47
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
48
|
+
const [synced, setSynced] = useState(false);
|
|
49
|
+
const [status, setStatus] = useState('connecting');
|
|
50
|
+
const [error, setError] = useState(null);
|
|
51
|
+
const [versions, setVersions] = useState([]);
|
|
52
|
+
const managerRef = useRef(null);
|
|
53
|
+
const createdViewRef = useRef(null);
|
|
54
|
+
const configRef = useRef(config);
|
|
55
|
+
const activeClientRef = useRef(null);
|
|
56
|
+
const activeEditorIdRef = useRef(null);
|
|
57
|
+
const activeMountRef = useRef(null);
|
|
58
|
+
const activeExternalViewRef = useRef(null);
|
|
59
|
+
const unsubscribersRef = useRef([]);
|
|
60
|
+
configRef.current = config;
|
|
61
|
+
const veltClient = config.veltClient ?? client;
|
|
62
|
+
const enabled = config.enabled ?? true;
|
|
63
|
+
const effectiveMount = config.mount ?? mount;
|
|
64
|
+
const externalView = config.editorView ?? null;
|
|
65
|
+
const cleanupActiveManager = useCallback(() => {
|
|
66
|
+
try {
|
|
67
|
+
for (const unsubscribe of unsubscribersRef.current) {
|
|
68
|
+
try {
|
|
69
|
+
unsubscribe();
|
|
70
|
+
}
|
|
71
|
+
catch { /* ignore */ }
|
|
72
|
+
}
|
|
73
|
+
unsubscribersRef.current = [];
|
|
74
|
+
try {
|
|
75
|
+
managerRef.current?.destroy();
|
|
76
|
+
}
|
|
77
|
+
catch { /* ignore */ }
|
|
78
|
+
managerRef.current = null;
|
|
79
|
+
const createdView = createdViewRef.current;
|
|
80
|
+
createdViewRef.current = null;
|
|
81
|
+
if (createdView && configRef.current.destroyViewOnUnmount !== false) {
|
|
82
|
+
try {
|
|
83
|
+
createdView.destroy();
|
|
84
|
+
}
|
|
85
|
+
catch { /* ignore */ }
|
|
86
|
+
}
|
|
87
|
+
activeClientRef.current = null;
|
|
88
|
+
activeEditorIdRef.current = null;
|
|
89
|
+
activeMountRef.current = null;
|
|
90
|
+
activeExternalViewRef.current = null;
|
|
91
|
+
setManager(null);
|
|
92
|
+
setEditorView(externalView);
|
|
93
|
+
setIsLoading(true);
|
|
94
|
+
setSynced(false);
|
|
95
|
+
setStatus('connecting');
|
|
96
|
+
setError(null);
|
|
97
|
+
setVersions([]);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
logError('Failed to cleanup ProseMirror collaboration manager', err);
|
|
101
|
+
}
|
|
102
|
+
}, [externalView]);
|
|
103
|
+
const mountRef = useCallback((element) => {
|
|
104
|
+
try {
|
|
105
|
+
setMount(element);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
logError('Failed to capture ProseMirror mount element', err);
|
|
109
|
+
}
|
|
110
|
+
}, []);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
try {
|
|
113
|
+
if (enabled)
|
|
114
|
+
return;
|
|
115
|
+
cleanupActiveManager();
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
logError('Failed to disable ProseMirror collaboration', err);
|
|
119
|
+
}
|
|
120
|
+
}, [enabled, cleanupActiveManager]);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
try {
|
|
123
|
+
if (!enabled || !veltClient || !veltInitState || !config.schema)
|
|
124
|
+
return;
|
|
125
|
+
if (!externalView && !effectiveMount)
|
|
126
|
+
return;
|
|
127
|
+
if (!getVeltUser(veltClient))
|
|
128
|
+
return;
|
|
129
|
+
if (managerRef.current
|
|
130
|
+
&& activeClientRef.current === veltClient
|
|
131
|
+
&& activeEditorIdRef.current === config.editorId
|
|
132
|
+
&& activeMountRef.current === effectiveMount
|
|
133
|
+
&& activeExternalViewRef.current === externalView) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
cleanupActiveManager();
|
|
137
|
+
let mounted = true;
|
|
138
|
+
const init = async () => {
|
|
139
|
+
try {
|
|
140
|
+
const latest = configRef.current;
|
|
141
|
+
const created = await createCollaboration({
|
|
142
|
+
editorId: latest.editorId,
|
|
143
|
+
veltClient: veltClient,
|
|
144
|
+
schema: latest.schema,
|
|
145
|
+
initialContent: latest.initialContent,
|
|
146
|
+
cursorData: latest.cursorData,
|
|
147
|
+
debounceMs: latest.debounceMs,
|
|
148
|
+
forceResetInitialContent: latest.forceResetInitialContent,
|
|
149
|
+
editorView: externalView ?? undefined,
|
|
150
|
+
autoInitialize: false,
|
|
151
|
+
onError: (err) => {
|
|
152
|
+
try {
|
|
153
|
+
if (mounted)
|
|
154
|
+
setError(err);
|
|
155
|
+
configRef.current.onError?.(err);
|
|
156
|
+
}
|
|
157
|
+
catch { /* ignore */ }
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
if (!mounted) {
|
|
161
|
+
try {
|
|
162
|
+
created.destroy();
|
|
163
|
+
}
|
|
164
|
+
catch { /* ignore */ }
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
let view = externalView;
|
|
168
|
+
if (!view && effectiveMount) {
|
|
169
|
+
view = created.createEditorView(effectiveMount, {
|
|
170
|
+
schema: latest.schema,
|
|
171
|
+
state: latest.state,
|
|
172
|
+
plugins: latest.plugins,
|
|
173
|
+
keymap: latest.keymap,
|
|
174
|
+
disableCursors: latest.disableCursors,
|
|
175
|
+
viewProps: latest.viewProps,
|
|
176
|
+
});
|
|
177
|
+
createdViewRef.current = view;
|
|
178
|
+
}
|
|
179
|
+
else if (view) {
|
|
180
|
+
created.attachEditorView(view);
|
|
181
|
+
}
|
|
182
|
+
if (!view) {
|
|
183
|
+
throw new Error('Failed to create ProseMirror EditorView');
|
|
184
|
+
}
|
|
185
|
+
managerRef.current = created;
|
|
186
|
+
activeClientRef.current = veltClient;
|
|
187
|
+
activeEditorIdRef.current = latest.editorId;
|
|
188
|
+
activeMountRef.current = effectiveMount;
|
|
189
|
+
activeExternalViewRef.current = externalView;
|
|
190
|
+
setManager(created);
|
|
191
|
+
setEditorView(view);
|
|
192
|
+
const unsubscribeStatus = created.onStatusChange((nextStatus) => {
|
|
193
|
+
try {
|
|
194
|
+
if (mounted)
|
|
195
|
+
setStatus(nextStatus);
|
|
196
|
+
}
|
|
197
|
+
catch { /* ignore */ }
|
|
198
|
+
});
|
|
199
|
+
const unsubscribeSynced = created.onSynced((isSynced) => {
|
|
200
|
+
try {
|
|
201
|
+
if (mounted)
|
|
202
|
+
setSynced(isSynced);
|
|
203
|
+
}
|
|
204
|
+
catch { /* ignore */ }
|
|
205
|
+
});
|
|
206
|
+
unsubscribersRef.current = [unsubscribeStatus, unsubscribeSynced];
|
|
207
|
+
await created.initialize();
|
|
208
|
+
if (mounted && created.synced)
|
|
209
|
+
setSynced(true);
|
|
210
|
+
if (mounted && created.status !== 'connecting')
|
|
211
|
+
setStatus(created.status);
|
|
212
|
+
try {
|
|
213
|
+
const list = await created.getVersions();
|
|
214
|
+
if (mounted)
|
|
215
|
+
setVersions(list);
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
logError('Failed to load initial ProseMirror versions', err);
|
|
219
|
+
}
|
|
220
|
+
if (mounted) {
|
|
221
|
+
setIsLoading(false);
|
|
222
|
+
setError(null);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
logError('Failed to initialize ProseMirror collaboration', err);
|
|
227
|
+
if (mounted) {
|
|
228
|
+
setError(toError(err));
|
|
229
|
+
setIsLoading(false);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
void init();
|
|
234
|
+
return () => {
|
|
235
|
+
try {
|
|
236
|
+
mounted = false;
|
|
237
|
+
cleanupActiveManager();
|
|
238
|
+
}
|
|
239
|
+
catch { /* ignore cleanup */ }
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
logError('Error in useCollaboration effect', err);
|
|
244
|
+
}
|
|
245
|
+
}, [
|
|
246
|
+
cleanupActiveManager,
|
|
247
|
+
effectiveMount,
|
|
248
|
+
enabled,
|
|
249
|
+
externalView,
|
|
250
|
+
veltClient,
|
|
251
|
+
veltInitState,
|
|
252
|
+
config.editorId,
|
|
253
|
+
config.schema,
|
|
254
|
+
]);
|
|
255
|
+
const refreshVersions = useCallback(async () => {
|
|
256
|
+
try {
|
|
257
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
258
|
+
setVersions(list);
|
|
259
|
+
return list;
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
logError('Failed to refresh ProseMirror versions', err);
|
|
263
|
+
return [];
|
|
264
|
+
}
|
|
265
|
+
}, []);
|
|
266
|
+
const saveVersion = useCallback(async (name) => {
|
|
267
|
+
try {
|
|
268
|
+
const id = (await managerRef.current?.saveVersion(name)) ?? '';
|
|
269
|
+
try {
|
|
270
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
271
|
+
setVersions(list);
|
|
272
|
+
}
|
|
273
|
+
catch { /* best-effort refresh */ }
|
|
274
|
+
return id;
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
logError('Failed to save ProseMirror version', err);
|
|
278
|
+
return '';
|
|
279
|
+
}
|
|
280
|
+
}, []);
|
|
281
|
+
const restoreVersion = useCallback(async (versionId) => {
|
|
282
|
+
try {
|
|
283
|
+
const restored = (await managerRef.current?.restoreVersion(versionId)) ?? false;
|
|
284
|
+
if (restored) {
|
|
285
|
+
try {
|
|
286
|
+
const list = (await managerRef.current?.getVersions()) ?? [];
|
|
287
|
+
setVersions(list);
|
|
288
|
+
}
|
|
289
|
+
catch { /* best-effort refresh */ }
|
|
290
|
+
}
|
|
291
|
+
return restored;
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
logError('Failed to restore ProseMirror version', err);
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}, []);
|
|
298
|
+
const destroy = useCallback(() => {
|
|
299
|
+
try {
|
|
300
|
+
cleanupActiveManager();
|
|
301
|
+
setStatus('disconnected');
|
|
302
|
+
setIsLoading(false);
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
logError('Failed to destroy ProseMirror collaboration', err);
|
|
306
|
+
}
|
|
307
|
+
}, [cleanupActiveManager]);
|
|
308
|
+
return {
|
|
309
|
+
mountRef,
|
|
310
|
+
editorView,
|
|
311
|
+
manager,
|
|
312
|
+
isLoading,
|
|
313
|
+
synced,
|
|
314
|
+
isSynced: synced,
|
|
315
|
+
status,
|
|
316
|
+
error,
|
|
317
|
+
versions,
|
|
318
|
+
refreshVersions,
|
|
319
|
+
saveVersion,
|
|
320
|
+
restoreVersion,
|
|
321
|
+
destroy,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// POLICY: Every function/method in this file MUST be wrapped in try/catch.
|
|
326
|
+
// The package must NEVER throw an exception to the consumer's code.
|
|
327
|
+
const DEFAULT_HIGHLIGHT_COLOR = '#fff59d';
|
|
328
|
+
function createHighlightMarkSpec(defaultColor = DEFAULT_HIGHLIGHT_COLOR) {
|
|
329
|
+
try {
|
|
330
|
+
return {
|
|
331
|
+
attrs: {
|
|
332
|
+
color: { default: defaultColor },
|
|
333
|
+
},
|
|
334
|
+
parseDOM: [
|
|
335
|
+
{
|
|
336
|
+
tag: 'span[data-highlight]',
|
|
337
|
+
getAttrs: (node) => {
|
|
338
|
+
try {
|
|
339
|
+
const element = node;
|
|
340
|
+
return {
|
|
341
|
+
color: element.getAttribute('data-highlight-color') || defaultColor,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return { color: defaultColor };
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
style: 'background-color',
|
|
351
|
+
getAttrs: (value) => {
|
|
352
|
+
try {
|
|
353
|
+
return { color: String(value || defaultColor) };
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
return { color: defaultColor };
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
toDOM(mark) {
|
|
362
|
+
try {
|
|
363
|
+
const color = mark.attrs.color || defaultColor;
|
|
364
|
+
return [
|
|
365
|
+
'span',
|
|
366
|
+
{
|
|
367
|
+
'data-highlight': 'true',
|
|
368
|
+
'data-highlight-color': color,
|
|
369
|
+
style: `background-color: ${color}`,
|
|
370
|
+
},
|
|
371
|
+
0,
|
|
372
|
+
];
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return ['span', { 'data-highlight': 'true' }, 0];
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
logError('Failed to create highlight mark spec', error);
|
|
382
|
+
return {};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function createDefaultProseMirrorSchema() {
|
|
386
|
+
try {
|
|
387
|
+
const nodes = addListNodes(schema.spec.nodes, 'paragraph block*', 'block');
|
|
388
|
+
return new Schema({
|
|
389
|
+
nodes,
|
|
390
|
+
marks: schema.spec.marks.addToEnd('highlight', createHighlightMarkSpec(DEFAULT_HIGHLIGHT_COLOR)),
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
logError('Failed to create default ProseMirror schema', error);
|
|
395
|
+
return schema;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const defaultProseMirrorSchema = createDefaultProseMirrorSchema();
|
|
399
|
+
|
|
400
|
+
function ProseMirrorCrdtEditor(props) {
|
|
401
|
+
const { editorId, documentId, veltClient, schema = defaultProseMirrorSchema, initialContent, forceResetInitialContent, cursorData, debounceMs, enabled, state, plugins, keymap, disableCursors, viewProps, destroyViewOnUnmount, onError, onStatusChange, onManagerReady, onEditorReady, className, editorClassName, } = props;
|
|
402
|
+
const resolvedEditorId = editorId ?? documentId ?? 'velt-prosemirror-crdt-document';
|
|
403
|
+
const { mountRef, editorView, manager, status } = useCollaboration({
|
|
404
|
+
editorId: resolvedEditorId,
|
|
405
|
+
veltClient,
|
|
406
|
+
schema,
|
|
407
|
+
initialContent,
|
|
408
|
+
forceResetInitialContent,
|
|
409
|
+
cursorData,
|
|
410
|
+
debounceMs,
|
|
411
|
+
enabled,
|
|
412
|
+
state,
|
|
413
|
+
plugins,
|
|
414
|
+
keymap,
|
|
415
|
+
disableCursors,
|
|
416
|
+
viewProps,
|
|
417
|
+
destroyViewOnUnmount,
|
|
418
|
+
onError,
|
|
419
|
+
});
|
|
420
|
+
const lastStatusRef = useRef(null);
|
|
421
|
+
useEffect(() => {
|
|
422
|
+
try {
|
|
423
|
+
if (status !== lastStatusRef.current) {
|
|
424
|
+
lastStatusRef.current = status;
|
|
425
|
+
onStatusChange?.(status);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
logError('Error in onStatusChange callback', error);
|
|
430
|
+
}
|
|
431
|
+
}, [status, onStatusChange]);
|
|
432
|
+
const notifiedManagerRef = useRef(null);
|
|
433
|
+
useEffect(() => {
|
|
434
|
+
try {
|
|
435
|
+
if (manager && manager !== notifiedManagerRef.current) {
|
|
436
|
+
notifiedManagerRef.current = manager;
|
|
437
|
+
onManagerReady?.(manager);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
logError('Error in onManagerReady callback', error);
|
|
442
|
+
}
|
|
443
|
+
}, [manager, onManagerReady]);
|
|
444
|
+
const notifiedEditorRef = useRef(null);
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
try {
|
|
447
|
+
if (editorView && editorView !== notifiedEditorRef.current) {
|
|
448
|
+
notifiedEditorRef.current = editorView;
|
|
449
|
+
onEditorReady?.(editorView);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
logError('Error in onEditorReady callback', error);
|
|
454
|
+
}
|
|
455
|
+
}, [editorView, onEditorReady]);
|
|
456
|
+
try {
|
|
457
|
+
return (jsx("div", { className: className, "data-velt-prosemirror-crdt": "true", children: jsx("div", { ref: mountRef, className: editorClassName, "data-prosemirror-crdt-mount": "true" }) }));
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
logError('Failed to render ProseMirrorCrdtEditor', error);
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export { ProseMirrorCrdtEditor, createDefaultProseMirrorSchema, createHighlightMarkSpec, defaultProseMirrorSchema, useCollaboration };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { useCollaboration } from './use-collaboration';
|
|
2
|
+
export { ProseMirrorCrdtEditor } from './prosemirror-crdt-editor';
|
|
3
|
+
export { createDefaultProseMirrorSchema, createHighlightMarkSpec, defaultProseMirrorSchema, } from './schema';
|
|
4
|
+
export type { CollaborationManager, CursorData, ProseMirrorCrdtEditorProps, ProseMirrorCrdtHookResult, ProseMirrorEditorViewOptions, ProseMirrorJSON, ProseMirrorPluginOptions, SyncStatus, Unsubscribe, UseCollaborationConfig, UseCollaborationReturn, UseProseMirrorCrdtConfig, Version, } from './types';
|
|
5
|
+
export { redo, undo } from '@veltdev/prosemirror-crdt';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,oBAAoB,EACpB,UAAU,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,OAAO,GACR,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prosemirror-crdt-editor.d.ts","sourceRoot":"","sources":["../../../src/prosemirror-crdt-editor.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAG1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,sCA8FtE"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Schema } from 'prosemirror-model';
|
|
2
|
+
import type { MarkSpec } from 'prosemirror-model';
|
|
3
|
+
export declare function createHighlightMarkSpec(defaultColor?: string): MarkSpec;
|
|
4
|
+
export declare function createDefaultProseMirrorSchema(): Schema;
|
|
5
|
+
export declare const defaultProseMirrorSchema: Schema<any, any>;
|
|
6
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/schema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAQlD,wBAAgB,uBAAuB,CAAC,YAAY,SAA0B,GAAG,QAAQ,CAoDxF;AAED,wBAAgB,8BAA8B,IAAI,MAAM,CAmBvD;AAED,eAAO,MAAM,wBAAwB,kBAAmC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Velt } from '@veltdev/types';
|
|
2
|
+
import type { CollaborationConfig as BaseCollaborationConfig, CollaborationManager, CursorData, ProseMirrorEditorViewOptions, ProseMirrorPluginOptions, ProseMirrorJSON, SyncStatus, Unsubscribe, Version } from '@veltdev/prosemirror-crdt';
|
|
3
|
+
import type { Command, EditorState, Plugin } from 'prosemirror-state';
|
|
4
|
+
import type { DirectEditorProps, EditorView } from 'prosemirror-view';
|
|
5
|
+
export type { CollaborationManager, CursorData, ProseMirrorEditorViewOptions, ProseMirrorJSON, ProseMirrorPluginOptions, SyncStatus, Unsubscribe, Version, };
|
|
6
|
+
export interface UseProseMirrorCrdtConfig extends Omit<BaseCollaborationConfig, 'veltClient' | 'autoInitialize' | 'editorView'> {
|
|
7
|
+
/** Optional Velt client override. Falls back to useVeltClient(). */
|
|
8
|
+
veltClient?: Velt;
|
|
9
|
+
/** Set false to delay manager creation or destroy it while mounted. */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
/** Existing EditorView owned by the consumer. If omitted, the hook creates one. */
|
|
12
|
+
editorView?: EditorView | null;
|
|
13
|
+
/** DOM mount used when the hook creates the EditorView. */
|
|
14
|
+
mount?: Element | null;
|
|
15
|
+
/** Optional pre-created state. Collaboration plugins are appended by the base manager. */
|
|
16
|
+
state?: EditorState;
|
|
17
|
+
/** Extra ProseMirror plugins placed after y-prosemirror sync/cursor/undo plugins. */
|
|
18
|
+
plugins?: Plugin[];
|
|
19
|
+
/** Keymap commands merged through the base package helper. */
|
|
20
|
+
keymap?: Record<string, Command>;
|
|
21
|
+
/** Disable remote cursor rendering while keeping document sync enabled. */
|
|
22
|
+
disableCursors?: boolean;
|
|
23
|
+
/** Optional EditorView props passed through when the hook creates the view. */
|
|
24
|
+
viewProps?: Omit<DirectEditorProps, 'state'>;
|
|
25
|
+
/** Destroy the created EditorView during cleanup. Default: true. */
|
|
26
|
+
destroyViewOnUnmount?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface ProseMirrorCrdtHookResult {
|
|
29
|
+
/** DOM mount receiver for the managed ProseMirror EditorView. */
|
|
30
|
+
mountRef: (element: HTMLDivElement | null) => void;
|
|
31
|
+
/** Active ProseMirror EditorView. */
|
|
32
|
+
editorView: EditorView | null;
|
|
33
|
+
/** Escape hatch - the underlying base CollaborationManager. */
|
|
34
|
+
manager: CollaborationManager | null;
|
|
35
|
+
/** true until Velt, mount/view, and the base manager are initialized. */
|
|
36
|
+
isLoading: boolean;
|
|
37
|
+
/** true after the provider reports initial backend sync complete. */
|
|
38
|
+
synced: boolean;
|
|
39
|
+
/** Alias for synced, matching other Velt CRDT React wrappers. */
|
|
40
|
+
isSynced: boolean;
|
|
41
|
+
/** Current provider connection status. */
|
|
42
|
+
status: SyncStatus;
|
|
43
|
+
/** Non-null if initialization fails or the base package reports an error. */
|
|
44
|
+
error: Error | null;
|
|
45
|
+
/** Saved version metadata. */
|
|
46
|
+
versions: Version[];
|
|
47
|
+
/** Re-fetch saved versions from the base manager. */
|
|
48
|
+
refreshVersions: () => Promise<Version[]>;
|
|
49
|
+
/** Save a named version snapshot. Returns an empty string on failure. */
|
|
50
|
+
saveVersion: (name: string) => Promise<string>;
|
|
51
|
+
/** Restore a specific version. Returns false on failure. */
|
|
52
|
+
restoreVersion: (versionId: string) => Promise<boolean>;
|
|
53
|
+
/** Destroy the active manager early. Also runs on unmount. */
|
|
54
|
+
destroy: () => void;
|
|
55
|
+
}
|
|
56
|
+
export type UseCollaborationConfig = UseProseMirrorCrdtConfig;
|
|
57
|
+
export type UseCollaborationReturn = ProseMirrorCrdtHookResult;
|
|
58
|
+
export interface ProseMirrorCrdtEditorProps extends Omit<UseProseMirrorCrdtConfig, 'mount' | 'editorView' | 'editorId'> {
|
|
59
|
+
/** Unique editor/document identifier for syncing. */
|
|
60
|
+
editorId?: string;
|
|
61
|
+
/** Convenience document identifier used as editorId when editorId is omitted. */
|
|
62
|
+
documentId?: string;
|
|
63
|
+
/** Class name for the outer wrapper. */
|
|
64
|
+
className?: string;
|
|
65
|
+
/** Class name for the ProseMirror mount element. */
|
|
66
|
+
editorClassName?: string;
|
|
67
|
+
/** Called once the base CollaborationManager is ready. */
|
|
68
|
+
onManagerReady?: (manager: CollaborationManager) => void;
|
|
69
|
+
/** Called when the EditorView is created. */
|
|
70
|
+
onEditorReady?: (editorView: EditorView) => void;
|
|
71
|
+
/** Called whenever the sync connection status changes. */
|
|
72
|
+
onStatusChange?: (status: SyncStatus) => void;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-collaboration.d.ts","sourceRoot":"","sources":["../../../src/use-collaboration.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAWnF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,wBAAwB,GAAG,yBAAyB,CAgR5F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAQ/D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAM7C"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Velt } from '@veltdev/types';
|
|
2
|
+
import { CollaborationConfig, CollaborationManager, SyncStatus, Version } from '@veltdev/prosemirror-crdt';
|
|
3
|
+
export { CollaborationManager, CursorData, ProseMirrorEditorViewOptions, ProseMirrorJSON, ProseMirrorPluginOptions, SyncStatus, Unsubscribe, Version, redo, undo } from '@veltdev/prosemirror-crdt';
|
|
4
|
+
import { EditorState, Plugin, Command } from 'prosemirror-state';
|
|
5
|
+
import { EditorView, DirectEditorProps } from 'prosemirror-view';
|
|
6
|
+
import * as react from 'react';
|
|
7
|
+
import { Schema, MarkSpec } from 'prosemirror-model';
|
|
8
|
+
|
|
9
|
+
interface UseProseMirrorCrdtConfig extends Omit<CollaborationConfig, 'veltClient' | 'autoInitialize' | 'editorView'> {
|
|
10
|
+
/** Optional Velt client override. Falls back to useVeltClient(). */
|
|
11
|
+
veltClient?: Velt;
|
|
12
|
+
/** Set false to delay manager creation or destroy it while mounted. */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** Existing EditorView owned by the consumer. If omitted, the hook creates one. */
|
|
15
|
+
editorView?: EditorView | null;
|
|
16
|
+
/** DOM mount used when the hook creates the EditorView. */
|
|
17
|
+
mount?: Element | null;
|
|
18
|
+
/** Optional pre-created state. Collaboration plugins are appended by the base manager. */
|
|
19
|
+
state?: EditorState;
|
|
20
|
+
/** Extra ProseMirror plugins placed after y-prosemirror sync/cursor/undo plugins. */
|
|
21
|
+
plugins?: Plugin[];
|
|
22
|
+
/** Keymap commands merged through the base package helper. */
|
|
23
|
+
keymap?: Record<string, Command>;
|
|
24
|
+
/** Disable remote cursor rendering while keeping document sync enabled. */
|
|
25
|
+
disableCursors?: boolean;
|
|
26
|
+
/** Optional EditorView props passed through when the hook creates the view. */
|
|
27
|
+
viewProps?: Omit<DirectEditorProps, 'state'>;
|
|
28
|
+
/** Destroy the created EditorView during cleanup. Default: true. */
|
|
29
|
+
destroyViewOnUnmount?: boolean;
|
|
30
|
+
}
|
|
31
|
+
interface ProseMirrorCrdtHookResult {
|
|
32
|
+
/** DOM mount receiver for the managed ProseMirror EditorView. */
|
|
33
|
+
mountRef: (element: HTMLDivElement | null) => void;
|
|
34
|
+
/** Active ProseMirror EditorView. */
|
|
35
|
+
editorView: EditorView | null;
|
|
36
|
+
/** Escape hatch - the underlying base CollaborationManager. */
|
|
37
|
+
manager: CollaborationManager | null;
|
|
38
|
+
/** true until Velt, mount/view, and the base manager are initialized. */
|
|
39
|
+
isLoading: boolean;
|
|
40
|
+
/** true after the provider reports initial backend sync complete. */
|
|
41
|
+
synced: boolean;
|
|
42
|
+
/** Alias for synced, matching other Velt CRDT React wrappers. */
|
|
43
|
+
isSynced: boolean;
|
|
44
|
+
/** Current provider connection status. */
|
|
45
|
+
status: SyncStatus;
|
|
46
|
+
/** Non-null if initialization fails or the base package reports an error. */
|
|
47
|
+
error: Error | null;
|
|
48
|
+
/** Saved version metadata. */
|
|
49
|
+
versions: Version[];
|
|
50
|
+
/** Re-fetch saved versions from the base manager. */
|
|
51
|
+
refreshVersions: () => Promise<Version[]>;
|
|
52
|
+
/** Save a named version snapshot. Returns an empty string on failure. */
|
|
53
|
+
saveVersion: (name: string) => Promise<string>;
|
|
54
|
+
/** Restore a specific version. Returns false on failure. */
|
|
55
|
+
restoreVersion: (versionId: string) => Promise<boolean>;
|
|
56
|
+
/** Destroy the active manager early. Also runs on unmount. */
|
|
57
|
+
destroy: () => void;
|
|
58
|
+
}
|
|
59
|
+
type UseCollaborationConfig = UseProseMirrorCrdtConfig;
|
|
60
|
+
type UseCollaborationReturn = ProseMirrorCrdtHookResult;
|
|
61
|
+
interface ProseMirrorCrdtEditorProps extends Omit<UseProseMirrorCrdtConfig, 'mount' | 'editorView' | 'editorId'> {
|
|
62
|
+
/** Unique editor/document identifier for syncing. */
|
|
63
|
+
editorId?: string;
|
|
64
|
+
/** Convenience document identifier used as editorId when editorId is omitted. */
|
|
65
|
+
documentId?: string;
|
|
66
|
+
/** Class name for the outer wrapper. */
|
|
67
|
+
className?: string;
|
|
68
|
+
/** Class name for the ProseMirror mount element. */
|
|
69
|
+
editorClassName?: string;
|
|
70
|
+
/** Called once the base CollaborationManager is ready. */
|
|
71
|
+
onManagerReady?: (manager: CollaborationManager) => void;
|
|
72
|
+
/** Called when the EditorView is created. */
|
|
73
|
+
onEditorReady?: (editorView: EditorView) => void;
|
|
74
|
+
/** Called whenever the sync connection status changes. */
|
|
75
|
+
onStatusChange?: (status: SyncStatus) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
declare function useCollaboration(config: UseProseMirrorCrdtConfig): ProseMirrorCrdtHookResult;
|
|
79
|
+
|
|
80
|
+
declare function ProseMirrorCrdtEditor(props: ProseMirrorCrdtEditorProps): react.JSX.Element | null;
|
|
81
|
+
|
|
82
|
+
declare function createHighlightMarkSpec(defaultColor?: string): MarkSpec;
|
|
83
|
+
declare function createDefaultProseMirrorSchema(): Schema;
|
|
84
|
+
declare const defaultProseMirrorSchema: Schema<any, any>;
|
|
85
|
+
|
|
86
|
+
export { ProseMirrorCrdtEditor, createDefaultProseMirrorSchema, createHighlightMarkSpec, defaultProseMirrorSchema, useCollaboration };
|
|
87
|
+
export type { ProseMirrorCrdtEditorProps, ProseMirrorCrdtHookResult, UseCollaborationConfig, UseCollaborationReturn, UseProseMirrorCrdtConfig };
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@veltdev/prosemirror-crdt-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ProseMirror CRDT React library for Velt",
|
|
5
|
+
"homepage": "https://velt.dev",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"prosemirror",
|
|
8
|
+
"react",
|
|
9
|
+
"velt",
|
|
10
|
+
"real-time",
|
|
11
|
+
"realtime",
|
|
12
|
+
"toolkit",
|
|
13
|
+
"multiplayer",
|
|
14
|
+
"websockets",
|
|
15
|
+
"collaboration",
|
|
16
|
+
"collaborative",
|
|
17
|
+
"presence",
|
|
18
|
+
"rooms",
|
|
19
|
+
"documents",
|
|
20
|
+
"conflict resolution",
|
|
21
|
+
"crdts",
|
|
22
|
+
"comment",
|
|
23
|
+
"comments",
|
|
24
|
+
"recording",
|
|
25
|
+
"screen recording",
|
|
26
|
+
"cursors",
|
|
27
|
+
"notifications",
|
|
28
|
+
"cord",
|
|
29
|
+
"liveblocks"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
33
|
+
"version:update": "node ../update-npm-package.mjs",
|
|
34
|
+
"publish:crdt": "npm publish --access public"
|
|
35
|
+
},
|
|
36
|
+
"author": "Velt Inc.",
|
|
37
|
+
"license": "Proprietary",
|
|
38
|
+
"main": "cjs/index.js",
|
|
39
|
+
"module": "esm/index.js",
|
|
40
|
+
"types": "index.d.ts",
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@veltdev/prosemirror-crdt": ">=1.0.0-beta.1",
|
|
43
|
+
"@veltdev/react": ">=5.0.2-beta.8",
|
|
44
|
+
"@veltdev/types": ">=5.0.2-beta.8",
|
|
45
|
+
"prosemirror-model": "^1.25.10",
|
|
46
|
+
"prosemirror-schema-basic": "^1.2.4",
|
|
47
|
+
"prosemirror-schema-list": "^1.5.1",
|
|
48
|
+
"prosemirror-state": "^1.4.4",
|
|
49
|
+
"prosemirror-view": "^1.42.0",
|
|
50
|
+
"react": "^18.2.0 || ^19.0.0",
|
|
51
|
+
"react-dom": "^18.2.0 || ^19.0.0",
|
|
52
|
+
"y-prosemirror": "^1.3.7",
|
|
53
|
+
"yjs": ">=13.6.31"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"@veltdev/types": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|