rte-react 0.1.0
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 +78 -0
- package/dist/editor-XH5ZEVLH.css +288 -0
- package/dist/index.d.mts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +604 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +567 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# rte-react
|
|
2
|
+
|
|
3
|
+
A lightweight, fully-typed React rich text editor with a configurable toolbar. Outputs clean HTML. Works with React 17 and higher.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install rte-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { RichEditor } from 'rte-react';
|
|
15
|
+
import 'rte-react/styles';
|
|
16
|
+
|
|
17
|
+
function App() {
|
|
18
|
+
const [content, setContent] = useState('<p>Hello world</p>');
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<RichEditor
|
|
22
|
+
value={content}
|
|
23
|
+
onChange={setContent}
|
|
24
|
+
placeholder="Start typing..."
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Custom Toolbar
|
|
31
|
+
|
|
32
|
+
Pass a `toolbar` prop to control which tools are shown:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<RichEditor
|
|
36
|
+
value={content}
|
|
37
|
+
onChange={setContent}
|
|
38
|
+
toolbar={['bold', 'italic', 'underline', 'divider', 'bulletList', 'orderedList', 'divider', 'link']}
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Available Tools
|
|
43
|
+
|
|
44
|
+
| Tool | Description |
|
|
45
|
+
|------|-------------|
|
|
46
|
+
| `bold` | Bold text |
|
|
47
|
+
| `italic` | Italic text |
|
|
48
|
+
| `underline` | Underline text |
|
|
49
|
+
| `strikethrough` | Strikethrough text |
|
|
50
|
+
| `heading1` – `heading6` | Headings |
|
|
51
|
+
| `bulletList` | Bullet list |
|
|
52
|
+
| `orderedList` | Numbered list |
|
|
53
|
+
| `blockquote` | Blockquote |
|
|
54
|
+
| `codeBlock` | Code block |
|
|
55
|
+
| `link` | Insert/edit link |
|
|
56
|
+
| `image` | Insert image by URL |
|
|
57
|
+
| `table` | Insert 3x3 table |
|
|
58
|
+
| `undo` | Undo |
|
|
59
|
+
| `redo` | Redo |
|
|
60
|
+
| `divider` | Visual separator in toolbar |
|
|
61
|
+
|
|
62
|
+
## Props
|
|
63
|
+
|
|
64
|
+
| Prop | Type | Default | Description |
|
|
65
|
+
|------|------|---------|-------------|
|
|
66
|
+
| `value` | `string` | `''` | HTML content |
|
|
67
|
+
| `onChange` | `(html: string) => void` | — | Called on content change |
|
|
68
|
+
| `toolbar` | `ToolbarTool[]` | All tools | Tools to show in toolbar |
|
|
69
|
+
| `placeholder` | `string` | `'Start typing...'` | Placeholder text |
|
|
70
|
+
| `editable` | `boolean` | `true` | Enable/disable editing |
|
|
71
|
+
| `className` | `string` | — | Class for outer wrapper |
|
|
72
|
+
| `toolbarClassName` | `string` | — | Class for toolbar |
|
|
73
|
+
| `contentClassName` | `string` | — | Class for content area |
|
|
74
|
+
| `style` | `CSSProperties` | — | Inline style for wrapper |
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/* react-rich-editor styles */
|
|
2
|
+
|
|
3
|
+
.rre-editor {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
border: 1px solid #e2e8f0;
|
|
7
|
+
border-radius: 8px;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
10
|
+
font-size: 15px;
|
|
11
|
+
line-height: 1.6;
|
|
12
|
+
color: #1a202c;
|
|
13
|
+
background: #fff;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Toolbar */
|
|
17
|
+
.rre-toolbar {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 2px;
|
|
22
|
+
padding: 6px 8px;
|
|
23
|
+
border-bottom: 1px solid #e2e8f0;
|
|
24
|
+
background: #f8fafc;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.rre-toolbar-btn {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
width: 32px;
|
|
32
|
+
height: 32px;
|
|
33
|
+
padding: 0;
|
|
34
|
+
border: none;
|
|
35
|
+
border-radius: 5px;
|
|
36
|
+
background: transparent;
|
|
37
|
+
color: #4a5568;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
40
|
+
outline: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.rre-toolbar-btn:hover:not(.rre-toolbar-btn--disabled) {
|
|
44
|
+
background: #e2e8f0;
|
|
45
|
+
color: #1a202c;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.rre-toolbar-btn--active {
|
|
49
|
+
background: #ebf4ff;
|
|
50
|
+
color: #3182ce;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.rre-toolbar-btn--active:hover {
|
|
54
|
+
background: #bee3f8;
|
|
55
|
+
color: #2b6cb0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.rre-toolbar-btn--disabled {
|
|
59
|
+
opacity: 0.35;
|
|
60
|
+
cursor: not-allowed;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.rre-toolbar-divider {
|
|
64
|
+
width: 1px;
|
|
65
|
+
height: 20px;
|
|
66
|
+
background: #e2e8f0;
|
|
67
|
+
margin: 0 4px;
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.rre-fontsize-select {
|
|
72
|
+
height: 28px;
|
|
73
|
+
padding: 0 6px;
|
|
74
|
+
border: 1px solid #e2e8f0;
|
|
75
|
+
border-radius: 5px;
|
|
76
|
+
background: #fff;
|
|
77
|
+
color: #4a5568;
|
|
78
|
+
font-size: 13px;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
outline: none;
|
|
81
|
+
transition: border-color 0.15s ease;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.rre-fontsize-select:hover,
|
|
85
|
+
.rre-fontsize-select:focus {
|
|
86
|
+
border-color: #a0aec0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.rre-icon {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
width: 16px;
|
|
94
|
+
height: 16px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.rre-icon svg {
|
|
98
|
+
width: 16px;
|
|
99
|
+
height: 16px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Editor content area */
|
|
103
|
+
.rre-content {
|
|
104
|
+
flex: 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.rre-content .ProseMirror {
|
|
108
|
+
min-height: 160px;
|
|
109
|
+
padding: 14px 16px;
|
|
110
|
+
outline: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.rre-content .ProseMirror p.is-editor-empty:first-child::before {
|
|
114
|
+
content: attr(data-placeholder);
|
|
115
|
+
float: left;
|
|
116
|
+
color: #a0aec0;
|
|
117
|
+
pointer-events: none;
|
|
118
|
+
height: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Typography */
|
|
122
|
+
.rre-content .ProseMirror h1 { font-size: 2em; font-weight: 700; margin: 0.67em 0; }
|
|
123
|
+
.rre-content .ProseMirror h2 { font-size: 1.5em; font-weight: 700; margin: 0.75em 0; }
|
|
124
|
+
.rre-content .ProseMirror h3 { font-size: 1.25em; font-weight: 600; margin: 0.83em 0; }
|
|
125
|
+
.rre-content .ProseMirror h4 { font-size: 1.1em; font-weight: 600; margin: 1em 0; }
|
|
126
|
+
.rre-content .ProseMirror h5 { font-size: 0.95em; font-weight: 600; margin: 1em 0; }
|
|
127
|
+
.rre-content .ProseMirror h6 { font-size: 0.85em; font-weight: 600; margin: 1em 0; color: #718096; }
|
|
128
|
+
|
|
129
|
+
.rre-content .ProseMirror p { margin: 0.5em 0; }
|
|
130
|
+
|
|
131
|
+
.rre-content .ProseMirror ul,
|
|
132
|
+
.rre-content .ProseMirror ol {
|
|
133
|
+
padding-left: 1.5em;
|
|
134
|
+
margin: 0.5em 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.rre-content .ProseMirror blockquote {
|
|
138
|
+
border-left: 3px solid #cbd5e0;
|
|
139
|
+
padding-left: 1em;
|
|
140
|
+
margin: 1em 0;
|
|
141
|
+
color: #718096;
|
|
142
|
+
font-style: italic;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.rre-content .ProseMirror code {
|
|
146
|
+
background: #edf2f7;
|
|
147
|
+
border-radius: 3px;
|
|
148
|
+
padding: 0.1em 0.3em;
|
|
149
|
+
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
|
150
|
+
font-size: 0.875em;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.rre-content .ProseMirror pre {
|
|
154
|
+
background: #2d3748;
|
|
155
|
+
color: #e2e8f0;
|
|
156
|
+
border-radius: 6px;
|
|
157
|
+
padding: 12px 16px;
|
|
158
|
+
margin: 1em 0;
|
|
159
|
+
overflow-x: auto;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.rre-content .ProseMirror pre code {
|
|
163
|
+
background: none;
|
|
164
|
+
color: inherit;
|
|
165
|
+
padding: 0;
|
|
166
|
+
font-size: 0.875em;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.rre-content .ProseMirror a {
|
|
170
|
+
color: #3182ce;
|
|
171
|
+
text-decoration: underline;
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.rre-content .ProseMirror img {
|
|
176
|
+
max-width: 100%;
|
|
177
|
+
border-radius: 4px;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Table */
|
|
181
|
+
.rre-content .ProseMirror table {
|
|
182
|
+
border-collapse: collapse;
|
|
183
|
+
width: 100%;
|
|
184
|
+
margin: 1em 0;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
border-radius: 4px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.rre-content .ProseMirror th,
|
|
190
|
+
.rre-content .ProseMirror td {
|
|
191
|
+
border: 1px solid #e2e8f0;
|
|
192
|
+
padding: 8px 12px;
|
|
193
|
+
text-align: left;
|
|
194
|
+
position: relative;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.rre-content .ProseMirror th {
|
|
198
|
+
background: #f8fafc;
|
|
199
|
+
font-weight: 600;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.rre-content .ProseMirror .selectedCell::after {
|
|
203
|
+
background: rgba(49, 130, 206, 0.1);
|
|
204
|
+
content: '';
|
|
205
|
+
left: 0;
|
|
206
|
+
right: 0;
|
|
207
|
+
top: 0;
|
|
208
|
+
bottom: 0;
|
|
209
|
+
pointer-events: none;
|
|
210
|
+
position: absolute;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* Popup wrapper */
|
|
214
|
+
.rre-toolbar-popup-wrapper {
|
|
215
|
+
position: relative;
|
|
216
|
+
display: inline-flex;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.rre-popup {
|
|
220
|
+
position: absolute;
|
|
221
|
+
top: calc(100% + 6px);
|
|
222
|
+
left: 0;
|
|
223
|
+
z-index: 100;
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
gap: 6px;
|
|
227
|
+
background: #fff;
|
|
228
|
+
border: 1px solid #e2e8f0;
|
|
229
|
+
border-radius: 8px;
|
|
230
|
+
padding: 8px 10px;
|
|
231
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.1);
|
|
232
|
+
white-space: nowrap;
|
|
233
|
+
flex-direction: column;
|
|
234
|
+
align-items: stretch;
|
|
235
|
+
min-width: 220px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.rre-popup--table {
|
|
239
|
+
flex-direction: row;
|
|
240
|
+
align-items: center;
|
|
241
|
+
min-width: unset;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.rre-popup-input {
|
|
245
|
+
height: 30px;
|
|
246
|
+
padding: 0 8px;
|
|
247
|
+
border: 1px solid #e2e8f0;
|
|
248
|
+
border-radius: 5px;
|
|
249
|
+
font-size: 13px;
|
|
250
|
+
color: #1a202c;
|
|
251
|
+
outline: none;
|
|
252
|
+
transition: border-color 0.15s;
|
|
253
|
+
width: 100%;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.rre-popup-input:focus {
|
|
257
|
+
border-color: #3182ce;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.rre-popup-input--num {
|
|
261
|
+
width: 52px;
|
|
262
|
+
text-align: center;
|
|
263
|
+
padding: 0 4px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.rre-popup-x {
|
|
267
|
+
font-size: 14px;
|
|
268
|
+
color: #718096;
|
|
269
|
+
font-weight: 500;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.rre-popup-btn {
|
|
273
|
+
height: 30px;
|
|
274
|
+
padding: 0 12px;
|
|
275
|
+
background: #3182ce;
|
|
276
|
+
color: #fff;
|
|
277
|
+
border: none;
|
|
278
|
+
border-radius: 5px;
|
|
279
|
+
font-size: 13px;
|
|
280
|
+
font-weight: 500;
|
|
281
|
+
cursor: pointer;
|
|
282
|
+
transition: background 0.15s;
|
|
283
|
+
white-space: nowrap;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.rre-popup-btn:hover {
|
|
287
|
+
background: #2b6cb0;
|
|
288
|
+
}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React$1 from 'react';
|
|
2
|
+
|
|
3
|
+
type ToolbarTool = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'heading1' | 'heading2' | 'heading3' | 'heading4' | 'heading5' | 'heading6' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' | 'link' | 'image' | 'table' | 'undo' | 'redo' | 'fontSize' | 'divider';
|
|
4
|
+
interface RichEditorProps {
|
|
5
|
+
value?: string;
|
|
6
|
+
onChange?: (html: string) => void;
|
|
7
|
+
toolbar?: ToolbarTool[];
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
editable?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
toolbarClassName?: string;
|
|
13
|
+
contentClassName?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ToolbarButtonProps {
|
|
16
|
+
onClick: () => void;
|
|
17
|
+
isActive?: boolean;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
title: string;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
interface ToolDefinition {
|
|
23
|
+
name: ToolbarTool;
|
|
24
|
+
title: string;
|
|
25
|
+
icon: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare const RichEditor: React$1.FC<RichEditorProps>;
|
|
29
|
+
|
|
30
|
+
export { RichEditor, type RichEditorProps, type ToolDefinition, type ToolbarButtonProps, type ToolbarTool };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React$1 from 'react';
|
|
2
|
+
|
|
3
|
+
type ToolbarTool = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'heading1' | 'heading2' | 'heading3' | 'heading4' | 'heading5' | 'heading6' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' | 'link' | 'image' | 'table' | 'undo' | 'redo' | 'fontSize' | 'divider';
|
|
4
|
+
interface RichEditorProps {
|
|
5
|
+
value?: string;
|
|
6
|
+
onChange?: (html: string) => void;
|
|
7
|
+
toolbar?: ToolbarTool[];
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
editable?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: React.CSSProperties;
|
|
12
|
+
toolbarClassName?: string;
|
|
13
|
+
contentClassName?: string;
|
|
14
|
+
}
|
|
15
|
+
interface ToolbarButtonProps {
|
|
16
|
+
onClick: () => void;
|
|
17
|
+
isActive?: boolean;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
title: string;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
interface ToolDefinition {
|
|
23
|
+
name: ToolbarTool;
|
|
24
|
+
title: string;
|
|
25
|
+
icon: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare const RichEditor: React$1.FC<RichEditorProps>;
|
|
29
|
+
|
|
30
|
+
export { RichEditor, type RichEditorProps, type ToolDefinition, type ToolbarButtonProps, type ToolbarTool };
|