rte-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/RichEditor.tsx","../src/hooks/useEditor.ts","../src/extensions/FontSize.ts","../src/components/Toolbar.tsx","../src/components/toolbar/ToolbarButton.tsx","../src/components/toolbar/tools.ts"],"sourcesContent":["export { default as RichEditor } from './components/RichEditor';\nexport type { RichEditorProps, ToolbarTool, ToolbarButtonProps, ToolDefinition } from './types';\n","import React from 'react';\nimport { EditorContent } from '@tiptap/react';\nimport { RichEditorProps, ToolbarTool } from '../types';\nimport { useEditor } from '../hooks/useEditor';\nimport Toolbar from './Toolbar';\nimport '../styles/editor.css';\n\nconst DEFAULT_TOOLBAR: ToolbarTool[] = [\n 'bold', 'italic', 'underline', 'strikethrough', 'divider',\n 'heading1', 'heading2', 'heading3', 'divider',\n 'bulletList', 'orderedList', 'blockquote', 'codeBlock', 'divider',\n 'link', 'image', 'table', 'divider',\n 'undo', 'redo',\n];\n\nconst RichEditor: React.FC<RichEditorProps> = ({\n value = '',\n onChange,\n toolbar = DEFAULT_TOOLBAR,\n placeholder = 'Start typing...',\n editable = true,\n className,\n style,\n toolbarClassName,\n contentClassName,\n}) => {\n const editor = useEditor({ value, onChange, placeholder, editable, toolbar });\n\n if (!editor) return null;\n\n return (\n <div\n className={['rre-editor', className].filter(Boolean).join(' ')}\n style={style}\n >\n {editable && (\n <Toolbar editor={editor} toolbar={toolbar} className={toolbarClassName} />\n )}\n <EditorContent\n editor={editor}\n className={['rre-content', contentClassName].filter(Boolean).join(' ')}\n />\n </div>\n );\n};\n\nexport default RichEditor;\n","import { useEffect } from 'react';\nimport { useEditor as useTiptapEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Underline from '@tiptap/extension-underline';\nimport TextStyle from '@tiptap/extension-text-style';\nimport Link from '@tiptap/extension-link';\nimport Image from '@tiptap/extension-image';\nimport Table from '@tiptap/extension-table';\nimport TableRow from '@tiptap/extension-table-row';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport FontSize from '../extensions/FontSize';\nimport { ToolbarTool } from '../types';\n\ninterface UseEditorOptions {\n value?: string;\n onChange?: (html: string) => void;\n placeholder?: string;\n editable?: boolean;\n toolbar?: ToolbarTool[];\n}\n\nexport const useEditor = ({\n value = '',\n onChange,\n placeholder = 'Start typing...',\n editable = true,\n}: UseEditorOptions) => {\n const editor = useTiptapEditor({\n extensions: [\n StarterKit,\n Underline,\n TextStyle,\n FontSize,\n Link.configure({ openOnClick: false }),\n Image,\n Table.configure({ resizable: true }),\n TableRow,\n TableCell,\n TableHeader,\n Placeholder.configure({ placeholder }),\n ],\n content: value,\n editable,\n onUpdate({ editor }) {\n onChange?.(editor.getHTML());\n },\n });\n\n useEffect(() => {\n if (editor && value !== editor.getHTML()) {\n editor.commands.setContent(value, false);\n }\n }, [value, editor]);\n\n useEffect(() => {\n if (editor) {\n editor.setEditable(editable ?? true);\n }\n }, [editable, editor]);\n\n return editor;\n};","import { Extension } from '@tiptap/core';\nimport '@tiptap/extension-text-style';\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n fontSize: {\n setFontSize: (size: string) => ReturnType;\n unsetFontSize: () => ReturnType;\n };\n }\n}\n\nconst FontSize = Extension.create({\n name: 'fontSize',\n\n addOptions() {\n return {\n types: ['textStyle'],\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n fontSize: {\n default: null,\n parseHTML: (element) => element.style.fontSize || null,\n renderHTML: (attributes) => {\n if (!attributes.fontSize) return {};\n return { style: `font-size: ${attributes.fontSize}` };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setFontSize:\n (fontSize: string) =>\n ({ chain }) => {\n return chain().setMark('textStyle', { fontSize }).run();\n },\n unsetFontSize:\n () =>\n ({ chain }) => {\n return chain().setMark('textStyle', { fontSize: null }).removeEmptyTextStyle().run();\n },\n };\n },\n});\n\nexport default FontSize;","import React, { useState, useRef, useEffect } from 'react';\nimport { Editor } from '@tiptap/react';\nimport { ToolbarTool } from '../types';\nimport ToolbarButton from './toolbar/ToolbarButton';\nimport { getToolDefinition } from './toolbar/tools';\n\nconst FONT_SIZES = ['12', '14', '16', '18', '20', '24', '28', '32', '36', '48'];\nconst MAX_IMAGE_SIZE = 10 * 1024 * 1024; // 10MB\n\ninterface ToolbarProps {\n editor: Editor;\n toolbar: ToolbarTool[];\n className?: string;\n}\n\ntype PopupType = 'link' | 'table' | null;\n\nconst Toolbar: React.FC<ToolbarProps> = ({ editor, toolbar, className }) => {\n const [popup, setPopup] = useState<PopupType>(null);\n const [linkUrl, setLinkUrl] = useState('');\n const [linkText, setLinkText] = useState('');\n const [tableRows, setTableRows] = useState('3');\n const [tableCols, setTableCols] = useState('3');\n const popupRef = useRef<HTMLDivElement>(null);\n const imageInputRef = useRef<HTMLInputElement>(null);\n\n const hasSelection = !editor.state.selection.empty;\n const currentFontSize = editor.getAttributes('textStyle').fontSize?.replace('px', '') || '16';\n\n // Close popup when clicking outside\n useEffect(() => {\n const handleClickOutside = (e: MouseEvent) => {\n if (popupRef.current && !popupRef.current.contains(e.target as Node)) {\n setPopup(null);\n }\n };\n if (popup) document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [popup]);\n\n const handleFontSize = (size: string) => {\n editor.chain().focus().setFontSize(`${size}px`).run();\n };\n\n const handleLinkOpen = () => {\n setLinkUrl(editor.getAttributes('link').href || '');\n setLinkText('');\n setPopup(popup === 'link' ? null : 'link');\n };\n\n const handleLinkSave = () => {\n if (!linkUrl) return;\n if (hasSelection) {\n editor.chain().focus().setLink({ href: linkUrl }).run();\n } else {\n if (!linkText) return;\n editor\n .chain()\n .focus()\n .insertContent(`<a href=\"${linkUrl}\">${linkText}</a>`)\n .run();\n }\n setLinkUrl('');\n setLinkText('');\n setPopup(null);\n };\n\n const handleLinkKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') handleLinkSave();\n if (e.key === 'Escape') setPopup(null);\n };\n\n const handleImageClick = () => {\n imageInputRef.current?.click();\n };\n\n const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n if (file.size > MAX_IMAGE_SIZE) {\n alert('Image is too large. Maximum size is 10MB.');\n return;\n }\n\n const reader = new FileReader();\n reader.onload = () => {\n const base64 = reader.result as string;\n editor.chain().focus().setImage({ src: base64 }).run();\n };\n reader.readAsDataURL(file);\n // Reset input so same file can be picked again\n e.target.value = '';\n };\n\n const handleTableOpen = () => {\n setPopup(popup === 'table' ? null : 'table');\n };\n\n const handleTableInsert = () => {\n const rows = Math.min(10, Math.max(1, parseInt(tableRows) || 3));\n const cols = Math.min(10, Math.max(1, parseInt(tableCols) || 3));\n editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();\n setPopup(null);\n };\n\n const handleTableKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') handleTableInsert();\n if (e.key === 'Escape') setPopup(null);\n };\n\n const handleTool = (tool: ToolbarTool) => {\n switch (tool) {\n case 'bold': editor.chain().focus().toggleBold().run(); break;\n case 'italic': editor.chain().focus().toggleItalic().run(); break;\n case 'underline': editor.chain().focus().toggleUnderline().run(); break;\n case 'strikethrough': editor.chain().focus().toggleStrike().run(); break;\n case 'heading1': editor.chain().focus().toggleHeading({ level: 1 }).run(); break;\n case 'heading2': editor.chain().focus().toggleHeading({ level: 2 }).run(); break;\n case 'heading3': editor.chain().focus().toggleHeading({ level: 3 }).run(); break;\n case 'heading4': editor.chain().focus().toggleHeading({ level: 4 }).run(); break;\n case 'heading5': editor.chain().focus().toggleHeading({ level: 5 }).run(); break;\n case 'heading6': editor.chain().focus().toggleHeading({ level: 6 }).run(); break;\n case 'bulletList': editor.chain().focus().toggleBulletList().run(); break;\n case 'orderedList': editor.chain().focus().toggleOrderedList().run(); break;\n case 'blockquote': editor.chain().focus().toggleBlockquote().run(); break;\n case 'codeBlock': editor.chain().focus().toggleCodeBlock().run(); break;\n case 'undo': editor.chain().focus().undo().run(); break;\n case 'redo': editor.chain().focus().redo().run(); break;\n }\n };\n\n const isActive = (tool: ToolbarTool): boolean => {\n switch (tool) {\n case 'bold': return editor.isActive('bold');\n case 'italic': return editor.isActive('italic');\n case 'underline': return editor.isActive('underline');\n case 'strikethrough': return editor.isActive('strike');\n case 'heading1': return editor.isActive('heading', { level: 1 });\n case 'heading2': return editor.isActive('heading', { level: 2 });\n case 'heading3': return editor.isActive('heading', { level: 3 });\n case 'heading4': return editor.isActive('heading', { level: 4 });\n case 'heading5': return editor.isActive('heading', { level: 5 });\n case 'heading6': return editor.isActive('heading', { level: 6 });\n case 'bulletList': return editor.isActive('bulletList');\n case 'orderedList': return editor.isActive('orderedList');\n case 'blockquote': return editor.isActive('blockquote');\n case 'codeBlock': return editor.isActive('codeBlock');\n case 'link': return editor.isActive('link');\n default: return false;\n }\n };\n\n const isDisabled = (tool: ToolbarTool): boolean => {\n if (tool === 'undo') return !editor.can().undo();\n if (tool === 'redo') return !editor.can().redo();\n return false;\n };\n\n const renderPopup = (tool: ToolbarTool) => {\n if (tool === 'link' && popup === 'link') {\n return (\n <div className=\"rre-popup\" ref={popupRef}>\n <input\n className=\"rre-popup-input\"\n type=\"url\"\n placeholder=\"https://example.com\"\n value={linkUrl}\n onChange={(e) => setLinkUrl(e.target.value)}\n onKeyDown={handleLinkKeyDown}\n autoFocus\n />\n {!hasSelection && (\n <input\n className=\"rre-popup-input\"\n type=\"text\"\n placeholder=\"Display text\"\n value={linkText}\n onChange={(e) => setLinkText(e.target.value)}\n onKeyDown={handleLinkKeyDown}\n />\n )}\n <button\n className=\"rre-popup-btn\"\n onMouseDown={(e) => { e.preventDefault(); handleLinkSave(); }}\n >\n Save\n </button>\n </div>\n );\n }\n\n if (tool === 'table' && popup === 'table') {\n return (\n <div className=\"rre-popup rre-popup--table\" ref={popupRef}>\n <input\n className=\"rre-popup-input rre-popup-input--num\"\n type=\"number\"\n min=\"1\"\n max=\"10\"\n value={tableRows}\n onChange={(e) => setTableRows(e.target.value)}\n onKeyDown={handleTableKeyDown}\n autoFocus\n />\n <span className=\"rre-popup-x\">×</span>\n <input\n className=\"rre-popup-input rre-popup-input--num\"\n type=\"number\"\n min=\"1\"\n max=\"10\"\n value={tableCols}\n onChange={(e) => setTableCols(e.target.value)}\n onKeyDown={handleTableKeyDown}\n />\n <button\n className=\"rre-popup-btn\"\n onMouseDown={(e) => { e.preventDefault(); handleTableInsert(); }}\n >\n Insert\n </button>\n </div>\n );\n }\n\n return null;\n };\n\n return (\n <div className={['rre-toolbar', className].filter(Boolean).join(' ')} role=\"toolbar\">\n {/* Hidden file input for image */}\n <input\n ref={imageInputRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={handleImageChange}\n />\n\n {toolbar.map((tool, i) => {\n if (tool === 'divider') {\n return <div key={`divider-${i}`} className=\"rre-toolbar-divider\" aria-hidden=\"true\" />;\n }\n\n if (tool === 'fontSize') {\n return (\n <select\n key=\"fontSize\"\n className=\"rre-fontsize-select\"\n value={currentFontSize}\n onChange={(e) => handleFontSize(e.target.value)}\n title=\"Font size\"\n >\n {FONT_SIZES.map((size) => (\n <option key={size} value={size}>{size}px</option>\n ))}\n </select>\n );\n }\n\n if (tool === 'link') {\n const def = getToolDefinition(tool);\n if (!def) return null;\n return (\n <div key=\"link\" className=\"rre-toolbar-popup-wrapper\" onMouseDown={(e) => e.stopPropagation()}> \n <ToolbarButton\n onClick={handleLinkOpen}\n isActive={editor.isActive('link') || popup === 'link'}\n title={def.title}\n >\n <span className=\"rre-icon\" dangerouslySetInnerHTML={{ __html: def.icon }} />\n </ToolbarButton>\n {renderPopup('link')}\n </div>\n );\n }\n\n if (tool === 'image') {\n const def = getToolDefinition(tool);\n if (!def) return null;\n return (\n <ToolbarButton\n key=\"image\"\n onClick={handleImageClick}\n title={def.title}\n >\n <span className=\"rre-icon\" dangerouslySetInnerHTML={{ __html: def.icon }} />\n </ToolbarButton>\n );\n }\n\n if (tool === 'table') {\n const def = getToolDefinition(tool);\n if (!def) return null;\n return (\n<div key=\"table\" className=\"rre-toolbar-popup-wrapper\" onMouseDown={(e) => e.stopPropagation()}>\n <ToolbarButton\n onClick={handleTableOpen}\n isActive={popup === 'table'}\n title={def.title}\n >\n <span className=\"rre-icon\" dangerouslySetInnerHTML={{ __html: def.icon }} />\n </ToolbarButton>\n {renderPopup('table')}\n </div>\n );\n }\n\n const def = getToolDefinition(tool);\n if (!def) return null;\n return (\n <ToolbarButton\n key={tool}\n onClick={() => handleTool(tool)}\n isActive={isActive(tool)}\n disabled={isDisabled(tool)}\n title={def.title}\n >\n <span className=\"rre-icon\" dangerouslySetInnerHTML={{ __html: def.icon }} />\n </ToolbarButton>\n );\n })}\n </div>\n );\n};\n\nexport default Toolbar;","import React from 'react';\nimport { ToolbarButtonProps } from '../../types';\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n onClick,\n isActive = false,\n disabled = false,\n title,\n children,\n}) => {\n return (\n <button\n type=\"button\"\n onMouseDown={(e) => {\n e.preventDefault();\n onClick();\n }}\n disabled={disabled}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n className={[\n 'rre-toolbar-btn',\n isActive ? 'rre-toolbar-btn--active' : '',\n disabled ? 'rre-toolbar-btn--disabled' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {children}\n </button>\n );\n};\n\nexport default ToolbarButton;\n","import { ToolDefinition } from '../../types';\n\nexport const toolDefinitions: ToolDefinition[] = [\n { name: 'bold', title: 'Bold', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/><path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\"/></svg>' },\n { name: 'italic', title: 'Italic', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"/><line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"/><line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"/></svg>' },\n { name: 'underline', title: 'Underline', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3\"/><line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"/></svg>' },\n { name: 'strikethrough', title: 'Strikethrough', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M17.3 4.9c-2.3-.6-4.4-1-6.2-.9-2.7 0-5.3.7-5.3 3.6 0 1.5 1.8 3.3 6.5 3.9h.1\"/><path d=\"M21.8 12H2.2\"/><path d=\"M6.7 19.1c2.3.6 4.4 1 6.2.9 2.7 0 5.3-.7 5.3-3.6 0-1.5-1.8-3.3-6.5-3.9H11\"/></svg>' },\n { name: 'heading1', title: 'Heading 1', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><path d=\"m17 12 3-2v8\"/></svg>' },\n { name: 'heading2', title: 'Heading 2', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><path d=\"M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1\"/></svg>' },\n { name: 'heading3', title: 'Heading 3', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><path d=\"M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2\"/><path d=\"M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2\"/></svg>' },\n { name: 'heading4', title: 'Heading 4', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><path d=\"M17 10v4h4\"/><path d=\"M21 10v8\"/></svg>' },\n { name: 'heading5', title: 'Heading 5', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><path d=\"M17 10h3\"/><path d=\"M17 14h2a2 2 0 0 1 0 4h-2v-4z\"/><path d=\"M17 10v4\"/></svg>' },\n { name: 'heading6', title: 'Heading 6', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M4 12h8\"/><path d=\"M4 18V6\"/><path d=\"M12 18V6\"/><circle cx=\"19\" cy=\"16\" r=\"2\"/><path d=\"M20 10c-2 2-3 3.5-3 6\"/></svg>' },\n { name: 'bulletList', title: 'Bullet List', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"8\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"8\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"8\" y1=\"18\" x2=\"21\" y2=\"18\"/><line x1=\"3\" y1=\"6\" x2=\"3.01\" y2=\"6\"/><line x1=\"3\" y1=\"12\" x2=\"3.01\" y2=\"12\"/><line x1=\"3\" y1=\"18\" x2=\"3.01\" y2=\"18\"/></svg>' },\n { name: 'orderedList', title: 'Ordered List', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"10\" y1=\"6\" x2=\"21\" y2=\"6\"/><line x1=\"10\" y1=\"12\" x2=\"21\" y2=\"12\"/><line x1=\"10\" y1=\"18\" x2=\"21\" y2=\"18\"/><path d=\"M4 6h1v4\"/><path d=\"M4 10h2\"/><path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1\"/></svg>' },\n { name: 'blockquote', title: 'Blockquote', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z\"/><path d=\"M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z\"/></svg>' },\n { name: 'codeBlock', title: 'Code Block', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"16 18 22 12 16 6\"/><polyline points=\"8 6 2 12 8 18\"/></svg>' },\n { name: 'link', title: 'Link', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/></svg>' },\n { name: 'image', title: 'Image', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/></svg>' },\n { name: 'table', title: 'Table', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"/><line x1=\"3\" y1=\"15\" x2=\"21\" y2=\"15\"/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"/></svg>' },\n { name: 'undo', title: 'Undo', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M3 7v6h6\"/><path d=\"M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13\"/></svg>' },\n { name: 'redo', title: 'Redo', icon: '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><path d=\"M21 7v6h-6\"/><path d=\"M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13\"/></svg>' },\n];\n\nexport const getToolDefinition = (name: string): ToolDefinition | undefined =>\n toolDefinitions.find((t) => t.name === name);\n"],"mappings":"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","names":["import_react","import_react","import_extension_text_style","useTiptapEditor","StarterKit","Underline","TextStyle","Link","Image","Table","TableRow","TableCell","TableHeader","Placeholder","editor","import_react","import_jsx_runtime","_a","def","import_jsx_runtime"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,567 @@
1
+ // src/components/RichEditor.tsx
2
+ import { EditorContent } from "@tiptap/react";
3
+
4
+ // src/hooks/useEditor.ts
5
+ import { useEffect } from "react";
6
+ import { useEditor as useTiptapEditor } from "@tiptap/react";
7
+ import StarterKit from "@tiptap/starter-kit";
8
+ import Underline from "@tiptap/extension-underline";
9
+ import TextStyle from "@tiptap/extension-text-style";
10
+ import Link from "@tiptap/extension-link";
11
+ import Image from "@tiptap/extension-image";
12
+ import Table from "@tiptap/extension-table";
13
+ import TableRow from "@tiptap/extension-table-row";
14
+ import TableCell from "@tiptap/extension-table-cell";
15
+ import TableHeader from "@tiptap/extension-table-header";
16
+ import Placeholder from "@tiptap/extension-placeholder";
17
+
18
+ // src/extensions/FontSize.ts
19
+ import { Extension } from "@tiptap/core";
20
+ import "@tiptap/extension-text-style";
21
+ var FontSize = Extension.create({
22
+ name: "fontSize",
23
+ addOptions() {
24
+ return {
25
+ types: ["textStyle"]
26
+ };
27
+ },
28
+ addGlobalAttributes() {
29
+ return [
30
+ {
31
+ types: this.options.types,
32
+ attributes: {
33
+ fontSize: {
34
+ default: null,
35
+ parseHTML: (element) => element.style.fontSize || null,
36
+ renderHTML: (attributes) => {
37
+ if (!attributes.fontSize) return {};
38
+ return { style: `font-size: ${attributes.fontSize}` };
39
+ }
40
+ }
41
+ }
42
+ }
43
+ ];
44
+ },
45
+ addCommands() {
46
+ return {
47
+ setFontSize: (fontSize) => ({ chain }) => {
48
+ return chain().setMark("textStyle", { fontSize }).run();
49
+ },
50
+ unsetFontSize: () => ({ chain }) => {
51
+ return chain().setMark("textStyle", { fontSize: null }).removeEmptyTextStyle().run();
52
+ }
53
+ };
54
+ }
55
+ });
56
+ var FontSize_default = FontSize;
57
+
58
+ // src/hooks/useEditor.ts
59
+ var useEditor = ({
60
+ value = "",
61
+ onChange,
62
+ placeholder = "Start typing...",
63
+ editable = true
64
+ }) => {
65
+ const editor = useTiptapEditor({
66
+ extensions: [
67
+ StarterKit,
68
+ Underline,
69
+ TextStyle,
70
+ FontSize_default,
71
+ Link.configure({ openOnClick: false }),
72
+ Image,
73
+ Table.configure({ resizable: true }),
74
+ TableRow,
75
+ TableCell,
76
+ TableHeader,
77
+ Placeholder.configure({ placeholder })
78
+ ],
79
+ content: value,
80
+ editable,
81
+ onUpdate({ editor: editor2 }) {
82
+ onChange == null ? void 0 : onChange(editor2.getHTML());
83
+ }
84
+ });
85
+ useEffect(() => {
86
+ if (editor && value !== editor.getHTML()) {
87
+ editor.commands.setContent(value, false);
88
+ }
89
+ }, [value, editor]);
90
+ useEffect(() => {
91
+ if (editor) {
92
+ editor.setEditable(editable != null ? editable : true);
93
+ }
94
+ }, [editable, editor]);
95
+ return editor;
96
+ };
97
+
98
+ // src/components/Toolbar.tsx
99
+ import { useState, useRef, useEffect as useEffect2 } from "react";
100
+
101
+ // src/components/toolbar/ToolbarButton.tsx
102
+ import { jsx } from "react/jsx-runtime";
103
+ var ToolbarButton = ({
104
+ onClick,
105
+ isActive = false,
106
+ disabled = false,
107
+ title,
108
+ children
109
+ }) => {
110
+ return /* @__PURE__ */ jsx(
111
+ "button",
112
+ {
113
+ type: "button",
114
+ onMouseDown: (e) => {
115
+ e.preventDefault();
116
+ onClick();
117
+ },
118
+ disabled,
119
+ title,
120
+ "aria-label": title,
121
+ "aria-pressed": isActive,
122
+ className: [
123
+ "rre-toolbar-btn",
124
+ isActive ? "rre-toolbar-btn--active" : "",
125
+ disabled ? "rre-toolbar-btn--disabled" : ""
126
+ ].filter(Boolean).join(" "),
127
+ children
128
+ }
129
+ );
130
+ };
131
+ var ToolbarButton_default = ToolbarButton;
132
+
133
+ // src/components/toolbar/tools.ts
134
+ var toolDefinitions = [
135
+ { name: "bold", title: "Bold", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"/></svg>' },
136
+ { name: "italic", title: "Italic", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="19" y1="4" x2="10" y2="4"/><line x1="14" y1="20" x2="5" y2="20"/><line x1="15" y1="4" x2="9" y2="20"/></svg>' },
137
+ { name: "underline", title: "Underline", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M6 3v7a6 6 0 0 0 6 6 6 6 0 0 0 6-6V3"/><line x1="4" y1="21" x2="20" y2="21"/></svg>' },
138
+ { name: "strikethrough", title: "Strikethrough", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M17.3 4.9c-2.3-.6-4.4-1-6.2-.9-2.7 0-5.3.7-5.3 3.6 0 1.5 1.8 3.3 6.5 3.9h.1"/><path d="M21.8 12H2.2"/><path d="M6.7 19.1c2.3.6 4.4 1 6.2.9 2.7 0 5.3-.7 5.3-3.6 0-1.5-1.8-3.3-6.5-3.9H11"/></svg>' },
139
+ { name: "heading1", title: "Heading 1", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="m17 12 3-2v8"/></svg>' },
140
+ { name: "heading2", title: "Heading 2", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1"/></svg>' },
141
+ { name: "heading3", title: "Heading 3", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2"/><path d="M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2"/></svg>' },
142
+ { name: "heading4", title: "Heading 4", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17 10v4h4"/><path d="M21 10v8"/></svg>' },
143
+ { name: "heading5", title: "Heading 5", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><path d="M17 10h3"/><path d="M17 14h2a2 2 0 0 1 0 4h-2v-4z"/><path d="M17 10v4"/></svg>' },
144
+ { name: "heading6", title: "Heading 6", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M4 12h8"/><path d="M4 18V6"/><path d="M12 18V6"/><circle cx="19" cy="16" r="2"/><path d="M20 10c-2 2-3 3.5-3 6"/></svg>' },
145
+ { name: "bulletList", title: "Bullet List", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>' },
146
+ { name: "orderedList", title: "Ordered List", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/></svg>' },
147
+ { name: "blockquote", title: "Blockquote", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M3 21c3 0 7-1 7-8V5c0-1.25-.756-2.017-2-2H4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 .008-1 1.031V20c0 1 0 1 1 1z"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.757-2.017-2-2h-4c-1.25 0-2 .75-2 1.972V11c0 1.25.75 2 2 2h.75c0 2.25.25 4-2.75 4v3c0 1 0 1 1 1z"/></svg>' },
148
+ { name: "codeBlock", title: "Code Block", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>' },
149
+ { name: "link", title: "Link", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>' },
150
+ { name: "image", title: "Image", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>' },
151
+ { name: "table", title: "Table", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>' },
152
+ { name: "undo", title: "Undo", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M3 7v6h6"/><path d="M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13"/></svg>' },
153
+ { name: "redo", title: "Redo", icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M21 7v6h-6"/><path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3L21 13"/></svg>' }
154
+ ];
155
+ var getToolDefinition = (name) => toolDefinitions.find((t) => t.name === name);
156
+
157
+ // src/components/Toolbar.tsx
158
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
159
+ var FONT_SIZES = ["12", "14", "16", "18", "20", "24", "28", "32", "36", "48"];
160
+ var MAX_IMAGE_SIZE = 10 * 1024 * 1024;
161
+ var Toolbar = ({ editor, toolbar, className }) => {
162
+ var _a;
163
+ const [popup, setPopup] = useState(null);
164
+ const [linkUrl, setLinkUrl] = useState("");
165
+ const [linkText, setLinkText] = useState("");
166
+ const [tableRows, setTableRows] = useState("3");
167
+ const [tableCols, setTableCols] = useState("3");
168
+ const popupRef = useRef(null);
169
+ const imageInputRef = useRef(null);
170
+ const hasSelection = !editor.state.selection.empty;
171
+ const currentFontSize = ((_a = editor.getAttributes("textStyle").fontSize) == null ? void 0 : _a.replace("px", "")) || "16";
172
+ useEffect2(() => {
173
+ const handleClickOutside = (e) => {
174
+ if (popupRef.current && !popupRef.current.contains(e.target)) {
175
+ setPopup(null);
176
+ }
177
+ };
178
+ if (popup) document.addEventListener("mousedown", handleClickOutside);
179
+ return () => document.removeEventListener("mousedown", handleClickOutside);
180
+ }, [popup]);
181
+ const handleFontSize = (size) => {
182
+ editor.chain().focus().setFontSize(`${size}px`).run();
183
+ };
184
+ const handleLinkOpen = () => {
185
+ setLinkUrl(editor.getAttributes("link").href || "");
186
+ setLinkText("");
187
+ setPopup(popup === "link" ? null : "link");
188
+ };
189
+ const handleLinkSave = () => {
190
+ if (!linkUrl) return;
191
+ if (hasSelection) {
192
+ editor.chain().focus().setLink({ href: linkUrl }).run();
193
+ } else {
194
+ if (!linkText) return;
195
+ editor.chain().focus().insertContent(`<a href="${linkUrl}">${linkText}</a>`).run();
196
+ }
197
+ setLinkUrl("");
198
+ setLinkText("");
199
+ setPopup(null);
200
+ };
201
+ const handleLinkKeyDown = (e) => {
202
+ if (e.key === "Enter") handleLinkSave();
203
+ if (e.key === "Escape") setPopup(null);
204
+ };
205
+ const handleImageClick = () => {
206
+ var _a2;
207
+ (_a2 = imageInputRef.current) == null ? void 0 : _a2.click();
208
+ };
209
+ const handleImageChange = (e) => {
210
+ var _a2;
211
+ const file = (_a2 = e.target.files) == null ? void 0 : _a2[0];
212
+ if (!file) return;
213
+ if (file.size > MAX_IMAGE_SIZE) {
214
+ alert("Image is too large. Maximum size is 10MB.");
215
+ return;
216
+ }
217
+ const reader = new FileReader();
218
+ reader.onload = () => {
219
+ const base64 = reader.result;
220
+ editor.chain().focus().setImage({ src: base64 }).run();
221
+ };
222
+ reader.readAsDataURL(file);
223
+ e.target.value = "";
224
+ };
225
+ const handleTableOpen = () => {
226
+ setPopup(popup === "table" ? null : "table");
227
+ };
228
+ const handleTableInsert = () => {
229
+ const rows = Math.min(10, Math.max(1, parseInt(tableRows) || 3));
230
+ const cols = Math.min(10, Math.max(1, parseInt(tableCols) || 3));
231
+ editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
232
+ setPopup(null);
233
+ };
234
+ const handleTableKeyDown = (e) => {
235
+ if (e.key === "Enter") handleTableInsert();
236
+ if (e.key === "Escape") setPopup(null);
237
+ };
238
+ const handleTool = (tool) => {
239
+ switch (tool) {
240
+ case "bold":
241
+ editor.chain().focus().toggleBold().run();
242
+ break;
243
+ case "italic":
244
+ editor.chain().focus().toggleItalic().run();
245
+ break;
246
+ case "underline":
247
+ editor.chain().focus().toggleUnderline().run();
248
+ break;
249
+ case "strikethrough":
250
+ editor.chain().focus().toggleStrike().run();
251
+ break;
252
+ case "heading1":
253
+ editor.chain().focus().toggleHeading({ level: 1 }).run();
254
+ break;
255
+ case "heading2":
256
+ editor.chain().focus().toggleHeading({ level: 2 }).run();
257
+ break;
258
+ case "heading3":
259
+ editor.chain().focus().toggleHeading({ level: 3 }).run();
260
+ break;
261
+ case "heading4":
262
+ editor.chain().focus().toggleHeading({ level: 4 }).run();
263
+ break;
264
+ case "heading5":
265
+ editor.chain().focus().toggleHeading({ level: 5 }).run();
266
+ break;
267
+ case "heading6":
268
+ editor.chain().focus().toggleHeading({ level: 6 }).run();
269
+ break;
270
+ case "bulletList":
271
+ editor.chain().focus().toggleBulletList().run();
272
+ break;
273
+ case "orderedList":
274
+ editor.chain().focus().toggleOrderedList().run();
275
+ break;
276
+ case "blockquote":
277
+ editor.chain().focus().toggleBlockquote().run();
278
+ break;
279
+ case "codeBlock":
280
+ editor.chain().focus().toggleCodeBlock().run();
281
+ break;
282
+ case "undo":
283
+ editor.chain().focus().undo().run();
284
+ break;
285
+ case "redo":
286
+ editor.chain().focus().redo().run();
287
+ break;
288
+ }
289
+ };
290
+ const isActive = (tool) => {
291
+ switch (tool) {
292
+ case "bold":
293
+ return editor.isActive("bold");
294
+ case "italic":
295
+ return editor.isActive("italic");
296
+ case "underline":
297
+ return editor.isActive("underline");
298
+ case "strikethrough":
299
+ return editor.isActive("strike");
300
+ case "heading1":
301
+ return editor.isActive("heading", { level: 1 });
302
+ case "heading2":
303
+ return editor.isActive("heading", { level: 2 });
304
+ case "heading3":
305
+ return editor.isActive("heading", { level: 3 });
306
+ case "heading4":
307
+ return editor.isActive("heading", { level: 4 });
308
+ case "heading5":
309
+ return editor.isActive("heading", { level: 5 });
310
+ case "heading6":
311
+ return editor.isActive("heading", { level: 6 });
312
+ case "bulletList":
313
+ return editor.isActive("bulletList");
314
+ case "orderedList":
315
+ return editor.isActive("orderedList");
316
+ case "blockquote":
317
+ return editor.isActive("blockquote");
318
+ case "codeBlock":
319
+ return editor.isActive("codeBlock");
320
+ case "link":
321
+ return editor.isActive("link");
322
+ default:
323
+ return false;
324
+ }
325
+ };
326
+ const isDisabled = (tool) => {
327
+ if (tool === "undo") return !editor.can().undo();
328
+ if (tool === "redo") return !editor.can().redo();
329
+ return false;
330
+ };
331
+ const renderPopup = (tool) => {
332
+ if (tool === "link" && popup === "link") {
333
+ return /* @__PURE__ */ jsxs("div", { className: "rre-popup", ref: popupRef, children: [
334
+ /* @__PURE__ */ jsx2(
335
+ "input",
336
+ {
337
+ className: "rre-popup-input",
338
+ type: "url",
339
+ placeholder: "https://example.com",
340
+ value: linkUrl,
341
+ onChange: (e) => setLinkUrl(e.target.value),
342
+ onKeyDown: handleLinkKeyDown,
343
+ autoFocus: true
344
+ }
345
+ ),
346
+ !hasSelection && /* @__PURE__ */ jsx2(
347
+ "input",
348
+ {
349
+ className: "rre-popup-input",
350
+ type: "text",
351
+ placeholder: "Display text",
352
+ value: linkText,
353
+ onChange: (e) => setLinkText(e.target.value),
354
+ onKeyDown: handleLinkKeyDown
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsx2(
358
+ "button",
359
+ {
360
+ className: "rre-popup-btn",
361
+ onMouseDown: (e) => {
362
+ e.preventDefault();
363
+ handleLinkSave();
364
+ },
365
+ children: "Save"
366
+ }
367
+ )
368
+ ] });
369
+ }
370
+ if (tool === "table" && popup === "table") {
371
+ return /* @__PURE__ */ jsxs("div", { className: "rre-popup rre-popup--table", ref: popupRef, children: [
372
+ /* @__PURE__ */ jsx2(
373
+ "input",
374
+ {
375
+ className: "rre-popup-input rre-popup-input--num",
376
+ type: "number",
377
+ min: "1",
378
+ max: "10",
379
+ value: tableRows,
380
+ onChange: (e) => setTableRows(e.target.value),
381
+ onKeyDown: handleTableKeyDown,
382
+ autoFocus: true
383
+ }
384
+ ),
385
+ /* @__PURE__ */ jsx2("span", { className: "rre-popup-x", children: "\xD7" }),
386
+ /* @__PURE__ */ jsx2(
387
+ "input",
388
+ {
389
+ className: "rre-popup-input rre-popup-input--num",
390
+ type: "number",
391
+ min: "1",
392
+ max: "10",
393
+ value: tableCols,
394
+ onChange: (e) => setTableCols(e.target.value),
395
+ onKeyDown: handleTableKeyDown
396
+ }
397
+ ),
398
+ /* @__PURE__ */ jsx2(
399
+ "button",
400
+ {
401
+ className: "rre-popup-btn",
402
+ onMouseDown: (e) => {
403
+ e.preventDefault();
404
+ handleTableInsert();
405
+ },
406
+ children: "Insert"
407
+ }
408
+ )
409
+ ] });
410
+ }
411
+ return null;
412
+ };
413
+ return /* @__PURE__ */ jsxs("div", { className: ["rre-toolbar", className].filter(Boolean).join(" "), role: "toolbar", children: [
414
+ /* @__PURE__ */ jsx2(
415
+ "input",
416
+ {
417
+ ref: imageInputRef,
418
+ type: "file",
419
+ accept: "image/*",
420
+ style: { display: "none" },
421
+ onChange: handleImageChange
422
+ }
423
+ ),
424
+ toolbar.map((tool, i) => {
425
+ if (tool === "divider") {
426
+ return /* @__PURE__ */ jsx2("div", { className: "rre-toolbar-divider", "aria-hidden": "true" }, `divider-${i}`);
427
+ }
428
+ if (tool === "fontSize") {
429
+ return /* @__PURE__ */ jsx2(
430
+ "select",
431
+ {
432
+ className: "rre-fontsize-select",
433
+ value: currentFontSize,
434
+ onChange: (e) => handleFontSize(e.target.value),
435
+ title: "Font size",
436
+ children: FONT_SIZES.map((size) => /* @__PURE__ */ jsxs("option", { value: size, children: [
437
+ size,
438
+ "px"
439
+ ] }, size))
440
+ },
441
+ "fontSize"
442
+ );
443
+ }
444
+ if (tool === "link") {
445
+ const def2 = getToolDefinition(tool);
446
+ if (!def2) return null;
447
+ return /* @__PURE__ */ jsxs("div", { className: "rre-toolbar-popup-wrapper", onMouseDown: (e) => e.stopPropagation(), children: [
448
+ /* @__PURE__ */ jsx2(
449
+ ToolbarButton_default,
450
+ {
451
+ onClick: handleLinkOpen,
452
+ isActive: editor.isActive("link") || popup === "link",
453
+ title: def2.title,
454
+ children: /* @__PURE__ */ jsx2("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
455
+ }
456
+ ),
457
+ renderPopup("link")
458
+ ] }, "link");
459
+ }
460
+ if (tool === "image") {
461
+ const def2 = getToolDefinition(tool);
462
+ if (!def2) return null;
463
+ return /* @__PURE__ */ jsx2(
464
+ ToolbarButton_default,
465
+ {
466
+ onClick: handleImageClick,
467
+ title: def2.title,
468
+ children: /* @__PURE__ */ jsx2("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
469
+ },
470
+ "image"
471
+ );
472
+ }
473
+ if (tool === "table") {
474
+ const def2 = getToolDefinition(tool);
475
+ if (!def2) return null;
476
+ return /* @__PURE__ */ jsxs("div", { className: "rre-toolbar-popup-wrapper", onMouseDown: (e) => e.stopPropagation(), children: [
477
+ /* @__PURE__ */ jsx2(
478
+ ToolbarButton_default,
479
+ {
480
+ onClick: handleTableOpen,
481
+ isActive: popup === "table",
482
+ title: def2.title,
483
+ children: /* @__PURE__ */ jsx2("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def2.icon } })
484
+ }
485
+ ),
486
+ renderPopup("table")
487
+ ] }, "table");
488
+ }
489
+ const def = getToolDefinition(tool);
490
+ if (!def) return null;
491
+ return /* @__PURE__ */ jsx2(
492
+ ToolbarButton_default,
493
+ {
494
+ onClick: () => handleTool(tool),
495
+ isActive: isActive(tool),
496
+ disabled: isDisabled(tool),
497
+ title: def.title,
498
+ children: /* @__PURE__ */ jsx2("span", { className: "rre-icon", dangerouslySetInnerHTML: { __html: def.icon } })
499
+ },
500
+ tool
501
+ );
502
+ })
503
+ ] });
504
+ };
505
+ var Toolbar_default = Toolbar;
506
+
507
+ // src/components/RichEditor.tsx
508
+ import "./editor-XH5ZEVLH.css";
509
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
510
+ var DEFAULT_TOOLBAR = [
511
+ "bold",
512
+ "italic",
513
+ "underline",
514
+ "strikethrough",
515
+ "divider",
516
+ "heading1",
517
+ "heading2",
518
+ "heading3",
519
+ "divider",
520
+ "bulletList",
521
+ "orderedList",
522
+ "blockquote",
523
+ "codeBlock",
524
+ "divider",
525
+ "link",
526
+ "image",
527
+ "table",
528
+ "divider",
529
+ "undo",
530
+ "redo"
531
+ ];
532
+ var RichEditor = ({
533
+ value = "",
534
+ onChange,
535
+ toolbar = DEFAULT_TOOLBAR,
536
+ placeholder = "Start typing...",
537
+ editable = true,
538
+ className,
539
+ style,
540
+ toolbarClassName,
541
+ contentClassName
542
+ }) => {
543
+ const editor = useEditor({ value, onChange, placeholder, editable, toolbar });
544
+ if (!editor) return null;
545
+ return /* @__PURE__ */ jsxs2(
546
+ "div",
547
+ {
548
+ className: ["rre-editor", className].filter(Boolean).join(" "),
549
+ style,
550
+ children: [
551
+ editable && /* @__PURE__ */ jsx3(Toolbar_default, { editor, toolbar, className: toolbarClassName }),
552
+ /* @__PURE__ */ jsx3(
553
+ EditorContent,
554
+ {
555
+ editor,
556
+ className: ["rre-content", contentClassName].filter(Boolean).join(" ")
557
+ }
558
+ )
559
+ ]
560
+ }
561
+ );
562
+ };
563
+ var RichEditor_default = RichEditor;
564
+ export {
565
+ RichEditor_default as RichEditor
566
+ };
567
+ //# sourceMappingURL=index.mjs.map