UNPKG

@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
# 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