wip react renderer
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import { useEditor, EditorContent } from '@tiptap/react'
|
||||
import { useEditor, EditorContent, ReactNodeViewRenderer } from '@tiptap/react'
|
||||
import { defaultExtensions } from '@tiptap/starter-kit'
|
||||
import Paragraph from '@tiptap/extension-paragraph'
|
||||
import './styles.scss'
|
||||
|
||||
const MenuBar = ({ editor }) => {
|
||||
@@ -125,38 +126,49 @@ const MenuBar = ({ editor }) => {
|
||||
export default () => {
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
...defaultExtensions(),
|
||||
Paragraph.extend({
|
||||
addNodeView() {
|
||||
return ReactNodeViewRenderer(({ selected }) => {
|
||||
console.log({selected})
|
||||
return (
|
||||
<div className="paragraph">noooode view {selected}</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
}),
|
||||
...defaultExtensions().filter(item => item.config.name !== 'paragraph'),
|
||||
],
|
||||
content: `
|
||||
<h2>
|
||||
Hi there,
|
||||
</h2>
|
||||
<p>
|
||||
this is a basic <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
That’s a bullet list with one …
|
||||
</li>
|
||||
<li>
|
||||
… or two list items.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
|
||||
</p>
|
||||
<pre><code class="language-css">body {
|
||||
display: none;
|
||||
}</code></pre>
|
||||
<p>
|
||||
I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
|
||||
</p>
|
||||
<blockquote>
|
||||
Wow, that’s amazing. Good work, boy! 👏
|
||||
<br />
|
||||
— Mom
|
||||
</blockquote>
|
||||
`,
|
||||
content: `<p>test</p>`,
|
||||
// content: `
|
||||
// <h2>
|
||||
// Hi there,
|
||||
// </h2>
|
||||
// <p>
|
||||
// this is a basic <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
|
||||
// </p>
|
||||
// <ul>
|
||||
// <li>
|
||||
// That’s a bullet list with one …
|
||||
// </li>
|
||||
// <li>
|
||||
// … or two list items.
|
||||
// </li>
|
||||
// </ul>
|
||||
// <p>
|
||||
// Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
|
||||
// </p>
|
||||
// <pre><code class="language-css">body {
|
||||
// display: none;
|
||||
// }</code></pre>
|
||||
// <p>
|
||||
// I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
|
||||
// </p>
|
||||
// <blockquote>
|
||||
// Wow, that’s amazing. Good work, boy! 👏
|
||||
// <br />
|
||||
// — Mom
|
||||
// </blockquote>
|
||||
// `,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,67 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Editor } from './Editor'
|
||||
|
||||
type EditorContentProps = {
|
||||
editor: Editor | null
|
||||
}
|
||||
|
||||
export class PureEditorContent extends React.Component<EditorContentProps, EditorContentProps> {
|
||||
// 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(
|
||||
// React.createElement(renderer.component),
|
||||
// renderer.teleportElement,
|
||||
// )
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// const Content = React.memo(({ reference }: { reference: React.RefObject<any> }) => {
|
||||
// return (
|
||||
// <div ref={reference} />
|
||||
// )
|
||||
// })
|
||||
|
||||
export class PureEditorContent extends React.Component<EditorContentProps, any> {
|
||||
editorContentRef: React.RefObject<any>
|
||||
|
||||
constructor(props: EditorContentProps) {
|
||||
@@ -13,14 +69,33 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
||||
this.editorContentRef = React.createRef()
|
||||
|
||||
this.state = {
|
||||
editor: this.props.editor
|
||||
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() {
|
||||
const { editor } = this.props
|
||||
|
||||
if (editor && editor.options.element) {
|
||||
if (editor.contentComponent) {
|
||||
return
|
||||
}
|
||||
|
||||
// this.setState({
|
||||
// editor,
|
||||
// })
|
||||
|
||||
console.log('UPDATE')
|
||||
|
||||
const element = this.editorContentRef.current
|
||||
|
||||
element.appendChild(editor.options.element.firstChild)
|
||||
@@ -39,10 +114,20 @@ export class PureEditorContent extends React.Component<EditorContentProps, Edito
|
||||
}
|
||||
|
||||
render() {
|
||||
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} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const EditorContent = React.memo(PureEditorContent);
|
||||
export const EditorContent = React.memo(PureEditorContent)
|
||||
|
||||
// export const EditorContent = PureEditorContent
|
||||
|
||||
@@ -1,208 +1,246 @@
|
||||
// // @ts-nocheck
|
||||
// import { Node, NodeViewRenderer, NodeViewRendererProps } from '@tiptap/core'
|
||||
// import { Decoration, NodeView } from 'prosemirror-view'
|
||||
// import { NodeSelection } from 'prosemirror-state'
|
||||
// import { Node as ProseMirrorNode } from 'prosemirror-model'
|
||||
// import React from 'react'
|
||||
// import ReactDOM from 'react-dom'
|
||||
// import { Editor } from './Editor'
|
||||
// import { ReactRenderer } from './ReactRenderer'
|
||||
// @ts-nocheck
|
||||
import { Node, NodeViewRenderer, NodeViewRendererProps } from '@tiptap/core'
|
||||
import { Decoration, NodeView } from 'prosemirror-view'
|
||||
import { NodeSelection } from 'prosemirror-state'
|
||||
import { Node as ProseMirrorNode } from 'prosemirror-model'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Editor } from './Editor'
|
||||
import { ReactRenderer } from './ReactRenderer'
|
||||
|
||||
// interface ReactNodeViewRendererOptions {
|
||||
// stopEvent: ((event: Event) => boolean) | null,
|
||||
// update: ((node: ProseMirrorNode, decorations: Decoration[]) => boolean) | null,
|
||||
// }
|
||||
interface ReactNodeViewRendererOptions {
|
||||
stopEvent: ((event: Event) => boolean) | null,
|
||||
update: ((node: ProseMirrorNode, decorations: Decoration[]) => boolean) | null,
|
||||
}
|
||||
|
||||
// class ReactNodeView implements NodeView {
|
||||
class ReactNodeView implements NodeView {
|
||||
|
||||
// renderer!: ReactRenderer
|
||||
renderer!: ReactRenderer
|
||||
|
||||
// editor: Editor
|
||||
editor: Editor
|
||||
|
||||
// extension!: Node
|
||||
extension!: Node
|
||||
|
||||
// node!: ProseMirrorNode
|
||||
node!: ProseMirrorNode
|
||||
|
||||
// decorations!: Decoration[]
|
||||
decorations!: Decoration[]
|
||||
|
||||
// getPos!: any
|
||||
getPos!: any
|
||||
|
||||
// isDragging = false
|
||||
isDragging = false
|
||||
|
||||
// options: ReactNodeViewRendererOptions = {
|
||||
// stopEvent: null,
|
||||
// update: null,
|
||||
// }
|
||||
options: ReactNodeViewRendererOptions = {
|
||||
stopEvent: null,
|
||||
update: null,
|
||||
}
|
||||
|
||||
// constructor(component: any, props: NodeViewRendererProps, options?: Partial<ReactNodeViewRendererOptions>) {
|
||||
// this.options = { ...this.options, ...options }
|
||||
// this.editor = props.editor as Editor
|
||||
// this.extension = props.extension
|
||||
// this.node = props.node
|
||||
// this.getPos = props.getPos
|
||||
// this.mount(component)
|
||||
// }
|
||||
domWrapper: Element
|
||||
|
||||
// mount(component: any) {
|
||||
// const props = {}
|
||||
contentDOMWrapper: Element
|
||||
|
||||
// if (!component.displayName) {
|
||||
// component.displayName = this.extension.config.name
|
||||
// }
|
||||
constructor(component: any, props: NodeViewRendererProps, options?: Partial<ReactNodeViewRendererOptions>) {
|
||||
this.options = { ...this.options, ...options }
|
||||
this.editor = props.editor as Editor
|
||||
this.extension = props.extension
|
||||
this.node = props.node
|
||||
this.getPos = props.getPos
|
||||
|
||||
// this.renderer = new ReactRenderer(component, {
|
||||
// editor: this.editor,
|
||||
// props,
|
||||
// })
|
||||
// }
|
||||
this.domWrapper = document.createElement('div')
|
||||
this.domWrapper.classList.add('dom-wrapper')
|
||||
this.contentDOMWrapper = document.createElement('div')
|
||||
this.contentDOMWrapper.classList.add('content-dom-wrapper')
|
||||
|
||||
// get dom() {
|
||||
// // if (!this.renderer.element) {
|
||||
// // return null
|
||||
// // }
|
||||
this.mount(component)
|
||||
}
|
||||
|
||||
// // if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
|
||||
// // throw Error('Please use the NodeViewWrapper component for your node view.')
|
||||
// // }
|
||||
mount(component: any) {
|
||||
const props = {
|
||||
editor: this.editor,
|
||||
node: this.node,
|
||||
decorations: this.decorations,
|
||||
selected: false,
|
||||
extension: this.extension,
|
||||
getPos: () => this.getPos(),
|
||||
updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
|
||||
}
|
||||
|
||||
// return this.renderer.element
|
||||
// }
|
||||
if (!component.displayName) {
|
||||
component.displayName = this.extension.config.name
|
||||
}
|
||||
|
||||
// get contentDOM() {
|
||||
// // console.log(this.dom)
|
||||
// // return null
|
||||
// // if (!this.renderer.element) {
|
||||
// // return null
|
||||
// // }
|
||||
this.renderer = new ReactRenderer(component, {
|
||||
editor: this.editor,
|
||||
props,
|
||||
})
|
||||
}
|
||||
|
||||
// const hasContent = !this.node.type.isAtom
|
||||
get dom() {
|
||||
return this.renderer.element
|
||||
// return this.domWrapper
|
||||
|
||||
// if (!hasContent) {
|
||||
// return null
|
||||
// }
|
||||
// if (!this.renderer.element) {
|
||||
// return null
|
||||
// }
|
||||
|
||||
// const contentElement = this.dom.querySelector('[data-node-view-content]')
|
||||
// if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
|
||||
// throw Error('Please use the NodeViewWrapper component for your node view.')
|
||||
// }
|
||||
|
||||
// return contentElement || this.dom
|
||||
// }
|
||||
// return this.renderer.element
|
||||
}
|
||||
|
||||
// stopEvent(event: Event) {
|
||||
// if (typeof this.options.stopEvent === 'function') {
|
||||
// return this.options.stopEvent(event)
|
||||
// }
|
||||
get contentDOM() {
|
||||
// return this.renderer.element
|
||||
return undefined
|
||||
// return this.renderer.element
|
||||
// return this.contentDOMWrapper
|
||||
|
||||
// const target = (event.target as HTMLElement)
|
||||
// const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target)
|
||||
// console.log(this.dom)
|
||||
// return null
|
||||
// if (!this.renderer.element) {
|
||||
// return null
|
||||
// }
|
||||
|
||||
// // ignore all events from child nodes
|
||||
// if (!isInElement) {
|
||||
// return false
|
||||
// }
|
||||
// const hasContent = !this.node.type.isAtom
|
||||
|
||||
// const { isEditable } = this.editor
|
||||
// const { isDragging } = this
|
||||
// const isDraggable = !!this.node.type.spec.draggable
|
||||
// const isSelectable = NodeSelection.isSelectable(this.node)
|
||||
// const isCopyEvent = event.type === 'copy'
|
||||
// const isPasteEvent = event.type === 'paste'
|
||||
// const isCutEvent = event.type === 'cut'
|
||||
// const isClickEvent = event.type === 'mousedown'
|
||||
// const isDragEvent = event.type.startsWith('drag') || event.type === 'drop'
|
||||
// if (!hasContent) {
|
||||
// return null
|
||||
// }
|
||||
|
||||
// // ProseMirror tries to drag selectable nodes
|
||||
// // even if `draggable` is set to `false`
|
||||
// // this fix prevents that
|
||||
// if (!isDraggable && isSelectable && isDragEvent) {
|
||||
// event.preventDefault()
|
||||
// }
|
||||
// const contentElement = this.dom.querySelector('[data-node-view-content]')
|
||||
|
||||
// if (isDraggable && isDragEvent && !isDragging) {
|
||||
// event.preventDefault()
|
||||
// return false
|
||||
// }
|
||||
// return contentElement || this.dom
|
||||
}
|
||||
|
||||
// // we have to store that dragging started
|
||||
// if (isDraggable && isEditable && !isDragging && isClickEvent) {
|
||||
// const dragHandle = target.closest('[data-drag-handle]')
|
||||
// const isValidDragHandle = dragHandle
|
||||
// && (this.dom === dragHandle || (this.dom.contains(dragHandle)))
|
||||
stopEvent(event: Event) {
|
||||
if (typeof this.options.stopEvent === 'function') {
|
||||
return this.options.stopEvent(event)
|
||||
}
|
||||
|
||||
// if (isValidDragHandle) {
|
||||
// this.isDragging = true
|
||||
// document.addEventListener('dragend', () => {
|
||||
// this.isDragging = false
|
||||
// }, { once: true })
|
||||
// }
|
||||
// }
|
||||
const target = (event.target as HTMLElement)
|
||||
const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target)
|
||||
|
||||
// // these events are handled by prosemirror
|
||||
// if (
|
||||
// isDragging
|
||||
// || isCopyEvent
|
||||
// || isPasteEvent
|
||||
// || isCutEvent
|
||||
// || (isClickEvent && isSelectable)
|
||||
// ) {
|
||||
// return false
|
||||
// }
|
||||
// ignore all events from child nodes
|
||||
if (!isInElement) {
|
||||
return false
|
||||
}
|
||||
|
||||
// return true
|
||||
// }
|
||||
const { isEditable } = this.editor
|
||||
const { isDragging } = this
|
||||
const isDraggable = !!this.node.type.spec.draggable
|
||||
const isSelectable = NodeSelection.isSelectable(this.node)
|
||||
const isCopyEvent = event.type === 'copy'
|
||||
const isPasteEvent = event.type === 'paste'
|
||||
const isCutEvent = event.type === 'cut'
|
||||
const isClickEvent = event.type === 'mousedown'
|
||||
const isDragEvent = event.type.startsWith('drag') || event.type === 'drop'
|
||||
|
||||
// ignoreMutation(mutation: MutationRecord | { type: 'selection'; target: Element }) {
|
||||
// if (mutation.type === 'selection') {
|
||||
// if (this.node.isLeaf) {
|
||||
// return true
|
||||
// }
|
||||
// ProseMirror tries to drag selectable nodes
|
||||
// even if `draggable` is set to `false`
|
||||
// this fix prevents that
|
||||
if (!isDraggable && isSelectable && isDragEvent) {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
// return false
|
||||
// }
|
||||
if (isDraggable && isDragEvent && !isDragging) {
|
||||
event.preventDefault()
|
||||
return false
|
||||
}
|
||||
|
||||
// if (!this.contentDOM) {
|
||||
// return true
|
||||
// }
|
||||
// we have to store that dragging started
|
||||
if (isDraggable && isEditable && !isDragging && isClickEvent) {
|
||||
const dragHandle = target.closest('[data-drag-handle]')
|
||||
const isValidDragHandle = dragHandle
|
||||
&& (this.dom === dragHandle || (this.dom.contains(dragHandle)))
|
||||
|
||||
// const contentDOMHasChanged = !this.contentDOM.contains(mutation.target)
|
||||
// || this.contentDOM === mutation.target
|
||||
if (isValidDragHandle) {
|
||||
this.isDragging = true
|
||||
document.addEventListener('dragend', () => {
|
||||
this.isDragging = false
|
||||
}, { once: true })
|
||||
}
|
||||
}
|
||||
|
||||
// return contentDOMHasChanged
|
||||
// }
|
||||
// these events are handled by prosemirror
|
||||
if (
|
||||
isDragging
|
||||
|| isCopyEvent
|
||||
|| isPasteEvent
|
||||
|| isCutEvent
|
||||
|| (isClickEvent && isSelectable)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
// destroy() {
|
||||
// this.renderer.destroy()
|
||||
// }
|
||||
return true
|
||||
}
|
||||
|
||||
// update(node: ProseMirrorNode, decorations: Decoration[]) {
|
||||
// if (typeof this.options.update === 'function') {
|
||||
// return this.options.update(node, decorations)
|
||||
// }
|
||||
ignoreMutation(mutation: MutationRecord | { type: 'selection'; target: Element }) {
|
||||
if (mutation.type === 'selection') {
|
||||
if (this.node.isLeaf) {
|
||||
return true
|
||||
}
|
||||
|
||||
// if (node.type !== this.node.type) {
|
||||
// return false
|
||||
// }
|
||||
return false
|
||||
}
|
||||
|
||||
// if (node === this.node && this.decorations === decorations) {
|
||||
// return true
|
||||
// }
|
||||
if (!this.contentDOM) {
|
||||
return true
|
||||
}
|
||||
|
||||
// this.node = node
|
||||
// this.decorations = decorations
|
||||
// // this.renderer.updateProps({ node, decorations })
|
||||
// this.renderer.render()
|
||||
const contentDOMHasChanged = !this.contentDOM.contains(mutation.target)
|
||||
|| this.contentDOM === mutation.target
|
||||
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
return contentDOMHasChanged
|
||||
}
|
||||
|
||||
// export function ReactNodeViewRenderer(component: any, options?: Partial<ReactNodeViewRendererOptions>): NodeViewRenderer {
|
||||
// return (props: NodeViewRendererProps) => {
|
||||
// // try to get the parent component
|
||||
// // this is important for vue devtools to show the component hierarchy correctly
|
||||
// // maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
||||
// if (!(props.editor as Editor).contentComponent) {
|
||||
// return {}
|
||||
// }
|
||||
destroy() {
|
||||
this.renderer.destroy()
|
||||
}
|
||||
|
||||
// return new ReactNodeView(component, props, options) as NodeView
|
||||
// }
|
||||
// }
|
||||
update(node: ProseMirrorNode, decorations: Decoration[]) {
|
||||
if (typeof this.options.update === 'function') {
|
||||
return this.options.update(node, decorations)
|
||||
}
|
||||
|
||||
if (node.type !== this.node.type) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (node === this.node && this.decorations === decorations) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.node = node
|
||||
this.decorations = decorations
|
||||
this.renderer.updateProps({ node, decorations })
|
||||
this.renderer.render()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
selectNode() {
|
||||
this.renderer.updateProps({
|
||||
selected: true,
|
||||
})
|
||||
}
|
||||
|
||||
deselectNode() {
|
||||
this.renderer.updateProps({
|
||||
selected: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function ReactNodeViewRenderer(component: any, options?: Partial<ReactNodeViewRendererOptions>): NodeViewRenderer {
|
||||
return (props: NodeViewRendererProps) => {
|
||||
// try to get the parent component
|
||||
// this is important for vue devtools to show the component hierarchy correctly
|
||||
// maybe it’s `undefined` because <editor-content> isn’t rendered yet
|
||||
if (!(props.editor as Editor).contentComponent) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return new ReactNodeView(component, props, options) as NodeView
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,91 @@
|
||||
// // @ts-nocheck
|
||||
// @ts-nocheck
|
||||
|
||||
// import React from 'react'
|
||||
// import { render, unmountComponentAtNode } from 'react-dom'
|
||||
import React from 'react'
|
||||
import ReactDOM, { render, unmountComponentAtNode } from 'react-dom'
|
||||
|
||||
// import { Editor } from './Editor'
|
||||
import { Editor } from './Editor'
|
||||
|
||||
// export interface VueRendererOptions {
|
||||
// as?: string;
|
||||
// editor: Editor;
|
||||
// props?: { [key: string]: any };
|
||||
// }
|
||||
export interface VueRendererOptions {
|
||||
as?: string;
|
||||
editor: Editor;
|
||||
props?: { [key: string]: any };
|
||||
}
|
||||
|
||||
// export class ReactRenderer {
|
||||
// id: string
|
||||
export class ReactRenderer {
|
||||
id: string
|
||||
|
||||
// editor: Editor
|
||||
editor: Editor
|
||||
|
||||
// component: any
|
||||
component: any
|
||||
|
||||
// teleportElement: Element
|
||||
teleportElement: Element
|
||||
|
||||
// element: Element
|
||||
element: Element
|
||||
|
||||
// props: { [key: string]: any }
|
||||
props: { [key: string]: any }
|
||||
|
||||
// constructor(component: any, { props = {}, editor }: VueRendererOptions) {
|
||||
// this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
||||
// this.component = component
|
||||
// this.editor = editor
|
||||
// this.props = props
|
||||
constructor(component: any, { props = {}, editor }: VueRendererOptions) {
|
||||
this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
|
||||
this.component = component
|
||||
this.editor = editor
|
||||
this.props = props
|
||||
|
||||
// this.teleportElement = document.createElement('div')
|
||||
// // this.teleportElement.setAttribute('data-bla', '')
|
||||
// // render(React.createElement(component), this.teleportElement)
|
||||
// // render(React.createElement(component), this.teleportElement)
|
||||
// this.render()
|
||||
// // this.element = this.teleportElement.firstElementChild as Element
|
||||
// this.element = this.teleportElement
|
||||
// }
|
||||
this.teleportElement = document.createElement('div')
|
||||
this.teleportElement.classList.add('teleport-element')
|
||||
this.element = this.teleportElement
|
||||
|
||||
// render() {
|
||||
// render(React.createElement(this.component), this.teleportElement)
|
||||
// }
|
||||
// this.teleportElement.setAttribute('data-bla', '')
|
||||
// render(React.createElement(component), this.teleportElement)
|
||||
// render(React.createElement(component), this.teleportElement)
|
||||
// this.render()
|
||||
// // this.element = this.teleportElement.firstElementChild as Element
|
||||
|
||||
// updateProps(props: { [key: string]: any } = {}) {
|
||||
// // TODO
|
||||
// }
|
||||
console.log({ props })
|
||||
|
||||
// destroy() {
|
||||
// // TODO
|
||||
// // console.log('DESTROY', { bla: this.teleportElement })
|
||||
// // console.log(document.querySelector('[data-bla]'))
|
||||
// unmountComponentAtNode(this.teleportElement)
|
||||
// // unmountComponentAtNode(document.querySelector('[data-bla]'))
|
||||
// }
|
||||
// this.bla = ReactDOM.createPortal(
|
||||
// React.createElement(this.component, props),
|
||||
// this.teleportElement,
|
||||
// )
|
||||
|
||||
// }
|
||||
this.bla = React.createElement(this.component, props)
|
||||
|
||||
// console.log({ bla })
|
||||
|
||||
if (this.editor?.contentComponent) {
|
||||
this.editor.contentComponent.setState({
|
||||
renderers: this.editor.contentComponent.state.renderers.set(
|
||||
this.id,
|
||||
this,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render(React.createElement(this.component), this.teleportElement)
|
||||
}
|
||||
|
||||
updateProps(props: { [key: string]: any } = {}) {
|
||||
// TODO
|
||||
console.log('update props', { props })
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// TODO
|
||||
// console.log('DESTROY', { bla: this.teleportElement })
|
||||
// console.log(document.querySelector('[data-bla]'))
|
||||
// unmountComponentAtNode(this.teleportElement)
|
||||
// unmountComponentAtNode(document.querySelector('[data-bla]'))
|
||||
|
||||
if (this.editor?.contentComponent) {
|
||||
const { renderers } = this.editor.contentComponent.state
|
||||
|
||||
renderers.delete(this.id)
|
||||
|
||||
this.editor.contentComponent.setState({
|
||||
renderers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
export * from '@tiptap/core'
|
||||
export { Editor } from './Editor'
|
||||
export * from './useEditor'
|
||||
// export * from './ReactRenderer'
|
||||
// export * from './ReactNodeViewRenderer'
|
||||
export * from './ReactRenderer'
|
||||
export * from './ReactNodeViewRenderer'
|
||||
export * from './EditorContent'
|
||||
|
||||
Reference in New Issue
Block a user