import { default as React } from 'react'; import { JSONContent } from '@tiptap/react'; import { Editor, Extensions } from '@tiptap/core'; import { OpenImagePicker } from './utils/mediaPicker'; export interface NotionEditorProps { content?: string | JSONContent; initialContent?: string | JSONContent; onChange?: (content: string) => void; /** * Hands the live Tiptap instance to the host application. * * The editor is otherwise completely sealed: `useEditor` owns the instance, * nothing forwards a ref, and there is no context provider, so a sibling of * this component has historically had exactly one way to reach the editor — * the `window.__nextblockEditor` global assigned further down this file. That * global is a genuine race as soon as two editors are mounted at once (a * block editor modal opened over a page that already renders one), because * the last mount silently wins and the loser's unmount can delete the * winner's entry. Anything that needs *this* editor rather than *an* editor * should take it from here instead; the global stays in place because other * code still reads it. * * Called with the instance once `useEditor` has produced one, and with `null` * on unmount so the host can drop its reference rather than hold a detached * ProseMirror view alive. The callback is read through a ref internally, so * an inline arrow function is safe to pass: a new identity on every parent * render will not re-fire the effect and produce a null/instance flapping * sequence. */ onEditorReady?: (editor: Editor | null) => void; onUpdate?: (content: JSONContent) => void; placeholder?: string; editable?: boolean; showToolbar?: boolean; showAiPrompt?: boolean; showCharacterCount?: boolean; /** * Optional companion UI rendered beside the writing surface — the CMS uses it * for the live SEO audit, which has to sit next to the prose it is grading * rather than in a dialog the author has to leave the document to open. * * This library cannot import anything application-specific (it declares no * dependencies, ships as a client bundle, and must not reach into * `apps/nextblock`), so the panel is injected as a node rather than * configured through a flag — the same idiom as `openImagePicker`. * * When omitted the component renders exactly the tree it always has: no extra * wrapper element, no changed class list on the root, and therefore no layout * shift for the callers that never pass it. The two-column layout only comes * into existence when there is something to put in the second column. */ sidePanel?: React.ReactNode; className?: string; onFocus?: () => void; onBlur?: () => void; openImagePicker?: OpenImagePicker; extensions?: Extensions; dynamicExtensions?: Extensions; } export declare const NotionEditor: React.FC; export default NotionEditor;