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:
@@ -14,23 +14,76 @@ import { Strike } from "@tiptap/extension-strike";
|
|||||||
import { Text } from "@tiptap/extension-text";
|
import { Text } from "@tiptap/extension-text";
|
||||||
import { Underline } from "@tiptap/extension-underline";
|
import { Underline } from "@tiptap/extension-underline";
|
||||||
import { Dropcursor, Gapcursor, UndoRedo } from "@tiptap/extensions";
|
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 { BubbleMenu, FloatingMenu } from "@tiptap/react/menus";
|
||||||
import { type ComponentProps, useEffect } from "react";
|
import { type ComponentProps, useEffect } from "react";
|
||||||
import { tv } from "tailwind-variants";
|
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 = [
|
const extensions = [
|
||||||
Document,
|
Document,
|
||||||
Paragraph,
|
Paragraph.configure({
|
||||||
Text,
|
HTMLAttributes: {
|
||||||
Heading.configure({ levels: [1, 2, 3] }),
|
class: "text-base py-2",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Text.configure({
|
||||||
|
HTMLAttributes: {
|
||||||
|
class: "text-base",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Heading.configure({
|
||||||
|
levels: [1, 2, 3],
|
||||||
|
}),
|
||||||
Bold,
|
Bold,
|
||||||
Italic,
|
Italic,
|
||||||
Strike,
|
Strike,
|
||||||
Underline,
|
Underline,
|
||||||
Code,
|
Code,
|
||||||
CodeBlock,
|
CodeBlock,
|
||||||
Link.configure({ openOnClick: false }),
|
ControlClickLink,
|
||||||
Blockquote,
|
Blockquote,
|
||||||
BulletList,
|
BulletList,
|
||||||
OrderedList,
|
OrderedList,
|
||||||
@@ -190,6 +243,11 @@ export function RichEditor(props: RichEditorProps) {
|
|||||||
active={editor.isActive("orderedList")}
|
active={editor.isActive("orderedList")}
|
||||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||||
/>
|
/>
|
||||||
|
<MenuButton
|
||||||
|
label="Code"
|
||||||
|
active={editor.isActive("code")}
|
||||||
|
onClick={() => editor.chain().focus().toggleCode().run()}
|
||||||
|
/>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
label="Code Block"
|
label="Code Block"
|
||||||
active={editor.isActive("codeBlock")}
|
active={editor.isActive("codeBlock")}
|
||||||
|
|||||||
@@ -281,4 +281,68 @@ button[data-cell]:focus-visible {
|
|||||||
.ProseMirror-focused {
|
.ProseMirror-focused {
|
||||||
outline-width: 0 !important;
|
outline-width: 0 !important;
|
||||||
outline-color: transparent !important;
|
outline-color: transparent !important;
|
||||||
|
outline-style: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap p { @apply py-2; }
|
||||||
|
|
||||||
|
.tiptap strong { @apply font-semibold; }
|
||||||
|
|
||||||
|
.tiptap h1 {
|
||||||
|
@apply text-4xl font-semibold pt-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap h2 {
|
||||||
|
@apply text-3xl font-semibold pt-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap h3 {
|
||||||
|
@apply text-2xl font-semibold pt-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap ul {
|
||||||
|
@apply list-disc list-inside py-2;
|
||||||
|
|
||||||
|
li {
|
||||||
|
p { @apply inline-block py-0 }
|
||||||
|
}
|
||||||
|
li::marker { @apply mx-2!; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap ol {
|
||||||
|
@apply list-decimal list-inside py-2;
|
||||||
|
|
||||||
|
li {
|
||||||
|
p { @apply inline-block py-0 }
|
||||||
|
}
|
||||||
|
li::marker { @apply mx-2!; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap a {
|
||||||
|
@apply text-txt-info underline font-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap.pointer-on-hovered-link {
|
||||||
|
a:hover { cursor: pointer; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap blockquote {
|
||||||
|
@apply py-2 pl-4 border-l-4 border-l-border-solid;
|
||||||
|
p { @apply py-0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap hr {
|
||||||
|
@apply my-4 border-t-border-solid border-t;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap pre {
|
||||||
|
@apply py-4 px-6 bg-border-solid rounded-lg text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap code {
|
||||||
|
@apply text-inherit font-mono bg-border-solid rounded-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tiptap p code {
|
||||||
|
@apply py-0.5 px-1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user