149 lines
4.2 KiB
TypeScript
149 lines
4.2 KiB
TypeScript
import {
|
|
BlockTypeSelect,
|
|
BoldItalicUnderlineToggles,
|
|
codeBlockPlugin,
|
|
CodeToggle,
|
|
CreateLink,
|
|
diffSourcePlugin,
|
|
DiffSourceToggleWrapper,
|
|
directivesPlugin,
|
|
headingsPlugin,
|
|
imagePlugin,
|
|
InsertCodeBlock,
|
|
InsertImage,
|
|
InsertTable,
|
|
InsertThematicBreak,
|
|
linkDialogPlugin,
|
|
linkPlugin,
|
|
listsPlugin,
|
|
ListsToggle,
|
|
markdownShortcutPlugin,
|
|
MDXEditor,
|
|
MDXEditorMethods,
|
|
MDXEditorProps,
|
|
quotePlugin,
|
|
Separator,
|
|
StrikeThroughSupSubToggles,
|
|
tablePlugin,
|
|
thematicBreakPlugin,
|
|
toolbarPlugin,
|
|
UndoRedo
|
|
} from '@mdxeditor/editor'
|
|
import { PlainTextCodeEditorDescriptor } from './PlainTextCodeEditorDescriptor'
|
|
import { YoutubeDirectiveDescriptor } from './YoutubeDirectiveDescriptor'
|
|
import { YouTubeButton } from './YoutubeButton'
|
|
import '@mdxeditor/editor/style.css'
|
|
import '../../styles/mdxEditor.scss'
|
|
import React, {
|
|
forwardRef,
|
|
useCallback,
|
|
useImperativeHandle,
|
|
useMemo,
|
|
useRef
|
|
} from 'react'
|
|
import { ImageDialog } from './ImageDialog'
|
|
import { LinkDialog } from './LinkDialog'
|
|
|
|
export interface EditorRef {
|
|
setMarkdown: (md: string) => void
|
|
}
|
|
interface EditorProps extends MDXEditorProps {}
|
|
/**
|
|
* The editor component is small wrapper (`forwardRef`) around {@link MDXEditor MDXEditor} that sets up the toolbars and plugins, and requires `markdown` and `onChange`.
|
|
* To reset editor markdown it's required to pass the {@link EditorRef EditorRef}.
|
|
*
|
|
* Extends {@link MDXEditorProps MDXEditorProps}
|
|
*
|
|
* **Important**: the markdown is not a state, but an _initialState_ and is not "controlled".
|
|
* All updates are handled with onChange and will not be reflected on markdown prop.
|
|
* This component should never re-render if used correctly.
|
|
* @see https://mdxeditor.dev/editor/docs/getting-started#basic-usage
|
|
*/
|
|
export const Editor = React.memo(
|
|
forwardRef<EditorRef, EditorProps>(({ markdown, onChange, ...rest }, ref) => {
|
|
const editorRef = useRef<MDXEditorMethods>(null)
|
|
const setMarkdown = useCallback((md: string) => {
|
|
editorRef.current?.setMarkdown(md)
|
|
}, [])
|
|
useImperativeHandle(ref, () => ({ setMarkdown }))
|
|
const plugins = useMemo(
|
|
() => [
|
|
toolbarPlugin({
|
|
toolbarContents: () => (
|
|
<DiffSourceToggleWrapper
|
|
children={
|
|
<>
|
|
<UndoRedo />
|
|
<Separator />
|
|
<BoldItalicUnderlineToggles />
|
|
<CodeToggle />
|
|
<Separator />
|
|
<StrikeThroughSupSubToggles />
|
|
<Separator />
|
|
<ListsToggle />
|
|
<Separator />
|
|
<BlockTypeSelect />
|
|
<Separator />
|
|
|
|
<CreateLink />
|
|
<InsertImage />
|
|
<YouTubeButton />
|
|
|
|
<Separator />
|
|
|
|
<InsertTable />
|
|
<InsertThematicBreak />
|
|
|
|
<Separator />
|
|
<InsertCodeBlock />
|
|
</>
|
|
}
|
|
/>
|
|
)
|
|
}),
|
|
headingsPlugin(),
|
|
diffSourcePlugin({
|
|
viewMode: 'rich-text',
|
|
diffMarkdown: markdown
|
|
}),
|
|
quotePlugin(),
|
|
imagePlugin({
|
|
ImageDialog: ImageDialog
|
|
}),
|
|
tablePlugin(),
|
|
linkPlugin(),
|
|
linkDialogPlugin({
|
|
LinkDialog: LinkDialog
|
|
}),
|
|
listsPlugin(),
|
|
thematicBreakPlugin(),
|
|
directivesPlugin({
|
|
directiveDescriptors: [YoutubeDirectiveDescriptor]
|
|
}),
|
|
markdownShortcutPlugin(),
|
|
// HACK: due to a bug with shortcut interaction shortcut for code block is disabled
|
|
// Editor freezes if you type in ```word and put a space in between ``` word
|
|
codeBlockPlugin({
|
|
defaultCodeBlockLanguage: '',
|
|
codeBlockEditorDescriptors: [PlainTextCodeEditorDescriptor]
|
|
})
|
|
],
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
[]
|
|
)
|
|
|
|
return (
|
|
<MDXEditor
|
|
ref={editorRef}
|
|
contentEditableClassName='editor'
|
|
className='dark-theme dark-editor'
|
|
markdown={markdown}
|
|
plugins={plugins}
|
|
onChange={onChange}
|
|
{...rest}
|
|
/>
|
|
)
|
|
}),
|
|
() => true
|
|
)
|