tiptap/packages/react/src/EditorContent.tsx

112 lines
2.2 KiB
TypeScript
Raw Normal View History

import React, { HTMLProps } from 'react'
2021-03-13 04:21:13 +08:00
import ReactDOM from 'react-dom'
2021-03-09 06:10:10 +08:00
import { Editor } from './Editor'
2021-03-15 01:00:50 +08:00
import { ReactRenderer } from './ReactRenderer'
2021-03-09 06:10:10 +08:00
2021-03-15 01:00:50 +08:00
const Portals: React.FC<{ renderers: Map<string, ReactRenderer> }> = ({ renderers }) => {
2021-03-13 04:21:13 +08:00
return (
2021-03-15 01:00:50 +08:00
<>
2021-03-13 04:21:13 +08:00
{Array.from(renderers).map(([key, renderer]) => {
2021-03-14 23:30:06 +08:00
return ReactDOM.createPortal(
2021-03-15 00:01:52 +08:00
renderer.reactElement,
2021-03-15 01:00:50 +08:00
renderer.element,
key,
2021-03-13 04:21:13 +08:00
)
})}
2021-03-15 01:00:50 +08:00
</>
2021-03-13 04:21:13 +08:00
)
}
export interface EditorContentProps extends HTMLProps<HTMLDivElement> {
2021-03-15 16:00:44 +08:00
editor: Editor | null,
}
export interface EditorContentState {
renderers: Map<string, ReactRenderer>
}
export class PureEditorContent extends React.Component<EditorContentProps, EditorContentState> {
2021-03-09 06:10:10 +08:00
editorContentRef: React.RefObject<any>
constructor(props: EditorContentProps) {
2021-03-08 20:19:05 +08:00
super(props)
this.editorContentRef = React.createRef()
this.state = {
2021-03-13 04:21:13 +08:00
renderers: new Map(),
2021-03-08 20:19:05 +08:00
}
}
2021-03-15 21:53:23 +08:00
componentDidMount() {
this.init()
}
2021-03-08 20:19:05 +08:00
componentDidUpdate() {
2021-03-15 21:53:23 +08:00
this.init()
}
init() {
2021-03-08 20:19:05 +08:00
const { editor } = this.props
if (editor && editor.options.element) {
2021-03-13 04:21:13 +08:00
if (editor.contentComponent) {
return
}
2021-03-08 20:19:05 +08:00
const element = this.editorContentRef.current
element.append(...editor.options.element.childNodes)
2021-03-08 20:19:05 +08:00
editor.setOptions({
element,
})
editor.contentComponent = this
2021-03-16 01:42:58 +08:00
// TODO: alternative to setTimeout?
setTimeout(() => editor.createNodeViews(), 0)
2021-03-08 20:19:05 +08:00
}
}
2021-03-15 21:53:23 +08:00
componentWillUnmount() {
const { editor } = this.props
if (!editor) {
return
}
if (!editor.isDestroyed) {
editor.view.setProps({
nodeViews: {},
})
}
editor.contentComponent = null
if (!editor.options.element.firstChild) {
return
}
const newElement = document.createElement('div')
newElement.append(...editor.options.element.childNodes)
2021-03-15 21:53:23 +08:00
editor.setOptions({
element: newElement,
})
}
2021-03-08 20:19:05 +08:00
render() {
const { editor, ...rest } = this.props
2021-03-08 20:19:05 +08:00
return (
2021-03-13 04:21:13 +08:00
<>
<div ref={this.editorContentRef} {...rest} />
2021-04-07 20:29:51 +08:00
<Portals renderers={this.state.renderers} />
2021-03-13 04:21:13 +08:00
</>
2021-03-08 20:19:05 +08:00
)
}
}
2021-03-09 05:00:07 +08:00
2021-03-13 04:21:13 +08:00
export const EditorContent = React.memo(PureEditorContent)