emin-lexical-editor-nohut
v1.0.32
Published
Lexical Editor with Equation Editor
Maintainers
Readme
Emin Lexical Editor
A modern, feature-rich, and easy-to-use text editor for React, built on top of Lexical. It supports controlled content management, light/dark themes, and file uploads.
npm install emin-lexical-editor-nohutor
yarn add emin-lexical-editor-nohutUsage
The EminEditor is a controlled component. Its content is managed by the editorState prop, which must be a serialized Lexical JSON string. This approach ensures reliable and predictable state management.
Here is a complete usage example with React's useState hook:
import React, { useState } from 'react';
import { EminEditor } from 'emin-lexical-editor-nohut';
// A sample serialized editor state. You can get this from the onChange event or your database.
// For a new, empty editor, you can pass an empty string "".
const SAMPLE_EDITOR_STATE = '{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"This is a sample content loaded externally!","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}';
function MyEditorComponent() {
// Manage the editor's state using React's useState hook.
const [editorState, setEditorState] = useState<string>('');
// The onChange handler provides the latest content in HTML and serialized JSON format.
// It's crucial to update your state here to keep the component controlled.
const handleChange = (data: { html: string; serialized: SerializedEditorState; charCount: number }) => {
// It's crucial to update your state with the serialized JSON to keep the component controlled.
setEditorState(JSON.stringify(data.serialized));
// You also get the clean HTML output.
console.log('HTML Output:', data.html);
console.log('Character Count:', data.charCount);
};
const loadSampleContent = () => {
setEditorState(SAMPLE_EDITOR_STATE);
};
return (
<div>
<button onClick={loadSampleContent}>Load Sample Content</button>
<EminEditor
editorState={editorState}
onChange={handleChange}
placeholder="Start typing..."
height="500px"
theme="light" // or "dark"
/>
</div>
);
}
export default MyEditorComponent;HTML Serialization
The editor ensures that custom elements are correctly serialized into clean, portable HTML. This is crucial for storing and rendering content outside the editor.
- LaTeX Equations: Rendered as
<span>tags with adata-latexattribute, preserving the original LaTeX code.<span data-latex="\sum_{i=1}^{n} x_i">...</span> - Media Elements: Images, videos, and audio are serialized to their standard HTML tags (
<img>,<video>,<audio>) withsrc,alt,title, and other attributes intact.<img src="/path/to/image.png" alt="Description"> <video src="/path/to/video.mp4" controls></video>
Features
- Controlled Component: Reliably manage content with the
editorStateprop. - Rich Text Editing: Bold, Italic, Underline, Strikethrough, etc.
- Headings & Lists: Structure your content with H1, H2, H3, and ordered/unordered lists.
- Link Insertion: Easily add and edit hyperlinks.
- File Uploads: Integrated toolbar button for uploading images, videos, and audio files (requires
fileUploadConfig). - LaTeX Equations: Inline and block equation support.
- Customizable: Change theme (light/dark) and height.
- Callbacks:
onChangeprovides HTML, serialized state, and character count.
Props
| Prop | Type | Default | Description |
| ---------------- | ----------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------ |
| editorState | string | '' | (Required) A serialized Lexical JSON string to control the editor's content. |
| onChange | (data: { html: string; serialized: SerializedEditorState; charCount: number; }) => void | () => {} | Callback that fires on change, providing HTML, serialized state, and character count. |
| placeholder | string | '' | The placeholder text to display when the editor is empty. |
| height | string | '400px' | The height of the editor container (e.g., '500px'). |
| theme | 'light' \| 'dark' | 'light' | The visual theme of the editor. |
| fileUploadConfig | object | undefined | File upload configuration. See details below. |
| toolbarToggle | boolean | false | If true, the toolbar is hidden by default and appears on hover over the editor area. If false, it's always visible. |
interface FileUploadConfig {
// --- Core Fields ---
uploadUrl: string; // Your backend endpoint.
token?: string; // Optional auth token.
// --- API & Upload Strategy ---
apiType?: 'rest' | 'graphql'; // default: 'rest'
uploadMethod?: 'file' | 'base64'; // default: 'file'
// --- GraphQL Specific ---
graphqlMutation?: string; // The GraphQL mutation query.
graphqlVariableName?: string; // The variable name for the file in the mutation. default: 'file'
// --- Callbacks & Response Handling ---
onUploadStart?: (file: File) => void;
onUploadSuccess?: (response: any, file: File) => void;
onUploadError?: (error: string, file: File) => void;
responseUrlExtractor?: (response: any) => string; // Extracts the URL from the server response.
}Usage Examples
1. Simple REST Upload (Default)
This is the simplest configuration. The editor sends the file as multipart/form-data to a REST endpoint.
const restConfig = {
uploadUrl: 'http://your-backend.com/upload',
token: 'your-auth-token',
responseUrlExtractor: (res) => res.fileUrl // Extracts URL from { fileUrl: '...' }
};
<EminEditor fileUploadConfig={restConfig} />Your backend should expect a POST request with a file field in the FormData.
2. REST Upload with Base64
To send the file as a Base64 string within a JSON payload:
const base64RestConfig = {
uploadUrl: 'http://your-backend.com/upload-base64',
token: 'your-auth-token',
apiType: 'rest',
uploadMethod: 'base64',
responseUrlExtractor: (res) => res.url
};
<EminEditor fileUploadConfig={base64RestConfig} />Your backend will receive a JSON body like this: { "file": "data:image/png;base64,...", "fileName": "...", "fileType": "..." }.
3. GraphQL Upload (File)
The editor supports the GraphQL multipart request specification for native file uploads.
const gqlConfig = {
uploadUrl: 'http://your-api.com/graphql',
apiType: 'graphql',
uploadMethod: 'file', // This is the default
graphqlMutation: `
mutation($file: Upload!) {
uploadFile(file: $file) {
url
filename
}
}
`,
responseUrlExtractor: (res) => res.data.uploadFile.url
};
<EminEditor fileUploadConfig={gqlConfig} />4. GraphQL Upload (Base64)
You can also send the file as a Base64 string to a GraphQL endpoint.
const gqlBase64Config = {
uploadUrl: 'http://your-api.com/graphql',
apiType: 'graphql',
uploadMethod: 'base64',
graphqlMutation: `
mutation($file: String!) {
uploadBase64(base64: $file) {
url
}
}
`,
graphqlVariableName: 'file', // Optional, defaults to 'file'
responseUrlExtractor: (res) => res.data.uploadBase64.url
};
<EminEditor fileUploadConfig={gqlBase64Config} />TypeScript Support
The package includes full TypeScript definitions:
import { EminEditor, EminEditorProps } from 'emin-lexical-editor-nohut';
const MyEditor: React.FC<EminEditorProps> = (props) => {
return <EminEditor {...props} />;
};
## License
MIT
