diff --git a/src/MDXEditor.tsx b/src/MDXEditor.tsx index 066c77da..eff097f5 100644 --- a/src/MDXEditor.tsx +++ b/src/MDXEditor.tsx @@ -1,4 +1,4 @@ -import { useCellValues, usePublisher, useRealm } from '@mdxeditor/gurx' +import { useCellValue, useCellValues, usePublisher, useRealm } from '@mdxeditor/gurx' import React from 'react' import { RealmPlugin, RealmWithPlugins } from './RealmWithPlugins' import { @@ -8,20 +8,16 @@ import { corePlugin, editorRootElementRef$, editorWrappers$, - initialRootEditorState$, insertMarkdown$, markdown$, markdownSourceEditorValue$, placeholder$, - readOnly$, rootEditor$, setMarkdown$, topAreaChildren$, - usedLexicalNodes$, viewMode$ } from './plugins/core' -import { LexicalComposer } from '@lexical/react/LexicalComposer.js' import { ContentEditable } from '@lexical/react/LexicalContentEditable.js' import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary.js' import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin.js' @@ -31,27 +27,18 @@ import { IconKey } from './plugins/core/Icon' import { lexicalTheme } from './styles/lexicalTheme' import styles from './styles/ui.module.css' import { noop } from './utils/fp' +import { createLexicalComposerContext, LexicalComposerContext, LexicalComposerContextType } from '@lexical/react/LexicalComposerContext' +import { LexicalEditor } from 'lexical' const LexicalProvider: React.FC<{ children: JSX.Element | string | (JSX.Element | string)[] }> = ({ children }) => { - const [initialRootEditorState, nodes, readOnly] = useCellValues(initialRootEditorState$, usedLexicalNodes$, readOnly$) - return ( - { - throw error - } - }} - > - {children} - - ) + const rootEditor = useCellValue(rootEditor$)! + const composerContextValue = React.useMemo(() => { + return [rootEditor, createLexicalComposerContext(null, lexicalTheme)] as [LexicalEditor, LexicalComposerContextType] + }, [rootEditor]) + + return {children} } const RichTextEditor: React.FC = () => { diff --git a/src/RealmWithPlugins.tsx b/src/RealmWithPlugins.tsx index 1517468d..099a8026 100644 --- a/src/RealmWithPlugins.tsx +++ b/src/RealmWithPlugins.tsx @@ -9,6 +9,7 @@ import { tap } from './utils/fp' export interface RealmPlugin { init?: (realm: Realm) => void update?: (realm: Realm) => void + postInit?: (realm: Realm) => void } /** @@ -21,6 +22,11 @@ export function realmPlugin(plugin: { * Called when the MDXEditor component is mounted and the plugin is initialized. */ init?: (realm: Realm, params?: Params) => void + + /** + * Called after the MDXEditor component is mounted and all plugins are initialized. + */ + postInit?: (realm: Realm, params?: Params) => void /** * Called on each re-render. Use this to update the realm with updated property values. */ @@ -29,6 +35,7 @@ export function realmPlugin(plugin: { return function (params?: Params) { return { init: (realm: Realm) => plugin.init?.(realm, params), + postInit: (realm: Realm) => plugin.postInit?.(realm, params), update: (realm: Realm) => plugin.update?.(realm, params) } } @@ -41,6 +48,9 @@ export function RealmWithPlugins({ children, plugins }: { children: React.ReactN for (const plugin of plugins) { plugin.init?.(r) } + for (const plugin of plugins) { + plugin.postInit?.(r) + } }) // eslint-disable-next-line react-hooks/exhaustive-deps }, []) diff --git a/src/plugins/core/index.ts b/src/plugins/core/index.ts index c8a8f150..3be2a138 100644 --- a/src/plugins/core/index.ts +++ b/src/plugins/core/index.ts @@ -1,5 +1,4 @@ import { realmPlugin } from '../../RealmWithPlugins' -import { InitialEditorStateType } from '@lexical/react/LexicalComposer.js' import { createEmptyHistoryState } from '@lexical/react/LexicalHistoryPlugin.js' import { $isHeadingNode, HeadingTagType } from '@lexical/rich-text' import { $setBlocksType } from '@lexical/selection' @@ -29,7 +28,8 @@ import { SELECTION_CHANGE_COMMAND, TextFormatType, TextNode, - createCommand + createCommand, + createEditor } from 'lexical' import * as Mdast from 'mdast' @@ -68,6 +68,7 @@ import { DirectiveDescriptor } from '../directives' import { CodeBlockEditorDescriptor } from '../codeblock' import { Directives } from 'mdast-util-directive' import { comment, commentFromMarkdown } from '../../mdastUtilHtmlComment' +import { lexicalTheme } from '../../styles/lexicalTheme' export * from './MdastHTMLNode' export * from './GenericHTMLNode' export * from './Icon' @@ -636,31 +637,6 @@ function tryImportingMarkdown(r: Realm, node: ImportPoint, markdownValue: string } } -// gets bound to the root editor state getter -/** @internal */ -export const initialRootEditorState$ = Cell(null, (r) => { - r.pub(initialRootEditorState$, (theRootEditor) => { - r.pub(rootEditor$, theRootEditor) - r.pub(activeEditor$, theRootEditor) - - tryImportingMarkdown(r, $getRoot(), r.getValue(initialMarkdown$)) - - const autoFocusValue = r.getValue(autoFocus$) - if (autoFocusValue) { - if (autoFocusValue === true) { - // Default 'on' state - setTimeout(() => theRootEditor.focus(noop, { defaultSelection: 'rootStart' })) - return - } - setTimeout(() => - theRootEditor.focus(noop, { - defaultSelection: autoFocusValue.defaultSelection ?? 'rootStart' - }) - ) - } - }) -}) - /** @internal */ export const composerChildren$ = Cell([]) @@ -901,6 +877,42 @@ export const corePlugin = realmPlugin<{ } }, + postInit(r, params) { + const newEditor = createEditor({ + editable: params?.readOnly !== true, + namespace: 'MDXEditor', + nodes: r.getValue(usedLexicalNodes$), + onError: (error) => { + throw error + }, + theme: lexicalTheme + }) + + newEditor.update(() => { + const markdown = params?.initialMarkdown.trim() + if (markdown) { + tryImportingMarkdown(r, $getRoot(), markdown) + } + + const autoFocusValue = params?.autoFocus + if (autoFocusValue) { + if (autoFocusValue === true) { + // Default 'on' state + setTimeout(() => newEditor.focus(noop, { defaultSelection: 'rootStart' })) + return + } + setTimeout(() => + newEditor.focus(noop, { + defaultSelection: autoFocusValue.defaultSelection ?? 'rootStart' + }) + ) + } + }) + + r.pub(rootEditor$, newEditor) + r.pub(activeEditor$, newEditor) + }, + update(realm, params) { realm.pubIn({ [contentEditableClassName$]: params?.contentEditableClassName,