Skip to content
Hooney
한국어

Engines & modules · In use

editors

A family of four editing surfaces, from short comments to translation, that share one editing core (built on Lexical) and pluggable features.

4Editing surfaces sharing one core: short input, body, document, and translation

Period
2024.04 ~ Present
Organization
Firstage
Role
Design and implementation (solo)
The IntlEditor translation mode in Storybook, with the Korean source on the left and the English translation on the right, aligned paragraph by paragraph.

Core value

New writing screens and other products don't build an editor of their own; they pick the features they need on the shared core.

Outcomes

  • 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.