2021-03-09 05:16:32 +08:00
|
|
|
import React 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
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-03-15 16:00:44 +08:00
|
|
|
export interface EditorContentProps {
|
|
|
|
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.appendChild(editor.options.element.firstChild)
|
|
|
|
|
|
|
|
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.appendChild(editor.options.element.firstChild)
|
|
|
|
|
|
|
|
editor.setOptions({
|
|
|
|
element: newElement,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-03-08 20:19:05 +08:00
|
|
|
render() {
|
|
|
|
return (
|
2021-03-13 04:21:13 +08:00
|
|
|
<>
|
|
|
|
<div ref={this.editorContentRef} />
|
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)
|