
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@seolhun/firstage-editor
Advanced tools
A modern, extensible rich text editor built with Lexical and React, featuring a **colocation architecture** for maximum maintainability and developer experience.
A modern, extensible rich text editor built with Lexical and React, featuring a colocation architecture for maximum maintainability and developer experience.
This editor supports two distinct modes optimized for different use cases:
The editor automatically loads appropriate nodes and plugins based on the isRichText setting:
// PlainText mode - minimal features
<RootEditor initialSettings={{ isRichText: false }} />
// RichText mode - full features
<RootEditor initialSettings={{ isRichText: true }} />
This editor follows a feature-first colocation approach where all related files for a feature are grouped together in a single directory. This improves code organization, reduces cognitive load, and makes features more maintainable.
packages/editor/src/features/emoji/
├── components/ # Components used by Node/Renderer/Plugin
├── emoji.node.ts # Lexical node definition
├── emoji.plugin.tsx # Main plugin with FloatingPortal
├── emoji.typeahead.tsx # Typeahead functionality
├── emoji.renderer.tsx # EmojiPicker renderer (@emoji-mart/react)
├── emoji.store.ts # Zustand state management
├── emoji.types.ts # TypeScript type definitions
├── emoji.utils.ts # Search and filtering utilities
├── emoji.item.tsx # Individual emoji item component
├── emoji.{feature-name}.tsx # Additional feature-specific files
└── index.ts # Exports (export * from pattern)
Pattern: {feature}.{type}.{ext}
{feature}.node.ts (e.g., emoji.node.ts){feature}.plugin.tsx (e.g., emoji.plugin.tsx){feature}.typeahead.tsx (e.g., emoji.typeahead.tsx){feature}.renderer.tsx (e.g., emoji.renderer.tsx){feature}.store.ts (e.g., emoji.store.ts){feature}.types.ts (e.g., emoji.types.ts){feature}.utils.ts (e.g., emoji.utils.ts){feature}.{component}.tsx (e.g., emoji.item.tsx)packages/editor/src/
├── features/ # Feature-first colocation
│ ├── emoji/ # ✅ Perfect colocation example
│ │ ├── emoji.node.ts # EmojiNode definition
│ │ ├── emoji.plugin.tsx # Main plugin
│ │ ├── emoji.typeahead.tsx # Typeahead functionality
│ │ ├── emoji.renderer.tsx # EmojiPicker renderer
│ │ ├── emoji.store.ts # State management
│ │ ├── emoji.types.ts # Type definitions
│ │ ├── emoji.utils.ts # Utilities
│ │ ├── emoji.item.tsx # Item component
│ │ ├── emoji.{feature-name}.ts # What you need for the feature
│ │ └── index.ts # Exports
│ ├── image/ # 🔄 Improved colocation
│ │ ├── image.node.tsx # ImageNode definition
│ │ ├── image.plugin.tsx # Main plugin
│ │ ├── image.component.tsx # Image component
│ │ ├── image.types.ts # Type definitions
│ │ ├── image.{feature-name}.ts # What you need for the feature
│ │ ├── index.ts # Exports
│ │ └── [legacy folders] # Backward compatibility
│ ├── mention/ # 🔄 New colocation structure
│ │ ├── mention.node.ts # MentionNode definition
│ │ ├── mention.plugin.tsx # Main plugin
│ │ ├── mention.item.tsx # Mention item component
│ │ ├── mention.types.ts # Type definitions
│ │ ├── mention.{feature-name}.ts # What you need for the feature
│ │ └── index.ts # Exports
│ ├── .../ # 🔄 New colocation structure
│ │ ├── ...node.ts # ...Node definition
│ │ ├── ...plugin.tsx # Main plugin
│ │ ├── ...types.ts # Type definitions
│ │ ├── ....{feature-name}.ts # What you need for the feature
│ │ └── index.ts # Exports
│ └── editors/ # Core editor components
├── plugins/ # Legacy plugins (migrating to features/)
├── nodes/ # Legacy nodes (migrating to features/)
├── ui/ # Shared UI components
├── context/ # React contexts
├── hooks/ # Custom hooks
└── utils/ # Utility functions
import { EmojiPlugin, EmojiTypeaheadPlugin } from '@/features/emoji';
function MyEditor() {
return (
<LexicalComposer>
<EmojiPlugin floatingAnchor={anchorElement} />
<EmojiTypeaheadPlugin floatingAnchor={anchorElement} />
</LexicalComposer>
);
}
import { ImagePlugin, ImageNode, INSERT_IMAGE_COMMAND } from '@/features/image';
function MyEditor() {
const [editor] = useLexicalComposerContext();
const insertImage = (payload: ImagePayload) => {
editor.dispatchCommand(INSERT_IMAGE_COMMAND, payload);
};
return (
<LexicalComposer initialConfig={{ nodes: [ImageNode] }}>
<ImagePlugin activeEditor={editor} />
</LexicalComposer>
);
}
import { MentionPlugin, MentionNode } from '@/features/mention';
function MyEditor() {
const fetchMentionOptions = async (query: string) => {
// Fetch users, teams, channels, etc.
return await api.searchMentions(query);
};
return (
<LexicalComposer initialConfig={{ nodes: [MentionNode] }}>
<MentionPlugin
floatingAnchor={anchorElement}
fetchMentionOptions={fetchMentionOptions}
minLength={1}
maxResults={10}
/>
</LexicalComposer>
);
}
Each feature includes its own SCSS file with scoped styles:
// features/emoji/emoji.scss
.__RootEditor__ {
.emoji-container {
// Emoji-specific styles
}
}
// features/image/image.scss
.__RootEditor__ {
.image-container {
// Image-specific styles
}
}
// features/mention/mention.scss
.__RootEditor__ {
.mention {
// Mention-specific styles
}
}
features/{feature-name}/{feature}.{type}.{ext}{feature}.node.ts){feature}.plugin.tsx){feature}.types.ts){feature}.scss)index.ts)features/table/
├── table.node.ts # TableNode, TableRowNode, TableCellNode
├── table.plugin.tsx # TablePlugin with commands
├── table.toolbar.tsx # Table toolbar component
├── table.types.ts # Table-related types
├── table.utils.ts # Table utilities
├── table.scss # Table styling
└── index.ts # Exports
Each feature should include its own test files:
features/emoji/
├── emoji.node.test.ts
├── emoji.plugin.test.tsx
└── emoji.utils.test.ts
When contributing to this editor:
export * from pattern in index.tsThis architecture ensures our editor remains maintainable, scalable, and developer-friendly as it grows in complexity and features.
FAQs
A modern, extensible rich text editor built with Lexical and React, featuring a **colocation architecture** for maximum maintainability and developer experience.
We found that @seolhun/firstage-editor demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.