@malaya_jeeva/rich-text-editor 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -0
- package/dist/index.js +12 -1
- package/dist/index.mjs +12 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# 📝 @malaya_jeeva/rich-text-editor
|
|
2
|
+
|
|
3
|
+
A lightweight, customizable **Rich Text Editor (WYSIWYG)** built with React. Supports formatting, lists, alignment, links, code view, and more.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @malaya_jeeva/rich-text-editor
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 Usage
|
|
16
|
+
|
|
17
|
+
### Basic Example
|
|
18
|
+
|
|
19
|
+
```jsx
|
|
20
|
+
'use client' // required for Next.js (App Router)
|
|
21
|
+
|
|
22
|
+
import React, { useState } from 'react'
|
|
23
|
+
import { RichTextEditor } from '@malaya_jeeva/rich-text-editor'
|
|
24
|
+
|
|
25
|
+
export default function Page() {
|
|
26
|
+
const [value, setValue] = useState('')
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div>
|
|
30
|
+
<RichTextEditor value={value} onChange={setValue} />
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## ⚙️ Props
|
|
39
|
+
|
|
40
|
+
| Prop | Type | Description |
|
|
41
|
+
| ---------- | ------------------------- | ----------------------------- |
|
|
42
|
+
| `value` | `string` | HTML content of the editor |
|
|
43
|
+
| `onChange` | `(value: string) => void` | Callback when content changes |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ✨ Features
|
|
48
|
+
|
|
49
|
+
* ✅ Bold, Italic, Underline
|
|
50
|
+
* 🎨 Text Color Picker
|
|
51
|
+
* 🔠 Headings (H1, H2, H3)
|
|
52
|
+
* 📌 Bullet & Numbered Lists
|
|
53
|
+
* ↔️ Text Alignment (Left, Center, Right, Justify)
|
|
54
|
+
* 🔗 Insert Links
|
|
55
|
+
* 💻 Code Block Support
|
|
56
|
+
* 🔄 Toggle HTML / Visual Mode
|
|
57
|
+
* 📋 Copy HTML Content
|
|
58
|
+
* ⌨️ Keyboard Shortcuts (Ctrl+B, Ctrl+I, Ctrl+U)
|
|
59
|
+
* 📊 Word Count
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🧠 Keyboard Shortcuts
|
|
64
|
+
|
|
65
|
+
| Shortcut | Action |
|
|
66
|
+
| ------------- | --------------------- |
|
|
67
|
+
| `Ctrl + B` | Bold |
|
|
68
|
+
| `Ctrl + I` | Italic |
|
|
69
|
+
| `Ctrl + U` | Underline |
|
|
70
|
+
| `Tab` | Indent (inside lists) |
|
|
71
|
+
| `Shift + Tab` | Outdent |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 🎯 Notes
|
|
76
|
+
|
|
77
|
+
* This is a **controlled component** → always pass `value` and `onChange`
|
|
78
|
+
* Works with **React 18+ and 19+**
|
|
79
|
+
* Compatible with **Next.js** (use `'use client'`)
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 🔄 Development Workflow
|
|
84
|
+
|
|
85
|
+
### Local Development
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm link
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
In your app:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm link @malaya_jeeva/rich-text-editor
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 📌 Future Improvements
|
|
100
|
+
|
|
101
|
+
* Toolbar customization
|
|
102
|
+
* Plugin system
|
|
103
|
+
* Image upload support
|
|
104
|
+
* Markdown support
|
|
105
|
+
* Theme customization
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 👨💻 Author
|
|
110
|
+
|
|
111
|
+
**Malaya Ranjan Jena**
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 📄 License
|
|
116
|
+
|
|
117
|
+
ISC
|
package/dist/index.js
CHANGED
|
@@ -407,12 +407,23 @@ function RichTextEditor({ value, onChange }) {
|
|
|
407
407
|
setSelCells([]);
|
|
408
408
|
dragStartCell.current = null;
|
|
409
409
|
}, []);
|
|
410
|
+
const fixListNesting = (0, import_react.useCallback)(() => {
|
|
411
|
+
const editor = editorRef.current;
|
|
412
|
+
if (!editor) return;
|
|
413
|
+
editor.querySelectorAll("ol > ol, ol > ul, ul > ol, ul > ul").forEach((orphan) => {
|
|
414
|
+
const prev = orphan.previousElementSibling;
|
|
415
|
+
if (prev && prev.tagName === "LI") {
|
|
416
|
+
prev.appendChild(orphan);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}, []);
|
|
410
420
|
const exec = (0, import_react.useCallback)((cmd, val = null) => {
|
|
411
421
|
var _a2;
|
|
412
422
|
(_a2 = editorRef.current) == null ? void 0 : _a2.focus();
|
|
413
423
|
document.execCommand(cmd, false, val != null ? val : void 0);
|
|
424
|
+
fixListNesting();
|
|
414
425
|
refresh();
|
|
415
|
-
}, []);
|
|
426
|
+
}, [fixListNesting]);
|
|
416
427
|
const refresh = (0, import_react.useCallback)(() => {
|
|
417
428
|
var _a2, _b, _c, _d;
|
|
418
429
|
const raw = document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g, "");
|
package/dist/index.mjs
CHANGED
|
@@ -386,12 +386,23 @@ function RichTextEditor({ value, onChange }) {
|
|
|
386
386
|
setSelCells([]);
|
|
387
387
|
dragStartCell.current = null;
|
|
388
388
|
}, []);
|
|
389
|
+
const fixListNesting = useCallback(() => {
|
|
390
|
+
const editor = editorRef.current;
|
|
391
|
+
if (!editor) return;
|
|
392
|
+
editor.querySelectorAll("ol > ol, ol > ul, ul > ol, ul > ul").forEach((orphan) => {
|
|
393
|
+
const prev = orphan.previousElementSibling;
|
|
394
|
+
if (prev && prev.tagName === "LI") {
|
|
395
|
+
prev.appendChild(orphan);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}, []);
|
|
389
399
|
const exec = useCallback((cmd, val = null) => {
|
|
390
400
|
var _a2;
|
|
391
401
|
(_a2 = editorRef.current) == null ? void 0 : _a2.focus();
|
|
392
402
|
document.execCommand(cmd, false, val != null ? val : void 0);
|
|
403
|
+
fixListNesting();
|
|
393
404
|
refresh();
|
|
394
|
-
}, []);
|
|
405
|
+
}, [fixListNesting]);
|
|
395
406
|
const refresh = useCallback(() => {
|
|
396
407
|
var _a2, _b, _c, _d;
|
|
397
408
|
const raw = document.queryCommandValue("formatBlock").toLowerCase().replace(/[<>]/g, "");
|