import { defineNodeViewComponent, defineNodeViewFactory, type Extension } from '@prosekit/core' import type { CoreNodeViewUserOptions } from '@prosemirror-adapter/core' import { AbstractReactNodeView, buildReactNodeViewCreator, type NodeViewContext, type ReactRendererResult, } from '@prosemirror-adapter/react' import { createElement, type ComponentType, type ReactPortal } from 'react' import { createPortal } from 'react-dom' export interface ReactNodeViewProps extends NodeViewContext {} export type ReactNodeViewComponent = ComponentType /** * Options for {@link defineReactNodeView}. */ export interface ReactNodeViewOptions extends CoreNodeViewUserOptions { /** * The name of the node type. */ name: string } class ProseKitReactNodeView extends AbstractReactNodeView { render = (): ReactPortal => { const UserComponent = this.component const props = { ...this.context } return createPortal( createElement(UserComponent, props), this.dom, this.key, ) } } /** * @internal */ export function defineReactNodeViewFactory( renderReactRenderer: ReactRendererResult['renderReactRenderer'], removeReactRenderer: ReactRendererResult['removeReactRenderer'], ): Extension { const factory = buildReactNodeViewCreator(renderReactRenderer, removeReactRenderer, ProseKitReactNodeView) return defineNodeViewFactory({ group: 'react', factory, }) } /** * Defines a node view using a React component. */ export function defineReactNodeView(options: ReactNodeViewOptions): Extension { return defineNodeViewComponent({ group: 'react', name: options.name, args: options, }) }