import Link from '@tiptap/extension-link' import { Editor, EditorContent, useEditor } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import React, { useEffect } from 'react' import '../styles/styles.css' import '../styles/tiptap.scss' interface InputFieldProps { label: string description?: string type?: 'text' | 'textarea' | 'richtext' placeholder: string name: string inputMode?: 'url' value: string error?: string onChange: (name: string, value: string) => void } export const InputField = React.memo( ({ label, description, type = 'text', placeholder, name, inputMode, value, error, onChange }: InputFieldProps) => { const handleChange = ( e: React.ChangeEvent ) => { onChange(name, e.target.value) } return (
{description &&

{description}

} {type === 'textarea' ? ( ) : type === 'richtext' ? ( onChange(name, content)} /> ) : ( )} {error && }
) } ) type InputErrorProps = { message: string } export const InputError = ({ message }: InputErrorProps) => { if (!message) return null return (

{message}

) } interface CheckboxFieldProps { label: string name: string isChecked: boolean handleChange: (e: React.ChangeEvent) => void } export const CheckboxField = React.memo( ({ label, name, isChecked, handleChange }: CheckboxFieldProps) => (
) ) type RichTextEditorProps = { content: string updateContent: (updatedContent: string) => void } const RichTextEditor = ({ content, updateContent }: RichTextEditorProps) => { const editor = useEditor({ extensions: [StarterKit, Link], onUpdate: ({ editor }) => { // Update the state when the editor content changes updateContent(editor.getHTML()) }, content }) // Update editor content when the `content` prop changes useEffect(() => { if (editor && editor.getHTML() !== content) { editor.commands.setContent(content, false) } }, [content, editor]) return (
{editor && ( <> )}
) } type MenuBarProps = { editor: Editor } const MenuBar = ({ editor }: MenuBarProps) => { const setLink = () => { const url = prompt('URL') if (url) { return editor.chain().focus().setLink({ href: url }).run() } return false } const unsetLink = () => editor.chain().focus().unsetLink().run() const buttons: MenuBarButtonProps[] = [ { label: 'Bold', disabled: !editor.can().chain().focus().toggleBold().run(), isActive: editor.isActive('bold'), onClick: () => editor.chain().focus().toggleBold().run() }, { label: 'Italic', disabled: !editor.can().chain().focus().toggleItalic().run(), isActive: editor.isActive('italic'), onClick: () => editor.chain().focus().toggleItalic().run() }, { label: 'Strike', disabled: !editor.can().chain().focus().toggleStrike().run(), isActive: editor.isActive('strike'), onClick: () => editor.chain().focus().toggleStrike().run() }, { label: 'Clear marks', onClick: () => editor.chain().focus().unsetAllMarks().run() }, { label: 'Clear nodes', onClick: () => editor.chain().focus().clearNodes().run() }, { label: 'Paragraph', isActive: editor.isActive('paragraph'), onClick: () => editor.chain().focus().toggleStrike().run() }, // eslint-disable-next-line @typescript-eslint/no-explicit-any ...[1, 2, 3, 4, 5, 6].map((level: any) => ({ label: `H${level}`, isActive: editor.isActive('heading', { level }), onClick: () => editor.chain().focus().toggleHeading({ level }).run() })), { label: 'Bullet list', isActive: editor.isActive('bulletList'), onClick: () => editor.chain().focus().toggleBulletList().run() }, { label: 'Ordered list', isActive: editor.isActive('orderedList'), onClick: () => editor.chain().focus().toggleOrderedList().run() }, { label: 'Code block', isActive: editor.isActive('codeBlock'), onClick: () => editor.chain().focus().toggleCodeBlock().run() }, { label: 'Blockquote', isActive: editor.isActive('blockquote'), onClick: () => editor.chain().focus().toggleBlockquote().run() }, { label: 'Link', isActive: editor.isActive('link'), onClick: editor.isActive('link') ? unsetLink : setLink }, { label: 'Horizontal rule', onClick: () => editor.chain().focus().setHorizontalRule().run() }, { label: 'Hard break', onClick: () => editor.chain().focus().setHardBreak().run() }, { label: 'Undo', disabled: !editor.can().chain().focus().undo().run(), onClick: () => editor.chain().focus().undo().run() }, { label: 'Redo', disabled: !editor.can().chain().focus().redo().run(), onClick: () => editor.chain().focus().redo().run() } ] return (
{buttons.map(({ label, disabled, isActive, onClick }) => ( ))}
) } interface MenuBarButtonProps { label: string isActive?: boolean disabled?: boolean onClick: () => boolean } const MenuBarButton = ({ label, isActive = false, disabled = false, onClick }: MenuBarButtonProps) => ( )