Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions packages/core/src/comments/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ export const CommentsExtension = createExtension(
return {
key: "comments",
store,
runsBefore: ["link"],
tiptapExtensions: [CommentMark],
prosemirrorPlugins: [
new Plugin<CommentsPluginState>({
key: PLUGIN_KEY,
Expand Down Expand Up @@ -224,7 +226,7 @@ export const CommentsExtension = createExtension(
},
handleClick: (view, pos, event) => {
if (event.button !== 0) {
return;
return false;
}

const node = view.state.doc.nodeAt(pos);
Expand All @@ -235,23 +237,41 @@ export const CommentsExtension = createExtension(
...prev,
selectedThreadId: undefined,
}));
return;
return false;
}

const commentMark = node.marks.find(
(mark) =>
mark.type.name === markType && mark.attrs.orphan !== true,
);

const threadId = commentMark?.attrs.threadId as
| string
| undefined;
if (threadId !== store.state.selectedThreadId) {
store.setState((prev) => ({
...prev,
selectedThreadId: threadId,
}));
if (!commentMark) {
// Clicked outside any comment thread. Deselect if needed but
// don't consume the event so other handlers (e.g. link
// navigation) can process it.
if (store.state.selectedThreadId !== undefined) {
store.setState((prev) => ({
...prev,
selectedThreadId: undefined,
}));
}
return false;
}

const threadId = commentMark.attrs.threadId as string;

// If the clicked thread is already selected, do nothing and let
// other handlers process the event (e.g. navigating a link).
if (threadId === store.state.selectedThreadId) {
return false;
}

store.setState((prev) => ({
...prev,
selectedThreadId: threadId,
}));

return true;
},
},
}),
Expand Down Expand Up @@ -356,7 +376,6 @@ export const CommentsExtension = createExtension(
},
userStore,
commentEditorSchema,
tiptapExtensions: [CommentMark],
} as const;
},
);
17 changes: 8 additions & 9 deletions packages/core/src/editor/managers/ExtensionManager/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Extension as TiptapExtension,
} from "@tiptap/core";
import { Gapcursor } from "@tiptap/extensions/gap-cursor";
import { Link } from "../../../extensions/tiptap-extensions/Link/link.js";
import { LinkExtension } from "../../../extensions/tiptap-extensions/Link/link.js";
import { Text } from "@tiptap/extension-text";
import { createDropFileExtension } from "../../../api/clipboard/fromClipboard/fileDropExtension.js";
import { createPasteFromClipboardExtension } from "../../../api/clipboard/fromClipboard/pasteExtension.js";
Expand Down Expand Up @@ -73,14 +73,6 @@ export function getDefaultTiptapExtensions(
SuggestionAddMark,
SuggestionDeleteMark,
SuggestionModificationMark,
Link.configure({
HTMLAttributes: options.links?.HTMLAttributes ?? {},
editor,
onClick: options.links?.onClick,
...(options.links?.isValidLink
? { isValidLink: options.links.isValidLink }
: {}),
}),
...(Object.values(editor.schema.styleSpecs).map((styleSpec) => {
return styleSpec.implementation.mark.configure({
editor: editor,
Expand Down Expand Up @@ -169,6 +161,13 @@ export function getDefaultExtensions(
DropCursorExtension(options),
FilePanelExtension(options),
FormattingToolbarExtension(options),
LinkExtension({
HTMLAttributes: options.links?.HTMLAttributes ?? {},
onClick: options.links?.onClick,
...(options.links?.isValidLink
? { isValidLink: options.links.isValidLink }
: {}),
}),
LinkToolbarExtension(options),
NodeSelectionKeyboardExtension(),
PlaceholderExtension(options),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Link } from "./link.js";
export { Link, LinkExtension } from "./link.js";
export { isAllowedUri } from "./link.js";
33 changes: 31 additions & 2 deletions packages/core/src/extensions/tiptap-extensions/Link/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { PasteRuleMatch } from "@tiptap/core";
import { Mark, markPasteRule, mergeAttributes } from "@tiptap/core";
import type { Plugin } from "@tiptap/pm/state";
import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor.js";
import { createExtension } from "../../../editor/BlockNoteExtension.js";
import { autolink } from "./helpers/autolink.js";
import { findLinks } from "./helpers/linkDetector.js";
import { clickHandler } from "./helpers/clickHandler.js";
Expand Down Expand Up @@ -67,8 +68,6 @@ export type LinkOptions = {
export const Link = Mark.create<LinkOptions>({
name: "link",

priority: 1000,

keepOnSplit: false,

exitable: true,
Expand Down Expand Up @@ -207,3 +206,33 @@ export const Link = Mark.create<LinkOptions>({
return plugins;
},
});

type LinkExtensionOptions = {
HTMLAttributes?: Record<string, any>;
onClick?: (
event: MouseEvent,
editor: BlockNoteEditor<any, any, any>,
) => boolean | void;
isValidLink?: (href: string) => boolean;
};

/**
* BlockNote extension wrapping the {@link Link} TipTap mark. Wrapping the mark
* lets other extensions order their click handlers relative to the link click
* handler via `runsBefore: ["link"]`.
*/
export const LinkExtension = createExtension<any, LinkExtensionOptions>(
({ editor, options }) => {
return {
key: "link",
tiptapExtensions: [
Link.configure({
HTMLAttributes: options.HTMLAttributes ?? {},
editor,
onClick: options.onClick,
...(options.isValidLink ? { isValidLink: options.isValidLink } : {}),
}),
],
} as const;
},
);
Loading
Loading