"use client";
import { Button } from "@mdxui/primitives/button";
import { Card } from "@mdxui/primitives/card";
import { cn } from "@mdxui/primitives/lib/utils";
import { Toggle } from "@mdxui/primitives/toggle";
import Link from "@tiptap/extension-link";
import Placeholder from "@tiptap/extension-placeholder";
import Table from "@tiptap/extension-table";
import TableCell from "@tiptap/extension-table-cell";
import TableHeader from "@tiptap/extension-table-header";
import TableRow from "@tiptap/extension-table-row";
import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list";
import Underline from "@tiptap/extension-underline";
import { type Editor, EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import {
Bold,
CheckSquare,
Code,
Heading1,
Heading2,
Heading3,
Italic,
Link as LinkIcon,
List,
ListOrdered,
Minus,
Quote,
Redo,
Strikethrough,
Table as TableIcon,
Underline as UnderlineIcon,
Undo,
} from "lucide-react";
import type React from "react";
import { useCallback } from "react";
export interface WYSIWYGEditorProps {
/** Initial HTML content */
initialValue?: string;
/** Callback when content changes */
onChange?: (html: string, json: any) => void;
/** Placeholder text */
placeholder?: string;
/** Height of the editor */
height?: string | number;
/** Additional CSS class */
className?: string;
/** Whether the editor is read-only */
readOnly?: boolean;
/** Enable tables */
enableTables?: boolean;
/** Enable task lists */
enableTaskLists?: boolean;
/** Custom toolbar */
toolbar?: (editor: Editor) => React.ReactNode;
}
const MenuBar: React.FC<{ editor: Editor }> = ({ editor }) => {
const setLink = useCallback(() => {
const url = window.prompt("Enter URL");
if (url) {
editor.chain().focus().setLink({ href: url }).run();
}
}, [editor]);
return (
editor.chain().focus().toggleBold().run()}
aria-label="Bold"
>
editor.chain().focus().toggleItalic().run()}
aria-label="Italic"
>
editor.chain().focus().toggleUnderline().run()}
aria-label="Underline"
>
editor.chain().focus().toggleStrike().run()}
aria-label="Strikethrough"
>
editor.chain().focus().toggleCode().run()}
aria-label="Code"
>
editor.chain().focus().toggleHeading({ level: 1 }).run()
}
aria-label="Heading 1"
>
editor.chain().focus().toggleHeading({ level: 2 }).run()
}
aria-label="Heading 2"
>
editor.chain().focus().toggleHeading({ level: 3 }).run()
}
aria-label="Heading 3"
>
editor.chain().focus().toggleBulletList().run()}
aria-label="Bullet List"
>
editor.chain().focus().toggleOrderedList().run()}
aria-label="Ordered List"
>
editor.chain().focus().toggleTaskList().run()}
aria-label="Task List"
>
editor.chain().focus().toggleBlockquote().run()}
aria-label="Quote"
>
);
};
export const WYSIWYGEditor: React.FC = ({
initialValue = "",
onChange,
placeholder = "Start writing...",
height = 400,
className,
readOnly = false,
enableTables = true,
enableTaskLists = true,
toolbar,
}) => {
const editor = useEditor({
extensions: [
StarterKit,
Placeholder.configure({
placeholder,
}),
Link.configure({
openOnClick: false,
}),
Underline,
...(enableTables ? [Table, TableRow, TableCell, TableHeader] : []),
...(enableTaskLists
? [
TaskList,
TaskItem.configure({
nested: true,
}),
]
: []),
],
content: initialValue,
editable: !readOnly,
onUpdate: ({ editor }) => {
const html = editor.getHTML();
const json = editor.getJSON();
onChange?.(html, json);
},
});
if (!editor) {
return null;
}
return (
{toolbar ? toolbar(editor) : }
);
};