Modules
editors
I built editors for comments, articles, documents, and translation, with a Lexical foundation and features that can be added as needed.
4Editing surfaces sharing one core: short input, body, document, and translation
- Period
- 2024.04 ~ Present
- Organization
- Firstage
- Role
- Design and implementation (solo)
- Runs on
- Frontend · Backend
- Key features
- Comment, article, document, and translation editors are built from only the features each one needs. Several people can edit at once, and content can be rendered on the server.
- Work and results
- Powers photo comments, journals, and record bodies in Journey
- ROUND reuses IntlEditor as is to edit event guides in several languages
- The chat composer and the web page builder run on the same core
- Real-time co-editing (Yjs) and server rendering were added without changing the core
- Tech stack
- Lexical
- Yjs
- React
Context
Firstage’s Journey app has writing surfaces of very different kinds, from short photo comments to diaries and record bodies. Separate editors for each screen would give each its own storage format and editing behavior, so I built an editor family that adds only the features each surface needs on a shared editing foundation. The package started in April 2024 in the same repository.
Decisions and implementation
- I first built a Markdown editor with Remirror, which is based on ProseMirror, tried Slate as well, and then chose Lexical. A small core with features moved into plugins suited keeping several editing surfaces working together.
- Four surfaces, short input (Plaintext), body text (Richtext), documents (Root), and translation (Intl), share a React-free core and plugin layer. Dependencies run one way, surfaces on plugins and plugins on the core, and a plugin never imports a surface.
- Yjs collaborative editing and DOM-free server rendering attach without changes to the core. The server imports only the headless entry points to render stored documents as HTML.
- Features that need outside data, such as mentions, image upload, and link previews, run on functions the host injects. Without a function, the related action is turned off and nothing pretends to save, and the host is responsible for authorization, storage, audience scope, and the save status it shows.
Current state
Photo comments, diaries, and record bodies in the Journey app use these packages. ROUND, a sports event service in the same monorepo, reuses IntlEditor as is to edit event guides in several languages, and the chats composer and the web page builder (cms) run on the same core. Moving the existing Root editor’s plain-text and rich-text paths onto the new shared base (EditorRoot) and verifying compatibility is still open.