mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
* tip tap version 2 * youtube * menu-bar * refactorng layout * fixed flex layout * fixed flex layout * a lot of ui fixes * optimizing flex layout & styling inputs * markdown styling * fix linting * updated snapshots * layout optimization * flex layout optimizations, text editor fine tuning and markdown rendering * updated snapshots --------- Co-authored-by: Anton Tranelis <mail@antontranelis.de> Co-authored-by: Anton Tranelis <31516529+antontranelis@users.noreply.github.com>
111 lines
3.0 KiB
TypeScript
111 lines
3.0 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 { 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,
|
|
labelStyle,
|
|
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 ? (
|
|
<label className='tw:label tw:pb-1'>
|
|
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
|
{labelTitle}
|
|
</span>
|
|
</label>
|
|
) : 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>
|
|
)
|
|
}
|