@datazymes/dz-rich-text-editor
Version:
A comprehensive React rich text editor component with image upload, resize functionality, and standalone CSS. Ready for NPM publishing.
504 lines (384 loc) โข 15.1 kB
Markdown
# DZRichTextEditor - A React Rich Text Editor Component
DZRichTextEditor is a comprehensive, parameterized React rich text editor component designed for easy integration and customization. It supports image uploads (via drag-drop, paste, or file dialog), client-side image resizing, and comes with a clean, standalone CSS file. It is configured for publishing to NPM and GitHub Packages.
**Note on Placeholders:** Before publishing, you must replace the placeholder values in `package.json` (`@datazymesrepository`, repository URL) and `./.npmrc` (`@datazymesrepository`) with your actual GitHub username or organization name.
## Installation
Install the package from GitHub Packages:
```bash
npm install @datazymesrepository/dz-rich-text-editor
```
You will also need to install the peer dependencies:
```bash
npm install react react-dom
```
## Publishing to GitHub Packages
To publish new versions of this package, follow these steps:
### 1. Authenticate with GitHub Packages
You need to authenticate `npm` with GitHub Packages.
- **Create a Personal Access Token (PAT):**
Go to your [GitHub Developer Settings](https://github.com/settings/tokens) and generate a new classic PAT. Grant it the `write:packages` scope.
- **Log in:**
Use the following command to log in, replacing `YOUR-USERNAME` with your GitHub username and `YOUR-PAT` with the token you just created.
```bash
npm login --scope=@datazymesrepository --registry=https://npm.pkg.github.com
```
### 2. Update Version
Before publishing, update the `version` in `package.json` according to semantic versioning rules.
### 3. Build the Package
Run the build script to transpile the component and generate the distributable files in the `dist/` directory.
```bash
npm run build
```
### 4. Publish
Finally, publish the package to the GitHub Packages registry.
```bash
npm publish
```
---
## Features
- **Image Upload**: Supports pasting, drag-and-drop, and a toolbar button for image uploads.
- **Backend Agnostic**: Uploads images via a `fetch` call to a configurable backend endpoint.
- **Image Resizing**: Simple and intuitive client-side image resizing with handles.
- **Customizable Uploads**: Pass API URLs and credentials via the `uploadConfig` prop.
- **Clean HTML**: The editor is designed to keep the underlying HTML clean from temporary resizing elements.
- **Standalone CSS**: A separate `index.css` file for easy styling and customization.
## Props
### `DZRichTextEditor`
| Prop | Type | Default | Description |
| -------------- | -------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `value` | `string` | `''` | The HTML content of the editor. |
| `onChange` | `func` | `(html) => {}` | A callback function that receives the updated HTML content whenever it changes. |
| `uploadConfig` | `object` | `{ clientId: 'default', clientSecret: 'default' }` | An object containing the configuration for the image upload endpoint. See `uploadConfig` section below for more details. |
| `placeholder` | `string` | `'Compose an epic...'` | Placeholder text to display when the editor is empty. |
## Quick Start
```jsx
import React, { useState } from "react";
import DZRichTextEditor from "dz-rich-text-editor";
import "dz-rich-text-editor/index.css"; // Import the CSS
function MyApp() {
const [content, setContent] = useState(
"<p>Welcome to <strong>DZ Rich Text Editor</strong>!</p>"
);
return (
<DZRichTextEditor
value={content}
onChange={setContent}
placeholder="Start typing..."
/>
);
}
```
## Image Upload Configuration
To enable image upload functionality, configure the `uploadConfig` prop:
```jsx
import React, { useState } from "react";
import DZRichTextEditor from "dz-rich-text-editor";
function EditorWithImageUpload() {
const [content, setContent] = useState("");
const uploadConfig = {
uploadApiUrl: "https://your-api.com/upload",
clientId: "your-client-id",
clientSecret: "your-client-secret",
};
return (
<DZRichTextEditor
value={content}
onChange={setContent}
uploadConfig={uploadConfig}
toolbarOptions={[
"bold",
"italic",
"underline",
"insertImage", // Enable image insert button
"link",
"blockquote",
]}
/>
);
}
```
### Upload API Requirements
Your upload API should:
1. **Accept POST requests** to the configured endpoint
2. **Accept FormData** with the following fields:
- `image`: The image file
- `client_id`: Authentication client ID (optional)
- `client_secret`: Authentication client secret (optional)
3. **Return JSON response** in this format:
```json
{
"data": {
"authenticatedUrl": "https://your-cdn.com/path/to/uploaded-image.jpg"
}
}
```
### Example Backend Implementation (Express.js)
```javascript
app.post("/upload", upload.single("image"), (req, res) => {
const { client_id, client_secret } = req.body;
// Validate credentials
if (!validateCredentials(client_id, client_secret)) {
return res.status(401).json({ error: "Invalid credentials" });
}
// Upload to your storage (GCS, AWS S3, etc.)
const imageUrl = uploadToStorage(req.file);
res.json({
data: {
authenticatedUrl: imageUrl,
},
});
});
```
## Image Features
### Image Upload Methods
1. **Toolbar Button**: Click the ๐ผ๏ธ button to select images from your device
2. **Drag & Drop**: Drag images directly into the editor
3. **Paste**: Paste images from clipboard (Ctrl+V)
### Image Resize Functionality
Images inserted into the editor can be resized:
1. **Click any image** to select it (shows blue border with resize handles)
2. **Drag corner handles** to resize freely (width and height independently)
3. **Drag edge handles** for single-dimension resizing
4. **Click outside** to deselect the image
**Resize Features:**
- 8 resize handles (4 corners + 4 edges)
- No aspect ratio constraints - resize to any dimensions
- Minimum size constraints (50px width, 30px height)
- Visual feedback during resize operations
- Clean HTML output (resize controls are editor-only)
## Props API
```typescript
interface DZRichTextEditorProps {
value?: string;
onChange?: (content: string) => void;
toolbarOptions?: string[];
placeholder?: string;
readOnly?: boolean;
height?: string;
width?: string;
toolbarPosition?: "top" | "bottom";
stickyToolbar?: boolean;
stickyOffset?: number;
debounceTime?: number;
customClasses?: CustomClasses;
uploadConfig?: UploadConfig;
}
interface UploadConfig {
uploadApiUrl?: string;
clientId?: string;
clientSecret?: string;
}
```
### Core Props
| Prop | Type | Default | Description |
| ---------------- | --------------------------- | ------------------- | ----------------------------- |
| `value` | `string` | `''` | HTML content of the editor |
| `onChange` | `(content: string) => void` | - | Callback when content changes |
| `toolbarOptions` | `string[]` | All options | Array of toolbar button names |
| `placeholder` | `string` | `'Start typing...'` | Placeholder text |
| `readOnly` | `boolean` | `false` | Disable editing |
| `uploadConfig` | `UploadConfig` | `{}` | Image upload configuration |
### Layout Props
| Prop | Type | Default | Description |
| ----------------- | ------------------- | ---------- | --------------------- |
| `height` | `string` | `'h-64'` | CSS height class |
| `width` | `string` | `'w-full'` | CSS width class |
| `toolbarPosition` | `'top' \| 'bottom'` | `'top'` | Toolbar position |
| `stickyToolbar` | `boolean` | `false` | Enable sticky toolbar |
| `stickyOffset` | `number` | `0` | Sticky toolbar offset |
### Performance Props
| Prop | Type | Default | Description |
| --------------- | --------------- | ------- | -------------------- |
| `debounceTime` | `number` | `300` | Debounce delay (ms) |
| `customClasses` | `CustomClasses` | `{}` | Override CSS classes |
## Toolbar Options
Configure which tools appear in the toolbar:
```jsx
// Minimal toolbar
<DZRichTextEditor
toolbarOptions={['bold', 'italic', 'link']}
// ... other props
/>
// Full toolbar (default)
<DZRichTextEditor
toolbarOptions={[
'bold', 'italic', 'underline', 'strikethrough',
'highlight', 'fontColor', 'headings', 'fontFamily',
'lineSpacing', 'alignLeft', 'alignCenter', 'alignRight',
'alignJustify', 'unorderedList', 'orderedList', 'todoList',
'increaseIndent', 'decreaseIndent', 'link', 'insertImage',
'blockquote', 'codeBlock', 'pageBreak', 'caseChange', 'insertTable'
]}
// ... other props
/>
```
### Available Options
**Basic Formatting:**
- `bold`, `italic`, `underline`, `strikethrough`
- `highlight`, `fontColor`
**Structure:**
- `headings`, `fontFamily`, `lineSpacing`
- `alignLeft`, `alignCenter`, `alignRight`, `alignJustify`
**Lists & Indentation:**
- `unorderedList`, `orderedList`, `todoList`
- `increaseIndent`, `decreaseIndent`
**Content:**
- `link`, `insertImage`, `blockquote`, `codeBlock`
- `insertTable`, `pageBreak`
**Utilities:**
- `caseChange`
## Advanced Examples
### Custom Styled Editor
```jsx
<DZRichTextEditor
value={content}
onChange={setContent}
height="h-96"
width="max-w-4xl"
customClasses={{
wrapper: "border-2 border-purple-300 rounded-xl",
toolbar: "bg-purple-50 border-purple-200",
contentArea: "bg-white min-h-64",
button: "hover:bg-purple-100",
}}
uploadConfig={{
uploadApiUrl: process.env.REACT_APP_UPLOAD_URL,
clientId: process.env.REACT_APP_CLIENT_ID,
clientSecret: process.env.REACT_APP_CLIENT_SECRET,
}}
/>
```
### Sticky Toolbar Example
```jsx
<DZRichTextEditor
value={content}
onChange={setContent}
stickyToolbar={true}
stickyOffset={60} // Account for fixed header
height="h-screen"
/>
```
### Blog Editor Example
```jsx
function BlogEditor({ post, onSave }) {
const [content, setContent] = useState(post.content);
const uploadConfig = {
uploadApiUrl: "/api/blog/upload-image",
clientId: "blog-client",
clientSecret: process.env.REACT_APP_BLOG_SECRET,
};
return (
<div className="max-w-4xl mx-auto">
<DZRichTextEditor
value={content}
onChange={setContent}
placeholder="Write your blog post..."
height="h-96"
uploadConfig={uploadConfig}
toolbarOptions={[
"bold",
"italic",
"underline",
"highlight",
"headings",
"alignLeft",
"alignCenter",
"alignRight",
"unorderedList",
"orderedList",
"link",
"insertImage",
"blockquote",
"insertTable",
]}
/>
<button onClick={() => onSave(content)}>Save Post</button>
</div>
);
}
```
## Environment Configuration
For applications using environment variables, you can configure the upload settings:
```javascript
// .env
REACT_APP_UPLOAD_URL=https://your-api.com/upload
REACT_APP_CLIENT_ID=your-client-id
REACT_APP_CLIENT_SECRET=your-client-secret
// Component
const uploadConfig = {
uploadApiUrl: process.env.REACT_APP_UPLOAD_URL,
clientId: process.env.REACT_APP_CLIENT_ID,
clientSecret: process.env.REACT_APP_CLIENT_SECRET
};
```
## Migration from Environment Variables
If you were previously using environment variables directly (VITE\_\* variables), update your configuration:
**Before:**
```javascript
// .env
VITE_UPLOAD_API_URL=https://api.example.com/upload
VITE_CLIENT_ID=client123
VITE_CLIENT_SECRET=secret456
// No explicit config needed - read automatically
<DZRichTextEditor value={content} onChange={setContent} />
```
**After:**
```javascript
// .env
REACT_APP_UPLOAD_URL=https://api.example.com/upload
REACT_APP_CLIENT_ID=client123
REACT_APP_CLIENT_SECRET=secret456
// Explicit config required
const uploadConfig = {
uploadApiUrl: process.env.REACT_APP_UPLOAD_URL,
clientId: process.env.REACT_APP_CLIENT_ID,
clientSecret: process.env.REACT_APP_CLIENT_SECRET
};
<DZRichTextEditor
value={content}
onChange={setContent}
uploadConfig={uploadConfig}
/>
```
## Keyboard Shortcuts
| Shortcut | Action |
| -------------- | ------------------- |
| `Ctrl/Cmd + B` | Bold |
| `Ctrl/Cmd + I` | Italic |
| `Ctrl/Cmd + U` | Underline |
| `Ctrl/Cmd + L` | Align Left |
| `Ctrl/Cmd + E` | Align Center |
| `Ctrl/Cmd + R` | Align Right |
| `Ctrl/Cmd + J` | Justify |
| `Ctrl/Cmd + 1` | Single Line Spacing |
| `Ctrl/Cmd + 2` | Double Line Spacing |
| `Ctrl/Cmd + 5` | 1.5 Line Spacing |
| `Tab` | Increase Indent |
| `Shift + Tab` | Decrease Indent |
## Browser Support
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
## Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.
## License
MIT License - see LICENSE file for details.
## Version History
### v1.3.0
- โจ Added configurable upload system via props
- ๐ผ๏ธ Implemented image resize functionality
- ๐งน Clean HTML output (no editor artifacts)
- ๐ฆ Prepared for npm package distribution
- ๐ง Added TypeScript definitions
### v1.2.0
- ๐จ Advanced table styling and resizing
- ๐ฑ Improved responsive design
- โก Performance optimizations
### v1.1.0
- ๐ผ๏ธ Image upload via drag & drop and paste
- ๐ Enhanced link management
- ๐ฏ Improved toolbar customization
### v1.0.0
- ๐ Initial release
- โจ Core rich text editing features
- ๐จ Tailwind CSS integration