npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pluto-rich-text-editor

v1.3.8

Published

Pluto Rich Text Editor

Readme

Pluto Rich Text Editor

Creating an editor and using it

import { PlutoRTE, DEFAULT_EDITOR_STATE } from '@pluto/rte';
import axios from '~/utils/axios';

const SomeComponent = () => {
  const editorRef = useRef < null > null;

  return <PlutoRTE editorRef={editorRef} initialEditorState={DEFAULT_EDITOR_STATE} axiosInstance={axios} mediaUploadEndpoint={'/media'} />;
};

Once you have an editor instance, when ready, you can associate the editor instance with a content editable <div> element in your document:

const contentEditableElement = document.getElementById('editor');

editor.setRootElement(contentEditableElement);

If you want to clear the editor instance from the element, you can pass null. Alternatively, you can switch to another element if need be, just pass an alternative element reference to setRootElement().

Generating rich text editor's JSON

import { generateJSON } from '@pluto/rte';

const SomeComponent = () => {
  const editorRef = useRef < null > null;

  const json = generateJSON(editorRef);

  return <PlutoRTE editorRef={editorRef} initialEditorState={DEFAULT_EDITOR_STATE} axiosInstance={axios} mediaUploadEndpoint={'/media'} />;
};

Converting Editor's JSON to HTML

import { convertToHTML } from '@pluto/rte';

const SomeComponent = () => {
  const htmlString = convertToHTML(editorsJSON);

  return <div dangerouslySetInnerHTML={{ __html: htmlString }}></div>;
};

Understanding the Editor State

With Lexical, the source of truth is not the DOM, but rather an underlying state model that Lexical maintains and associates with an editor instance. You can get the latest editor state from an editor by calling editor.getEditorState().

Editor states have two phases:

  • During an update they can be thought of as "mutable". See "Updating an editor" below to mutate an editor state.
  • After an update, the editor state is then locked and deemed immutable from there one. This editor state can therefore be thought of as a "snapshot".

Editor states contain two core things:

  • The editor node tree (starting from the root node).
  • The editor selection (which can be null).

Editor states are serializable to JSON, and the editor instance provides a useful method to deserialize stringified editor states.

const stringifiedEditorState = JSON.stringify(editor.getEditorState().toJSON());

const newEditorState = editor.parseEditorState(stringifiedEditorState);

Updating an editor

There are a few ways to update an editor instance:

  • Trigger an update with editor.update()
  • Setting the editor state via editor.setEditorState()
  • Applying a change as part of an existing update via editor.registerNodeTransform()
  • Using a command listener with editor.registerCommand(EXAMPLE_COMMAND, () => {...}, priority)

The most common way to update the editor is to use editor.update(). Calling this function requires a function to be passed in that will provide access to mutate the underlying editor state. When starting a fresh update, the current editor state is cloned and used as the starting point. From a technical perspective, this means that Lexical leverages a technique called double-buffering during updates. There's an editor state to represent what is current on the screen, and another work-in-progress editor state that represents future changes.

Creating an update is typically an async process that allows Lexical to batch multiple updates together in a single update – improving performance. When Lexical is ready to commit the update to the DOM, the underlying mutations and changes in the update will form a new immutable editor state. Calling editor.getEditorState() will then return the latest editor state based on the changes from the update.

Here's an example of how you can update an editor instance:

import { $getRoot, $getSelection } from 'lexical';
import { $createParagraphNode } from 'lexical/PargraphNode';

// Inside the `editor.update` you can use special $ prefixed helper functions.
// These functions cannot be used outside the closure, and will error if you try.
// (If you're familiar with React, you can imagine these to be a bit like using a hook
// outside of a React function component).
editor.update(() => {
  // Get the RootNode from the EditorState
  const root = $getRoot();

  // Get the selection from the EditorState
  const selection = $getSelection();

  // Create a new ParagraphNode
  const paragraphNode = $createParagraphNode();

  // Create a new TextNode
  const textNode = $createTextNode('Hello world');

  // Append the text node to the paragraph
  paragraphNode.append(textNode);

  // Finally, append the paragraph to the root
  root.append(paragraphNode);
});

If you want to know when the editor updates so you can react to the changes, you can add an update listener to the editor, as shown below:

editor.registerUpdateListener(({ editorState }) => {
  // The latest EditorState can be found as `editorState`.
  // To read the contents of the EditorState, use the following API:

  editorState.read(() => {
    // Just like editor.update(), .read() expects a closure where you can use
    // the $ prefixed helper functions.
  });
});