S
SolidJS•2y ago
Mant

Lexical (or another)

Hi, I tried to make a poc with Lexical again. Did you also have a bug that blocks the delete? Or did I do something wrong? (my goal is to do like discord, everything is displayed with only a visual improvement) @foolswisdom
const ExampleTheme: EditorThemeClasses = {
ltr: "ltr",
rtl: "rtl",
placeholder: "editor-placeholder",
paragraph: "editor-paragraph",
text: {
bold: "editor-text-bold",
italic: "editor-text-italic",
},
};

function Placeholder() {
return <div class="editor-placeholder">Enter some plain text...</div>;
}

function onChange(editorState: EditorState, editor: LexicalEditor) {
editorState.read(() => {
// Read the contents of the EditorState here.
const root = $getRoot();
const selection = $getSelection();

console.log(root, selection);
});
}

export default function TextareaAuto(props: {
ref_scroll: HTMLElement | undefined,
value: string,
placeholder: string,
class: string,
onChange: (e: any) => void,
onInput: (e: string) => void,
onFocus: () => void,
onClick?: () => void,
}) {
const editorConfig = {
theme: ExampleTheme,
namespace: "",
onError(error: any) {
throw error;
},
// editorState: () => $convertFromMarkdownString(props.value, TRANSFORMERS),
};

return (
<LexicalComposer initialConfig={editorConfig}>
<div class="editor-container">
<div class="editor-inner">
<RichTextPlugin
contentEditable={<ContentEditable class="editor-input" />}
placeholder={<Placeholder />}
errorBoundary={LexicalErrorBoundary}
/>
<TreeViewPlugin />
<OnChangePlugin onChange={onChange} />
</div>
</div>
</LexicalComposer>
);
}
const ExampleTheme: EditorThemeClasses = {
ltr: "ltr",
rtl: "rtl",
placeholder: "editor-placeholder",
paragraph: "editor-paragraph",
text: {
bold: "editor-text-bold",
italic: "editor-text-italic",
},
};

function Placeholder() {
return <div class="editor-placeholder">Enter some plain text...</div>;
}

function onChange(editorState: EditorState, editor: LexicalEditor) {
editorState.read(() => {
// Read the contents of the EditorState here.
const root = $getRoot();
const selection = $getSelection();

console.log(root, selection);
});
}

export default function TextareaAuto(props: {
ref_scroll: HTMLElement | undefined,
value: string,
placeholder: string,
class: string,
onChange: (e: any) => void,
onInput: (e: string) => void,
onFocus: () => void,
onClick?: () => void,
}) {
const editorConfig = {
theme: ExampleTheme,
namespace: "",
onError(error: any) {
throw error;
},
// editorState: () => $convertFromMarkdownString(props.value, TRANSFORMERS),
};

return (
<LexicalComposer initialConfig={editorConfig}>
<div class="editor-container">
<div class="editor-inner">
<RichTextPlugin
contentEditable={<ContentEditable class="editor-input" />}
placeholder={<Placeholder />}
errorBoundary={LexicalErrorBoundary}
/>
<TreeViewPlugin />
<OnChangePlugin onChange={onChange} />
</div>
</div>
</LexicalComposer>
);
}
24 Replies
foolswisdom
foolswisdom•2y ago
Hey! I didn't notice such a bug in my personal projects, and I unfortunately won't be near my computer until late this evening, so it will be difficult for me to offer support. It does seem like your code is pretty basic, so I can't imagine the issue Do you mind confirming the lexical-solid version you are using? (I assume you're using the latest)
Mant
MantOP•2y ago
yes the 0.3.2, no worries, if I manage to unblock myself between so many ^^ I don't know what happened, but after reinstalling and restarting quickly the bug disappeared, a failed build must have been left in the cache. My next step is to pass the value that uses a signal. string -> Lexical -> string -> Lexical. If you have an idea I'm quite interested
foolswisdom
foolswisdom•2y ago
You mean like a controlled input? There was a bug in previous versions of 0.3.x btw That broke the editor
Mant
MantOP•2y ago
no it's more that I use redux to centralize the modifications and the multi user.
foolswisdom
foolswisdom•2y ago
Generally it's best to let lexical manage state, and it you need to control the input, to use either a node transform or an update listener https://lexical.dev/docs/intro#listeners-node-transforms-and-commands
Introduction | Lexical
Lexical is an extensible JavaScript web text-editor framework with an emphasis on reliability, accessibility, and performance. Lexical aims to provide a best-in-class developer experience, so you can easily prototype and build features with confidence. Combined with a highly extensible architecture, Lexical allows developers to create unique tex...
foolswisdom
foolswisdom•2y ago
You're using a custom sync solution? (since you mentioned multi user)
Mant
MantOP•2y ago
Yes, I synchronise with the server, which returns the changes.
foolswisdom
foolswisdom•2y ago
I see So, the thing about this is that you could easily make an effect that updates the editor state based on the new value. You just need to make sure that yoy handle the selection state correctly (you don't want the cursor jumping to the end or beginning on every edit...) The alternative approach would be to use the yjs plugin, using yjs to synchronize. I have honestly not tested the yjs implementation in lexical-solid yet, so while it should work... I have no idea if it actually does But that may be more than you are willing to take on
Mant
MantOP•2y ago
I had a quick look at yjs, it's true that it looks really practical, after a little fear of being trapped. The solution of building an effect seems more simple my project is made for annotating pdf's. So I have lots of little editors.
foolswisdom
foolswisdom•2y ago
Well, whichever option you choose, let me know how it goes
Mant
MantOP•2y ago
Hi, I managed to move forward, not incredible but it seems to work a little bit. 😀 I was inspired by the hashtag and am turning everything into text.. I don't really understand why the value is updated, but I have a crash, did you ever get it to work?
function Initialise(props: {value: string;}) {
const [editor] = useLexicalComposerContext();

editor.update(() => {
const initialSelection = $getSelection()?.clone() ?? null;
$getRoot().clear();
$getRoot().select(); // for some reason this is not even necessary
$getSelection()?.insertText(props.value);
$setSelection(initialSelection);
});

return null;
}
function Initialise(props: {value: string;}) {
const [editor] = useLexicalComposerContext();

editor.update(() => {
const initialSelection = $getSelection()?.clone() ?? null;
$getRoot().clear();
$getRoot().select(); // for some reason this is not even necessary
$getSelection()?.insertText(props.value);
$setSelection(initialSelection);
});

return null;
}
foolswisdom
foolswisdom•2y ago
Hey. Do you mind showing all your code, so I can debug appropriately? You can share with a playground, for example (https://playground.solidjs.com)
Mant
MantOP•2y ago
https://playground.solidjs.com/anonymous/573f999b-9c49-4954-ba82-0d1c58519bd6 but I have no idea how to install the package on the site.
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
foolswisdom
foolswisdom•2y ago
Hey, so the playground usually downloads dependencies automatically when you import them, but I realized that won't work with lexical due to how the dependencies are set up. So I created a stackblitz: https://stackblitz.com/edit/github-xtm9nr?file=src/App.tsx There are no styles there right now, but it seems working fine? Doesn't crash (though I do need to put yjs in optimizeDeps.exclude, check out the vite config in the stackblitz)
Solidjs - Templates - StackBlitz
Vite + solid templates
Mant
MantOP•2y ago
Yes it doesn't crash because I have deactivated the set / get, wait I activate it. L. 142 TextareaAuto
foolswisdom
foolswisdom•2y ago
You mean // onChange(getText(editorState.toJSON()));? What do I change on L142?
Mant
MantOP•2y ago
yes this makes the call setValue in App.tsx
foolswisdom
foolswisdom•2y ago
Hang on, it works fine for me whether that is commented out or not. It only breaks when I uncomment the <Test /> component (it could be I commented that out?)
Mant
MantOP•2y ago
No, it does work, I don't understand, I have to see the difference with my code.
foolswisdom
foolswisdom•2y ago
Alright
Mant
MantOP•2y ago
Because on my side I have a throw Error(Reconciliation: could not find DOM element for node key ${key}); maybe due to a lag
foolswisdom
foolswisdom•2y ago
Interesting 🤔
Mant
MantOP•2y ago
Strange, strange, I don't see any real difference. Probably a proxy problem I think with the solid-js store So I guess that was it, I changed the props.value to String(props.value) 🙃 Otherwise nothing to see, but you work with YJS ? it's not too hard ?
foolswisdom
foolswisdom•2y ago
Nope, I don't work with yjs. In my projects I also exclude it in the vite config Basically, because not everyone using lexical will want to install yjs, it's specified as a peer dependency Unlike lexical and it's packages which are specified as dependencies But because vite tries to prebundle everything, it chokes when it can't find yjs, so you need to exclude it Very interesting 🤔. Well, at least it's working!
Want results from more Discord servers?
Add your server