Before anything else

I promise to release one blog every month this year. This is a bet we (Rushikesh and I) made, and we both are gonna stick to it (we’ll try to). We haven’t decided on the failure punishment yet, do let us know if you have any ideas.

Do check him out at https://rushikeshtote.com/

Blog starts here

What?.. When?.. How?..

So this is something around August 2023 I guess. I just returned to college for my final year after spending a lot of time at home lol :-)

I came to know about Zenskar from my friend who was working there at the time, and he referred me and couple others to the company. I interviewed, waited almost a month, and got the offer.

Well I’m not here to tell you my interview experience, you can refer GeekforGeeks or Leetcode for that. But I also can’t tell you what I did there, now can I?

… Well I think I can (like I believe no one’s gonna read this anyway so), no.. I can because majority of the stuff I worked on there was open source yayy!

Jumping into the business

So the initial weeks went smoothly, picked up a couple of good first issues, checked out the codebase, have 1-1s with the team blah blah.. Oh FYI I was majorly dealing with Frontend stuff, so I was working with React, Redux, Typescript .etc

Once I got familiar, I picked up something which defined the majority of my internship period. Lexical

Have you ever heard of it?… No? Don’t worry, I’ll tell you

Lexical Editor

Again, just a reminder, this is a open source editor framework for React so chill.

Quoting from the repo itself:

Lexical is an extensible JavaScript web text-editor framework with an emphasis on reliability, accessibility, and performance.

You can check out the repo here.

Anyways, before starting with this, I feel like I should tell you something about editors in general, having worked on two three editors, I feel like I have a good idea about them.

My journey with editors

So I first encountered them, with my personal project. Its called Leetcode code formatter, you can check it out here. Its a simple Javascript extension, which injects itself on the Leetcode’s question page, picks up the code, formats it, and replace the code with the formatted one.

During that time (when this was still under process, Leetcode started rolling out new UI out of the sudden), Leetcode used CodeMirror as their editor. I somehow managed to scrape out the code from it, and format it. But this lasted only for a few weeks. Once they rolled out the new UI, they migrated to Monaco.

Now scraping the code became more difficult here, and so I read some docs (majorly Stack Overflow answers), and found out that there exists a term called editor state. Now I’m pretty sure you’re familiar with this term, but if you’re not, its basically gives the active state of the editor, which contains the code, cursor position, theme, etc.

Editor State

The editor state, as defined above, gives you the current status of the editor. We primarily use it to get the content from the editor, and set the content to the editor.

Back to Lexical

So similarly in Lexical as well, if you need to extract the content from the editor, you could do something like

const editorState = editor.getEditorState();

which gives a string afaik.

If you want a JSON instead, you can do something like

const editorState = editor.parseEditorState();

You can also extract the editor state in HTML format, by doing

import { $generateHtmlFromNodes } from "@lexical/html";

const htmlString = $generateHtmlFromNodes(editor, selection | null);

More on this here

Lexical Plugins

Now the most important part in any editor, is the plugins. Plugins are basically the features that you see in the editor, like the toolbar, the syntax highlighting, the code completion, etc.

Say you want to attach a hyperlink to a text, we have something called a LinkPlugin for Lexical

Structure of a plugin

Say you want to create a plugin for Lexical. For that you may have to create a custom Javascript class, and define certain member functions which are required for the plugin to work.

So lets say we’re replicating the LinkPlugin, we’ll have to create a class like

import { ElementNode } from "lexical";
import { $createLinkNode } from "@lexical/link";

export class LinkNode extends ElementNode {
  __url: string;

  static getType(): string {
    return "link";
  }

  createDOM(config: EditorConfig): HTMLAnchorElement {
    // return how the link should look like in the DOM
    const element = document.createElement("a");
    element.href = this.__url;
    return element;
  }

  static importJSON(
    serializedNode: SerializedLinkNode | SerializedAutoLinkNode
  ): LinkNode {
    // return how the link should look like in the serialized JSON
    const node = $createLinkNode(url);
    return node;
  }
}

So as you can see we define member functions like getType, createDOM, importJSON.

Now we have to register this plugin to the editor, for that we do

import { Editor } from "lexical";
import { LinkNode } from "./LinkNode";

const editor = new Editor({
  plugins: [LinkNode],
});

and that’s it, now you can use the plugin in your editor.

You can check out a sample playground here to see how it works.

Conclusion

Lol I diverted from the main topic, but I hope you learnt something about editors from this. I’ll try to write more about Lexical, and maybe incorporate this on one of my personal projects.

Thanks for reading, and see you next month (hopefully) :-)