@liveblocks/react-tiptap 2.15.1 → 2.16.0-rc1
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/dist/LiveblocksExtension.js +1 -5
- package/dist/LiveblocksExtension.js.map +1 -1
- package/dist/LiveblocksExtension.mjs +3 -7
- package/dist/LiveblocksExtension.mjs.map +1 -1
- package/dist/comments/AnchoredThreads.js +34 -16
- package/dist/comments/AnchoredThreads.js.map +1 -1
- package/dist/comments/AnchoredThreads.mjs +33 -15
- package/dist/comments/AnchoredThreads.mjs.map +1 -1
- package/dist/comments/CommentsExtension.js +9 -14
- package/dist/comments/CommentsExtension.js.map +1 -1
- package/dist/comments/CommentsExtension.mjs +10 -15
- package/dist/comments/CommentsExtension.mjs.map +1 -1
- package/dist/comments/FloatingComposer.js +12 -8
- package/dist/comments/FloatingComposer.js.map +1 -1
- package/dist/comments/FloatingComposer.mjs +12 -8
- package/dist/comments/FloatingComposer.mjs.map +1 -1
- package/dist/comments/FloatingThreads.js +5 -2
- package/dist/comments/FloatingThreads.js.map +1 -1
- package/dist/comments/FloatingThreads.mjs +5 -2
- package/dist/comments/FloatingThreads.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/mentions/MentionsList.js +117 -107
- package/dist/mentions/MentionsList.js.map +1 -1
- package/dist/mentions/MentionsList.mjs +119 -109
- package/dist/mentions/MentionsList.mjs.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +8 -8
|
@@ -149,7 +149,7 @@ const CommentsExtension = core.Extension.create({
|
|
|
149
149
|
},
|
|
150
150
|
addStorage() {
|
|
151
151
|
return {
|
|
152
|
-
|
|
152
|
+
pendingComment: false
|
|
153
153
|
};
|
|
154
154
|
},
|
|
155
155
|
addCommands() {
|
|
@@ -164,10 +164,7 @@ const CommentsExtension = core.Extension.create({
|
|
|
164
164
|
data: null
|
|
165
165
|
})
|
|
166
166
|
);
|
|
167
|
-
this.storage.
|
|
168
|
-
this.editor.state.selection.$anchor,
|
|
169
|
-
this.editor.state.selection.$head
|
|
170
|
-
);
|
|
167
|
+
this.storage.pendingComment = true;
|
|
171
168
|
return true;
|
|
172
169
|
},
|
|
173
170
|
selectThread: (id) => () => {
|
|
@@ -180,33 +177,31 @@ const CommentsExtension = core.Extension.create({
|
|
|
180
177
|
return true;
|
|
181
178
|
},
|
|
182
179
|
addComment: (id) => ({ commands }) => {
|
|
183
|
-
if (!this.storage.
|
|
180
|
+
if (!this.storage.pendingComment || this.editor.state.selection.empty) {
|
|
184
181
|
return false;
|
|
185
182
|
}
|
|
186
|
-
this.editor.state.selection = this.storage.pendingCommentSelection;
|
|
187
183
|
commands.setMark(types.LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });
|
|
188
|
-
this.storage.
|
|
184
|
+
this.storage.pendingComment = false;
|
|
189
185
|
return true;
|
|
190
186
|
}
|
|
191
187
|
};
|
|
192
188
|
},
|
|
193
189
|
onSelectionUpdate({ transaction }) {
|
|
194
|
-
if (!this.storage.
|
|
190
|
+
if (!this.storage.pendingComment || transaction.getMeta(yProsemirror.ySyncPluginKey)) {
|
|
195
191
|
return;
|
|
196
192
|
}
|
|
197
|
-
this.storage.
|
|
193
|
+
this.storage.pendingComment = false;
|
|
198
194
|
},
|
|
199
195
|
addProseMirrorPlugins() {
|
|
200
196
|
return [
|
|
201
197
|
new state.Plugin({
|
|
202
198
|
key: types.ACTIVE_SELECTION_PLUGIN,
|
|
203
199
|
props: {
|
|
204
|
-
decorations: ({ doc }) => {
|
|
205
|
-
|
|
206
|
-
if (!active) {
|
|
200
|
+
decorations: ({ doc, selection }) => {
|
|
201
|
+
if (!this.storage.pendingComment) {
|
|
207
202
|
return view.DecorationSet.create(doc, []);
|
|
208
203
|
}
|
|
209
|
-
const { from, to } =
|
|
204
|
+
const { from, to } = selection;
|
|
210
205
|
const decorations = [
|
|
211
206
|
view.Decoration.inline(from, to, {
|
|
212
207
|
class: "lb-root lb-tiptap-active-selection"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentsExtension.js","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type { Node } from \"@tiptap/pm/model\";\nimport type { Transaction } from \"@tiptap/pm/state\";\nimport { Plugin, TextSelection } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n ACTIVE_SELECTION_PLUGIN,\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string | null;\n};\n\n/**\n * Known issues: Overlapping marks are merged when reloading the doc. May be related:\n * https://github.com/ueberdosis/tiptap/issues/4339\n * https://github.com/yjs/y-prosemirror/issues/47\n */\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (doc: Node, selectedThreadId: string | null) => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type === this.type) {\n const thisThreadId = (\n mark.attrs as { threadId: string | undefined }\n ).threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n\n if (selectedThreadId === thisThreadId) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n });\n return {\n decorations: DecorationSet.create(doc, decorations),\n selectedThreadId,\n threadPositions,\n selectedThreadPos:\n selectedThreadId !== null\n ? threadPositions.get(selectedThreadId)?.to ?? null\n : null,\n };\n };\n\n return [\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init() {\n return {\n threadPositions: new Map<string, { from: number; to: number }>(),\n selectedThreadId: null,\n selectedThreadPos: null,\n decorations: DecorationSet.empty,\n } as ThreadPluginState;\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as ThreadPluginAction;\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n // Doc changed, but no action, just update rects\n return updateState(tr.doc, state.selectedThreadId);\n }\n // handle actions, possibly support more actions\n if (\n action.name === ThreadPluginActions.SET_SELECTED_THREAD_ID &&\n state.selectedThreadId !== action.data\n ) {\n return updateState(tr.doc, action.data);\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const selectThread = (threadId: string | null) => {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: threadId,\n })\n );\n };\n\n const node = view.state.doc.nodeAt(pos);\n if (!node) {\n selectThread(null);\n return;\n }\n const commentMark = node.marks.find(\n (mark) => mark.type === this.type\n );\n // don't allow selecting orphaned threads\n if (commentMark?.attrs.orphan) {\n selectThread(null);\n return;\n }\n const threadId = commentMark?.attrs.threadId as string | undefined;\n selectThread(threadId ?? null);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n never,\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingCommentSelection: null,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // unselect any open threads\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: null,\n })\n );\n this.storage.pendingCommentSelection = new TextSelection(\n this.editor.state.selection.$anchor,\n this.editor.state.selection.$head\n );\n return true;\n },\n selectThread: (id: string | null) => () => {\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: id,\n })\n );\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (!this.storage.pendingCommentSelection) {\n return false;\n }\n this.editor.state.selection = this.storage.pendingCommentSelection;\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingCommentSelection = null;\n\n return true;\n },\n };\n },\n\n //@ts-expect-error - this is incorrectly typed upstream in Mark.ts of TipTap. This event does include transaction\n // correct: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/types.ts#L60\n // incorrect: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/Mark.ts#L330\n onSelectionUpdate(\n this: { storage: Storage }, // NOTE: there are more types here I didn't override, this gets removed after submitting PR to tiptap\n { transaction }: { transaction: Transaction } // TODO: remove this after submitting PR to tiptap\n ) {\n // ignore changes made by yjs\n if (\n !this.storage.pendingCommentSelection ||\n transaction.getMeta(ySyncPluginKey)\n ) {\n return;\n }\n this.storage.pendingCommentSelection = null;\n },\n // TODO: this.storage.pendingCommentSelection needs to be a Yjs Relative Position that gets translated back to absolute position.\n // Commit: eba949d32d6010a3d8b3f7967d73d4deb015b02a has code that can help with this.\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc }) => {\n const active = this.storage.pendingCommentSelection !== null;\n if (!active) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = this.storage\n .pendingCommentSelection as TextSelection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n ];\n },\n});\n"],"names":["Mark","LIVEBLOCKS_COMMENT_MARK_TYPE","mergeAttributes","Decoration","DecorationSet","Plugin","THREADS_PLUGIN_KEY","ThreadPluginActions","threadId","Extension","TextSelection","ySyncPluginKey","ACTIVE_SELECTION_PLUGIN"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommentsExtension.js","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type { Node } from \"@tiptap/pm/model\";\nimport type { Transaction } from \"@tiptap/pm/state\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n ACTIVE_SELECTION_PLUGIN,\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string | null;\n};\n\n/**\n * Known issues: Overlapping marks are merged when reloading the doc. May be related:\n * https://github.com/ueberdosis/tiptap/issues/4339\n * https://github.com/yjs/y-prosemirror/issues/47\n */\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (doc: Node, selectedThreadId: string | null) => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type === this.type) {\n const thisThreadId = (\n mark.attrs as { threadId: string | undefined }\n ).threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n\n if (selectedThreadId === thisThreadId) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n });\n return {\n decorations: DecorationSet.create(doc, decorations),\n selectedThreadId,\n threadPositions,\n selectedThreadPos:\n selectedThreadId !== null\n ? threadPositions.get(selectedThreadId)?.to ?? null\n : null,\n };\n };\n\n return [\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init() {\n return {\n threadPositions: new Map<string, { from: number; to: number }>(),\n selectedThreadId: null,\n selectedThreadPos: null,\n decorations: DecorationSet.empty,\n } as ThreadPluginState;\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as ThreadPluginAction;\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n // Doc changed, but no action, just update rects\n return updateState(tr.doc, state.selectedThreadId);\n }\n // handle actions, possibly support more actions\n if (\n action.name === ThreadPluginActions.SET_SELECTED_THREAD_ID &&\n state.selectedThreadId !== action.data\n ) {\n return updateState(tr.doc, action.data);\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const selectThread = (threadId: string | null) => {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: threadId,\n })\n );\n };\n\n const node = view.state.doc.nodeAt(pos);\n if (!node) {\n selectThread(null);\n return;\n }\n const commentMark = node.marks.find(\n (mark) => mark.type === this.type\n );\n // don't allow selecting orphaned threads\n if (commentMark?.attrs.orphan) {\n selectThread(null);\n return;\n }\n const threadId = commentMark?.attrs.threadId as string | undefined;\n selectThread(threadId ?? null);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n never,\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingComment: false,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // unselect any open threads\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: null,\n })\n );\n this.storage.pendingComment = true;\n return true;\n },\n selectThread: (id: string | null) => () => {\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: id,\n })\n );\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (\n !this.storage.pendingComment ||\n this.editor.state.selection.empty\n ) {\n return false;\n }\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingComment = false;\n return true;\n },\n };\n },\n\n //@ts-expect-error - this is incorrectly typed upstream in Mark.ts of TipTap. This event does include transaction\n // correct: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/types.ts#L60\n // incorrect: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/Mark.ts#L330\n onSelectionUpdate(\n this: { storage: Storage }, // NOTE: there are more types here I didn't override, this gets removed after submitting PR to tiptap\n { transaction }: { transaction: Transaction } // TODO: remove this after submitting PR to tiptap\n ) {\n // ignore changes made by yjs\n if (!this.storage.pendingComment || transaction.getMeta(ySyncPluginKey)) {\n return;\n }\n // if selection changes, hide the composer. We could keep the composer open and move it to the new selection?\n this.storage.pendingComment = false;\n },\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc, selection }) => {\n if (!this.storage.pendingComment) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = selection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n ];\n },\n});\n"],"names":["Mark","LIVEBLOCKS_COMMENT_MARK_TYPE","mergeAttributes","Decoration","DecorationSet","Plugin","THREADS_PLUGIN_KEY","ThreadPluginActions","threadId","Extension","ySyncPluginKey","ACTIVE_SELECTION_PLUGIN"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Mark, mergeAttributes, Extension } from '@tiptap/core';
|
|
2
|
-
import { Plugin
|
|
2
|
+
import { Plugin } from '@tiptap/pm/state';
|
|
3
3
|
import { Decoration, DecorationSet } from '@tiptap/pm/view';
|
|
4
4
|
import { ySyncPluginKey } from 'y-prosemirror';
|
|
5
5
|
import { LIVEBLOCKS_COMMENT_MARK_TYPE, THREADS_PLUGIN_KEY, ThreadPluginActions, ACTIVE_SELECTION_PLUGIN } from '../types.mjs';
|
|
@@ -147,7 +147,7 @@ const CommentsExtension = Extension.create({
|
|
|
147
147
|
},
|
|
148
148
|
addStorage() {
|
|
149
149
|
return {
|
|
150
|
-
|
|
150
|
+
pendingComment: false
|
|
151
151
|
};
|
|
152
152
|
},
|
|
153
153
|
addCommands() {
|
|
@@ -162,10 +162,7 @@ const CommentsExtension = Extension.create({
|
|
|
162
162
|
data: null
|
|
163
163
|
})
|
|
164
164
|
);
|
|
165
|
-
this.storage.
|
|
166
|
-
this.editor.state.selection.$anchor,
|
|
167
|
-
this.editor.state.selection.$head
|
|
168
|
-
);
|
|
165
|
+
this.storage.pendingComment = true;
|
|
169
166
|
return true;
|
|
170
167
|
},
|
|
171
168
|
selectThread: (id) => () => {
|
|
@@ -178,33 +175,31 @@ const CommentsExtension = Extension.create({
|
|
|
178
175
|
return true;
|
|
179
176
|
},
|
|
180
177
|
addComment: (id) => ({ commands }) => {
|
|
181
|
-
if (!this.storage.
|
|
178
|
+
if (!this.storage.pendingComment || this.editor.state.selection.empty) {
|
|
182
179
|
return false;
|
|
183
180
|
}
|
|
184
|
-
this.editor.state.selection = this.storage.pendingCommentSelection;
|
|
185
181
|
commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });
|
|
186
|
-
this.storage.
|
|
182
|
+
this.storage.pendingComment = false;
|
|
187
183
|
return true;
|
|
188
184
|
}
|
|
189
185
|
};
|
|
190
186
|
},
|
|
191
187
|
onSelectionUpdate({ transaction }) {
|
|
192
|
-
if (!this.storage.
|
|
188
|
+
if (!this.storage.pendingComment || transaction.getMeta(ySyncPluginKey)) {
|
|
193
189
|
return;
|
|
194
190
|
}
|
|
195
|
-
this.storage.
|
|
191
|
+
this.storage.pendingComment = false;
|
|
196
192
|
},
|
|
197
193
|
addProseMirrorPlugins() {
|
|
198
194
|
return [
|
|
199
195
|
new Plugin({
|
|
200
196
|
key: ACTIVE_SELECTION_PLUGIN,
|
|
201
197
|
props: {
|
|
202
|
-
decorations: ({ doc }) => {
|
|
203
|
-
|
|
204
|
-
if (!active) {
|
|
198
|
+
decorations: ({ doc, selection }) => {
|
|
199
|
+
if (!this.storage.pendingComment) {
|
|
205
200
|
return DecorationSet.create(doc, []);
|
|
206
201
|
}
|
|
207
|
-
const { from, to } =
|
|
202
|
+
const { from, to } = selection;
|
|
208
203
|
const decorations = [
|
|
209
204
|
Decoration.inline(from, to, {
|
|
210
205
|
class: "lb-root lb-tiptap-active-selection"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentsExtension.mjs","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type { Node } from \"@tiptap/pm/model\";\nimport type { Transaction } from \"@tiptap/pm/state\";\nimport { Plugin, TextSelection } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n ACTIVE_SELECTION_PLUGIN,\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string | null;\n};\n\n/**\n * Known issues: Overlapping marks are merged when reloading the doc. May be related:\n * https://github.com/ueberdosis/tiptap/issues/4339\n * https://github.com/yjs/y-prosemirror/issues/47\n */\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (doc: Node, selectedThreadId: string | null) => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type === this.type) {\n const thisThreadId = (\n mark.attrs as { threadId: string | undefined }\n ).threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n\n if (selectedThreadId === thisThreadId) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n });\n return {\n decorations: DecorationSet.create(doc, decorations),\n selectedThreadId,\n threadPositions,\n selectedThreadPos:\n selectedThreadId !== null\n ? threadPositions.get(selectedThreadId)?.to ?? null\n : null,\n };\n };\n\n return [\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init() {\n return {\n threadPositions: new Map<string, { from: number; to: number }>(),\n selectedThreadId: null,\n selectedThreadPos: null,\n decorations: DecorationSet.empty,\n } as ThreadPluginState;\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as ThreadPluginAction;\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n // Doc changed, but no action, just update rects\n return updateState(tr.doc, state.selectedThreadId);\n }\n // handle actions, possibly support more actions\n if (\n action.name === ThreadPluginActions.SET_SELECTED_THREAD_ID &&\n state.selectedThreadId !== action.data\n ) {\n return updateState(tr.doc, action.data);\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const selectThread = (threadId: string | null) => {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: threadId,\n })\n );\n };\n\n const node = view.state.doc.nodeAt(pos);\n if (!node) {\n selectThread(null);\n return;\n }\n const commentMark = node.marks.find(\n (mark) => mark.type === this.type\n );\n // don't allow selecting orphaned threads\n if (commentMark?.attrs.orphan) {\n selectThread(null);\n return;\n }\n const threadId = commentMark?.attrs.threadId as string | undefined;\n selectThread(threadId ?? null);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n never,\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingCommentSelection: null,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // unselect any open threads\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: null,\n })\n );\n this.storage.pendingCommentSelection = new TextSelection(\n this.editor.state.selection.$anchor,\n this.editor.state.selection.$head\n );\n return true;\n },\n selectThread: (id: string | null) => () => {\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: id,\n })\n );\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (!this.storage.pendingCommentSelection) {\n return false;\n }\n this.editor.state.selection = this.storage.pendingCommentSelection;\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingCommentSelection = null;\n\n return true;\n },\n };\n },\n\n //@ts-expect-error - this is incorrectly typed upstream in Mark.ts of TipTap. This event does include transaction\n // correct: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/types.ts#L60\n // incorrect: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/Mark.ts#L330\n onSelectionUpdate(\n this: { storage: Storage }, // NOTE: there are more types here I didn't override, this gets removed after submitting PR to tiptap\n { transaction }: { transaction: Transaction } // TODO: remove this after submitting PR to tiptap\n ) {\n // ignore changes made by yjs\n if (\n !this.storage.pendingCommentSelection ||\n transaction.getMeta(ySyncPluginKey)\n ) {\n return;\n }\n this.storage.pendingCommentSelection = null;\n },\n // TODO: this.storage.pendingCommentSelection needs to be a Yjs Relative Position that gets translated back to absolute position.\n // Commit: eba949d32d6010a3d8b3f7967d73d4deb015b02a has code that can help with this.\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc }) => {\n const active = this.storage.pendingCommentSelection !== null;\n if (!active) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = this.storage\n .pendingCommentSelection as TextSelection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n ];\n },\n});\n"],"names":["threadId"],"mappings":";;;;;;AAyBA,MAAM,OAAA,GAAU,KAAK,MAAO,CAAA;AAAA,EAC1B,IAAM,EAAA,4BAAA;AAAA,EACN,QAAU,EAAA,EAAA;AAAA,EACV,SAAW,EAAA,KAAA;AAAA,EACX,WAAa,EAAA,IAAA;AAAA,EACb,aAAgB,GAAA;AAEd,IAAO,OAAA;AAAA,MACL,MAAQ,EAAA;AAAA,QACN,WAAW,CAAC,OAAA,KAAY,CAAC,CAAC,OAAA,CAAQ,aAAa,aAAa,CAAA;AAAA,QAC5D,UAAA,EAAY,CAAC,UAAe,KAAA;AAC1B,UAAA,OAAQ,WAAmC,MACvC,GAAA;AAAA,YACE,aAAe,EAAA,MAAA;AAAA,cAEjB,EAAC,CAAA;AAAA,SACP;AAAA,QACA,OAAS,EAAA,KAAA;AAAA,OACX;AAAA,MACA,QAAU,EAAA;AAAA,QACR,SAAW,EAAA,CAAC,OAAY,KAAA,OAAA,CAAQ,aAAa,mBAAmB,CAAA;AAAA,QAChE,UAAA,EAAY,CAAC,UAAe,KAAA;AAC1B,UAAO,OAAA;AAAA,YACL,qBAAsB,UAAoC,CAAA,QAAA;AAAA,WAC5D,CAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,EAAA;AAAA,OACX;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,UAAA,CAAW,EAAE,cAAA,EAA2D,EAAA;AACtE,IAAO,OAAA;AAAA,MACL,MAAA;AAAA,MACA,gBAAgB,cAAgB,EAAA;AAAA,QAC9B,KAAO,EAAA,+BAAA;AAAA,OACR,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EAKA,qBAAwB,GAAA;AACtB,IAAM,MAAA,WAAA,GAAc,CAAC,GAAA,EAAW,gBAAoC,KAAA;AAClE,MAAM,MAAA,eAAA,uBAAsB,GAA0C,EAAA,CAAA;AACtE,MAAA,MAAM,cAA4B,EAAC,CAAA;AAEnC,MAAI,GAAA,CAAA,WAAA,CAAY,CAAC,IAAA,EAAM,GAAQ,KAAA;AAC7B,QAAK,IAAA,CAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,IAAS,KAAA;AAC3B,UAAI,IAAA,IAAA,CAAK,IAAS,KAAA,IAAA,CAAK,IAAM,EAAA;AAC3B,YAAM,MAAA,YAAA,GACJ,KAAK,KACL,CAAA,QAAA,CAAA;AACF,YAAA,IAAI,CAAC,YAAc,EAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAA,MAAM,IAAO,GAAA,GAAA,CAAA;AACb,YAAM,MAAA,EAAA,GAAK,OAAO,IAAK,CAAA,QAAA,CAAA;AAIvB,YAAA,MAAM,eAAkB,GAAA,eAAA,CAAgB,GAAI,CAAA,YAAY,CAAK,IAAA;AAAA,cAC3D,IAAM,EAAA,QAAA;AAAA,cACN,EAAI,EAAA,CAAA;AAAA,aACN,CAAA;AACA,YAAA,eAAA,CAAgB,IAAI,YAAc,EAAA;AAAA,cAChC,IAAM,EAAA,IAAA,CAAK,GAAI,CAAA,IAAA,EAAM,gBAAgB,IAAI,CAAA;AAAA,cACzC,EAAI,EAAA,IAAA,CAAK,GAAI,CAAA,EAAA,EAAI,gBAAgB,EAAE,CAAA;AAAA,aACpC,CAAA,CAAA;AAED,YAAA,IAAI,qBAAqB,YAAc,EAAA;AACrC,cAAY,WAAA,CAAA,IAAA;AAAA,gBACV,UAAA,CAAW,MAAO,CAAA,IAAA,EAAM,EAAI,EAAA;AAAA,kBAC1B,KAAO,EAAA,wCAAA;AAAA,iBACR,CAAA;AAAA,eACH,CAAA;AAAA,aACF;AAAA,WACF;AAAA,SACD,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AACD,MAAO,OAAA;AAAA,QACL,WAAa,EAAA,aAAA,CAAc,MAAO,CAAA,GAAA,EAAK,WAAW,CAAA;AAAA,QAClD,gBAAA;AAAA,QACA,eAAA;AAAA,QACA,iBAAA,EACE,qBAAqB,IACjB,GAAA,eAAA,CAAgB,IAAI,gBAAgB,CAAA,EAAG,MAAM,IAC7C,GAAA,IAAA;AAAA,OACR,CAAA;AAAA,KACF,CAAA;AAEA,IAAO,OAAA;AAAA,MACL,IAAI,MAAO,CAAA;AAAA,QACT,GAAK,EAAA,kBAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL,IAAO,GAAA;AACL,YAAO,OAAA;AAAA,cACL,eAAA,sBAAqB,GAA0C,EAAA;AAAA,cAC/D,gBAAkB,EAAA,IAAA;AAAA,cAClB,iBAAmB,EAAA,IAAA;AAAA,cACnB,aAAa,aAAc,CAAA,KAAA;AAAA,aAC7B,CAAA;AAAA,WACF;AAAA,UACA,KAAA,CAAM,IAAI,KAAO,EAAA;AACf,YAAM,MAAA,MAAA,GAAS,EAAG,CAAA,OAAA,CAAQ,kBAAkB,CAAA,CAAA;AAC5C,YAAA,IAAI,CAAC,EAAA,CAAG,UAAc,IAAA,CAAC,MAAQ,EAAA;AAC7B,cAAO,OAAA,KAAA,CAAA;AAAA,aACT;AAEA,YAAA,IAAI,CAAC,MAAQ,EAAA;AAEX,cAAA,OAAO,WAAY,CAAA,EAAA,CAAG,GAAK,EAAA,KAAA,CAAM,gBAAgB,CAAA,CAAA;AAAA,aACnD;AAEA,YAAA,IACE,OAAO,IAAS,KAAA,mBAAA,CAAoB,0BACpC,KAAM,CAAA,gBAAA,KAAqB,OAAO,IAClC,EAAA;AACA,cAAA,OAAO,WAAY,CAAA,EAAA,CAAG,GAAK,EAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,aACxC;AAEA,YAAO,OAAA,KAAA,CAAA;AAAA,WACT;AAAA,SACF;AAAA,QACA,KAAO,EAAA;AAAA,UACL,WAAA,EAAa,CAAC,KAAU,KAAA;AACtB,YAAA,OACE,kBAAmB,CAAA,QAAA,CAAS,KAAK,CAAA,EAAG,eACpC,aAAc,CAAA,KAAA,CAAA;AAAA,WAElB;AAAA,UACA,WAAa,EAAA,CAAC,IAAM,EAAA,GAAA,EAAK,KAAU,KAAA;AACjC,YAAI,IAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACtB,cAAA,OAAA;AAAA,aACF;AAEA,YAAM,MAAA,YAAA,GAAe,CAACA,SAA4B,KAAA;AAChD,cAAK,IAAA,CAAA,QAAA;AAAA,gBACH,IAAK,CAAA,KAAA,CAAM,EAAG,CAAA,OAAA,CAAQ,kBAAoB,EAAA;AAAA,kBACxC,MAAM,mBAAoB,CAAA,sBAAA;AAAA,kBAC1B,IAAMA,EAAAA,SAAAA;AAAA,iBACP,CAAA;AAAA,eACH,CAAA;AAAA,aACF,CAAA;AAEA,YAAA,MAAM,IAAO,GAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAA;AACtC,YAAA,IAAI,CAAC,IAAM,EAAA;AACT,cAAA,YAAA,CAAa,IAAI,CAAA,CAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAM,MAAA,WAAA,GAAc,KAAK,KAAM,CAAA,IAAA;AAAA,cAC7B,CAAC,IAAA,KAAS,IAAK,CAAA,IAAA,KAAS,IAAK,CAAA,IAAA;AAAA,aAC/B,CAAA;AAEA,YAAI,IAAA,WAAA,EAAa,MAAM,MAAQ,EAAA;AAC7B,cAAA,YAAA,CAAa,IAAI,CAAA,CAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAM,MAAA,QAAA,GAAW,aAAa,KAAM,CAAA,QAAA,CAAA;AACpC,YAAA,YAAA,CAAa,YAAY,IAAI,CAAA,CAAA;AAAA,WAC/B;AAAA,SACF;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AACF,CAAC,CAAA,CAAA;AAEY,MAAA,iBAAA,GAAoB,UAAU,MAGzC,CAAA;AAAA,EACA,IAAM,EAAA,oBAAA;AAAA,EACN,QAAU,EAAA,EAAA;AAAA,EACV,aAAgB,GAAA;AACd,IAAA,OAAO,CAAC,OAAO,CAAA,CAAA;AAAA,GACjB;AAAA,EAEA,UAAa,GAAA;AACX,IAAO,OAAA;AAAA,MACL,uBAAyB,EAAA,IAAA;AAAA,KAC3B,CAAA;AAAA,GACF;AAAA,EAEA,WAAc,GAAA;AACZ,IAAO,OAAA;AAAA,MACL,iBAAA,EAAmB,MAAM,MAAM;AAC7B,QAAA,IAAI,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,SAAA,CAAU,KAAO,EAAA;AACrC,UAAO,OAAA,KAAA,CAAA;AAAA,SACT;AAEA,QAAA,IAAA,CAAK,OAAO,IAAK,CAAA,QAAA;AAAA,UACf,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,EAAA,CAAG,QAAQ,kBAAoB,EAAA;AAAA,YAC/C,MAAM,mBAAoB,CAAA,sBAAA;AAAA,YAC1B,IAAM,EAAA,IAAA;AAAA,WACP,CAAA;AAAA,SACH,CAAA;AACA,QAAK,IAAA,CAAA,OAAA,CAAQ,0BAA0B,IAAI,aAAA;AAAA,UACzC,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,SAAU,CAAA,OAAA;AAAA,UAC5B,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,SAAU,CAAA,KAAA;AAAA,SAC9B,CAAA;AACA,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,MACA,YAAA,EAAc,CAAC,EAAA,KAAsB,MAAM;AACzC,QAAA,IAAA,CAAK,OAAO,IAAK,CAAA,QAAA;AAAA,UACf,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,EAAA,CAAG,QAAQ,kBAAoB,EAAA;AAAA,YAC/C,MAAM,mBAAoB,CAAA,sBAAA;AAAA,YAC1B,IAAM,EAAA,EAAA;AAAA,WACP,CAAA;AAAA,SACH,CAAA;AACA,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,MACA,YACE,CAAC,EAAA,KACD,CAAC,EAAE,UAAe,KAAA;AAChB,QAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,uBAAyB,EAAA;AACzC,UAAO,OAAA,KAAA,CAAA;AAAA,SACT;AACA,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA,CAAM,SAAY,GAAA,IAAA,CAAK,OAAQ,CAAA,uBAAA,CAAA;AAC3C,QAAA,QAAA,CAAS,OAAQ,CAAA,4BAAA,EAA8B,EAAE,QAAA,EAAU,IAAI,CAAA,CAAA;AAC/D,QAAA,IAAA,CAAK,QAAQ,uBAA0B,GAAA,IAAA,CAAA;AAEvC,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,KACJ,CAAA;AAAA,GACF;AAAA,EAKA,iBAAA,CAEE,EAAE,WAAA,EACF,EAAA;AAEA,IAAA,IACE,CAAC,IAAK,CAAA,OAAA,CAAQ,2BACd,WAAY,CAAA,OAAA,CAAQ,cAAc,CAClC,EAAA;AACA,MAAA,OAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,QAAQ,uBAA0B,GAAA,IAAA,CAAA;AAAA,GACzC;AAAA,EAGA,qBAAwB,GAAA;AACtB,IAAO,OAAA;AAAA,MACL,IAAI,MAAO,CAAA;AAAA,QACT,GAAK,EAAA,uBAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL,WAAa,EAAA,CAAC,EAAE,GAAA,EAAU,KAAA;AACxB,YAAM,MAAA,MAAA,GAAS,IAAK,CAAA,OAAA,CAAQ,uBAA4B,KAAA,IAAA,CAAA;AACxD,YAAA,IAAI,CAAC,MAAQ,EAAA;AACX,cAAA,OAAO,aAAc,CAAA,MAAA,CAAO,GAAK,EAAA,EAAE,CAAA,CAAA;AAAA,aACrC;AACA,YAAA,MAAM,EAAE,IAAA,EAAM,EAAG,EAAA,GAAI,KAAK,OACvB,CAAA,uBAAA,CAAA;AACH,YAAA,MAAM,WAA4B,GAAA;AAAA,cAChC,UAAA,CAAW,MAAO,CAAA,IAAA,EAAM,EAAI,EAAA;AAAA,gBAC1B,KAAO,EAAA,oCAAA;AAAA,eACR,CAAA;AAAA,aACH,CAAA;AACA,YAAO,OAAA,aAAA,CAAc,MAAO,CAAA,GAAA,EAAK,WAAW,CAAA,CAAA;AAAA,WAC9C;AAAA,SACF;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AACF,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"CommentsExtension.mjs","sources":["../../src/comments/CommentsExtension.ts"],"sourcesContent":["import { Extension, Mark, mergeAttributes } from \"@tiptap/core\";\nimport type { Node } from \"@tiptap/pm/model\";\nimport type { Transaction } from \"@tiptap/pm/state\";\nimport { Plugin } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport { ySyncPluginKey } from \"y-prosemirror\";\n\nimport type { CommentsExtensionStorage, ThreadPluginState } from \"../types\";\nimport {\n ACTIVE_SELECTION_PLUGIN,\n LIVEBLOCKS_COMMENT_MARK_TYPE,\n ThreadPluginActions,\n THREADS_PLUGIN_KEY,\n} from \"../types\";\n\ntype ThreadPluginAction = {\n name: ThreadPluginActions;\n data: string | null;\n};\n\n/**\n * Known issues: Overlapping marks are merged when reloading the doc. May be related:\n * https://github.com/ueberdosis/tiptap/issues/4339\n * https://github.com/yjs/y-prosemirror/issues/47\n */\nconst Comment = Mark.create({\n name: LIVEBLOCKS_COMMENT_MARK_TYPE,\n excludes: \"\",\n inclusive: false,\n keepOnSplit: true,\n addAttributes() {\n // Return an object with attribute configuration\n return {\n orphan: {\n parseHTML: (element) => !!element.getAttribute(\"data-orphan\"),\n renderHTML: (attributes) => {\n return (attributes as { orphan: boolean }).orphan\n ? {\n \"data-orphan\": \"true\",\n }\n : {};\n },\n default: false,\n },\n threadId: {\n parseHTML: (element) => element.getAttribute(\"data-lb-thread-id\"),\n renderHTML: (attributes) => {\n return {\n \"data-lb-thread-id\": (attributes as { threadId: string }).threadId,\n };\n },\n default: \"\",\n },\n };\n },\n\n renderHTML({ HTMLAttributes }: { HTMLAttributes: Record<string, any> }) {\n return [\n \"span\",\n mergeAttributes(HTMLAttributes, {\n class: \"lb-root lb-tiptap-thread-mark\",\n }),\n ];\n },\n\n /**\n * This plugin tracks the (first) position of each thread mark in the doc and creates a decoration for the selected thread\n */\n addProseMirrorPlugins() {\n const updateState = (doc: Node, selectedThreadId: string | null) => {\n const threadPositions = new Map<string, { from: number; to: number }>();\n const decorations: Decoration[] = [];\n // find all thread marks and store their position + create decoration for selected thread\n doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type === this.type) {\n const thisThreadId = (\n mark.attrs as { threadId: string | undefined }\n ).threadId;\n if (!thisThreadId) {\n return;\n }\n const from = pos;\n const to = from + node.nodeSize;\n\n // FloatingThreads component uses \"to\" as the position, so always store the largest \"to\" found\n // AnchoredThreads component uses \"from\" as the position, so always store the smallest \"from\" found\n const currentPosition = threadPositions.get(thisThreadId) ?? {\n from: Infinity,\n to: 0,\n };\n threadPositions.set(thisThreadId, {\n from: Math.min(from, currentPosition.from),\n to: Math.max(to, currentPosition.to),\n });\n\n if (selectedThreadId === thisThreadId) {\n decorations.push(\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-thread-mark-selected\",\n })\n );\n }\n }\n });\n });\n return {\n decorations: DecorationSet.create(doc, decorations),\n selectedThreadId,\n threadPositions,\n selectedThreadPos:\n selectedThreadId !== null\n ? threadPositions.get(selectedThreadId)?.to ?? null\n : null,\n };\n };\n\n return [\n new Plugin({\n key: THREADS_PLUGIN_KEY,\n state: {\n init() {\n return {\n threadPositions: new Map<string, { from: number; to: number }>(),\n selectedThreadId: null,\n selectedThreadPos: null,\n decorations: DecorationSet.empty,\n } as ThreadPluginState;\n },\n apply(tr, state) {\n const action = tr.getMeta(THREADS_PLUGIN_KEY) as ThreadPluginAction;\n if (!tr.docChanged && !action) {\n return state;\n }\n\n if (!action) {\n // Doc changed, but no action, just update rects\n return updateState(tr.doc, state.selectedThreadId);\n }\n // handle actions, possibly support more actions\n if (\n action.name === ThreadPluginActions.SET_SELECTED_THREAD_ID &&\n state.selectedThreadId !== action.data\n ) {\n return updateState(tr.doc, action.data);\n }\n\n return state;\n },\n },\n props: {\n decorations: (state) => {\n return (\n THREADS_PLUGIN_KEY.getState(state)?.decorations ??\n DecorationSet.empty\n );\n },\n handleClick: (view, pos, event) => {\n if (event.button !== 0) {\n return;\n }\n\n const selectThread = (threadId: string | null) => {\n view.dispatch(\n view.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: threadId,\n })\n );\n };\n\n const node = view.state.doc.nodeAt(pos);\n if (!node) {\n selectThread(null);\n return;\n }\n const commentMark = node.marks.find(\n (mark) => mark.type === this.type\n );\n // don't allow selecting orphaned threads\n if (commentMark?.attrs.orphan) {\n selectThread(null);\n return;\n }\n const threadId = commentMark?.attrs.threadId as string | undefined;\n selectThread(threadId ?? null);\n },\n },\n }),\n ];\n },\n});\n\nexport const CommentsExtension = Extension.create<\n never,\n CommentsExtensionStorage\n>({\n name: \"liveblocksComments\",\n priority: 95,\n addExtensions() {\n return [Comment];\n },\n\n addStorage() {\n return {\n pendingComment: false,\n };\n },\n\n addCommands() {\n return {\n addPendingComment: () => () => {\n if (this.editor.state.selection.empty) {\n return false;\n }\n // unselect any open threads\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: null,\n })\n );\n this.storage.pendingComment = true;\n return true;\n },\n selectThread: (id: string | null) => () => {\n this.editor.view.dispatch(\n this.editor.state.tr.setMeta(THREADS_PLUGIN_KEY, {\n name: ThreadPluginActions.SET_SELECTED_THREAD_ID,\n data: id,\n })\n );\n return true;\n },\n addComment:\n (id: string) =>\n ({ commands }) => {\n if (\n !this.storage.pendingComment ||\n this.editor.state.selection.empty\n ) {\n return false;\n }\n commands.setMark(LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });\n this.storage.pendingComment = false;\n return true;\n },\n };\n },\n\n //@ts-expect-error - this is incorrectly typed upstream in Mark.ts of TipTap. This event does include transaction\n // correct: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/types.ts#L60\n // incorrect: https://github.com/ueberdosis/tiptap/blob/2ff327ced84df6865b4ef98947b667aa79992292/packages/core/src/Mark.ts#L330\n onSelectionUpdate(\n this: { storage: Storage }, // NOTE: there are more types here I didn't override, this gets removed after submitting PR to tiptap\n { transaction }: { transaction: Transaction } // TODO: remove this after submitting PR to tiptap\n ) {\n // ignore changes made by yjs\n if (!this.storage.pendingComment || transaction.getMeta(ySyncPluginKey)) {\n return;\n }\n // if selection changes, hide the composer. We could keep the composer open and move it to the new selection?\n this.storage.pendingComment = false;\n },\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: ACTIVE_SELECTION_PLUGIN,\n props: {\n decorations: ({ doc, selection }) => {\n if (!this.storage.pendingComment) {\n return DecorationSet.create(doc, []);\n }\n const { from, to } = selection;\n const decorations: Decoration[] = [\n Decoration.inline(from, to, {\n class: \"lb-root lb-tiptap-active-selection\",\n }),\n ];\n return DecorationSet.create(doc, decorations);\n },\n },\n }),\n ];\n },\n});\n"],"names":["threadId"],"mappings":";;;;;;AAyBA,MAAM,OAAA,GAAU,KAAK,MAAO,CAAA;AAAA,EAC1B,IAAM,EAAA,4BAAA;AAAA,EACN,QAAU,EAAA,EAAA;AAAA,EACV,SAAW,EAAA,KAAA;AAAA,EACX,WAAa,EAAA,IAAA;AAAA,EACb,aAAgB,GAAA;AAEd,IAAO,OAAA;AAAA,MACL,MAAQ,EAAA;AAAA,QACN,WAAW,CAAC,OAAA,KAAY,CAAC,CAAC,OAAA,CAAQ,aAAa,aAAa,CAAA;AAAA,QAC5D,UAAA,EAAY,CAAC,UAAe,KAAA;AAC1B,UAAA,OAAQ,WAAmC,MACvC,GAAA;AAAA,YACE,aAAe,EAAA,MAAA;AAAA,cAEjB,EAAC,CAAA;AAAA,SACP;AAAA,QACA,OAAS,EAAA,KAAA;AAAA,OACX;AAAA,MACA,QAAU,EAAA;AAAA,QACR,SAAW,EAAA,CAAC,OAAY,KAAA,OAAA,CAAQ,aAAa,mBAAmB,CAAA;AAAA,QAChE,UAAA,EAAY,CAAC,UAAe,KAAA;AAC1B,UAAO,OAAA;AAAA,YACL,qBAAsB,UAAoC,CAAA,QAAA;AAAA,WAC5D,CAAA;AAAA,SACF;AAAA,QACA,OAAS,EAAA,EAAA;AAAA,OACX;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,UAAA,CAAW,EAAE,cAAA,EAA2D,EAAA;AACtE,IAAO,OAAA;AAAA,MACL,MAAA;AAAA,MACA,gBAAgB,cAAgB,EAAA;AAAA,QAC9B,KAAO,EAAA,+BAAA;AAAA,OACR,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AAAA,EAKA,qBAAwB,GAAA;AACtB,IAAM,MAAA,WAAA,GAAc,CAAC,GAAA,EAAW,gBAAoC,KAAA;AAClE,MAAM,MAAA,eAAA,uBAAsB,GAA0C,EAAA,CAAA;AACtE,MAAA,MAAM,cAA4B,EAAC,CAAA;AAEnC,MAAI,GAAA,CAAA,WAAA,CAAY,CAAC,IAAA,EAAM,GAAQ,KAAA;AAC7B,QAAK,IAAA,CAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,IAAS,KAAA;AAC3B,UAAI,IAAA,IAAA,CAAK,IAAS,KAAA,IAAA,CAAK,IAAM,EAAA;AAC3B,YAAM,MAAA,YAAA,GACJ,KAAK,KACL,CAAA,QAAA,CAAA;AACF,YAAA,IAAI,CAAC,YAAc,EAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAA,MAAM,IAAO,GAAA,GAAA,CAAA;AACb,YAAM,MAAA,EAAA,GAAK,OAAO,IAAK,CAAA,QAAA,CAAA;AAIvB,YAAA,MAAM,eAAkB,GAAA,eAAA,CAAgB,GAAI,CAAA,YAAY,CAAK,IAAA;AAAA,cAC3D,IAAM,EAAA,QAAA;AAAA,cACN,EAAI,EAAA,CAAA;AAAA,aACN,CAAA;AACA,YAAA,eAAA,CAAgB,IAAI,YAAc,EAAA;AAAA,cAChC,IAAM,EAAA,IAAA,CAAK,GAAI,CAAA,IAAA,EAAM,gBAAgB,IAAI,CAAA;AAAA,cACzC,EAAI,EAAA,IAAA,CAAK,GAAI,CAAA,EAAA,EAAI,gBAAgB,EAAE,CAAA;AAAA,aACpC,CAAA,CAAA;AAED,YAAA,IAAI,qBAAqB,YAAc,EAAA;AACrC,cAAY,WAAA,CAAA,IAAA;AAAA,gBACV,UAAA,CAAW,MAAO,CAAA,IAAA,EAAM,EAAI,EAAA;AAAA,kBAC1B,KAAO,EAAA,wCAAA;AAAA,iBACR,CAAA;AAAA,eACH,CAAA;AAAA,aACF;AAAA,WACF;AAAA,SACD,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AACD,MAAO,OAAA;AAAA,QACL,WAAa,EAAA,aAAA,CAAc,MAAO,CAAA,GAAA,EAAK,WAAW,CAAA;AAAA,QAClD,gBAAA;AAAA,QACA,eAAA;AAAA,QACA,iBAAA,EACE,qBAAqB,IACjB,GAAA,eAAA,CAAgB,IAAI,gBAAgB,CAAA,EAAG,MAAM,IAC7C,GAAA,IAAA;AAAA,OACR,CAAA;AAAA,KACF,CAAA;AAEA,IAAO,OAAA;AAAA,MACL,IAAI,MAAO,CAAA;AAAA,QACT,GAAK,EAAA,kBAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL,IAAO,GAAA;AACL,YAAO,OAAA;AAAA,cACL,eAAA,sBAAqB,GAA0C,EAAA;AAAA,cAC/D,gBAAkB,EAAA,IAAA;AAAA,cAClB,iBAAmB,EAAA,IAAA;AAAA,cACnB,aAAa,aAAc,CAAA,KAAA;AAAA,aAC7B,CAAA;AAAA,WACF;AAAA,UACA,KAAA,CAAM,IAAI,KAAO,EAAA;AACf,YAAM,MAAA,MAAA,GAAS,EAAG,CAAA,OAAA,CAAQ,kBAAkB,CAAA,CAAA;AAC5C,YAAA,IAAI,CAAC,EAAA,CAAG,UAAc,IAAA,CAAC,MAAQ,EAAA;AAC7B,cAAO,OAAA,KAAA,CAAA;AAAA,aACT;AAEA,YAAA,IAAI,CAAC,MAAQ,EAAA;AAEX,cAAA,OAAO,WAAY,CAAA,EAAA,CAAG,GAAK,EAAA,KAAA,CAAM,gBAAgB,CAAA,CAAA;AAAA,aACnD;AAEA,YAAA,IACE,OAAO,IAAS,KAAA,mBAAA,CAAoB,0BACpC,KAAM,CAAA,gBAAA,KAAqB,OAAO,IAClC,EAAA;AACA,cAAA,OAAO,WAAY,CAAA,EAAA,CAAG,GAAK,EAAA,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,aACxC;AAEA,YAAO,OAAA,KAAA,CAAA;AAAA,WACT;AAAA,SACF;AAAA,QACA,KAAO,EAAA;AAAA,UACL,WAAA,EAAa,CAAC,KAAU,KAAA;AACtB,YAAA,OACE,kBAAmB,CAAA,QAAA,CAAS,KAAK,CAAA,EAAG,eACpC,aAAc,CAAA,KAAA,CAAA;AAAA,WAElB;AAAA,UACA,WAAa,EAAA,CAAC,IAAM,EAAA,GAAA,EAAK,KAAU,KAAA;AACjC,YAAI,IAAA,KAAA,CAAM,WAAW,CAAG,EAAA;AACtB,cAAA,OAAA;AAAA,aACF;AAEA,YAAM,MAAA,YAAA,GAAe,CAACA,SAA4B,KAAA;AAChD,cAAK,IAAA,CAAA,QAAA;AAAA,gBACH,IAAK,CAAA,KAAA,CAAM,EAAG,CAAA,OAAA,CAAQ,kBAAoB,EAAA;AAAA,kBACxC,MAAM,mBAAoB,CAAA,sBAAA;AAAA,kBAC1B,IAAMA,EAAAA,SAAAA;AAAA,iBACP,CAAA;AAAA,eACH,CAAA;AAAA,aACF,CAAA;AAEA,YAAA,MAAM,IAAO,GAAA,IAAA,CAAK,KAAM,CAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAA;AACtC,YAAA,IAAI,CAAC,IAAM,EAAA;AACT,cAAA,YAAA,CAAa,IAAI,CAAA,CAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAM,MAAA,WAAA,GAAc,KAAK,KAAM,CAAA,IAAA;AAAA,cAC7B,CAAC,IAAA,KAAS,IAAK,CAAA,IAAA,KAAS,IAAK,CAAA,IAAA;AAAA,aAC/B,CAAA;AAEA,YAAI,IAAA,WAAA,EAAa,MAAM,MAAQ,EAAA;AAC7B,cAAA,YAAA,CAAa,IAAI,CAAA,CAAA;AACjB,cAAA,OAAA;AAAA,aACF;AACA,YAAM,MAAA,QAAA,GAAW,aAAa,KAAM,CAAA,QAAA,CAAA;AACpC,YAAA,YAAA,CAAa,YAAY,IAAI,CAAA,CAAA;AAAA,WAC/B;AAAA,SACF;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AACF,CAAC,CAAA,CAAA;AAEY,MAAA,iBAAA,GAAoB,UAAU,MAGzC,CAAA;AAAA,EACA,IAAM,EAAA,oBAAA;AAAA,EACN,QAAU,EAAA,EAAA;AAAA,EACV,aAAgB,GAAA;AACd,IAAA,OAAO,CAAC,OAAO,CAAA,CAAA;AAAA,GACjB;AAAA,EAEA,UAAa,GAAA;AACX,IAAO,OAAA;AAAA,MACL,cAAgB,EAAA,KAAA;AAAA,KAClB,CAAA;AAAA,GACF;AAAA,EAEA,WAAc,GAAA;AACZ,IAAO,OAAA;AAAA,MACL,iBAAA,EAAmB,MAAM,MAAM;AAC7B,QAAA,IAAI,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,SAAA,CAAU,KAAO,EAAA;AACrC,UAAO,OAAA,KAAA,CAAA;AAAA,SACT;AAEA,QAAA,IAAA,CAAK,OAAO,IAAK,CAAA,QAAA;AAAA,UACf,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,EAAA,CAAG,QAAQ,kBAAoB,EAAA;AAAA,YAC/C,MAAM,mBAAoB,CAAA,sBAAA;AAAA,YAC1B,IAAM,EAAA,IAAA;AAAA,WACP,CAAA;AAAA,SACH,CAAA;AACA,QAAA,IAAA,CAAK,QAAQ,cAAiB,GAAA,IAAA,CAAA;AAC9B,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,MACA,YAAA,EAAc,CAAC,EAAA,KAAsB,MAAM;AACzC,QAAA,IAAA,CAAK,OAAO,IAAK,CAAA,QAAA;AAAA,UACf,IAAK,CAAA,MAAA,CAAO,KAAM,CAAA,EAAA,CAAG,QAAQ,kBAAoB,EAAA;AAAA,YAC/C,MAAM,mBAAoB,CAAA,sBAAA;AAAA,YAC1B,IAAM,EAAA,EAAA;AAAA,WACP,CAAA;AAAA,SACH,CAAA;AACA,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,MACA,YACE,CAAC,EAAA,KACD,CAAC,EAAE,UAAe,KAAA;AAChB,QACE,IAAA,CAAC,KAAK,OAAQ,CAAA,cAAA,IACd,KAAK,MAAO,CAAA,KAAA,CAAM,UAAU,KAC5B,EAAA;AACA,UAAO,OAAA,KAAA,CAAA;AAAA,SACT;AACA,QAAA,QAAA,CAAS,OAAQ,CAAA,4BAAA,EAA8B,EAAE,QAAA,EAAU,IAAI,CAAA,CAAA;AAC/D,QAAA,IAAA,CAAK,QAAQ,cAAiB,GAAA,KAAA,CAAA;AAC9B,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,KACJ,CAAA;AAAA,GACF;AAAA,EAKA,iBAAA,CAEE,EAAE,WAAA,EACF,EAAA;AAEA,IAAA,IAAI,CAAC,IAAK,CAAA,OAAA,CAAQ,kBAAkB,WAAY,CAAA,OAAA,CAAQ,cAAc,CAAG,EAAA;AACvE,MAAA,OAAA;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,QAAQ,cAAiB,GAAA,KAAA,CAAA;AAAA,GAChC;AAAA,EACA,qBAAwB,GAAA;AACtB,IAAO,OAAA;AAAA,MACL,IAAI,MAAO,CAAA;AAAA,QACT,GAAK,EAAA,uBAAA;AAAA,QACL,KAAO,EAAA;AAAA,UACL,WAAa,EAAA,CAAC,EAAE,GAAA,EAAK,WAAgB,KAAA;AACnC,YAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,cAAgB,EAAA;AAChC,cAAA,OAAO,aAAc,CAAA,MAAA,CAAO,GAAK,EAAA,EAAE,CAAA,CAAA;AAAA,aACrC;AACA,YAAM,MAAA,EAAE,IAAM,EAAA,EAAA,EAAO,GAAA,SAAA,CAAA;AACrB,YAAA,MAAM,WAA4B,GAAA;AAAA,cAChC,UAAA,CAAW,MAAO,CAAA,IAAA,EAAM,EAAI,EAAA;AAAA,gBAC1B,KAAO,EAAA,oCAAA;AAAA,eACR,CAAA;AAAA,aACH,CAAA;AACA,YAAO,OAAA,aAAA,CAAc,MAAO,CAAA,GAAA,EAAK,WAAW,CAAA,CAAA;AAAA,WAC9C;AAAA,SACF;AAAA,OACD,CAAA;AAAA,KACH,CAAA;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var reactDom = require('@floating-ui/react-dom');
|
|
5
5
|
var react$1 = require('@liveblocks/react');
|
|
6
|
+
var _private = require('@liveblocks/react/_private');
|
|
6
7
|
var reactUi = require('@liveblocks/react-ui');
|
|
7
8
|
var react$2 = require('@tiptap/react');
|
|
8
9
|
var react = require('react');
|
|
@@ -15,7 +16,7 @@ const FloatingComposer = react.forwardRef(function FloatingComposer2(props, forw
|
|
|
15
16
|
const { showComposer } = react$2.useEditorState({
|
|
16
17
|
editor,
|
|
17
18
|
selector: (ctx) => ({
|
|
18
|
-
showComposer: !!ctx.editor?.storage.liveblocksComments?.
|
|
19
|
+
showComposer: !!ctx.editor?.storage.liveblocksComments?.pendingComment && !editor?.state.selection.empty
|
|
19
20
|
}),
|
|
20
21
|
equalityFn: (prev, next) => {
|
|
21
22
|
if (!next)
|
|
@@ -65,7 +66,7 @@ const FloatingComposer = react.forwardRef(function FloatingComposer2(props, forw
|
|
|
65
66
|
editor.off("transaction", updateRef);
|
|
66
67
|
};
|
|
67
68
|
}, [editor, updateRef, showComposer]);
|
|
68
|
-
|
|
69
|
+
_private.useLayoutEffect(updateRef, [updateRef]);
|
|
69
70
|
const handleComposerSubmit = react.useCallback(
|
|
70
71
|
(comment, event) => {
|
|
71
72
|
onComposerSubmit?.(comment, event);
|
|
@@ -84,12 +85,15 @@ const FloatingComposer = react.forwardRef(function FloatingComposer2(props, forw
|
|
|
84
85
|
},
|
|
85
86
|
[onComposerSubmit, editor, createThread, props.metadata]
|
|
86
87
|
);
|
|
87
|
-
const handleKeyDown = react.useCallback(
|
|
88
|
-
|
|
89
|
-
editor
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
const handleKeyDown = react.useCallback(
|
|
89
|
+
(event) => {
|
|
90
|
+
if (event.key === "Escape" && editor) {
|
|
91
|
+
editor.commands.focus();
|
|
92
|
+
}
|
|
93
|
+
onKeyDown?.(event);
|
|
94
|
+
},
|
|
95
|
+
[editor, onKeyDown]
|
|
96
|
+
);
|
|
93
97
|
if (!showComposer || !editor) {
|
|
94
98
|
return null;
|
|
95
99
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingComposer.js","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback, useEffect
|
|
1
|
+
{"version":3,"file":"FloatingComposer.js","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback, useEffect } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport type { CommentsExtensionStorage } from \"../types\";\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n> & {\n editor: Editor | null;\n};\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const createThread = useCreateThread();\n const { editor, onComposerSubmit, onKeyDown } = props;\n const { showComposer } = useEditorState({\n editor,\n selector: (ctx) => ({\n showComposer: !!(\n ctx.editor?.storage.liveblocksComments as\n | CommentsExtensionStorage\n | undefined\n )?.pendingComment && !editor?.state.selection.empty,\n }),\n equalityFn: (prev, next) => {\n if (!next) return false;\n return prev.showComposer === next.showComposer;\n },\n }) ?? { showComposer: false };\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n if (!editor || !showComposer) {\n return;\n }\n const el = editor.view.dom.querySelector(\".lb-tiptap-active-selection\");\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, showComposer]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n if (!editor || !showComposer) {\n return;\n }\n editor.on(\"transaction\", updateRef);\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef, showComposer]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n // Submit a new thread and update the comment highlight to show a completed highlight\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n if (!editor) {\n return;\n }\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n editor.commands.addComment(thread.id);\n },\n [onComposerSubmit, editor, createThread, props.metadata]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === \"Escape\" && editor) {\n editor.commands.focus();\n }\n onKeyDown?.(event);\n },\n [editor, onKeyDown]\n );\n\n if (!showComposer || !editor) {\n return null;\n }\n\n return createPortal(\n <div\n className=\"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-composer\"\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n >\n <Composer\n ref={forwardedRef}\n {...props}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n onClick={(e) => {\n // Don't send up a click event from emoji popout and close the composer\n e.stopPropagation();\n }}\n autoFocus={true}\n />\n </div>,\n document.body\n );\n});\n"],"names":["forwardRef","FloatingComposer","useCreateThread","useEditorState","useFloating","flip","offset","hide","shift","limitShift","size","autoUpdate","useCallback","useEffect","useLayoutEffect","createPortal","jsx","Composer"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
3
3
|
import { useCreateThread } from '@liveblocks/react';
|
|
4
|
+
import { useLayoutEffect } from '@liveblocks/react/_private';
|
|
4
5
|
import { Composer } from '@liveblocks/react-ui';
|
|
5
6
|
import { useEditorState } from '@tiptap/react';
|
|
6
|
-
import { forwardRef, useCallback, useEffect
|
|
7
|
+
import { forwardRef, useCallback, useEffect } from 'react';
|
|
7
8
|
import { createPortal } from 'react-dom';
|
|
8
9
|
|
|
9
10
|
const FLOATING_COMPOSER_COLLISION_PADDING = 10;
|
|
@@ -13,7 +14,7 @@ const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedR
|
|
|
13
14
|
const { showComposer } = useEditorState({
|
|
14
15
|
editor,
|
|
15
16
|
selector: (ctx) => ({
|
|
16
|
-
showComposer: !!ctx.editor?.storage.liveblocksComments?.
|
|
17
|
+
showComposer: !!ctx.editor?.storage.liveblocksComments?.pendingComment && !editor?.state.selection.empty
|
|
17
18
|
}),
|
|
18
19
|
equalityFn: (prev, next) => {
|
|
19
20
|
if (!next)
|
|
@@ -82,12 +83,15 @@ const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedR
|
|
|
82
83
|
},
|
|
83
84
|
[onComposerSubmit, editor, createThread, props.metadata]
|
|
84
85
|
);
|
|
85
|
-
const handleKeyDown = useCallback(
|
|
86
|
-
|
|
87
|
-
editor
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
const handleKeyDown = useCallback(
|
|
87
|
+
(event) => {
|
|
88
|
+
if (event.key === "Escape" && editor) {
|
|
89
|
+
editor.commands.focus();
|
|
90
|
+
}
|
|
91
|
+
onKeyDown?.(event);
|
|
92
|
+
},
|
|
93
|
+
[editor, onKeyDown]
|
|
94
|
+
);
|
|
91
95
|
if (!showComposer || !editor) {
|
|
92
96
|
return null;
|
|
93
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingComposer.mjs","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback, useEffect
|
|
1
|
+
{"version":3,"file":"FloatingComposer.mjs","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback, useEffect } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport type { CommentsExtensionStorage } from \"../types\";\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n> & {\n editor: Editor | null;\n};\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const createThread = useCreateThread();\n const { editor, onComposerSubmit, onKeyDown } = props;\n const { showComposer } = useEditorState({\n editor,\n selector: (ctx) => ({\n showComposer: !!(\n ctx.editor?.storage.liveblocksComments as\n | CommentsExtensionStorage\n | undefined\n )?.pendingComment && !editor?.state.selection.empty,\n }),\n equalityFn: (prev, next) => {\n if (!next) return false;\n return prev.showComposer === next.showComposer;\n },\n }) ?? { showComposer: false };\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n if (!editor || !showComposer) {\n return;\n }\n const el = editor.view.dom.querySelector(\".lb-tiptap-active-selection\");\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, showComposer]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n if (!editor || !showComposer) {\n return;\n }\n editor.on(\"transaction\", updateRef);\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef, showComposer]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n // Submit a new thread and update the comment highlight to show a completed highlight\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n if (!editor) {\n return;\n }\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n editor.commands.addComment(thread.id);\n },\n [onComposerSubmit, editor, createThread, props.metadata]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === \"Escape\" && editor) {\n editor.commands.focus();\n }\n onKeyDown?.(event);\n },\n [editor, onKeyDown]\n );\n\n if (!showComposer || !editor) {\n return null;\n }\n\n return createPortal(\n <div\n className=\"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-composer\"\n ref={setFloating}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n >\n <Composer\n ref={forwardedRef}\n {...props}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n onClick={(e) => {\n // Don't send up a click event from emoji popout and close the composer\n e.stopPropagation();\n }}\n autoFocus={true}\n />\n </div>,\n document.body\n );\n});\n"],"names":["FloatingComposer"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var reactDom = require('@floating-ui/react-dom');
|
|
5
|
+
var _private = require('@liveblocks/react/_private');
|
|
5
6
|
var reactUi = require('@liveblocks/react-ui');
|
|
6
7
|
var react = require('@tiptap/react');
|
|
7
8
|
var react$1 = require('react');
|
|
@@ -116,7 +117,9 @@ function FloatingThreadPortal({
|
|
|
116
117
|
}
|
|
117
118
|
});
|
|
118
119
|
const updateRef = react$1.useCallback(() => {
|
|
119
|
-
const el = editor.view.dom.querySelector(
|
|
120
|
+
const el = editor.view.dom.querySelector(
|
|
121
|
+
`[data-lb-thread-id="${thread.id}"]`
|
|
122
|
+
);
|
|
120
123
|
if (el) {
|
|
121
124
|
setReference(el);
|
|
122
125
|
}
|
|
@@ -127,7 +130,7 @@ function FloatingThreadPortal({
|
|
|
127
130
|
editor.off("transaction", updateRef);
|
|
128
131
|
};
|
|
129
132
|
}, [editor, updateRef]);
|
|
130
|
-
|
|
133
|
+
_private.useLayoutEffect(updateRef, [updateRef]);
|
|
131
134
|
return reactDom$1.createPortal(
|
|
132
135
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
133
136
|
ref: setFloating,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingThreads.js","sources":["../../src/comments/FloatingThreads.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { classNames } from \"../classnames\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\n\n /**\n * The tiptap editor\n */\n editor: Editor | null;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n editor,\n ...props\n}: FloatingThreadsProps) {\n const Thread = components?.Thread ?? DefaultThread;\n\n const { pluginState } = useEditorState({\n editor,\n selector: (ctx) => {\n if (!ctx?.editor?.state) return { pluginState: undefined };\n const state = THREADS_PLUGIN_KEY.getState(ctx.editor.state);\n return {\n pluginState: state,\n };\n },\n equalityFn: (prev, next) => {\n if (!prev || !next) return false;\n return prev.pluginState?.selectedThreadPos === next.pluginState?.selectedThreadPos &&\n prev.pluginState?.selectedThreadId === next.pluginState?.selectedThreadId;\n },\n }) ?? { pluginState: undefined };\n\n const [activeThread, setActiveThread] = useState<ThreadData | null>(null);\n\n useEffect(() => {\n if (!editor || !pluginState) {\n setActiveThread(null);\n return;\n }\n const { selectedThreadId, selectedThreadPos } = pluginState;\n if (selectedThreadId === null || selectedThreadPos === null) {\n setActiveThread(null);\n return;\n }\n const active = (threads ?? []).find((thread) =>\n selectedThreadId === thread.id\n );\n setActiveThread(active ?? null);\n }, [editor, pluginState, threads]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (!editor || activeThread === null) return false;\n editor.commands.selectThread(null);\n return true;\n }, [activeThread, editor]);\n\n if (!activeThread || !editor || activeThread.resolved) return null;\n\n return (\n <FloatingThreadPortal\n thread={activeThread}\n editor={editor}\n container={document.body}\n {...props}\n >\n {activeThread &&\n <ThreadWrapper\n key={activeThread.id}\n thread={activeThread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-tiptap-floating-threads-thread\"\n />\n }\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n thread: ThreadData;\n editor: Editor;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n container,\n editor,\n thread,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n const el = editor.view.dom.querySelector(`[data-lb-thread-id=\"${thread.id}\"]`);\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, thread.id]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n editor.on(\"transaction\", updateRef)\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n return createPortal(\n <div\n ref={setFloating}\n {...props}\n style={{\n ...style,\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n"],"names":["DefaultThread","useEditorState","THREADS_PLUGIN_KEY","useState","useEffect","useCallback","jsx","useFloating","flip","offset","hide","shift","limitShift","size","autoUpdate","useLayoutEffect","createPortal","classNames"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FloatingThreads.js","sources":["../../src/comments/FloatingThreads.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata, DM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { classNames } from \"../classnames\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\n\n /**\n * The tiptap editor\n */\n editor: Editor | null;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n editor,\n ...props\n}: FloatingThreadsProps) {\n const Thread = components?.Thread ?? DefaultThread;\n\n const { pluginState } = useEditorState({\n editor,\n selector: (ctx) => {\n if (!ctx?.editor?.state) return { pluginState: undefined };\n const state = THREADS_PLUGIN_KEY.getState(ctx.editor.state);\n return {\n pluginState: state,\n };\n },\n equalityFn: (prev, next) => {\n if (!prev || !next) return false;\n return (\n prev.pluginState?.selectedThreadPos ===\n next.pluginState?.selectedThreadPos &&\n prev.pluginState?.selectedThreadId ===\n next.pluginState?.selectedThreadId\n );\n },\n }) ?? { pluginState: undefined };\n\n const [activeThread, setActiveThread] = useState<ThreadData | null>(null);\n\n useEffect(() => {\n if (!editor || !pluginState) {\n setActiveThread(null);\n return;\n }\n const { selectedThreadId, selectedThreadPos } = pluginState;\n if (selectedThreadId === null || selectedThreadPos === null) {\n setActiveThread(null);\n return;\n }\n const active = (threads ?? []).find(\n (thread) => selectedThreadId === thread.id\n );\n setActiveThread(active ?? null);\n }, [editor, pluginState, threads]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (!editor || activeThread === null) return false;\n editor.commands.selectThread(null);\n return true;\n }, [activeThread, editor]);\n\n if (!activeThread || !editor || activeThread.resolved) return null;\n\n return (\n <FloatingThreadPortal\n thread={activeThread}\n editor={editor}\n container={document.body}\n {...props}\n >\n {activeThread && (\n <ThreadWrapper\n key={activeThread.id}\n thread={activeThread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-tiptap-floating-threads-thread\"\n />\n )}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n thread: ThreadData;\n editor: Editor;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n container,\n editor,\n thread,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n const el = editor.view.dom.querySelector(\n `[data-lb-thread-id=\"${thread.id}\"]`\n );\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, thread.id]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n editor.on(\"transaction\", updateRef);\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n return createPortal(\n <div\n ref={setFloating}\n {...props}\n style={{\n ...style,\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n"],"names":["DefaultThread","useEditorState","THREADS_PLUGIN_KEY","useState","useEffect","useCallback","jsx","useFloating","flip","offset","hide","shift","limitShift","size","autoUpdate","useLayoutEffect","createPortal","classNames"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
3
|
+
import { useLayoutEffect } from '@liveblocks/react/_private';
|
|
3
4
|
import { Thread } from '@liveblocks/react-ui';
|
|
4
5
|
import { useEditorState } from '@tiptap/react';
|
|
5
|
-
import { useState, useEffect, useCallback
|
|
6
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
6
7
|
import { createPortal } from 'react-dom';
|
|
7
8
|
import { classNames } from '../classnames.mjs';
|
|
8
9
|
import { THREADS_PLUGIN_KEY } from '../types.mjs';
|
|
@@ -114,7 +115,9 @@ function FloatingThreadPortal({
|
|
|
114
115
|
}
|
|
115
116
|
});
|
|
116
117
|
const updateRef = useCallback(() => {
|
|
117
|
-
const el = editor.view.dom.querySelector(
|
|
118
|
+
const el = editor.view.dom.querySelector(
|
|
119
|
+
`[data-lb-thread-id="${thread.id}"]`
|
|
120
|
+
);
|
|
118
121
|
if (el) {
|
|
119
122
|
setReference(el);
|
|
120
123
|
}
|