import { MantineThemeOverride } from "@mantine/core"; import { TippyProps } from "@tippyjs/react"; import { EditorElement, RequiredDynamicParams } from "bocknoat-core"; import { FC } from "react"; import { createRoot } from "react-dom/client"; import { EditorElementComponentWrapper } from "./EditorElementComponentWrapper"; /** * The ReactElementFactory is a generic function used to create all other ElementFactories, which are then used in the * BlockNote editor. The type of ElementFactory created depends on the provided ElementStaticParams and * ElementDynamicParams, which determine what static/dynamic properties are used in rendering the element. * ElementStaticParams are initialized when the editor mounts and do not change, while ElementDynamicParams change based * on the editor state. * * @param staticParams Properties used in rendering the element which do not change, regardless of editor state. * @param EditorElementComponent The element to render, which is a React component. Takes EditorStaticParams and * EditorDynamicParams as props. * @param theme The Mantine theme used to style the element. * @param tippyProps Tippy props, which affect the elements' popup behaviour, e.g. popup position, animation, etc. */ export const ReactElementFactory = < ElementStaticParams extends Record, ElementDynamicParams extends RequiredDynamicParams >( staticParams: ElementStaticParams, EditorElementComponent: FC, theme: MantineThemeOverride, tippyProps?: TippyProps ): EditorElement => { const rootElement = document.createElement("div"); const root = createRoot(rootElement); // Used when hiding the element. If we were to pass in undefined instead, the element would be immediately cleared, not // leaving time for the fade out animation to complete. let prevDynamicParams: ElementDynamicParams | undefined = undefined; return { element: rootElement, render: (dynamicParams: ElementDynamicParams, _isHidden: boolean) => { prevDynamicParams = dynamicParams; root.render( ); }, hide: () => { root.render( ); }, }; };