Skip to content

Commit 2d0afdd

Browse files
authored
fix(comments): always surface the closest mark to the current position (#2164)
1 parent 0d7e496 commit 2d0afdd

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

packages/core/src/extensions/Comments/CommentsPlugin.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { BlockNoteEditor } from "../../editor/BlockNoteEditor.js";
1212
import { BlockNoteExtension } from "../../editor/BlockNoteExtension.js";
1313
import { CustomBlockNoteSchema } from "../../schema/schema.js";
1414
import { UserStore } from "./userstore/UserStore.js";
15+
import { getMarkRange } from "@tiptap/core";
1516

1617
const PLUGIN_KEY = new PluginKey(`blocknote-comments`);
1718
const SET_SELECTED_THREAD_ID = "SET_SELECTED_THREAD_ID";
@@ -239,10 +240,39 @@ export class CommentsPlugin extends BlockNoteExtension {
239240
return;
240241
}
241242

242-
const commentMark = node.marks.find(
243-
(mark) =>
244-
mark.type.name === markType && mark.attrs.orphan !== true,
245-
);
243+
const markInSchema = view.state.schema.marks[markType];
244+
const resolvedPos = view.state.doc.resolve(pos);
245+
const commentMark = node.marks
246+
.filter(
247+
(mark) =>
248+
mark.type.name === markType && mark.attrs.orphan !== true,
249+
)
250+
.map((mark) => {
251+
// get the range of this mark within the document, to check how close it is to the click position
252+
const range = getMarkRange(
253+
resolvedPos,
254+
markInSchema,
255+
mark.attrs,
256+
)!;
257+
258+
return {
259+
mark,
260+
// calculate how far the mark is from the click position
261+
distance:
262+
(Math.abs(range.from - pos) + Math.abs(range.to - pos)) / 2,
263+
// calculate the length of text the mark spans
264+
length: range.to - range.from,
265+
};
266+
})
267+
// This allows us to not have comments which are unreachable because they are completely overlapped by other comments (issue #2073)
268+
.sort((a, b) => {
269+
// Find the mark which is closest to the click position
270+
if (a.distance !== b.distance) {
271+
return a.distance - b.distance;
272+
}
273+
// Otherwise, select the mark which spans the smallest amount of text (most likely to be unreachable)
274+
return a.length - b.length;
275+
})[0]?.mark;
246276

247277
const threadId = commentMark?.attrs.threadId as string | undefined;
248278
self.selectThread(threadId, false);

0 commit comments

Comments
 (0)