import { useEffect, useRef, useState } from 'react'; import Image from '@tiptap/extension-image'; import Link from '@tiptap/extension-link'; import Placeholder from '@tiptap/extension-placeholder'; import TaskItem from '@tiptap/extension-task-item'; import TaskList from '@tiptap/extension-task-list'; import { EditorContent, useEditor } from '@tiptap/react'; import StarterKit from '@tiptap/starter-kit'; import { useField } from '@unform/core'; import difference from 'lodash.difference'; import { useTheme } from '../../../hooks/theme'; import { Separator } from '../../Separator'; import { RichTextInputContainer, Label, Error } from '../styles'; import { MenuBar } from './MenuBar'; import { Content } from './styles'; interface Props { name: string; label?: string; placeholder?: string; removeOptions?: string[]; } type RichTextInputProps = JSX.IntrinsicElements['input'] & Props; const defaultOptions = [ 'heading-1', 'heading-2', 'heading-3', 'bold', 'italic', 'strike', 'code', 'quote', 'link', 'bullet-list', 'ordered-list', 'todo-list', 'image', ]; export function RichTextInput({ name, label, disabled, onBlur, onFocus, onChange, placeholder, removeOptions = [], }: RichTextInputProps): JSX.Element { const editorRef = useRef(null); const { colorScheme } = useTheme(); const { fieldName, defaultValue, registerField, error } = useField(name); const [isFocused, setIsFocused] = useState(false); const [isFilled, setIsFilled] = useState(defaultValue); function handleBlur( event?: React.FocusEvent, ): void { setIsFocused(false); if (onBlur && event) { onBlur(event); } } function handleFocus( event?: React.FocusEvent, ): void { setIsFocused(true); if (onFocus && event) { onFocus(event); } } function handleChange( event?: React.ChangeEvent | null, data?: string, ): void { const value = data ?? event?.target.value; if (!value) { return; } setIsFilled(value); if (onChange && event) { onChange(event); } } const editor = useEditor({ extensions: [ StarterKit, Link.configure({ openOnClick: true, linkOnPaste: true, }), Image, TaskList.configure({ HTMLAttributes: { class: 'editor-task-list', }, }), TaskItem.configure({ nested: true, }), Placeholder.configure({ placeholder, }), ], content: defaultValue, onUpdate: (value) => { handleChange(null, value.editor.getHTML()); }, onFocus: () => { handleFocus(); }, onBlur: () => { handleBlur(); }, }); function setContent(content: string): void { if (editor) { editor.commands.setContent(content); } } useEffect(() => { if (disabled) { handleBlur(); } }, [disabled]); function handleClear(): void { setIsFilled(''); setContent(''); } useEffect(() => { registerField({ name: fieldName, ref: editorRef, getValue: () => { const value = editor?.getHTML() ?? ''; if (!editor?.getText()) { return ''; } return value; }, setValue: (ref, value: string) => { ref.current.props.editor.commands.setContent(value); }, clearValue: () => { handleClear(); }, }); }, [fieldName, registerField, editor]); return ( {label && ( )} {error && {error}} ); }