utopia-ui/lib/src/Components/Input/RichTextEditor.tsx
Anton Tranelis 12aba6a67e
fix(lib): fix labels (#278)
* fix labels

* more lables

* and the rest of the lables

* updated snapshots

* fix linting
2025-07-04 08:36:11 +02:00

105 lines
2.8 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { Color } from '@tiptap/extension-color'
import { Image } from '@tiptap/extension-image'
import { Link } from '@tiptap/extension-link'
import { Placeholder } from '@tiptap/extension-placeholder'
import { EditorContent, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { useEffect } from 'react'
import { Markdown } from 'tiptap-markdown'
import { InputLabel } from './InputLabel'
import { TextEditorMenu } from './TextEditorMenu'
interface RichTextEditorProps {
labelTitle?: string
labelStyle?: string
containerStyle?: string
defaultValue: string
placeholder?: string
showMenu?: boolean
updateFormValue?: (value: string) => void
}
/**
* @category Input
*/
export function RichTextEditor({
labelTitle,
containerStyle,
defaultValue,
placeholder,
showMenu = true,
updateFormValue,
}: RichTextEditorProps) {
const handleChange = () => {
let newValue: string | undefined = editor?.storage.markdown.getMarkdown()
const regex = /!\[.*?\]\(.*?\)/g
newValue = newValue?.replace(regex, (match: string) => match + '\n\n')
if (updateFormValue && newValue) {
updateFormValue(newValue)
}
}
const editor = useEditor({
extensions: [
Color.configure({ types: ['textStyle', 'listItem'] }),
StarterKit.configure({
bulletList: {
keepMarks: true,
keepAttributes: false,
},
orderedList: {
keepMarks: true,
keepAttributes: false,
},
}),
Markdown.configure({
linkify: true,
transformCopiedText: true,
transformPastedText: true,
}),
Image,
Link,
Placeholder.configure({
placeholder,
emptyEditorClass: 'is-editor-empty',
}),
],
content: defaultValue,
onUpdate: handleChange,
editorProps: {
attributes: {
class: `tw:h-full markdown tw:max-h-full tw:p-2 tw:overflow-y-auto`,
},
},
})
useEffect(() => {
if (editor?.storage.markdown.getMarkdown() === '' || !editor?.storage.markdown.getMarkdown()) {
editor?.commands.setContent(defaultValue)
}
}, [defaultValue, editor])
return (
<div
className={`tw:form-control tw:w-full tw:flex tw:flex-col tw:min-h-0 ${containerStyle ?? ''}`}
>
{labelTitle ? <InputLabel label={labelTitle} /> : null}
<div
className={`editor-wrapper tw:border-base-content/20 tw:rounded-box tw:border tw:flex tw:flex-col tw:flex-1 tw:min-h-0`}
>
{editor ? (
<>
{showMenu ? <TextEditorMenu editor={editor} /> : null}
<EditorContent editor={editor} />
</>
) : null}
</div>
</div>
)
}