Add document node styling + extensions to handle clicking links with ctrl or cmd

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-03-18 16:16:10 +04:00
parent 6d18c7fce7
commit 21eb2e5197
2 changed files with 127 additions and 5 deletions

View File

@@ -14,23 +14,76 @@ import { Strike } from "@tiptap/extension-strike";
import { Text } from "@tiptap/extension-text";
import { Underline } from "@tiptap/extension-underline";
import { Dropcursor, Gapcursor, UndoRedo } from "@tiptap/extensions";
import { type Content, EditorContent, useEditor, useEditorState } from "@tiptap/react";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { type Content, EditorContent, getAttributes, useEditor, useEditorState } from "@tiptap/react";
import { BubbleMenu, FloatingMenu } from "@tiptap/react/menus";
import { type ComponentProps, useEffect } from "react";
import { tv } from "tailwind-variants";
export const ControlClickLink = Link.extend({
addProseMirrorPlugins: () => {
return [
new Plugin({
key: new PluginKey("handleControlClick"),
props: {
handleKeyDown: (view, event) => {
if (event.key === "Control" || event.key === "Meta") {
view.dom.classList.add("pointer-on-hovered-link");
}
},
handleDOMEvents: {
keyup: (view, event) => {
if (event.key === "Control" || event.key === "Meta") {
view.dom.classList.remove("pointer-on-hovered-link");
}
},
},
handleClick: (view, _, event) => {
const { ctrlKey, metaKey } = event; // Check for Ctrl (Windows) or Cmd (Mac)
const keyPressed = ctrlKey || metaKey;
if (keyPressed) {
// Get attributes of the mark at the clicked position
const attrs = getAttributes(view.state, "link");
const link = (event.target as Element | null)?.closest("a");
if (link && attrs.href) {
window.open(attrs.href as string, "_blank", "noopener,noreferrer"); // Open link in a new tab
return true; // Handle the event
}
}
return false; // Let other handlers run
},
},
}),
];
},
}).configure({
openOnClick: false,
});
const extensions = [
Document,
Paragraph,
Text,
Heading.configure({ levels: [1, 2, 3] }),
Paragraph.configure({
HTMLAttributes: {
class: "text-base py-2",
},
}),
Text.configure({
HTMLAttributes: {
class: "text-base",
},
}),
Heading.configure({
levels: [1, 2, 3],
}),
Bold,
Italic,
Strike,
Underline,
Code,
CodeBlock,
Link.configure({ openOnClick: false }),
ControlClickLink,
Blockquote,
BulletList,
OrderedList,
@@ -190,6 +243,11 @@ export function RichEditor(props: RichEditorProps) {
active={editor.isActive("orderedList")}
onClick={() => editor.chain().focus().toggleOrderedList().run()}
/>
<MenuButton
label="Code"
active={editor.isActive("code")}
onClick={() => editor.chain().focus().toggleCode().run()}
/>
<MenuButton
label="Code Block"
active={editor.isActive("codeBlock")}