# 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.

**New in v3.2.0:** Latest stable release with enhanced text formatting capabilities including subscript and superscript options for mathematical expressions, chemical formulas, and footnotes.

## Installation

Install the package from npm:

```bash
npm install dz-rich-text-editor
```

You will also need to install the peer dependencies:

```bash
npm install react react-dom
```

## Importing the Component and CSS

```jsx
// Import the component
import DZRichTextEditor from "dz-rich-text-editor";

// Import the CSS file
import "dz-rich-text-editor/dist/editor.css";
```

### Alternative CSS Import Options

You can also import the CSS file in different ways:

1. In your HTML file:

```html
<link
  rel="stylesheet"
  href="node_modules/dz-rich-text-editor/dist/editor.css"
/>
```

2. Using CSS/SASS imports:

```css
@import "~dz-rich-text-editor/dist/editor.css";
```

3. For webpack configurations, you might need to use:

```javascript
import "dz-rich-text-editor/dist/editor.css";
```

### Standalone Implementation

For standalone implementation, you can wrap your editor with the provided CSS classes for better styling and responsive design:

```jsx
// Import the component
import DZRichTextEditor from "dz-rich-text-editor";
import "dz-rich-text-editor/dist/editor.css";

function MyEditor() {
  const [content, setContent] = useState("");

  return (
    <div className="dz-editor-container dz-editor-reset">
      <DZRichTextEditor
        value={content}
        onChange={setContent}
        placeholder="Start typing..."
      />
    </div>
  );
}
```

The standalone CSS includes:

- Proper button styling for formatting options (B, I, U, S)
- Enhanced dropdown components with wide layouts and selected value display
- Visual feedback for active dropdown selections
- Responsive design for mobile devices
- Properly aligned button groups and separators
- Support for theme customization
- Improved z-index management for dropdown menus

## 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 `editor.css` file for easy styling and customization.
- **Enhanced Dropdowns**: Wide dropdown components that display selected values directly on the button for better user experience.
- **Visual Feedback**: Active dropdown selections are highlighted and the current value is always visible.

## 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/dist/editor.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,
    },
  });
});
```

## Dropdown Features

### Enhanced Dropdown Components

The editor includes four main dropdown components, each designed for optimal user experience:

1. **Headings Dropdown**:

   - Shows current heading level (Normal, Heading 1, Heading 2, etc.)
   - Wide layout for better readability
   - Visual feedback for active selection

2. **Font Family Dropdown**:

   - Displays current font selection (Arial, Times New Roman, etc.)
   - Font preview in dropdown items
   - Wide layout to accommodate font names

3. **Line & Paragraph Spacing Dropdown**:

   - Shows current spacing setting (Single, 1.5, Double, etc.)
   - Includes paragraph spacing options
   - Clear visual representation of spacing values

4. **Bullet List Style Dropdown**:
   - Displays current bullet style (● Disc, ○ Circle, ■ Square)
   - Visual bullet previews
   - Easy switching between list styles

### Dropdown Benefits

- **Always Visible**: Selected values are displayed directly on the dropdown button
- **Wide Layout**: Increased width for better readability and longer text
- **Visual Feedback**: Active selections are highlighted
- **Consistent Styling**: Uniform appearance across all dropdown types
- **Responsive Design**: Adapts to different screen sizes

## 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', 'subscript', 'superscript',
    '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`, `subscript`, `superscript`
- `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

### v3.2.0

- 🔄 Minor version bump for publishing updates
- 📦 Updated package configuration and dependencies

### v3.1.0

- ✨ Added subscript (X₂) and superscript (X²) text formatting buttons
- 📝 Enhanced text formatting capabilities for mathematical expressions and footnotes
- 🎯 Added active state detection for subscript/superscript formatting
- 🔧 Improved toolbar configuration to include new formatting options

### v3.0.0

- 🎉 Major version release with enhanced dropdown components
- 🎯 Enhanced dropdown components with wider layouts
- 📝 Added selected value display on dropdown buttons
- 🎨 Improved visual feedback for active selections
- 📱 Better responsive design for dropdown components
- 🔧 Updated CSS structure for improved maintainability

### v2.3.2

- 🎯 Enhanced dropdown components with wider layouts
- 📝 Added selected value display on dropdown buttons
- 🎨 Improved visual feedback for active selections
- 📱 Better responsive design for dropdown components
- 🔧 Updated CSS structure for improved maintainability

### v2.2.x Series

- 🎨 Improved standalone CSS with better responsive design
- 📦 Enhanced npm package configuration
- 🔧 Better build optimization and CSS bundling
- 📱 Mobile-friendly toolbar and dropdown layouts

### 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
