Open vadimkantorov opened 8 months ago
I hoped I could get it working with:
import * as React from 'react';
window.LexicalMarkdownEditor = query_selector =>
{
const htmlElem = document.querySelector(query_selector) as HTMLElement;
const root = createRoot(htmlElem);
const initialConfig = {
editorState: null, // undefined?
//editorState: () => {
// $convertFromMarkdownString(markdown, TRANSFORMERS);
//},
namespace: 'Playground',
nodes: [...PlaygroundNodes],
onError: (error: Error) => {
throw error;
},
theme: PlaygroundEditorTheme,
};
// fails with TypeError: Cannot read properties of null (reading 'useRef')
//const myRef = React.useRef(null);
const app = (
<LexicalComposer initialConfig={initialConfig}>
<TableContext>
<div className="editor-shell">
<EditorOnly showTreeView={false} showActions={false} />
</div>
</TableContext>
</LexicalComposer>
);
// fails with TypeError: Cannot read properties of null (reading 'useEffect')
//React.useEffect(() => console.log('window.LexicalMarkdownEditor2', myRef));
console.log('window.LexicalMarkdownEditor1', app)
const res = root.render(app);
console.log('window.LexicalMarkdownEditor3', res)
return app;
}
but both useRef
(to get an instance to the rendered JSX component instance) and useEffect
(to get a notification when the component is mounted and ready) fail with an extremely strange error which I cannot resolve (despite both useRef
/useEffect
being employed in other tsx files without issues)...
I've tried using createRef
instead of useRef
:
window.myRef = React.createRef(null);
const res = root.render(
<LexicalComposer initialConfig={initialConfig} ref={window.myRef}>
<TableContext>
<div className="editor-shell">
<EditorOnly showTreeView={false} showActions={false} />
</div>
</TableContext>
</LexicalComposer>
);
This does not error out, but window.myRef.current
is always null.
I realized that the component instance might not be ready right away. Is it true?
I've also tried adding ref={(myRef) => console.log('window.LexicalMarkdownEditor2', myRef)}
, but it's not triggered.
How can I get a notification when the editor is ready (for calling instance methods like setEditorState
/getEditorState
) and get its instance?
Thank you!
I've also tried an alternative route of using class component. This prints both window.LexicalMarkdownEditor3
and window.LexicalMarkdownEditor4
(as opposed to my other attempts using function components), but none of them have access to the instance of LexicalComposer
:( Still looking for a way to get hands on this instance :)
class AppEditorOnly extends React.Component
{
componentDidMount()
{
console.log('window.LexicalMarkdownEditor3', this);
}
render()
{
return <LexicalComposer initialConfig={this.props.initialConfig} ref={(myRef) => console.log('window.LexicalMarkdownEditor4', myRef)}>
<TableContext>
<div className="editor-shell">
<EditorOnly showTreeView={false} showActions={false} />
</div>
</TableContext>
</LexicalComposer>
}
}
window.LexicalMarkdownEditor = query_selector =>
{
const root = createRoot(document.querySelector(query_selector) as HTMLElement);
const initialConfig = {
editorState: null, // undefined?
//editorState: () => {
// $convertFromMarkdownString(markdown, TRANSFORMERS);
//},
namespace: 'Playground',
nodes: [...PlaygroundNodes],
onError: (error: Error) => {
throw error;
},
theme: PlaygroundEditorTheme,
};
const res = root.render(
<AppEditorOnly initialConfig={initialConfig} />
);
return null;
}
Replacing it with the code below doesn't print anything useful either (when componentDidMount
triggers, this.myRef
contains only {current: null}
):
class AppEditorOnly extends React.Component
{
constructor()
{
super();
this.myRef = React.createRef();
}
componentDidMount()
{
console.log('window.LexicalMarkdownEditor3', this.myRef);
}
render()
{
return <LexicalComposer initialConfig={this.props.initialConfig} ref={this.myRef}>
<TableContext>
<div className="editor-shell">
<EditorOnly showTreeView={false} showActions={false} />
</div>
</TableContext>
</LexicalComposer>
}
}
I found a workaround, but this is obviously a crazy hack, and there must be a proper solution (via refs? via class-based component? via createEffect?). I hope that React-savvy people can easily spot what I was doing wrong! It would be great to have a proper way of getting notified of a the readiness of an editor instance and get this instance as output (i.e. the promise-based return value, of the kind I'm using below)
window.LexicalMarkdownEditor = query_selector =>
{
const root = createRoot(document.querySelector(query_selector) as HTMLElement);
const initialConfig = {
editorState: null, // undefined?
//editorState: () => {
// $convertFromMarkdownString(markdown, TRANSFORMERS);
//},
namespace: 'Playground',
nodes: [...PlaygroundNodes],
onError: (error: Error) => {
throw error;
},
theme: PlaygroundEditorTheme,
};
let resolveEditor = null;
const resultPromise = new Promise((resolve, reject) => {resolveEditor = resolve});
const GetLexicalComposerContext = () =>
{
const [editor] = useLexicalComposerContext();
resolveEditor(editor);
return null;
}
root.render(
<LexicalComposer initialConfig={initialConfig}>
<TableContext>
<div className="editor-shell">
<EditorOnly showTreeView={false} showActions={false} />
</div>
</TableContext>
<GetLexicalComposerContext />
</LexicalComposer>
);
return resultPromise;
}
Should I try instead https://lexical.dev/docs/react/plugins#lexicaleditorrefplugin in place of GetLexicalComposerContext
?
I'm building a single-user, rich-text editor using playground as a starting point. My editor would be used in a React-less / vanilla JavaScript callee script. I'm not a front-end dev (in most likelihood, I'm hitting some react-beginner mistakes), so I'm lacking basic React understanding, but I almost managed to create a custom React-based lexical-based editor control.
I created two files with source below. In my final consuming file I have (modulo copying the
assets
dir). Currently, the editor loads okay, but I don't seegetEditorState
on thewindow.editor
andwindow.LexicalMarkdownEditor_getEditor()
throws some cryptic error (which I'm not able to decrypt because I managed to build onlyvite.prod.config.js
) which might mean that I cannot useuseLexicalComposerContext
as a free function).How can I get an instance with methods like
getEditorState
/setEditorState
out of theapp
instance (i.e. get notified when the component was mounted and get a component instance back)?Thank you very much!
Error:
and