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 { useEditor, EditorContent, ReactNodeViewRenderer } from '@tiptap/react'
import { useEditor, EditorContent, ReactNodeViewRenderer, NodeViewWrapper, NodeViewContent } from '@tiptap/react'
import { defaultExtensions } from '@tiptap/starter-kit'
import Heading from '@tiptap/extension-heading'
import Paragraph from '@tiptap/extension-paragraph'
import './styles.scss'
@@ -126,19 +127,35 @@ const MenuBar = ({ editor }) => {
export default () => {
const editor = useEditor({
extensions: [
Paragraph.extend({
...defaultExtensions().filter(item => item.config.name !== 'heading'),
Heading.extend({
draggable: true,
addNodeView() {
return ReactNodeViewRenderer(({ selected }) => {
console.log({selected})
return ReactNodeViewRenderer((props) => {
// console.log({props})
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: `
// <h2>
// Hi there,

View File

@@ -6,50 +6,15 @@ type EditorContentProps = {
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> }) => {
return (
<div>
{Array.from(renderers).map(([key, renderer]) => {
// console.log({renderer})
// return (
// <div key={key}>{value}</div>
// )
// 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(
renderer.comp,
renderer.teleportElement,
renderer.id,
)
// return ReactDOM.createPortal(
// React.createElement(renderer.component),
// renderer.teleportElement,
// )
})}
</div>
)
@@ -72,14 +37,6 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
editor: this.props.editor,
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() {
@@ -94,8 +51,6 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
// editor,
// })
console.log('UPDATE')
const element = this.editorContentRef.current
element.appendChild(editor.options.element.firstChild)
@@ -114,14 +69,11 @@ export class PureEditorContent extends React.Component<EditorContentProps, any>
}
render() {
console.log('render', this.state)
// console.log('render', this.state)
// console.log('render', this.props.editor, this.state.editor)
return (
<>
<div ref={this.editorContentRef} />
{/* <Content reference={this.editorContentRef} /> */}
{/* <Portals editor={this.props.editor} /> */}
<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 = 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,
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() {
return this.renderer.element
// return this.domWrapper
// return this.renderer.element
// return this.renderer.element.firstChild
return this.domWrapper
// if (!this.renderer.element) {
// return null
@@ -90,6 +104,7 @@ class ReactNodeView implements NodeView {
}
get contentDOM() {
return this.contentDOMWrapper
// return this.renderer.element
return undefined
// return this.renderer.element
@@ -196,6 +211,8 @@ class ReactNodeView implements NodeView {
destroy() {
this.renderer.destroy()
this.domWrapper = undefined
this.contentDOMWrapper = undefined
}
update(node: ProseMirrorNode, decorations: Decoration[]) {

View File

@@ -40,16 +40,37 @@ export class ReactRenderer {
// this.render()
// // this.element = this.teleportElement.firstElementChild as Element
console.log({ props })
// console.log({ props })
// this.bla = ReactDOM.createPortal(
// React.createElement(this.component, props),
// 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) {
this.editor.contentComponent.setState({
@@ -61,13 +82,9 @@ export class ReactRenderer {
}
}
render() {
render(React.createElement(this.component), this.teleportElement)
}
updateProps(props: { [key: string]: any } = {}) {
// TODO
console.log('update props', { props })
// console.log('update props', { props })
}
destroy() {

View File

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

View File

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