@liveblocks/react-tiptap 3.19.5-pre1 → 3.20.0-exp1

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.
Files changed (50) hide show
  1. package/dist/LiveblocksExtension.cjs +51 -5
  2. package/dist/LiveblocksExtension.cjs.map +1 -1
  3. package/dist/LiveblocksExtension.js +51 -5
  4. package/dist/LiveblocksExtension.js.map +1 -1
  5. package/dist/ai/AiExtension.cjs +2 -1
  6. package/dist/ai/AiExtension.cjs.map +1 -1
  7. package/dist/ai/AiExtension.js +2 -1
  8. package/dist/ai/AiExtension.js.map +1 -1
  9. package/dist/collaboration-liveblocks/cursors.cjs +267 -0
  10. package/dist/collaboration-liveblocks/cursors.cjs.map +1 -0
  11. package/dist/collaboration-liveblocks/cursors.js +264 -0
  12. package/dist/collaboration-liveblocks/cursors.js.map +1 -0
  13. package/dist/collaboration-liveblocks/mapping.cjs +218 -0
  14. package/dist/collaboration-liveblocks/mapping.cjs.map +1 -0
  15. package/dist/collaboration-liveblocks/mapping.js +207 -0
  16. package/dist/collaboration-liveblocks/mapping.js.map +1 -0
  17. package/dist/collaboration-liveblocks/plugin.cjs +249 -0
  18. package/dist/collaboration-liveblocks/plugin.cjs.map +1 -0
  19. package/dist/collaboration-liveblocks/plugin.js +246 -0
  20. package/dist/collaboration-liveblocks/plugin.js.map +1 -0
  21. package/dist/collaboration-liveblocks/remote.cjs +210 -0
  22. package/dist/collaboration-liveblocks/remote.cjs.map +1 -0
  23. package/dist/collaboration-liveblocks/remote.js +207 -0
  24. package/dist/collaboration-liveblocks/remote.js.map +1 -0
  25. package/dist/collaboration-liveblocks/schema.cjs +150 -0
  26. package/dist/collaboration-liveblocks/schema.cjs.map +1 -0
  27. package/dist/collaboration-liveblocks/schema.js +135 -0
  28. package/dist/collaboration-liveblocks/schema.js.map +1 -0
  29. package/dist/collaboration-liveblocks/steps.cjs +359 -0
  30. package/dist/collaboration-liveblocks/steps.cjs.map +1 -0
  31. package/dist/collaboration-liveblocks/steps.js +356 -0
  32. package/dist/collaboration-liveblocks/steps.js.map +1 -0
  33. package/dist/comments/CommentsExtension.cjs +7 -1
  34. package/dist/comments/CommentsExtension.cjs.map +1 -1
  35. package/dist/comments/CommentsExtension.js +7 -1
  36. package/dist/comments/CommentsExtension.js.map +1 -1
  37. package/dist/index.d.cts +5 -0
  38. package/dist/index.d.ts +5 -0
  39. package/dist/mentions/MentionExtension.cjs +4 -1
  40. package/dist/mentions/MentionExtension.cjs.map +1 -1
  41. package/dist/mentions/MentionExtension.js +4 -1
  42. package/dist/mentions/MentionExtension.js.map +1 -1
  43. package/dist/types.cjs.map +1 -1
  44. package/dist/types.js.map +1 -1
  45. package/dist/version.cjs +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +6 -6
  48. package/src/styles/index.css +12 -4
  49. package/styles.css +1 -1
  50. package/styles.css.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursors.cjs","sources":["../../src/collaboration-liveblocks/cursors.ts"],"sourcesContent":["import type { JsonObject } from \"@liveblocks/client\";\nimport { Extension } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey, Selection } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"./plugin\";\nimport type { LiveblocksTiptapRoom } from \"./types\";\n\nconst PRESENCE_KEY = \"liveblocksTiptap\";\n\ntype 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\ntype CollaborationCaretStorage = {\n users: { clientId: number; [key: string]: unknown }[];\n};\n\ntype RemoteCursor = {\n anchor: number;\n connectionId: number;\n head: number;\n rawAnchor: number;\n rawHead: number;\n user?: CursorUser;\n};\n\ntype CollaborationCaretPluginState = {\n cursors: RemoteCursor[];\n decorations: DecorationSet;\n};\n\ntype CollaborationCaretOptions = {\n room?: LiveblocksTiptapRoom;\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\nfunction 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\nfunction presencePatch(presence: CursorPresence): JsonObject {\n const user = getCursorUser(presence.user);\n\n return {\n [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: LiveblocksTiptapRoom,\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[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\nfunction createLiveblocksCaretPlugin(\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[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({ [PRESENCE_KEY]: null });\n },\n };\n },\n });\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n collaborationCaret: {\n updateUser: (attributes: Record<string, any>) => ReturnType;\n user: (attributes: Record<string, any>) => ReturnType;\n };\n }\n}\n\nexport const LiveblocksCollaborationCaret = Extension.create<\n CollaborationCaretOptions,\n CollaborationCaretStorage\n>({\n name: \"collaborationCaret\",\n priority: 999,\n\n addOptions() {\n return {\n room: undefined,\n field: \"default\",\n user: {\n name: undefined,\n color: undefined,\n },\n };\n },\n\n addStorage() {\n return {\n users: [],\n };\n },\n\n addCommands() {\n return {\n updateUser:\n (attributes) =>\n ({ editor }) => {\n const nextUser = getCursorUser({\n ...this.options.user,\n name:\n typeof attributes.name === \"string\"\n ? attributes.name\n : this.options.user.name,\n color:\n typeof attributes.color === \"string\"\n ? attributes.color\n : this.options.user.color,\n }) ?? {};\n\n if (\n nextUser.name === this.options.user.name &&\n nextUser.color === this.options.user.color\n ) {\n return true;\n }\n\n this.options.user = nextUser;\n\n if (this.options.room !== undefined) {\n const { anchor, head } = editor.state.selection;\n this.options.room.updatePresence(\n presencePatch({\n field: this.options.field,\n anchor,\n head,\n user: this.options.user,\n })\n );\n }\n return true;\n },\n user:\n (attributes) =>\n ({ editor }) => {\n return editor.commands.updateUser(attributes);\n },\n };\n },\n\n addProseMirrorPlugins() {\n return [createLiveblocksCaretPlugin(this.options, this.storage)];\n },\n});\n"],"names":["PluginKey","Selection","Decoration","DecorationSet","view","Plugin","LIVEBLOCKS_COLLABORATION_PLUGIN_KEY","Extension"],"mappings":"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"}
@@ -0,0 +1,264 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import { PluginKey, Selection, Plugin } from '@tiptap/pm/state';
3
+ import { Decoration, DecorationSet } from '@tiptap/pm/view';
4
+ import { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from './plugin.js';
5
+
6
+ const PRESENCE_KEY = "liveblocksTiptap";
7
+ const LIVEBLOCKS_CARET_PLUGIN_KEY = new PluginKey("liveblocks-collaboration-caret");
8
+ function isCursorPresence(value) {
9
+ return typeof value === "object" && value !== null && typeof value.field === "string" && typeof value.anchor === "number" && typeof value.head === "number";
10
+ }
11
+ function getCursorUser(value) {
12
+ if (typeof value !== "object" || value === null) {
13
+ return void 0;
14
+ }
15
+ const user = value;
16
+ const name = typeof user.name === "string" ? user.name : void 0;
17
+ const color = typeof user.color === "string" ? user.color : void 0;
18
+ return name !== void 0 || color !== void 0 ? { name, color } : void 0;
19
+ }
20
+ function presencePatch(presence) {
21
+ const user = getCursorUser(presence.user);
22
+ return {
23
+ [PRESENCE_KEY]: {
24
+ field: presence.field,
25
+ anchor: presence.anchor,
26
+ head: presence.head,
27
+ ...user !== void 0 ? { user } : {}
28
+ }
29
+ };
30
+ }
31
+ function createCursorElement(user) {
32
+ const color = user?.color ?? "#0f83ff";
33
+ const name = user?.name ?? "Anonymous";
34
+ const cursor = document.createElement("span");
35
+ cursor.classList.add("collaboration-carets__caret");
36
+ cursor.setAttribute("style", `border-color: ${color}`);
37
+ const label = document.createElement("div");
38
+ label.classList.add("collaboration-carets__label");
39
+ label.setAttribute("style", `background-color: ${color}`);
40
+ label.insertBefore(document.createTextNode(name), null);
41
+ cursor.insertBefore(label, null);
42
+ return cursor;
43
+ }
44
+ function clampPosition(position, doc) {
45
+ return Math.max(0, Math.min(position, doc.content.size));
46
+ }
47
+ function normalizeCaretPosition(position, doc) {
48
+ const clampedPosition = clampPosition(position, doc);
49
+ const $position = doc.resolve(clampedPosition);
50
+ if ($position.parent.isTextblock) {
51
+ return clampedPosition;
52
+ }
53
+ return Selection.near($position, -1).anchor;
54
+ }
55
+ function getRemoteCursors(room, field, previousCursors = []) {
56
+ const cursors = [];
57
+ for (const other of room.getOthers()) {
58
+ const rawPresence = other.presence[PRESENCE_KEY];
59
+ if (!isCursorPresence(rawPresence) || rawPresence.field !== field) {
60
+ continue;
61
+ }
62
+ const user = getCursorUser(rawPresence.user) ?? getCursorUser(other.info);
63
+ const previousCursor = previousCursors.find(
64
+ (cursor) => cursor.connectionId === other.connectionId
65
+ );
66
+ const hasPresencePositionChanged = previousCursor === void 0 || previousCursor.rawAnchor !== rawPresence.anchor || previousCursor.rawHead !== rawPresence.head;
67
+ cursors.push({
68
+ anchor: hasPresencePositionChanged ? rawPresence.anchor : previousCursor.anchor,
69
+ connectionId: other.connectionId,
70
+ head: hasPresencePositionChanged ? rawPresence.head : previousCursor.head,
71
+ rawAnchor: rawPresence.anchor,
72
+ rawHead: rawPresence.head,
73
+ user
74
+ });
75
+ }
76
+ return cursors;
77
+ }
78
+ function buildDecorationsFromCursors(cursors, doc) {
79
+ const decorations = [];
80
+ for (const cursor of cursors) {
81
+ const anchor = clampPosition(cursor.anchor, doc);
82
+ const head = clampPosition(cursor.head, doc);
83
+ const from = Math.min(anchor, head);
84
+ const to = Math.max(anchor, head);
85
+ const user = cursor.user;
86
+ const color = user?.color ?? "#0f83ff";
87
+ if (from !== to) {
88
+ decorations.push(
89
+ Decoration.inline(from, to, {
90
+ class: "collaboration-carets__selection",
91
+ style: `background-color: ${color}33`
92
+ })
93
+ );
94
+ }
95
+ decorations.push(
96
+ Decoration.widget(
97
+ normalizeCaretPosition(head, doc),
98
+ () => createCursorElement(user),
99
+ {
100
+ key: `liveblocks-caret-${cursor.connectionId}`,
101
+ side: -1
102
+ }
103
+ )
104
+ );
105
+ }
106
+ return DecorationSet.create(doc, decorations);
107
+ }
108
+ function createLiveblocksCaretPlugin(options, storage) {
109
+ const room = options.room;
110
+ if (room === void 0) {
111
+ throw new Error("[Liveblocks] The Liveblocks caret plugin requires a room.");
112
+ }
113
+ let view;
114
+ let unsubscribe;
115
+ const updatePresence = (nextView) => {
116
+ const { anchor, head } = nextView.state.selection;
117
+ room.updatePresence(
118
+ presencePatch({
119
+ field: options.field,
120
+ anchor,
121
+ head,
122
+ user: options.user
123
+ })
124
+ );
125
+ };
126
+ const updateDecorations = () => {
127
+ if (view === void 0) {
128
+ return;
129
+ }
130
+ storage.users = room.getOthers().map((other) => {
131
+ const rawPresence = other.presence[PRESENCE_KEY];
132
+ const cursorPresence = isCursorPresence(rawPresence) ? rawPresence : void 0;
133
+ return {
134
+ clientId: other.connectionId,
135
+ ...getCursorUser(cursorPresence?.user) ?? getCursorUser(other.info)
136
+ };
137
+ });
138
+ const previousCursors = LIVEBLOCKS_CARET_PLUGIN_KEY.getState(view.state)?.cursors ?? [];
139
+ const cursors = getRemoteCursors(room, options.field, previousCursors);
140
+ view.dispatch(
141
+ view.state.tr.setMeta(LIVEBLOCKS_CARET_PLUGIN_KEY, {
142
+ cursors
143
+ })
144
+ );
145
+ };
146
+ return new Plugin({
147
+ key: LIVEBLOCKS_CARET_PLUGIN_KEY,
148
+ state: {
149
+ init(_, state) {
150
+ return {
151
+ cursors: [],
152
+ decorations: DecorationSet.create(state.doc, [])
153
+ };
154
+ },
155
+ apply(tr, state) {
156
+ const meta = tr.getMeta(LIVEBLOCKS_CARET_PLUGIN_KEY);
157
+ if (meta !== void 0) {
158
+ return {
159
+ cursors: meta.cursors,
160
+ decorations: buildDecorationsFromCursors(meta.cursors, tr.doc)
161
+ };
162
+ }
163
+ if (!tr.docChanged) {
164
+ return state;
165
+ }
166
+ if (!tr.getMeta(LIVEBLOCKS_COLLABORATION_PLUGIN_KEY)) {
167
+ const cursors = state.cursors.map((cursor) => ({
168
+ ...cursor,
169
+ anchor: tr.mapping.map(cursor.anchor, -1),
170
+ head: tr.mapping.map(cursor.head, -1)
171
+ }));
172
+ return {
173
+ cursors,
174
+ decorations: buildDecorationsFromCursors(cursors, tr.doc)
175
+ };
176
+ }
177
+ return {
178
+ cursors: state.cursors,
179
+ decorations: buildDecorationsFromCursors(state.cursors, tr.doc)
180
+ };
181
+ }
182
+ },
183
+ props: {
184
+ decorations(state) {
185
+ return LIVEBLOCKS_CARET_PLUGIN_KEY.getState(state)?.decorations ?? DecorationSet.empty;
186
+ }
187
+ },
188
+ view(editorView) {
189
+ view = editorView;
190
+ updatePresence(editorView);
191
+ updateDecorations();
192
+ unsubscribe = room.events.others.subscribe(updateDecorations);
193
+ return {
194
+ update(nextView, prevState) {
195
+ view = nextView;
196
+ if (!nextView.state.selection.eq(prevState.selection)) {
197
+ updatePresence(nextView);
198
+ }
199
+ },
200
+ destroy() {
201
+ unsubscribe?.();
202
+ unsubscribe = void 0;
203
+ view = void 0;
204
+ room.updatePresence({ [PRESENCE_KEY]: null });
205
+ }
206
+ };
207
+ }
208
+ });
209
+ }
210
+ const LiveblocksCollaborationCaret = Extension.create({
211
+ name: "collaborationCaret",
212
+ priority: 999,
213
+ addOptions() {
214
+ return {
215
+ room: void 0,
216
+ field: "default",
217
+ user: {
218
+ name: void 0,
219
+ color: void 0
220
+ }
221
+ };
222
+ },
223
+ addStorage() {
224
+ return {
225
+ users: []
226
+ };
227
+ },
228
+ addCommands() {
229
+ return {
230
+ updateUser: (attributes) => ({ editor }) => {
231
+ const nextUser = getCursorUser({
232
+ ...this.options.user,
233
+ name: typeof attributes.name === "string" ? attributes.name : this.options.user.name,
234
+ color: typeof attributes.color === "string" ? attributes.color : this.options.user.color
235
+ }) ?? {};
236
+ if (nextUser.name === this.options.user.name && nextUser.color === this.options.user.color) {
237
+ return true;
238
+ }
239
+ this.options.user = nextUser;
240
+ if (this.options.room !== void 0) {
241
+ const { anchor, head } = editor.state.selection;
242
+ this.options.room.updatePresence(
243
+ presencePatch({
244
+ field: this.options.field,
245
+ anchor,
246
+ head,
247
+ user: this.options.user
248
+ })
249
+ );
250
+ }
251
+ return true;
252
+ },
253
+ user: (attributes) => ({ editor }) => {
254
+ return editor.commands.updateUser(attributes);
255
+ }
256
+ };
257
+ },
258
+ addProseMirrorPlugins() {
259
+ return [createLiveblocksCaretPlugin(this.options, this.storage)];
260
+ }
261
+ });
262
+
263
+ export { LIVEBLOCKS_CARET_PLUGIN_KEY, LiveblocksCollaborationCaret };
264
+ //# sourceMappingURL=cursors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursors.js","sources":["../../src/collaboration-liveblocks/cursors.ts"],"sourcesContent":["import type { JsonObject } from \"@liveblocks/client\";\nimport { Extension } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Plugin, PluginKey, Selection } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\n\nimport { LIVEBLOCKS_COLLABORATION_PLUGIN_KEY } from \"./plugin\";\nimport type { LiveblocksTiptapRoom } from \"./types\";\n\nconst PRESENCE_KEY = \"liveblocksTiptap\";\n\ntype 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\ntype CollaborationCaretStorage = {\n users: { clientId: number; [key: string]: unknown }[];\n};\n\ntype RemoteCursor = {\n anchor: number;\n connectionId: number;\n head: number;\n rawAnchor: number;\n rawHead: number;\n user?: CursorUser;\n};\n\ntype CollaborationCaretPluginState = {\n cursors: RemoteCursor[];\n decorations: DecorationSet;\n};\n\ntype CollaborationCaretOptions = {\n room?: LiveblocksTiptapRoom;\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\nfunction 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\nfunction presencePatch(presence: CursorPresence): JsonObject {\n const user = getCursorUser(presence.user);\n\n return {\n [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: LiveblocksTiptapRoom,\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[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\nfunction createLiveblocksCaretPlugin(\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[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({ [PRESENCE_KEY]: null });\n },\n };\n },\n });\n}\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n collaborationCaret: {\n updateUser: (attributes: Record<string, any>) => ReturnType;\n user: (attributes: Record<string, any>) => ReturnType;\n };\n }\n}\n\nexport const LiveblocksCollaborationCaret = Extension.create<\n CollaborationCaretOptions,\n CollaborationCaretStorage\n>({\n name: \"collaborationCaret\",\n priority: 999,\n\n addOptions() {\n return {\n room: undefined,\n field: \"default\",\n user: {\n name: undefined,\n color: undefined,\n },\n };\n },\n\n addStorage() {\n return {\n users: [],\n };\n },\n\n addCommands() {\n return {\n updateUser:\n (attributes) =>\n ({ editor }) => {\n const nextUser = getCursorUser({\n ...this.options.user,\n name:\n typeof attributes.name === \"string\"\n ? attributes.name\n : this.options.user.name,\n color:\n typeof attributes.color === \"string\"\n ? attributes.color\n : this.options.user.color,\n }) ?? {};\n\n if (\n nextUser.name === this.options.user.name &&\n nextUser.color === this.options.user.color\n ) {\n return true;\n }\n\n this.options.user = nextUser;\n\n if (this.options.room !== undefined) {\n const { anchor, head } = editor.state.selection;\n this.options.room.updatePresence(\n presencePatch({\n field: this.options.field,\n anchor,\n head,\n user: this.options.user,\n })\n );\n }\n return true;\n },\n user:\n (attributes) =>\n ({ editor }) => {\n return editor.commands.updateUser(attributes);\n },\n };\n },\n\n addProseMirrorPlugins() {\n return [createLiveblocksCaretPlugin(this.options, this.storage)];\n },\n});\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,218 @@
1
+ 'use strict';
2
+
3
+ var schema = require('./schema.cjs');
4
+
5
+ function selectionToLiveblocksPosition(selection) {
6
+ return {
7
+ anchor: selection.anchor,
8
+ head: selection.head
9
+ };
10
+ }
11
+ function clampLiveblocksPosition(position, max) {
12
+ return {
13
+ anchor: Math.max(0, Math.min(position.anchor, max)),
14
+ head: Math.max(0, Math.min(position.head, max))
15
+ };
16
+ }
17
+ function childStart(parent, parentPos) {
18
+ return parent.type.name === "doc" ? parentPos : parentPos + 1;
19
+ }
20
+ function indexChildren(nodeRanges, listRanges, textRanges, pmParent, liveParent, parentPos) {
21
+ const liveContent = schema.getLiveblocksNodeContent(liveParent);
22
+ if (liveContent === void 0) {
23
+ return;
24
+ }
25
+ listRanges.push({
26
+ content: liveContent,
27
+ from: parentPos,
28
+ node: liveParent,
29
+ nodeId: schema.getLiveblocksNodeId(liveParent),
30
+ pmNode: pmParent,
31
+ to: parentPos + pmParent.nodeSize
32
+ });
33
+ let pmChildIndex = 0;
34
+ let pmOffset = 0;
35
+ const start = childStart(pmParent, parentPos);
36
+ for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {
37
+ const liveChild = liveContent.get(liveIndex);
38
+ const pmChild = pmParent.maybeChild(pmChildIndex);
39
+ if (liveChild === void 0 || pmChild === null) {
40
+ return;
41
+ }
42
+ const from = start + pmOffset;
43
+ const to = from + pmChild.nodeSize;
44
+ nodeRanges.push({
45
+ childIndex: liveIndex,
46
+ content: liveContent,
47
+ from,
48
+ node: liveChild,
49
+ nodeId: schema.getLiveblocksNodeId(liveChild),
50
+ parent: liveParent,
51
+ pmNode: pmChild,
52
+ to
53
+ });
54
+ if (schema.getLiveblocksNodeType(liveChild) === "text") {
55
+ const text = schema.getLiveblocksNodeText(liveChild);
56
+ if (text === void 0) {
57
+ return;
58
+ }
59
+ let liveOffset = 0;
60
+ let remaining = text.length;
61
+ while (remaining > 0) {
62
+ const textChild = pmParent.maybeChild(pmChildIndex);
63
+ if (textChild === null || !textChild.isText) {
64
+ return;
65
+ }
66
+ const length = Math.min(remaining, textChild.nodeSize);
67
+ const textFrom = start + pmOffset;
68
+ textRanges.push({
69
+ from: textFrom,
70
+ to: textFrom + length,
71
+ liveOffset,
72
+ node: liveChild,
73
+ nodeId: schema.getLiveblocksNodeId(liveChild),
74
+ text
75
+ });
76
+ liveOffset += length;
77
+ remaining -= length;
78
+ pmOffset += textChild.nodeSize;
79
+ pmChildIndex++;
80
+ }
81
+ } else {
82
+ indexChildren(
83
+ nodeRanges,
84
+ listRanges,
85
+ textRanges,
86
+ pmChild,
87
+ liveChild,
88
+ from
89
+ );
90
+ pmOffset += pmChild.nodeSize;
91
+ pmChildIndex++;
92
+ }
93
+ }
94
+ }
95
+ function buildLiveblocksTreeIndex(pmDoc, liveRoot) {
96
+ const nodeRanges = [
97
+ {
98
+ from: 0,
99
+ node: liveRoot,
100
+ nodeId: schema.getLiveblocksNodeId(liveRoot),
101
+ pmNode: pmDoc,
102
+ to: pmDoc.content.size
103
+ }
104
+ ];
105
+ const listRanges = [];
106
+ const textRanges = [];
107
+ indexChildren(nodeRanges, listRanges, textRanges, pmDoc, liveRoot, 0);
108
+ return { listRanges, nodeRanges, textRanges };
109
+ }
110
+ function findTextRangeAtPosition(index, position) {
111
+ return index.textRanges.find(
112
+ (range) => position >= range.from && position <= range.to
113
+ );
114
+ }
115
+ function findTextRangeAtPositionInChildren(pmParent, liveParent, parentPos, position) {
116
+ const liveContent = schema.getLiveblocksNodeContent(liveParent);
117
+ if (liveContent === void 0) {
118
+ return void 0;
119
+ }
120
+ let pmChildIndex = 0;
121
+ let pmOffset = 0;
122
+ const start = childStart(pmParent, parentPos);
123
+ for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {
124
+ const liveChild = liveContent.get(liveIndex);
125
+ const pmChild = pmParent.maybeChild(pmChildIndex);
126
+ if (liveChild === void 0 || pmChild === null) {
127
+ return void 0;
128
+ }
129
+ if (schema.getLiveblocksNodeType(liveChild) === "text") {
130
+ const text = schema.getLiveblocksNodeText(liveChild);
131
+ if (text === void 0) {
132
+ return void 0;
133
+ }
134
+ let liveOffset = 0;
135
+ let remaining = text.length;
136
+ while (remaining > 0) {
137
+ const textChild = pmParent.maybeChild(pmChildIndex);
138
+ if (textChild === null || !textChild.isText) {
139
+ return void 0;
140
+ }
141
+ const length = Math.min(remaining, textChild.nodeSize);
142
+ const from = start + pmOffset;
143
+ const to = from + length;
144
+ if (position >= from && position <= to) {
145
+ return {
146
+ from,
147
+ to,
148
+ liveOffset,
149
+ node: liveChild,
150
+ nodeId: schema.getLiveblocksNodeId(liveChild),
151
+ text
152
+ };
153
+ }
154
+ liveOffset += length;
155
+ remaining -= length;
156
+ pmOffset += textChild.nodeSize;
157
+ pmChildIndex++;
158
+ }
159
+ } else {
160
+ const from = start + pmOffset;
161
+ const to = from + pmChild.nodeSize;
162
+ if (position >= from && position <= to) {
163
+ return findTextRangeAtPositionInChildren(
164
+ pmChild,
165
+ liveChild,
166
+ from,
167
+ position
168
+ );
169
+ }
170
+ pmOffset += pmChild.nodeSize;
171
+ pmChildIndex++;
172
+ }
173
+ }
174
+ return void 0;
175
+ }
176
+ function findTextRangeAtPositionInDocument(pmDoc, liveRoot, position) {
177
+ return findTextRangeAtPositionInChildren(pmDoc, liveRoot, 0, position);
178
+ }
179
+ function findTextRangesInRange(index, from, to) {
180
+ return index.textRanges.filter(
181
+ (range) => Math.max(range.from, from) < Math.min(range.to, to)
182
+ );
183
+ }
184
+ function findTextRangeByLiveText(index, text) {
185
+ return index.textRanges.find((range) => range.text === text);
186
+ }
187
+ function findNodeRangeByLiveNode(index, node) {
188
+ return index.nodeRanges.find((range) => range.node === node);
189
+ }
190
+ function findListRangeByLiveList(index, content) {
191
+ return index.listRanges.find((range) => range.content === content);
192
+ }
193
+ function getChildPosition(parent, parentPos, index) {
194
+ if (index < 0 || index > parent.childCount) {
195
+ return void 0;
196
+ }
197
+ let offset = 0;
198
+ for (let childIndex = 0; childIndex < index; childIndex++) {
199
+ const child = parent.maybeChild(childIndex);
200
+ if (child === null) {
201
+ return void 0;
202
+ }
203
+ offset += child.nodeSize;
204
+ }
205
+ return childStart(parent, parentPos) + offset;
206
+ }
207
+
208
+ exports.buildLiveblocksTreeIndex = buildLiveblocksTreeIndex;
209
+ exports.clampLiveblocksPosition = clampLiveblocksPosition;
210
+ exports.findListRangeByLiveList = findListRangeByLiveList;
211
+ exports.findNodeRangeByLiveNode = findNodeRangeByLiveNode;
212
+ exports.findTextRangeAtPosition = findTextRangeAtPosition;
213
+ exports.findTextRangeAtPositionInDocument = findTextRangeAtPositionInDocument;
214
+ exports.findTextRangeByLiveText = findTextRangeByLiveText;
215
+ exports.findTextRangesInRange = findTextRangesInRange;
216
+ exports.getChildPosition = getChildPosition;
217
+ exports.selectionToLiveblocksPosition = selectionToLiveblocksPosition;
218
+ //# sourceMappingURL=mapping.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapping.cjs","sources":["../../src/collaboration-liveblocks/mapping.ts"],"sourcesContent":["import type { LiveList, LiveText } from \"@liveblocks/client\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport type { Selection } from \"@tiptap/pm/state\";\n\nimport {\n getLiveblocksNodeContent,\n getLiveblocksNodeId,\n getLiveblocksNodeText,\n getLiveblocksNodeType,\n type LiveblocksTiptapNode,\n} from \"./schema\";\n\nexport type LiveblocksTiptapPosition = {\n anchor: number;\n head: number;\n};\n\nexport function selectionToLiveblocksPosition(\n selection: Selection\n): LiveblocksTiptapPosition {\n return {\n anchor: selection.anchor,\n head: selection.head,\n };\n}\n\nexport function clampLiveblocksPosition(\n position: LiveblocksTiptapPosition,\n max: number\n): LiveblocksTiptapPosition {\n return {\n anchor: Math.max(0, Math.min(position.anchor, max)),\n head: Math.max(0, Math.min(position.head, max)),\n };\n}\n\nexport type LiveblocksTextRange = {\n from: number;\n to: number;\n liveOffset: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n text: LiveText;\n};\n\nexport type LiveblocksNodeRange = {\n childIndex?: number;\n content?: LiveList<LiveblocksTiptapNode>;\n from: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n parent?: LiveblocksTiptapNode;\n pmNode: ProseMirrorNode;\n to: number;\n};\n\nexport type LiveblocksListRange = {\n content: LiveList<LiveblocksTiptapNode>;\n from: number;\n node: LiveblocksTiptapNode;\n nodeId: string;\n pmNode: ProseMirrorNode;\n to: number;\n};\n\nexport type LiveblocksTreeIndex = {\n listRanges: LiveblocksListRange[];\n nodeRanges: LiveblocksNodeRange[];\n textRanges: LiveblocksTextRange[];\n};\n\nfunction childStart(parent: ProseMirrorNode, parentPos: number): number {\n return parent.type.name === \"doc\" ? parentPos : parentPos + 1;\n}\n\nfunction indexChildren(\n nodeRanges: LiveblocksNodeRange[],\n listRanges: LiveblocksListRange[],\n textRanges: LiveblocksTextRange[],\n pmParent: ProseMirrorNode,\n liveParent: LiveblocksTiptapNode,\n parentPos: number\n): void {\n const liveContent = getLiveblocksNodeContent(liveParent);\n if (liveContent === undefined) {\n return;\n }\n\n listRanges.push({\n content: liveContent,\n from: parentPos,\n node: liveParent,\n nodeId: getLiveblocksNodeId(liveParent),\n pmNode: pmParent,\n to: parentPos + pmParent.nodeSize,\n });\n\n let pmChildIndex = 0;\n let pmOffset = 0;\n const start = childStart(pmParent, parentPos);\n\n for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {\n const liveChild = liveContent.get(liveIndex);\n const pmChild = pmParent.maybeChild(pmChildIndex);\n if (liveChild === undefined || pmChild === null) {\n return;\n }\n\n const from = start + pmOffset;\n const to = from + pmChild.nodeSize;\n\n nodeRanges.push({\n childIndex: liveIndex,\n content: liveContent,\n from,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n parent: liveParent,\n pmNode: pmChild,\n to,\n });\n\n if (getLiveblocksNodeType(liveChild) === \"text\") {\n const text = getLiveblocksNodeText(liveChild);\n if (text === undefined) {\n return;\n }\n\n let liveOffset = 0;\n let remaining = text.length;\n\n while (remaining > 0) {\n const textChild = pmParent.maybeChild(pmChildIndex);\n if (textChild === null || !textChild.isText) {\n return;\n }\n\n const length = Math.min(remaining, textChild.nodeSize);\n const textFrom = start + pmOffset;\n\n textRanges.push({\n from: textFrom,\n to: textFrom + length,\n liveOffset,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n text,\n });\n\n liveOffset += length;\n remaining -= length;\n pmOffset += textChild.nodeSize;\n pmChildIndex++;\n }\n } else {\n indexChildren(\n nodeRanges,\n listRanges,\n textRanges,\n pmChild,\n liveChild,\n from\n );\n pmOffset += pmChild.nodeSize;\n pmChildIndex++;\n }\n }\n}\n\nexport function buildLiveblocksTreeIndex(\n pmDoc: ProseMirrorNode,\n liveRoot: LiveblocksTiptapNode\n): LiveblocksTreeIndex {\n const nodeRanges: LiveblocksNodeRange[] = [\n {\n from: 0,\n node: liveRoot,\n nodeId: getLiveblocksNodeId(liveRoot),\n pmNode: pmDoc,\n to: pmDoc.content.size,\n },\n ];\n const listRanges: LiveblocksListRange[] = [];\n const textRanges: LiveblocksTextRange[] = [];\n indexChildren(nodeRanges, listRanges, textRanges, pmDoc, liveRoot, 0);\n return { listRanges, nodeRanges, textRanges };\n}\n\nexport function findTextRangeAtPosition(\n index: LiveblocksTreeIndex,\n position: number\n): LiveblocksTextRange | undefined {\n return index.textRanges.find(\n (range) => position >= range.from && position <= range.to\n );\n}\n\nfunction findTextRangeAtPositionInChildren(\n pmParent: ProseMirrorNode,\n liveParent: LiveblocksTiptapNode,\n parentPos: number,\n position: number\n): LiveblocksTextRange | undefined {\n const liveContent = getLiveblocksNodeContent(liveParent);\n if (liveContent === undefined) {\n return undefined;\n }\n\n let pmChildIndex = 0;\n let pmOffset = 0;\n const start = childStart(pmParent, parentPos);\n\n for (let liveIndex = 0; liveIndex < liveContent.length; liveIndex++) {\n const liveChild = liveContent.get(liveIndex);\n const pmChild = pmParent.maybeChild(pmChildIndex);\n if (liveChild === undefined || pmChild === null) {\n return undefined;\n }\n\n if (getLiveblocksNodeType(liveChild) === \"text\") {\n const text = getLiveblocksNodeText(liveChild);\n if (text === undefined) {\n return undefined;\n }\n\n let liveOffset = 0;\n let remaining = text.length;\n\n while (remaining > 0) {\n const textChild = pmParent.maybeChild(pmChildIndex);\n if (textChild === null || !textChild.isText) {\n return undefined;\n }\n\n const length = Math.min(remaining, textChild.nodeSize);\n const from = start + pmOffset;\n const to = from + length;\n\n if (position >= from && position <= to) {\n return {\n from,\n to,\n liveOffset,\n node: liveChild,\n nodeId: getLiveblocksNodeId(liveChild),\n text,\n };\n }\n\n liveOffset += length;\n remaining -= length;\n pmOffset += textChild.nodeSize;\n pmChildIndex++;\n }\n } else {\n const from = start + pmOffset;\n const to = from + pmChild.nodeSize;\n\n if (position >= from && position <= to) {\n return findTextRangeAtPositionInChildren(\n pmChild,\n liveChild,\n from,\n position\n );\n }\n\n pmOffset += pmChild.nodeSize;\n pmChildIndex++;\n }\n }\n\n return undefined;\n}\n\nexport function findTextRangeAtPositionInDocument(\n pmDoc: ProseMirrorNode,\n liveRoot: LiveblocksTiptapNode,\n position: number\n): LiveblocksTextRange | undefined {\n return findTextRangeAtPositionInChildren(pmDoc, liveRoot, 0, position);\n}\n\nexport function findTextRangesInRange(\n index: LiveblocksTreeIndex,\n from: number,\n to: number\n): LiveblocksTextRange[] {\n return index.textRanges.filter(\n (range) => Math.max(range.from, from) < Math.min(range.to, to)\n );\n}\n\nexport function findTextRangeByLiveText(\n index: LiveblocksTreeIndex,\n text: LiveText\n): LiveblocksTextRange | undefined {\n return index.textRanges.find((range) => range.text === text);\n}\n\nexport function findNodeRangeByLiveNode(\n index: LiveblocksTreeIndex,\n node: LiveblocksTiptapNode\n): LiveblocksNodeRange | undefined {\n return index.nodeRanges.find((range) => range.node === node);\n}\n\nexport function findListRangeByLiveList(\n index: LiveblocksTreeIndex,\n content: unknown\n): LiveblocksListRange | undefined {\n return index.listRanges.find((range) => range.content === content);\n}\n\nexport function getChildPosition(\n parent: ProseMirrorNode,\n parentPos: number,\n index: number\n): number | undefined {\n if (index < 0 || index > parent.childCount) {\n return undefined;\n }\n\n let offset = 0;\n for (let childIndex = 0; childIndex < index; childIndex++) {\n const child = parent.maybeChild(childIndex);\n if (child === null) {\n return undefined;\n }\n\n offset += child.nodeSize;\n }\n\n return childStart(parent, parentPos) + offset;\n}\n"],"names":["getLiveblocksNodeContent","getLiveblocksNodeId","getLiveblocksNodeType","getLiveblocksNodeText"],"mappings":"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"}