@liveblocks/prosemirror 0.0.0 → 3.21.0-exp4

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/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2021-present Liveblocks
2
+
3
+ This repository contains software under two licenses:
4
+
5
+ 1. Most of the code in this repository is licensed under the
6
+ Apache License 2.0 — see licenses/LICENSE-APACHE-2.0 for the
7
+ full license text.
8
+
9
+ 2. The following components are licensed under the
10
+ GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later)
11
+ — see licenses/LICENSE-AGPL-3.0 for the full license text:
12
+
13
+ - packages/liveblocks-server (published as @liveblocks/server)
14
+ - tools/liveblocks-cli (published as liveblocks)
15
+
16
+ Each package's own LICENSE or package.json specifies its applicable license.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # `@liveblocks/prosemirror`
2
+
3
+ ProseMirror collaboration plugins backed by Liveblocks.
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+
3
+ var prosemirrorState = require('prosemirror-state');
4
+ var prosemirrorView = require('prosemirror-view');
5
+ var plugin = require('./plugin.cjs');
6
+
7
+ const LIVEBLOCKS_CARET_PRESENCE_KEY = "liveblocksTiptap";
8
+ const LIVEBLOCKS_CARET_PLUGIN_KEY = new prosemirrorState.PluginKey("liveblocks-collaboration-caret");
9
+ function isCursorPresence(value) {
10
+ return typeof value === "object" && value !== null && typeof value.field === "string" && typeof value.anchor === "number" && typeof value.head === "number";
11
+ }
12
+ function getCursorUser(value) {
13
+ if (typeof value !== "object" || value === null) {
14
+ return void 0;
15
+ }
16
+ const user = value;
17
+ const name = typeof user.name === "string" ? user.name : void 0;
18
+ const color = typeof user.color === "string" ? user.color : void 0;
19
+ return name !== void 0 || color !== void 0 ? { name, color } : void 0;
20
+ }
21
+ function presencePatch(presence) {
22
+ const user = getCursorUser(presence.user);
23
+ return {
24
+ [LIVEBLOCKS_CARET_PRESENCE_KEY]: {
25
+ field: presence.field,
26
+ anchor: presence.anchor,
27
+ head: presence.head,
28
+ ...user !== void 0 ? { user } : {}
29
+ }
30
+ };
31
+ }
32
+ function createCursorElement(user) {
33
+ const color = user?.color ?? "#0f83ff";
34
+ const name = user?.name ?? "Anonymous";
35
+ const cursor = document.createElement("span");
36
+ cursor.classList.add("collaboration-carets__caret");
37
+ cursor.setAttribute("style", `border-color: ${color}`);
38
+ const label = document.createElement("div");
39
+ label.classList.add("collaboration-carets__label");
40
+ label.setAttribute("style", `background-color: ${color}`);
41
+ label.insertBefore(document.createTextNode(name), null);
42
+ cursor.insertBefore(label, null);
43
+ return cursor;
44
+ }
45
+ function clampPosition(position, doc) {
46
+ return Math.max(0, Math.min(position, doc.content.size));
47
+ }
48
+ function normalizeCaretPosition(position, doc) {
49
+ const clampedPosition = clampPosition(position, doc);
50
+ const $position = doc.resolve(clampedPosition);
51
+ if ($position.parent.isTextblock) {
52
+ return clampedPosition;
53
+ }
54
+ return prosemirrorState.Selection.near($position, -1).anchor;
55
+ }
56
+ function getRemoteCursors(room, field, previousCursors = []) {
57
+ const cursors = [];
58
+ for (const other of room.getOthers()) {
59
+ const rawPresence = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];
60
+ if (!isCursorPresence(rawPresence) || rawPresence.field !== field) {
61
+ continue;
62
+ }
63
+ const user = getCursorUser(rawPresence.user) ?? getCursorUser(other.info);
64
+ const previousCursor = previousCursors.find(
65
+ (cursor) => cursor.connectionId === other.connectionId
66
+ );
67
+ const hasPresencePositionChanged = previousCursor === void 0 || previousCursor.rawAnchor !== rawPresence.anchor || previousCursor.rawHead !== rawPresence.head;
68
+ cursors.push({
69
+ anchor: hasPresencePositionChanged ? rawPresence.anchor : previousCursor.anchor,
70
+ connectionId: other.connectionId,
71
+ head: hasPresencePositionChanged ? rawPresence.head : previousCursor.head,
72
+ rawAnchor: rawPresence.anchor,
73
+ rawHead: rawPresence.head,
74
+ user
75
+ });
76
+ }
77
+ return cursors;
78
+ }
79
+ function buildDecorationsFromCursors(cursors, doc) {
80
+ const decorations = [];
81
+ for (const cursor of cursors) {
82
+ const anchor = clampPosition(cursor.anchor, doc);
83
+ const head = clampPosition(cursor.head, doc);
84
+ const from = Math.min(anchor, head);
85
+ const to = Math.max(anchor, head);
86
+ const user = cursor.user;
87
+ const color = user?.color ?? "#0f83ff";
88
+ if (from !== to) {
89
+ decorations.push(
90
+ prosemirrorView.Decoration.inline(from, to, {
91
+ class: "collaboration-carets__selection",
92
+ style: `background-color: ${color}33`
93
+ })
94
+ );
95
+ }
96
+ decorations.push(
97
+ prosemirrorView.Decoration.widget(
98
+ normalizeCaretPosition(head, doc),
99
+ () => createCursorElement(user),
100
+ {
101
+ key: `liveblocks-caret-${cursor.connectionId}`,
102
+ side: -1
103
+ }
104
+ )
105
+ );
106
+ }
107
+ return prosemirrorView.DecorationSet.create(doc, decorations);
108
+ }
109
+ function createLiveblocksCollaborationCaretPlugin(options, storage) {
110
+ const room = options.room;
111
+ if (room === void 0) {
112
+ throw new Error("[Liveblocks] The Liveblocks caret plugin requires a room.");
113
+ }
114
+ let view;
115
+ let unsubscribe;
116
+ const updatePresence = (nextView) => {
117
+ const { anchor, head } = nextView.state.selection;
118
+ room.updatePresence(
119
+ presencePatch({
120
+ field: options.field,
121
+ anchor,
122
+ head,
123
+ user: options.user
124
+ })
125
+ );
126
+ };
127
+ const updateDecorations = () => {
128
+ if (view === void 0) {
129
+ return;
130
+ }
131
+ storage.users = room.getOthers().map((other) => {
132
+ const rawPresence = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];
133
+ const cursorPresence = isCursorPresence(rawPresence) ? rawPresence : void 0;
134
+ return {
135
+ clientId: other.connectionId,
136
+ ...getCursorUser(cursorPresence?.user) ?? getCursorUser(other.info)
137
+ };
138
+ });
139
+ const previousCursors = LIVEBLOCKS_CARET_PLUGIN_KEY.getState(view.state)?.cursors ?? [];
140
+ const cursors = getRemoteCursors(room, options.field, previousCursors);
141
+ view.dispatch(
142
+ view.state.tr.setMeta(LIVEBLOCKS_CARET_PLUGIN_KEY, {
143
+ cursors
144
+ })
145
+ );
146
+ };
147
+ return new prosemirrorState.Plugin({
148
+ key: LIVEBLOCKS_CARET_PLUGIN_KEY,
149
+ state: {
150
+ init(_, state) {
151
+ return {
152
+ cursors: [],
153
+ decorations: prosemirrorView.DecorationSet.create(state.doc, [])
154
+ };
155
+ },
156
+ apply(tr, state) {
157
+ const meta = tr.getMeta(LIVEBLOCKS_CARET_PLUGIN_KEY);
158
+ if (meta !== void 0) {
159
+ return {
160
+ cursors: meta.cursors,
161
+ decorations: buildDecorationsFromCursors(meta.cursors, tr.doc)
162
+ };
163
+ }
164
+ if (!tr.docChanged) {
165
+ return state;
166
+ }
167
+ if (!tr.getMeta(plugin.LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)) {
168
+ const cursors = state.cursors.map((cursor) => ({
169
+ ...cursor,
170
+ anchor: tr.mapping.map(cursor.anchor, -1),
171
+ head: tr.mapping.map(cursor.head, -1)
172
+ }));
173
+ return {
174
+ cursors,
175
+ decorations: buildDecorationsFromCursors(cursors, tr.doc)
176
+ };
177
+ }
178
+ return {
179
+ cursors: state.cursors,
180
+ decorations: buildDecorationsFromCursors(state.cursors, tr.doc)
181
+ };
182
+ }
183
+ },
184
+ props: {
185
+ decorations(state) {
186
+ return LIVEBLOCKS_CARET_PLUGIN_KEY.getState(state)?.decorations ?? prosemirrorView.DecorationSet.empty;
187
+ }
188
+ },
189
+ view(editorView) {
190
+ view = editorView;
191
+ updatePresence(editorView);
192
+ updateDecorations();
193
+ unsubscribe = room.events.others.subscribe(updateDecorations);
194
+ return {
195
+ update(nextView, prevState) {
196
+ view = nextView;
197
+ if (!nextView.state.selection.eq(prevState.selection)) {
198
+ updatePresence(nextView);
199
+ }
200
+ },
201
+ destroy() {
202
+ unsubscribe?.();
203
+ unsubscribe = void 0;
204
+ view = void 0;
205
+ room.updatePresence({ [LIVEBLOCKS_CARET_PRESENCE_KEY]: null });
206
+ }
207
+ };
208
+ }
209
+ });
210
+ }
211
+
212
+ exports.LIVEBLOCKS_CARET_PLUGIN_KEY = LIVEBLOCKS_CARET_PLUGIN_KEY;
213
+ exports.LIVEBLOCKS_CARET_PRESENCE_KEY = LIVEBLOCKS_CARET_PRESENCE_KEY;
214
+ exports.createLiveblocksCollaborationCaretPlugin = createLiveblocksCollaborationCaretPlugin;
215
+ exports.getCursorUser = getCursorUser;
216
+ exports.presencePatch = presencePatch;
217
+ //# sourceMappingURL=cursors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursors.cjs","sources":["../src/cursors.ts"],"sourcesContent":["import type { JsonObject } from \"@liveblocks/client\";\nimport type { Node as ProseMirrorNode } from \"prosemirror-model\";\nimport { Plugin, PluginKey, Selection } from \"prosemirror-state\";\nimport type { EditorView } from \"prosemirror-view\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"./plugin\";\nimport type { LiveblocksProsemirrorRoom } from \"./types\";\n\nexport const LIVEBLOCKS_CARET_PRESENCE_KEY = \"liveblocksTiptap\";\n\nexport type CursorUser = {\n name?: string;\n color?: string;\n};\n\ntype CursorPresence = {\n field: string;\n anchor: number;\n head: number;\n user?: CursorUser;\n};\n\nexport type CollaborationCaretStorage = {\n users: { clientId: number; [key: string]: unknown }[];\n};\n\nexport type RemoteCursor = {\n anchor: number;\n connectionId: number;\n head: number;\n rawAnchor: number;\n rawHead: number;\n user?: CursorUser;\n};\n\nexport type CollaborationCaretPluginState = {\n cursors: RemoteCursor[];\n decorations: DecorationSet;\n};\n\nexport type CollaborationCaretOptions = {\n room?: LiveblocksProsemirrorRoom;\n field: string;\n user: CursorUser;\n};\n\nexport const LIVEBLOCKS_CARET_PLUGIN_KEY =\n new PluginKey<CollaborationCaretPluginState>(\"liveblocks-collaboration-caret\");\n\nfunction isCursorPresence(value: unknown): value is CursorPresence {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { field?: unknown }).field === \"string\" &&\n typeof (value as { anchor?: unknown }).anchor === \"number\" &&\n typeof (value as { head?: unknown }).head === \"number\"\n );\n}\n\nexport function getCursorUser(value: unknown): CursorUser | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const user = value as { name?: unknown; color?: unknown };\n const name = typeof user.name === \"string\" ? user.name : undefined;\n const color = typeof user.color === \"string\" ? user.color : undefined;\n\n return name !== undefined || color !== undefined ? { name, color } : undefined;\n}\n\nexport function presencePatch(presence: CursorPresence): JsonObject {\n const user = getCursorUser(presence.user);\n\n return {\n [LIVEBLOCKS_CARET_PRESENCE_KEY]: {\n field: presence.field,\n anchor: presence.anchor,\n head: presence.head,\n ...(user !== undefined ? { user } : {}),\n },\n };\n}\n\nfunction createCursorElement(user: CursorUser | undefined): HTMLElement {\n const color = user?.color ?? \"#0f83ff\";\n const name = user?.name ?? \"Anonymous\";\n const cursor = document.createElement(\"span\");\n\n cursor.classList.add(\"collaboration-carets__caret\");\n cursor.setAttribute(\"style\", `border-color: ${color}`);\n\n const label = document.createElement(\"div\");\n label.classList.add(\"collaboration-carets__label\");\n label.setAttribute(\"style\", `background-color: ${color}`);\n label.insertBefore(document.createTextNode(name), null);\n cursor.insertBefore(label, null);\n\n return cursor;\n}\n\nfunction clampPosition(position: number, doc: ProseMirrorNode): number {\n return Math.max(0, Math.min(position, doc.content.size));\n}\n\nfunction normalizeCaretPosition(position: number, doc: ProseMirrorNode): number {\n const clampedPosition = clampPosition(position, doc);\n const $position = doc.resolve(clampedPosition);\n\n if ($position.parent.isTextblock) {\n return clampedPosition;\n }\n\n return Selection.near($position, -1).anchor;\n}\n\nfunction getRemoteCursors(\n room: LiveblocksProsemirrorRoom,\n field: string,\n previousCursors: readonly RemoteCursor[] = []\n): RemoteCursor[] {\n const cursors: RemoteCursor[] = [];\n\n for (const other of room.getOthers()) {\n const rawPresence: unknown = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];\n if (!isCursorPresence(rawPresence) || rawPresence.field !== field) {\n continue;\n }\n\n const user = getCursorUser(rawPresence.user) ?? getCursorUser(other.info);\n const previousCursor = previousCursors.find(\n (cursor) => cursor.connectionId === other.connectionId\n );\n const hasPresencePositionChanged =\n previousCursor === undefined ||\n previousCursor.rawAnchor !== rawPresence.anchor ||\n previousCursor.rawHead !== rawPresence.head;\n\n cursors.push({\n anchor: hasPresencePositionChanged\n ? rawPresence.anchor\n : previousCursor.anchor,\n connectionId: other.connectionId,\n head: hasPresencePositionChanged ? rawPresence.head : previousCursor.head,\n rawAnchor: rawPresence.anchor,\n rawHead: rawPresence.head,\n user,\n });\n }\n\n return cursors;\n}\n\nfunction buildDecorationsFromCursors(\n cursors: readonly RemoteCursor[],\n doc: ProseMirrorNode\n): DecorationSet {\n const decorations: Decoration[] = [];\n\n for (const cursor of cursors) {\n const anchor = clampPosition(cursor.anchor, doc);\n const head = clampPosition(cursor.head, doc);\n const from = Math.min(anchor, head);\n const to = Math.max(anchor, head);\n const user = cursor.user;\n const color = user?.color ?? \"#0f83ff\";\n\n if (from !== to) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"collaboration-carets__selection\",\n style: `background-color: ${color}33`,\n })\n );\n }\n\n decorations.push(\n Decoration.widget(\n normalizeCaretPosition(head, doc),\n () => createCursorElement(user),\n {\n key: `liveblocks-caret-${cursor.connectionId}`,\n side: -1,\n }\n )\n );\n }\n\n return DecorationSet.create(doc, decorations);\n}\n\nexport function createLiveblocksCollaborationCaretPlugin(\n options: CollaborationCaretOptions,\n storage: CollaborationCaretStorage\n): Plugin {\n const room = options.room;\n if (room === undefined) {\n throw new Error(\"[Liveblocks] The Liveblocks caret plugin requires a room.\");\n }\n\n let view: EditorView | undefined;\n let unsubscribe: (() => void) | undefined;\n\n const updatePresence = (nextView: EditorView) => {\n const { anchor, head } = nextView.state.selection;\n room.updatePresence(\n presencePatch({\n field: options.field,\n anchor,\n head,\n user: options.user,\n })\n );\n };\n\n const updateDecorations = () => {\n if (view === undefined) {\n return;\n }\n\n storage.users = room.getOthers().map((other) => {\n const rawPresence: unknown = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];\n const cursorPresence = isCursorPresence(rawPresence)\n ? rawPresence\n : undefined;\n\n return {\n clientId: other.connectionId,\n ...(getCursorUser(cursorPresence?.user) ?? getCursorUser(other.info)),\n };\n });\n\n const previousCursors =\n LIVEBLOCKS_CARET_PLUGIN_KEY.getState(view.state)?.cursors ?? [];\n const cursors = getRemoteCursors(room, options.field, previousCursors);\n\n view.dispatch(\n view.state.tr.setMeta(LIVEBLOCKS_CARET_PLUGIN_KEY, {\n cursors,\n })\n );\n };\n\n return new Plugin({\n key: LIVEBLOCKS_CARET_PLUGIN_KEY,\n state: {\n init(_, state): CollaborationCaretPluginState {\n return {\n cursors: [],\n decorations: DecorationSet.create(state.doc, []),\n };\n },\n apply(tr, state): CollaborationCaretPluginState {\n const meta = tr.getMeta(LIVEBLOCKS_CARET_PLUGIN_KEY) as\n | { cursors: RemoteCursor[] }\n | undefined;\n\n if (meta !== undefined) {\n return {\n cursors: meta.cursors,\n decorations: buildDecorationsFromCursors(meta.cursors, tr.doc),\n };\n }\n\n if (!tr.docChanged) {\n return state;\n }\n\n if (!tr.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)) {\n const cursors = state.cursors.map((cursor) => ({\n ...cursor,\n anchor: tr.mapping.map(cursor.anchor, -1),\n head: tr.mapping.map(cursor.head, -1),\n }));\n\n return {\n cursors,\n decorations: buildDecorationsFromCursors(cursors, tr.doc),\n };\n }\n\n // Remote presence can arrive before the matching remote document\n // update. Keep the stored cursor positions and rebuild them against\n // the new document so pre-arrived presence is no longer clamped to the\n // old document size.\n return {\n cursors: state.cursors,\n decorations: buildDecorationsFromCursors(state.cursors, tr.doc),\n };\n },\n },\n props: {\n decorations(state) {\n return (\n LIVEBLOCKS_CARET_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n },\n view(editorView) {\n view = editorView;\n updatePresence(editorView);\n updateDecorations();\n unsubscribe = room.events.others.subscribe(updateDecorations);\n\n return {\n update(nextView, prevState) {\n view = nextView;\n\n if (!nextView.state.selection.eq(prevState.selection)) {\n updatePresence(nextView);\n }\n\n },\n destroy() {\n unsubscribe?.();\n unsubscribe = undefined;\n view = undefined;\n room.updatePresence({ [LIVEBLOCKS_CARET_PRESENCE_KEY]: null });\n },\n };\n },\n });\n}\n"],"names":["PluginKey","Selection","Decoration","DecorationSet","Plugin","LIVEBLOCKS_COLLABORATION_PLUGIN_KEY"],"mappings":"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"}
@@ -0,0 +1,211 @@
1
+ import { PluginKey, Selection, Plugin } from 'prosemirror-state';
2
+ import { Decoration, DecorationSet } from 'prosemirror-view';
3
+ import { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from './plugin.js';
4
+
5
+ const LIVEBLOCKS_CARET_PRESENCE_KEY = "liveblocksTiptap";
6
+ const LIVEBLOCKS_CARET_PLUGIN_KEY = new PluginKey("liveblocks-collaboration-caret");
7
+ function isCursorPresence(value) {
8
+ return typeof value === "object" && value !== null && typeof value.field === "string" && typeof value.anchor === "number" && typeof value.head === "number";
9
+ }
10
+ function getCursorUser(value) {
11
+ if (typeof value !== "object" || value === null) {
12
+ return void 0;
13
+ }
14
+ const user = value;
15
+ const name = typeof user.name === "string" ? user.name : void 0;
16
+ const color = typeof user.color === "string" ? user.color : void 0;
17
+ return name !== void 0 || color !== void 0 ? { name, color } : void 0;
18
+ }
19
+ function presencePatch(presence) {
20
+ const user = getCursorUser(presence.user);
21
+ return {
22
+ [LIVEBLOCKS_CARET_PRESENCE_KEY]: {
23
+ field: presence.field,
24
+ anchor: presence.anchor,
25
+ head: presence.head,
26
+ ...user !== void 0 ? { user } : {}
27
+ }
28
+ };
29
+ }
30
+ function createCursorElement(user) {
31
+ const color = user?.color ?? "#0f83ff";
32
+ const name = user?.name ?? "Anonymous";
33
+ const cursor = document.createElement("span");
34
+ cursor.classList.add("collaboration-carets__caret");
35
+ cursor.setAttribute("style", `border-color: ${color}`);
36
+ const label = document.createElement("div");
37
+ label.classList.add("collaboration-carets__label");
38
+ label.setAttribute("style", `background-color: ${color}`);
39
+ label.insertBefore(document.createTextNode(name), null);
40
+ cursor.insertBefore(label, null);
41
+ return cursor;
42
+ }
43
+ function clampPosition(position, doc) {
44
+ return Math.max(0, Math.min(position, doc.content.size));
45
+ }
46
+ function normalizeCaretPosition(position, doc) {
47
+ const clampedPosition = clampPosition(position, doc);
48
+ const $position = doc.resolve(clampedPosition);
49
+ if ($position.parent.isTextblock) {
50
+ return clampedPosition;
51
+ }
52
+ return Selection.near($position, -1).anchor;
53
+ }
54
+ function getRemoteCursors(room, field, previousCursors = []) {
55
+ const cursors = [];
56
+ for (const other of room.getOthers()) {
57
+ const rawPresence = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];
58
+ if (!isCursorPresence(rawPresence) || rawPresence.field !== field) {
59
+ continue;
60
+ }
61
+ const user = getCursorUser(rawPresence.user) ?? getCursorUser(other.info);
62
+ const previousCursor = previousCursors.find(
63
+ (cursor) => cursor.connectionId === other.connectionId
64
+ );
65
+ const hasPresencePositionChanged = previousCursor === void 0 || previousCursor.rawAnchor !== rawPresence.anchor || previousCursor.rawHead !== rawPresence.head;
66
+ cursors.push({
67
+ anchor: hasPresencePositionChanged ? rawPresence.anchor : previousCursor.anchor,
68
+ connectionId: other.connectionId,
69
+ head: hasPresencePositionChanged ? rawPresence.head : previousCursor.head,
70
+ rawAnchor: rawPresence.anchor,
71
+ rawHead: rawPresence.head,
72
+ user
73
+ });
74
+ }
75
+ return cursors;
76
+ }
77
+ function buildDecorationsFromCursors(cursors, doc) {
78
+ const decorations = [];
79
+ for (const cursor of cursors) {
80
+ const anchor = clampPosition(cursor.anchor, doc);
81
+ const head = clampPosition(cursor.head, doc);
82
+ const from = Math.min(anchor, head);
83
+ const to = Math.max(anchor, head);
84
+ const user = cursor.user;
85
+ const color = user?.color ?? "#0f83ff";
86
+ if (from !== to) {
87
+ decorations.push(
88
+ Decoration.inline(from, to, {
89
+ class: "collaboration-carets__selection",
90
+ style: `background-color: ${color}33`
91
+ })
92
+ );
93
+ }
94
+ decorations.push(
95
+ Decoration.widget(
96
+ normalizeCaretPosition(head, doc),
97
+ () => createCursorElement(user),
98
+ {
99
+ key: `liveblocks-caret-${cursor.connectionId}`,
100
+ side: -1
101
+ }
102
+ )
103
+ );
104
+ }
105
+ return DecorationSet.create(doc, decorations);
106
+ }
107
+ function createLiveblocksCollaborationCaretPlugin(options, storage) {
108
+ const room = options.room;
109
+ if (room === void 0) {
110
+ throw new Error("[Liveblocks] The Liveblocks caret plugin requires a room.");
111
+ }
112
+ let view;
113
+ let unsubscribe;
114
+ const updatePresence = (nextView) => {
115
+ const { anchor, head } = nextView.state.selection;
116
+ room.updatePresence(
117
+ presencePatch({
118
+ field: options.field,
119
+ anchor,
120
+ head,
121
+ user: options.user
122
+ })
123
+ );
124
+ };
125
+ const updateDecorations = () => {
126
+ if (view === void 0) {
127
+ return;
128
+ }
129
+ storage.users = room.getOthers().map((other) => {
130
+ const rawPresence = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];
131
+ const cursorPresence = isCursorPresence(rawPresence) ? rawPresence : void 0;
132
+ return {
133
+ clientId: other.connectionId,
134
+ ...getCursorUser(cursorPresence?.user) ?? getCursorUser(other.info)
135
+ };
136
+ });
137
+ const previousCursors = LIVEBLOCKS_CARET_PLUGIN_KEY.getState(view.state)?.cursors ?? [];
138
+ const cursors = getRemoteCursors(room, options.field, previousCursors);
139
+ view.dispatch(
140
+ view.state.tr.setMeta(LIVEBLOCKS_CARET_PLUGIN_KEY, {
141
+ cursors
142
+ })
143
+ );
144
+ };
145
+ return new Plugin({
146
+ key: LIVEBLOCKS_CARET_PLUGIN_KEY,
147
+ state: {
148
+ init(_, state) {
149
+ return {
150
+ cursors: [],
151
+ decorations: DecorationSet.create(state.doc, [])
152
+ };
153
+ },
154
+ apply(tr, state) {
155
+ const meta = tr.getMeta(LIVEBLOCKS_CARET_PLUGIN_KEY);
156
+ if (meta !== void 0) {
157
+ return {
158
+ cursors: meta.cursors,
159
+ decorations: buildDecorationsFromCursors(meta.cursors, tr.doc)
160
+ };
161
+ }
162
+ if (!tr.docChanged) {
163
+ return state;
164
+ }
165
+ if (!tr.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)) {
166
+ const cursors = state.cursors.map((cursor) => ({
167
+ ...cursor,
168
+ anchor: tr.mapping.map(cursor.anchor, -1),
169
+ head: tr.mapping.map(cursor.head, -1)
170
+ }));
171
+ return {
172
+ cursors,
173
+ decorations: buildDecorationsFromCursors(cursors, tr.doc)
174
+ };
175
+ }
176
+ return {
177
+ cursors: state.cursors,
178
+ decorations: buildDecorationsFromCursors(state.cursors, tr.doc)
179
+ };
180
+ }
181
+ },
182
+ props: {
183
+ decorations(state) {
184
+ return LIVEBLOCKS_CARET_PLUGIN_KEY.getState(state)?.decorations ?? DecorationSet.empty;
185
+ }
186
+ },
187
+ view(editorView) {
188
+ view = editorView;
189
+ updatePresence(editorView);
190
+ updateDecorations();
191
+ unsubscribe = room.events.others.subscribe(updateDecorations);
192
+ return {
193
+ update(nextView, prevState) {
194
+ view = nextView;
195
+ if (!nextView.state.selection.eq(prevState.selection)) {
196
+ updatePresence(nextView);
197
+ }
198
+ },
199
+ destroy() {
200
+ unsubscribe?.();
201
+ unsubscribe = void 0;
202
+ view = void 0;
203
+ room.updatePresence({ [LIVEBLOCKS_CARET_PRESENCE_KEY]: null });
204
+ }
205
+ };
206
+ }
207
+ });
208
+ }
209
+
210
+ export { LIVEBLOCKS_CARET_PLUGIN_KEY, LIVEBLOCKS_CARET_PRESENCE_KEY, createLiveblocksCollaborationCaretPlugin, getCursorUser, presencePatch };
211
+ //# sourceMappingURL=cursors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursors.js","sources":["../src/cursors.ts"],"sourcesContent":["import type { JsonObject } from \"@liveblocks/client\";\nimport type { Node as ProseMirrorNode } from \"prosemirror-model\";\nimport { Plugin, PluginKey, Selection } from \"prosemirror-state\";\nimport type { EditorView } from \"prosemirror-view\";\nimport { Decoration, DecorationSet } from \"prosemirror-view\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"./plugin\";\nimport type { LiveblocksProsemirrorRoom } from \"./types\";\n\nexport const LIVEBLOCKS_CARET_PRESENCE_KEY = \"liveblocksTiptap\";\n\nexport type CursorUser = {\n name?: string;\n color?: string;\n};\n\ntype CursorPresence = {\n field: string;\n anchor: number;\n head: number;\n user?: CursorUser;\n};\n\nexport type CollaborationCaretStorage = {\n users: { clientId: number; [key: string]: unknown }[];\n};\n\nexport type RemoteCursor = {\n anchor: number;\n connectionId: number;\n head: number;\n rawAnchor: number;\n rawHead: number;\n user?: CursorUser;\n};\n\nexport type CollaborationCaretPluginState = {\n cursors: RemoteCursor[];\n decorations: DecorationSet;\n};\n\nexport type CollaborationCaretOptions = {\n room?: LiveblocksProsemirrorRoom;\n field: string;\n user: CursorUser;\n};\n\nexport const LIVEBLOCKS_CARET_PLUGIN_KEY =\n new PluginKey<CollaborationCaretPluginState>(\"liveblocks-collaboration-caret\");\n\nfunction isCursorPresence(value: unknown): value is CursorPresence {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { field?: unknown }).field === \"string\" &&\n typeof (value as { anchor?: unknown }).anchor === \"number\" &&\n typeof (value as { head?: unknown }).head === \"number\"\n );\n}\n\nexport function getCursorUser(value: unknown): CursorUser | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const user = value as { name?: unknown; color?: unknown };\n const name = typeof user.name === \"string\" ? user.name : undefined;\n const color = typeof user.color === \"string\" ? user.color : undefined;\n\n return name !== undefined || color !== undefined ? { name, color } : undefined;\n}\n\nexport function presencePatch(presence: CursorPresence): JsonObject {\n const user = getCursorUser(presence.user);\n\n return {\n [LIVEBLOCKS_CARET_PRESENCE_KEY]: {\n field: presence.field,\n anchor: presence.anchor,\n head: presence.head,\n ...(user !== undefined ? { user } : {}),\n },\n };\n}\n\nfunction createCursorElement(user: CursorUser | undefined): HTMLElement {\n const color = user?.color ?? \"#0f83ff\";\n const name = user?.name ?? \"Anonymous\";\n const cursor = document.createElement(\"span\");\n\n cursor.classList.add(\"collaboration-carets__caret\");\n cursor.setAttribute(\"style\", `border-color: ${color}`);\n\n const label = document.createElement(\"div\");\n label.classList.add(\"collaboration-carets__label\");\n label.setAttribute(\"style\", `background-color: ${color}`);\n label.insertBefore(document.createTextNode(name), null);\n cursor.insertBefore(label, null);\n\n return cursor;\n}\n\nfunction clampPosition(position: number, doc: ProseMirrorNode): number {\n return Math.max(0, Math.min(position, doc.content.size));\n}\n\nfunction normalizeCaretPosition(position: number, doc: ProseMirrorNode): number {\n const clampedPosition = clampPosition(position, doc);\n const $position = doc.resolve(clampedPosition);\n\n if ($position.parent.isTextblock) {\n return clampedPosition;\n }\n\n return Selection.near($position, -1).anchor;\n}\n\nfunction getRemoteCursors(\n room: LiveblocksProsemirrorRoom,\n field: string,\n previousCursors: readonly RemoteCursor[] = []\n): RemoteCursor[] {\n const cursors: RemoteCursor[] = [];\n\n for (const other of room.getOthers()) {\n const rawPresence: unknown = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];\n if (!isCursorPresence(rawPresence) || rawPresence.field !== field) {\n continue;\n }\n\n const user = getCursorUser(rawPresence.user) ?? getCursorUser(other.info);\n const previousCursor = previousCursors.find(\n (cursor) => cursor.connectionId === other.connectionId\n );\n const hasPresencePositionChanged =\n previousCursor === undefined ||\n previousCursor.rawAnchor !== rawPresence.anchor ||\n previousCursor.rawHead !== rawPresence.head;\n\n cursors.push({\n anchor: hasPresencePositionChanged\n ? rawPresence.anchor\n : previousCursor.anchor,\n connectionId: other.connectionId,\n head: hasPresencePositionChanged ? rawPresence.head : previousCursor.head,\n rawAnchor: rawPresence.anchor,\n rawHead: rawPresence.head,\n user,\n });\n }\n\n return cursors;\n}\n\nfunction buildDecorationsFromCursors(\n cursors: readonly RemoteCursor[],\n doc: ProseMirrorNode\n): DecorationSet {\n const decorations: Decoration[] = [];\n\n for (const cursor of cursors) {\n const anchor = clampPosition(cursor.anchor, doc);\n const head = clampPosition(cursor.head, doc);\n const from = Math.min(anchor, head);\n const to = Math.max(anchor, head);\n const user = cursor.user;\n const color = user?.color ?? \"#0f83ff\";\n\n if (from !== to) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"collaboration-carets__selection\",\n style: `background-color: ${color}33`,\n })\n );\n }\n\n decorations.push(\n Decoration.widget(\n normalizeCaretPosition(head, doc),\n () => createCursorElement(user),\n {\n key: `liveblocks-caret-${cursor.connectionId}`,\n side: -1,\n }\n )\n );\n }\n\n return DecorationSet.create(doc, decorations);\n}\n\nexport function createLiveblocksCollaborationCaretPlugin(\n options: CollaborationCaretOptions,\n storage: CollaborationCaretStorage\n): Plugin {\n const room = options.room;\n if (room === undefined) {\n throw new Error(\"[Liveblocks] The Liveblocks caret plugin requires a room.\");\n }\n\n let view: EditorView | undefined;\n let unsubscribe: (() => void) | undefined;\n\n const updatePresence = (nextView: EditorView) => {\n const { anchor, head } = nextView.state.selection;\n room.updatePresence(\n presencePatch({\n field: options.field,\n anchor,\n head,\n user: options.user,\n })\n );\n };\n\n const updateDecorations = () => {\n if (view === undefined) {\n return;\n }\n\n storage.users = room.getOthers().map((other) => {\n const rawPresence: unknown = other.presence[LIVEBLOCKS_CARET_PRESENCE_KEY];\n const cursorPresence = isCursorPresence(rawPresence)\n ? rawPresence\n : undefined;\n\n return {\n clientId: other.connectionId,\n ...(getCursorUser(cursorPresence?.user) ?? getCursorUser(other.info)),\n };\n });\n\n const previousCursors =\n LIVEBLOCKS_CARET_PLUGIN_KEY.getState(view.state)?.cursors ?? [];\n const cursors = getRemoteCursors(room, options.field, previousCursors);\n\n view.dispatch(\n view.state.tr.setMeta(LIVEBLOCKS_CARET_PLUGIN_KEY, {\n cursors,\n })\n );\n };\n\n return new Plugin({\n key: LIVEBLOCKS_CARET_PLUGIN_KEY,\n state: {\n init(_, state): CollaborationCaretPluginState {\n return {\n cursors: [],\n decorations: DecorationSet.create(state.doc, []),\n };\n },\n apply(tr, state): CollaborationCaretPluginState {\n const meta = tr.getMeta(LIVEBLOCKS_CARET_PLUGIN_KEY) as\n | { cursors: RemoteCursor[] }\n | undefined;\n\n if (meta !== undefined) {\n return {\n cursors: meta.cursors,\n decorations: buildDecorationsFromCursors(meta.cursors, tr.doc),\n };\n }\n\n if (!tr.docChanged) {\n return state;\n }\n\n if (!tr.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)) {\n const cursors = state.cursors.map((cursor) => ({\n ...cursor,\n anchor: tr.mapping.map(cursor.anchor, -1),\n head: tr.mapping.map(cursor.head, -1),\n }));\n\n return {\n cursors,\n decorations: buildDecorationsFromCursors(cursors, tr.doc),\n };\n }\n\n // Remote presence can arrive before the matching remote document\n // update. Keep the stored cursor positions and rebuild them against\n // the new document so pre-arrived presence is no longer clamped to the\n // old document size.\n return {\n cursors: state.cursors,\n decorations: buildDecorationsFromCursors(state.cursors, tr.doc),\n };\n },\n },\n props: {\n decorations(state) {\n return (\n LIVEBLOCKS_CARET_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n },\n view(editorView) {\n view = editorView;\n updatePresence(editorView);\n updateDecorations();\n unsubscribe = room.events.others.subscribe(updateDecorations);\n\n return {\n update(nextView, prevState) {\n view = nextView;\n\n if (!nextView.state.selection.eq(prevState.selection)) {\n updatePresence(nextView);\n }\n\n },\n destroy() {\n unsubscribe?.();\n unsubscribe = undefined;\n view = undefined;\n room.updatePresence({ [LIVEBLOCKS_CARET_PRESENCE_KEY]: null });\n },\n };\n },\n });\n}\n"],"names":[],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var core = require('@liveblocks/core');
4
+ var version = require('./version.cjs');
5
+ var cursors = require('./cursors.cjs');
6
+ var plugin = require('./plugin.cjs');
7
+ var schema = require('./schema.cjs');
8
+
9
+ core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
10
+
11
+ exports.LIVEBLOCKS_CARET_PLUGIN_KEY = cursors.LIVEBLOCKS_CARET_PLUGIN_KEY;
12
+ exports.LIVEBLOCKS_CARET_PRESENCE_KEY = cursors.LIVEBLOCKS_CARET_PRESENCE_KEY;
13
+ exports.createLiveblocksCollaborationCaretPlugin = cursors.createLiveblocksCollaborationCaretPlugin;
14
+ exports.getCursorUser = cursors.getCursorUser;
15
+ exports.presencePatch = cursors.presencePatch;
16
+ exports.LIVEBLOCKS_COLLABORATION_PLUGIN_KEY = plugin.LIVEBLOCKS_COLLABORATION_PLUGIN_KEY;
17
+ exports.createLiveblocksCollaborationPlugin = plugin.createLiveblocksCollaborationPlugin;
18
+ exports.createLiveblocksProsemirrorNode = schema.createLiveblocksProsemirrorNode;
19
+ exports.getLiveblocksNodeContent = schema.getLiveblocksNodeContent;
20
+ exports.getLiveblocksNodeId = schema.getLiveblocksNodeId;
21
+ exports.getLiveblocksNodeText = schema.getLiveblocksNodeText;
22
+ exports.liveblocksProsemirrorNodeToJson = schema.liveblocksProsemirrorNodeToJson;
23
+ exports.liveblocksProsemirrorNodeToJsonNodes = schema.liveblocksProsemirrorNodeToJsonNodes;
24
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n CollaborationCaretOptions,\n CollaborationCaretPluginState,\n CollaborationCaretStorage,\n CursorUser,\n RemoteCursor,\n} from \"./cursors\";\nexport {\n createLiveblocksCollaborationCaretPlugin,\n getCursorUser,\n LIVEBLOCKS_CARET_PLUGIN_KEY,\n LIVEBLOCKS_CARET_PRESENCE_KEY,\n presencePatch,\n} from \"./cursors\";\nexport type { LiveblocksCollaborationOptions } from \"./plugin\";\nexport {\n createLiveblocksCollaborationPlugin,\n LIVEBLOCKS_COLLABORATION_PLUGIN_KEY,\n} from \"./plugin\";\nexport type {\n LiveblocksProsemirrorNode,\n ProseMirrorJsonMark,\n ProseMirrorJsonNode,\n} from \"./schema\";\nexport {\n createLiveblocksProsemirrorNode,\n getLiveblocksNodeContent,\n getLiveblocksNodeId,\n getLiveblocksNodeText,\n liveblocksProsemirrorNodeToJson,\n liveblocksProsemirrorNodeToJsonNodes,\n} from \"./schema\";\nexport type { LiveblocksProsemirrorRoom } from \"./types\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,109 @@
1
+ import { JsonObject, LiveObject, LsonObject, StorageUpdate, LiveList, LiveText } from '@liveblocks/client';
2
+ import { PluginKey, Plugin } from 'prosemirror-state';
3
+ import { DecorationSet } from 'prosemirror-view';
4
+
5
+ type LiveblocksProsemirrorRoom = {
6
+ batch(callback: () => void): void;
7
+ getOthers(): readonly {
8
+ connectionId: number;
9
+ info?: JsonObject;
10
+ presence: JsonObject;
11
+ }[];
12
+ getStorage(): Promise<{
13
+ root: LiveObject<LsonObject>;
14
+ }>;
15
+ history: {
16
+ canUndo(): boolean;
17
+ canRedo(): boolean;
18
+ disable<T>(callback: () => T): T;
19
+ undo(): void;
20
+ redo(): void;
21
+ };
22
+ subscribe(node: LiveObject<LsonObject>, callback: (updates: StorageUpdate[]) => void, options: {
23
+ isDeep: true;
24
+ }): () => void;
25
+ updatePresence(patch: JsonObject): void;
26
+ events: {
27
+ others: {
28
+ subscribe(callback: () => void): () => void;
29
+ };
30
+ };
31
+ };
32
+
33
+ declare const LIVEBLOCKS_CARET_PRESENCE_KEY = "liveblocksTiptap";
34
+ type CursorUser = {
35
+ name?: string;
36
+ color?: string;
37
+ };
38
+ type CursorPresence = {
39
+ field: string;
40
+ anchor: number;
41
+ head: number;
42
+ user?: CursorUser;
43
+ };
44
+ type CollaborationCaretStorage = {
45
+ users: {
46
+ clientId: number;
47
+ [key: string]: unknown;
48
+ }[];
49
+ };
50
+ type RemoteCursor = {
51
+ anchor: number;
52
+ connectionId: number;
53
+ head: number;
54
+ rawAnchor: number;
55
+ rawHead: number;
56
+ user?: CursorUser;
57
+ };
58
+ type CollaborationCaretPluginState = {
59
+ cursors: RemoteCursor[];
60
+ decorations: DecorationSet;
61
+ };
62
+ type CollaborationCaretOptions = {
63
+ room?: LiveblocksProsemirrorRoom;
64
+ field: string;
65
+ user: CursorUser;
66
+ };
67
+ declare const LIVEBLOCKS_CARET_PLUGIN_KEY: PluginKey<CollaborationCaretPluginState>;
68
+ declare function getCursorUser(value: unknown): CursorUser | undefined;
69
+ declare function presencePatch(presence: CursorPresence): JsonObject;
70
+ declare function createLiveblocksCollaborationCaretPlugin(options: CollaborationCaretOptions, storage: CollaborationCaretStorage): Plugin;
71
+
72
+ type ProseMirrorJsonNode = {
73
+ type: string;
74
+ attrs?: JsonObject;
75
+ content?: ProseMirrorJsonNode[];
76
+ text?: string;
77
+ marks?: ProseMirrorJsonMark[];
78
+ };
79
+ type ProseMirrorJsonMark = {
80
+ type: string;
81
+ attrs?: JsonObject;
82
+ };
83
+ type LiveblocksProsemirrorNodeData = {
84
+ id: string;
85
+ type: string;
86
+ attrs?: JsonObject;
87
+ content?: LiveList<LiveblocksProsemirrorNode>;
88
+ text?: LiveText;
89
+ };
90
+ type LiveblocksProsemirrorNode = LiveObject<LiveblocksProsemirrorNodeData>;
91
+ declare function createLiveblocksProsemirrorNode(node: ProseMirrorJsonNode): LiveblocksProsemirrorNode;
92
+ declare function getLiveblocksNodeId(node: LiveblocksProsemirrorNode): string;
93
+ declare function getLiveblocksNodeContent(node: LiveblocksProsemirrorNode): LiveList<LiveblocksProsemirrorNode> | undefined;
94
+ declare function getLiveblocksNodeText(node: LiveblocksProsemirrorNode): LiveText | undefined;
95
+ declare function liveblocksProsemirrorNodeToJsonNodes(node: LiveblocksProsemirrorNode): ProseMirrorJsonNode[];
96
+ declare function liveblocksProsemirrorNodeToJson(node: LiveblocksProsemirrorNode, fallbackDocument?: () => ProseMirrorJsonNode): ProseMirrorJsonNode;
97
+
98
+ declare const LIVEBLOCKS_COLLABORATION_PLUGIN_KEY: PluginKey<{
99
+ isReady: boolean;
100
+ }>;
101
+ type LiveblocksCollaborationOptions = {
102
+ room?: LiveblocksProsemirrorRoom;
103
+ field: string;
104
+ initialContent?: ProseMirrorJsonNode;
105
+ fallbackDocument?: () => ProseMirrorJsonNode;
106
+ };
107
+ declare function createLiveblocksCollaborationPlugin(options: LiveblocksCollaborationOptions): Plugin;
108
+
109
+ export { CollaborationCaretOptions, CollaborationCaretPluginState, CollaborationCaretStorage, CursorUser, LIVEBLOCKS_CARET_PLUGIN_KEY, LIVEBLOCKS_CARET_PRESENCE_KEY, LIVEBLOCKS_COLLABORATION_PLUGIN_KEY, LiveblocksCollaborationOptions, LiveblocksProsemirrorNode, LiveblocksProsemirrorRoom, ProseMirrorJsonMark, ProseMirrorJsonNode, RemoteCursor, createLiveblocksCollaborationCaretPlugin, createLiveblocksCollaborationPlugin, createLiveblocksProsemirrorNode, getCursorUser, getLiveblocksNodeContent, getLiveblocksNodeId, getLiveblocksNodeText, liveblocksProsemirrorNodeToJson, liveblocksProsemirrorNodeToJsonNodes, presencePatch };