import { Editor } from '@tiptap/core' import React from 'react' import { Editor as ExtendedEditor } from './Editor.js' function isClassComponent(Component: any) { return !!( typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent ) } function isForwardRefComponent(Component: any) { return !!( typeof Component === 'object' && Component.$$typeof?.toString() === 'Symbol(react.forward_ref)' ) } export interface ReactRendererOptions { editor: Editor, props?: Record, as?: string, className?: string, attrs?: Record, } type ComponentType = React.ComponentClass

| React.FunctionComponent

| React.ForwardRefExoticComponent & React.RefAttributes>; export class ReactRenderer { id: string editor: ExtendedEditor component: any element: Element props: Record reactElement: React.ReactNode ref: R | null = null constructor(component: ComponentType, { editor, props = {}, as = 'div', className = '', attrs, }: ReactRendererOptions) { this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString() this.component = component this.editor = editor as ExtendedEditor this.props = props this.element = document.createElement(as) this.element.classList.add('react-renderer') if (className) { this.element.classList.add(...className.split(' ')) } if (attrs) { Object.keys(attrs).forEach(key => { this.element.setAttribute(key, attrs[key]) }) } this.render() } render(): void { const Component = this.component const props = this.props if (isClassComponent(Component) || isForwardRefComponent(Component)) { props.ref = (ref: R) => { this.ref = ref } } this.reactElement = this.editor?.contentComponent?.setRenderer(this.id, this) } updateProps(props: Record = {}): void { this.props = { ...this.props, ...props, } this.render() } destroy(): void { this.editor?.contentComponent?.removeRenderer(this.id) } }