"use client"; import { useEditor, EditorContent } from "@tiptap/react"; import { BubbleMenu } from "@tiptap/react/menus"; import StarterKit from "@tiptap/starter-kit"; import Underline from "@tiptap/extension-underline"; import Link from "@tiptap/extension-link"; import { useState } from "react"; import { Bold, Italic, Underline as UnderlineIcon, Strikethrough, Link as LinkIcon, Unlink } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; interface RichTextEditorProps { value: string; onChange: (value: string) => void; placeholder?: string; className?: string; } export function RichTextEditor({ value, onChange, placeholder, className }: RichTextEditorProps) { const [isLinkDialogOpen, setIsLinkDialogOpen] = useState(false); const [linkUrl, setLinkUrl] = useState(""); const [linkText, setLinkText] = useState(""); const editor = useEditor({ extensions: [ StarterKit, Underline, Link.configure({ openOnClick: false, HTMLAttributes: { class: "text-primary hover:underline underline-offset-4", target: "_blank", rel: "noopener noreferrer" }, }), ], content: value, onUpdate: ({ editor }) => { // Get HTML output. If empty, maybe output empty string to avoid empty p tags. let html = editor.getHTML(); if (html === "
") html = ""; onChange(html); }, editorProps: { attributes: { class: "prose prose-sm dark:prose-invert max-w-none focus:outline-none min-h-[40px] px-3 py-2", }, }, immediatelyRender: false, }); if (!editor) { return null; } const toggleLink = () => { const previousUrl = editor.getAttributes("link").href; if (previousUrl) { editor.chain().focus().unsetLink().run(); return; } const { from, to } = editor.state.selection; const selectedText = editor.state.doc.textBetween(from, to, ' '); setLinkText(selectedText || ""); setLinkUrl(""); setIsLinkDialogOpen(true); }; const saveLink = () => { if (linkUrl === "") { editor.chain().focus().extendMarkRange("link").unsetLink().run(); } else { if (linkText) { editor.chain().focus().insertContent(`${linkText}`).run(); } else { editor.chain().focus().extendMarkRange("link").setLink({ href: linkUrl }).run(); } } setIsLinkDialogOpen(false); setLinkUrl(""); setLinkText(""); }; const handleKeyDown = (e: React.KeyboardEvent