add basic react nodeviewrenderer

This commit is contained in:
Philipp Kühn
2021-03-14 16:30:06 +01:00
parent bc60a91904
commit 5e9a0d4225
8 changed files with 118 additions and 73 deletions

View File

@@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { useEditor, EditorContent, ReactNodeViewRenderer } from '@tiptap/react' import { useEditor, EditorContent, ReactNodeViewRenderer, NodeViewWrapper, NodeViewContent } from '@tiptap/react'
import { defaultExtensions } from '@tiptap/starter-kit' import { defaultExtensions } from '@tiptap/starter-kit'
import Heading from '@tiptap/extension-heading'
import Paragraph from '@tiptap/extension-paragraph' import Paragraph from '@tiptap/extension-paragraph'
import './styles.scss' import './styles.scss'
@@ -126,19 +127,35 @@ const MenuBar = ({ editor }) => {
export default () => { export default () => {
const editor = useEditor({ const editor = useEditor({
extensions: [ extensions: [
Paragraph.extend({ ...defaultExtensions().filter(item => item.config.name !== 'heading'),
Heading.extend({
draggable: true,
addNodeView() { addNodeView() {
return ReactNodeViewRenderer(({ selected }) => { return ReactNodeViewRenderer((props) => {
console.log({selected}) // console.log({props})
return ( return (
<div className="paragraph">noooode view {selected}</div> <NodeViewWrapper>
<div className="heading">
<span
data-drag-handle
contentEditable={false}
draggable={true}
suppressContentEditableWarning={true}
></span>
<NodeViewContent />
</div>
</NodeViewWrapper>
) )
}) })
} }
}), }),
...defaultExtensions().filter(item => item.config.name !== 'paragraph'),
], ],
content: `<p>test</p>`, content: `
<h1>h1</h1>
<h2>h2</h2>
<p>paragraph</p>
`,
// content: ` // content: `
// <h2> // <h2>
// Hi there, // Hi there,

View File

@@ -6,50 +6,15 @@ type EditorContentProps = {
editor: Editor | null editor: Editor | null
} }
// const Portals = ({ editor }: { editor: Editor | null }) => {
// if (!editor?.contentComponent) {
// return null
// }
// console.log('render portals')
// return (
// <div>portaaals</div>
// )
// }
const Portals = ({ renderers }: { renderers: Map<any, any> }) => { const Portals = ({ renderers }: { renderers: Map<any, any> }) => {
return ( return (
<div> <div>
{Array.from(renderers).map(([key, renderer]) => { {Array.from(renderers).map(([key, renderer]) => {
return ReactDOM.createPortal(
// console.log({renderer}) renderer.comp,
// return ( renderer.teleportElement,
// <div key={key}>{value}</div> renderer.id,
// )
// return React.createElement(renderer.component)
// return (
// <React.Fragment key={renderer.id}>
// {ReactDOM.createPortal(
// React.createElement(renderer.component),
// renderer.teleportElement,
// )}
// </React.Fragment>
// )
return (
<React.Fragment key={renderer.id}>
{renderer.bla}
</React.Fragment>
) )
// return ReactDOM.createPortal(
// React.createElement(renderer.component),
// renderer.teleportElement,
// )
})} })}
</div> </div>
) )
@@ -72,14 +37,6 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
editor: this.props.editor, editor: this.props.editor,
renderers: new Map(), renderers: new Map(),
} }
// setInterval(() => {
// if (this.props?.editor?.contentComponent) {
// this.props.editor.contentComponent.setState({
// renderers: this.state.renderers.set(Math.random(), Math.random())
// })
// }
// }, 1000)
} }
componentDidUpdate() { componentDidUpdate() {
@@ -94,8 +51,6 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
// editor, // editor,
// }) // })
console.log('UPDATE')
const element = this.editorContentRef.current const element = this.editorContentRef.current
element.appendChild(editor.options.element.firstChild) element.appendChild(editor.options.element.firstChild)
@@ -114,14 +69,11 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
} }
render() { render() {
console.log('render', this.state) // console.log('render', this.state)
// console.log('render', this.props.editor, this.state.editor) // console.log('render', this.props.editor, this.state.editor)
return ( return (
<> <>
<div ref={this.editorContentRef} /> <div ref={this.editorContentRef} />
{/* <Content reference={this.editorContentRef} /> */}
{/* <Portals editor={this.props.editor} /> */}
<Portals renderers={this.state.renderers} /> <Portals renderers={this.state.renderers} />
</> </>
) )
@@ -129,5 +81,3 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
} }
export const EditorContent = React.memo(PureEditorContent) export const EditorContent = React.memo(PureEditorContent)
// export const EditorContent = PureEditorContent

View File

@@ -0,0 +1,18 @@
import React from 'react'
export const NodeViewContent: React.FC = props => {
// TODO
const isEditable = true
return (
<div
data-node-view-content=""
contentEditable={isEditable}
style={{
whiteSpace: 'pre-wrap'
}}
/>
)
}

View File

@@ -0,0 +1,23 @@
import React from 'react'
export const NodeViewWrapper: React.FC = props => {
// TODO
const onDragStart = () => {
console.log('drag start')
}
return (
<div
data-node-view-wrapper=""
// contentEditable={false}
style={{
whiteSpace: 'normal'
}}
onDragStart={onDragStart}
>
{props.children}
</div>
)
}

View File

@@ -72,11 +72,25 @@ class ReactNodeView implements NodeView {
editor: this.editor, editor: this.editor,
props, props,
}) })
// console.log(this.renderer.element.firstChild)
this.domWrapper.appendChild(this.renderer.element)
const contentElement = this.renderer.element.querySelector('[data-node-view-content]')
// console.log({ contentElement })
contentElement.appendChild(this.contentDOMWrapper)
// this.renderer.element.firstChild?.appendChild(this.contentDOMWrapper)
// this.domWrapper.appendChild(this.contentDOMWrapper)
} }
get dom() { get dom() {
return this.renderer.element // return this.renderer.element
// return this.domWrapper // return this.renderer.element.firstChild
return this.domWrapper
// if (!this.renderer.element) { // if (!this.renderer.element) {
// return null // return null
@@ -90,6 +104,7 @@ class ReactNodeView implements NodeView {
} }
get contentDOM() { get contentDOM() {
return this.contentDOMWrapper
// return this.renderer.element // return this.renderer.element
return undefined return undefined
// return this.renderer.element // return this.renderer.element
@@ -196,6 +211,8 @@ class ReactNodeView implements NodeView {
destroy() { destroy() {
this.renderer.destroy() this.renderer.destroy()
this.domWrapper = undefined
this.contentDOMWrapper = undefined
} }
update(node: ProseMirrorNode, decorations: Decoration[]) { update(node: ProseMirrorNode, decorations: Decoration[]) {

View File

@@ -40,16 +40,37 @@ export class ReactRenderer {
// this.render() // this.render()
// // this.element = this.teleportElement.firstElementChild as Element // // this.element = this.teleportElement.firstElementChild as Element
console.log({ props }) // console.log({ props })
// this.bla = ReactDOM.createPortal( // this.bla = ReactDOM.createPortal(
// React.createElement(this.component, props), // React.createElement(this.component, props),
// this.teleportElement, // this.teleportElement,
// ) // )
this.render()
// this.comp = React.createElement(this.component, { foo: 1 })
this.bla = React.createElement(this.component, props) // // this.bla = React.createElement(this.component, props)
// console.log({ bla }) // // console.log({ bla })
// if (this.editor?.contentComponent) {
// this.editor.contentComponent.setState({
// renderers: this.editor.contentComponent.state.renderers.set(
// this.id,
// this,
// ),
// })
// }
}
// get comp() {
// console.log('get comp')
// return React.createElement(this.component, { foo: 1 })
// }
render() {
this.comp = React.createElement(this.component, { foo: 1 })
// render(React.createElement(this.component), this.teleportElement)
if (this.editor?.contentComponent) { if (this.editor?.contentComponent) {
this.editor.contentComponent.setState({ this.editor.contentComponent.setState({
@@ -61,13 +82,9 @@ export class ReactRenderer {
} }
} }
render() {
render(React.createElement(this.component), this.teleportElement)
}
updateProps(props: { [key: string]: any } = {}) { updateProps(props: { [key: string]: any } = {}) {
// TODO // TODO
console.log('update props', { props }) // console.log('update props', { props })
} }
destroy() { destroy() {

View File

@@ -5,3 +5,5 @@ export * from './useEditor'
export * from './ReactRenderer' export * from './ReactRenderer'
export * from './ReactNodeViewRenderer' export * from './ReactNodeViewRenderer'
export * from './EditorContent' export * from './EditorContent'
export * from './NodeViewWrapper'
export * from './NodeViewContent'

View File

@@ -28,7 +28,8 @@
"./shims/vue.d.ts" "./shims/vue.d.ts"
], ],
"include": [ "include": [
"**/*.ts" "**/*.ts",
"**/*.tsx"
], ],
"exclude": [ "exclude": [
"**/node_modules", "**/node_modules",