Leaf Editor: Track Editor Feature Progress and Brainstorming
Using this document to test new features added to the Leaf editor, and document my thoughts and findings
Sunday, January 28, 2024

Hi there, this is a heading

This is Les and I am adding new stuff to this document. I want to see if these things will reflect. I am continuing to type and to send things to the server in the hope that they will reflect


Hello again. I am typing now but I will stop to see if the inactive timer works.


Okay now I want to see if it'll reset the timer. I'm adding more things now to see whether the notification system works. I am typing in more things and I want to see if this stuff persists. Uhm hi hello.


Okay I am now typing again. Okay I am adding more things to see if the save delay works. Okay it seems to work :)


Whoops, I found the issue which cause all my text to disappear. The transfer from Quill to ProseMirror wasn't checking correctly :(


Okay, new block quote. Okay I am writing more things in the blockquotes to see how it evaluates


Okay, I need to find a proper way to highlight this code syntax. There is the ProseMirror highlightjs package you can use: https://github.com/b-kelly/prosemirror-highlightjs/tree/master

// This is TypeScript btw <3
// Well apparently it is lmao
function main(args: Array<String>) {
    const myString: string = "Hello there!";
    console.log(myString, args)
}

Okay one thing I need to do is check if there is a hard_break after the code block. If there isn’t one, I should create one otherwise the text cursor gets stuck in the code block and can’t escape below.


This document is really cool for tracking new features I’m adding to the editor. I might publish this in the future once I deem it ready to use…

// This is what a typical step might look like
{
    "stepType": "replace",
    "from": 1738,
    "to": 1738,
    "slice": {
        "content": [
            {
                "type": "paragraph"
            },
            {
                "type": "paragraph"
            }
        ],
        "openStart": 1,
        "openEnd": 1
    },
    "structure": true
}

Okay, I am adding some text below <3

[
    {
        "stepType": "replace",
        "from": 2083,
        "to": 2083,
        "slice": {
            "content": [
                {
                    "type": "text",
                    "text": "Okay, I am adding some text below <3"
                }
            ]
        }
    }
]

Okay I am attempting to add an image (through Quill) to the editor 🚶🏾‍♀️

Okay so currently, as of right now (08:00 - 12 November 2023), list input rules and shortcuts are not being detected and some Mod-Shift-* keyboard shortcuts are not being detected soooo idk. I will have to try and do a comparison between my setup and the example setup to find the issues.


Things to do before shipping to production:

Just some things to implement before having something useable for production:

  • Add image toolbar (maybe inside overall menu) where I can edit the image source. Image source can either be a local file or a URL and user can get the choice to choose between the two (20/12 - This is a prompt that shows up in the floating menu)

  • Add indentation shortcuts, text highlighting, custom code modal for editing ProseMirror raw HTML (20/12 - Don’t know how useful editing raw HTML would be actually)

  • Use sidebars for more useful information about the editor and the post (similar to how the NYTimes does it). Right now all it does is display basic metadata about publish status and dates

  • Enhance editor and post status UI’s (e.g. Updating button text)

  • Make Svelte components for several bits of UI instead of whatever mish-mash of things I have going on right now (20/12 - Most things have been turned into components now)

  • Add quality of life improvements to the editor - e.g. adding quotes on both sides of the text selection, VSCode style Ctrl+Enter implementation, having a choice between a floating toolbar and static, expand document edit size when user reaches the bottom of the usable typing space, allow images to be resized in the editor (20/12 - Ctrl+Enter works now, no static menu yet, when user reaches the bottom of the page, the editor scrolling stays in place, no image resize yet, no smart quotes yet)

  • Add home page context menu for running actions on posts (20/12 - Pretty much done now)

  • Embed live preview <iframe> for published posts (20/12 - Will do at some point)

  • Enable tweeting about post from home page (20/12 - Will do at some point)

  • Fix performance issues (at least in dev mode, idk if it’ll happen in production) (20/12 - This just had to do with highlight.js, this is fixed)


Things to do after shipping to production:

Cool things to make after production, which require more time to implement:

  • Edit history with changes highlighted in colour

  • Comments with them being shown in the sidebar

  • Convert pasted tweets into nodes/iframes, <iframe> embeds within in the editor

  • Image picker linked to custom image backend service

  • Move image upload endpoint into its own backend service (for more than just the editor), similar to The Guardian’s Grid

  • Support for image gallery as opposed a single image

  • Collaborative editing? Maybe, just as a nice to have

  • Generate Open Graph images automatically based on post information

There is currently an issue I am facing where wrapping rules for all types of list nodes result in the following error:

index.js:3284 Uncaught TypeError: this.nodes[node.type.name] is not a function
    at _DOMSerializer.serializeNodeInner (index.js:3284:99)
    at index.js:3276:34
    at _Fragment.forEach (index.js:255:13)
    at _DOMSerializer.serializeFragment (index.js:3250:18)
    at nodeToElement (utils.ts:156:52)
    at update (leaf.editor.svelte:225:39)
    at LeafNodeView.update (leaf.nodeview.ts:170:34)
    at CustomNodeViewDesc.update (index.js:1500:36)
    at ViewTreeUpdater.updateNextNode (index.js:1809:37)
    at index.js:1305:30

The issue has been filed on the ProseMirror forum: https://discuss.prosemirror.net/t/this-nodes-node-type-name-is-not-a-function-for-wrapping-list-nodes/6001/1


Lmao okay, so now it works? But when I filed the issue, I had left it in the exact same state and it was breaking, so what the fuck went wrong? :( Programming is extremely annoying sometimes, let me tell you something.


ProseMirror typing test

Okay I am typing to see the Svelte performance.


Okay so I was testing that in dev mode and it was kind of atrocious. Now I’m typing in preview mode and it seems to be running better idk 🤔. I think this is fine. Also my laptop just has a million things running right now so that could be a potential problem. My worry is that Svelte is continuously destroying and creating components every time I type which could severely undermine performance :(


Okay so I am typing again in Svelte and I will try and get a screenshot of the profile waterfall. It’s scary lmao

Quill Typing Test

Okay, so typing in Quill is significantly faster and doesn't use Svelte components to render anything in the editor so I think this is confirming my suspicions about ProseMirror going through a cycle of deleting and creating components :/


Okay so now I am typing in Quill and the profiling result is not nearly as dramatic as the one above, which leads me to suspect that I was right about the constant "rendering" that the ProseMirror editor is doing. Okay now I am typing in Quill and the waterfall is basically non-existent. Nothing is really "re-rendering" so I suspect that because the ProseMirror editor is implemented as a component (with multiple child components) of its own instead of directly in the +page.server.ts file, it's having these render issues

Okay so I am trying again with the immutable=true on both the Svelte component for the editorBody and the actual editor and I don’t think it’s making much difference. Typing is still very laggy :( Okay so I don’t know what else to do to try and address the issue but typing is hard like this and it’s not usable. I don’t know. Sandsjdksjdsdsdsdsdsddsdsdssssss. Okay I think this is slightly faster. I’ve temporarily removed the LeafHeader component and that kind of helps.


Check your plugins

That was fun. The performance is now better (considerably). The issue was that the syntax highlighting plugin had no checks to see if anything was changing or if any updates had to be made so it just kept running the highlighting on every transaction made to the document, which of course was going to severely hamper performance. That is on me for leaving code that was not supposed to be commented, commented.


I still think there *might* be some input lag caused elsewhere, but this is WAY better. I can sleep (eventually) satisfied.

The above image was added through the image prompt on the floating menu, which is fucking great :) However, there are still a number of issues to solve:

  • The image prompt’s state is still tied to the first image which is added to the editor instead of being tied to each individual image/image component

  • In addition to the above issue, there is still the issues of destroying/closing the image prompt component when I am done using it. A solution to (sort of) solve both issues would be to reset the state of the image prompt when I am done with adding an image, before closing the prompt

  • Another solution to this is to run the MenuView’s destroy if the menu needs to be hidden, which destroys the menu’s Svelte component and possibly the children, which include all the prompts (and its state). Hmm…

Okay, now I am going to add a new image below from my laptop, and it should upload to the image server and return the URL.

One thing I would like to implement is two views: A full editor view which is the default, and a compact editor view which would display for information about the post, similar to The Guardian’s Composer.

Wow, almost all the hard work is almost over. There are few things left to add and work on now. Didn’t even realise till things started feeling easier to use. I can be proud 🤭

Converting old HTML from Quill into ProseMirror still needs some work. Image credits are being converted into plain text when switching to Quill so in the Quill editor I should probably convert figcaption’s into attributes. Another thing that’s happening is that extra text breaks are being added after images/figure boxes in ProseMirror. Not sure where that is coming from right now.


I’m going to paste a text link in here and try to convert it into link mark.

https://design-lesisonline.webflow.io/posts/leaf-editor-track-editor-feature-progress-and-brainstorming-tul7X5r018xNhXZ7aedOuKc6ufCpA5QJ.

  • Using the Ctrl+/ keyboard shortcut will show the floating menu :)

  • Pressing Ctrl+Shift+Enter now inserts a new paragraph below the current selection position, exactly how it works in VSCode. I’m so satisfied it works, this is really one of the best ways to type.

At this point, I just need to fix several bugs. The image prompt still needs some work to display the correct state for inserting images.

Okay, it’s actually still very broken but I will fix it.
For now…, it’s all a little hacky

Also, for some unknown reasons, editor is sometimes really jumpy and will just randomly scroll to the top when clicking somewhere. I think this has something to do with the scroll position and what not, but I have no idea what might be setting the scroll position to somewhere where it is not. I think the scrollPosition value isn’t being updated sometimes when the editor has weird state changes (like clicking on the image prompt randomly closes the menu or scrolls the editor to the top).

// Something like this might be able to fix it
mainElement.addEventListener("scroll", () => {
    scrollPosition = mainElement.scrollHeight;
});

Link prompt still needs so much work. Still very buggy. Okay, let’s give this a shot.


This is some text that will be linked.


Brah this thing is so fucked, I need to rewrite the if statement logic for which UI to show because this is a mess. A solution to all my mishaps is to have a confirm/apply button to the link prompt which will apply the relative state instead of doing it on input.


Okay, it is now the 26th of December. I think most critical bugs have now been fixed. Image prompt works fine, link prompt works fine and I’ve disabled the menu showing up when a new paragraph is created because it’s a bit distracting while I’m typing.


I have so many stories to tell about trying to set up the production server… 5 days of this shit yoh 🤚


God damn I am tired


Okay, it is now the 26th of December. I think most critical bugs have now been fixed. Image prompt works fine, link prompt works fine and I’ve disabled the menu showing up when a new paragraph is created because it’s a bit distracting while I’m typing.


The Leaf editor has been feature complete for a few days now and the paragraph I am currently writing is being written in the production environment and everything seems to running alright.


Another feature which needs to be implemented is the ability to add a thumbnail directly from the editor. Right now, post thumbnails need to be added directly through Webflow, which is uhhh, fine but I’d want just do it directly through here. This is more motivation for creating a new image management system for all my images. In addition to this, the natural next step for me is to have a “metadata” section for things like custom slugs, adding tags, allowing multiple authors, choosing a thumbnail and many more features.


I’m thinking about potentially using ProseMirror’s concept of Nodes to extract the text, metadata of each individual node and save that data as its own model, outside of HTML. While the only place the where articles are rendered is the web, saving the text as its own data can allow it to be rendered in multiple different contexts.


Okay, I’m working on this thing again after several weeks of not touching it and there some definite bugs that need working on. For starters, images uploaded to Google Cloud aren’t returning their links and applying them to ProseMirror attributes. Shift+Enter is not breaking into the next line right below, instead it’s just adding a space… for some reason. Sometimes this… just happens and and then it works again.


Next thing is that the website is not hosted on Webflow anymore so significant work needs to be put in to decoupling the application from there and making sure it runs independently. After all this work is done, the next step would be to add enhancements to the Leaf Editor to make it better like a spellchecker. One good modification to make would be to the image component which takes up too much space in the editor. Instead, I would like to shrink the image size and use more available space to be able to edit the metadata.


I’ve been working on fixing adding an image all afternoon. It’s… fine. Making progress but the whole point has been to show a loading state for the image until we can get an image URL back from the server which will be used to replace the loading state, but it’s not working the way I want to so I will have to find a different approach for showing a loading state.

Steps steps