@zencemarketing/text-editor-sdk 0.1.0-alpha.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 +666 -0
- package/dist/App.d.ts +4 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/components/ColorPicker.d.ts +10 -0
- package/dist/components/ColorPicker.d.ts.map +1 -0
- package/dist/components/EditorElement.d.ts +4 -0
- package/dist/components/EditorElement.d.ts.map +1 -0
- package/dist/components/EditorLeaf.d.ts +4 -0
- package/dist/components/EditorLeaf.d.ts.map +1 -0
- package/dist/components/EmojiPicker.d.ts +7 -0
- package/dist/components/EmojiPicker.d.ts.map +1 -0
- package/dist/components/PasteOptionsMenu.d.ts +13 -0
- package/dist/components/PasteOptionsMenu.d.ts.map +1 -0
- package/dist/components/Resizable.d.ts +17 -0
- package/dist/components/Resizable.d.ts.map +1 -0
- package/dist/components/RichTextEditor.d.ts +6 -0
- package/dist/components/RichTextEditor.d.ts.map +1 -0
- package/dist/components/Toolbar.d.ts +24 -0
- package/dist/components/Toolbar.d.ts.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.css +1 -0
- package/dist/index.esm.js +37225 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +37230 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/types/index.d.ts +390 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/slate.d.ts +82 -0
- package/dist/types/slate.d.ts.map +1 -0
- package/dist/utils/pasteHelpers.d.ts +5 -0
- package/dist/utils/pasteHelpers.d.ts.map +1 -0
- package/dist/utils/slateHelpers.d.ts +25 -0
- package/dist/utils/slateHelpers.d.ts.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
# @zencemarketing/text-editor-sdk
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Alpha Release**: This is an early alpha version (0.1.0-alpha.0). APIs may change before the stable 1.0.0 release. Use in production at your own risk.
|
|
4
|
+
|
|
5
|
+
A highly customizable, feature-rich React text editor built with Slate.js. Perfect for content management systems, messaging apps, comment sections, and any application requiring rich text editing capabilities.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@zencemarketing/text-editor-sdk)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
|
|
10
|
+
## 🚀 Features
|
|
11
|
+
|
|
12
|
+
- **📝 Rich Text Formatting** - Bold, italic, underline, strikethrough, headings (H1-H3)
|
|
13
|
+
- **🎨 Lists** - Bulleted and numbered lists
|
|
14
|
+
- **🔗 Links & Media** - Insert links and upload images/videos
|
|
15
|
+
- **👥 Mentions** - @mention users with autocomplete
|
|
16
|
+
- **#️⃣ Tags/Variables** - Insert dynamic placeholders for content personalization
|
|
17
|
+
- **😊 Emoji Picker** - Built-in emoji selector
|
|
18
|
+
- **💻 Code Blocks** - Syntax-highlighted code snippets
|
|
19
|
+
- **📋 Smart Paste** - Keep formatting, match style, or paste as plain text
|
|
20
|
+
- **🔢 Character Counter** - Track and limit character count
|
|
21
|
+
- **⚙️ Fully Customizable** - Control height, width, colors, borders, and more
|
|
22
|
+
- **🎯 Configurable Toolbars** - Top, bottom, or both with custom button selection
|
|
23
|
+
- **✅ Action Buttons** - Built-in Cancel/Submit buttons with callbacks
|
|
24
|
+
- **📱 Responsive** - Works on desktop and mobile
|
|
25
|
+
- **♿ Accessible** - Keyboard navigation and ARIA support
|
|
26
|
+
- **📦 TypeScript** - Full type definitions included
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @zencemarketing/text-editor-sdk
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or with yarn:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
yarn add @zencemarketing/text-editor-sdk
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For alpha version specifically:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install @zencemarketing/text-editor-sdk@alpha
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Peer Dependencies
|
|
47
|
+
|
|
48
|
+
Make sure you have React installed:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install react react-dom
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 🎯 Quick Start
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import React, { useState } from 'react';
|
|
58
|
+
import RichTextEditor from '@zencemarketing/text-editor-sdk';
|
|
59
|
+
|
|
60
|
+
function App() {
|
|
61
|
+
const [content, setContent] = useState('');
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<RichTextEditor
|
|
65
|
+
value={content}
|
|
66
|
+
onChange={setContent}
|
|
67
|
+
placeholder="Start typing..."
|
|
68
|
+
features={{
|
|
69
|
+
bold: true,
|
|
70
|
+
italic: true,
|
|
71
|
+
underline: true,
|
|
72
|
+
links: true,
|
|
73
|
+
bulletList: true
|
|
74
|
+
}}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 📖 Documentation
|
|
81
|
+
|
|
82
|
+
### Props
|
|
83
|
+
|
|
84
|
+
#### Content Management
|
|
85
|
+
|
|
86
|
+
| Prop | Type | Default | Description |
|
|
87
|
+
|------|------|---------|-------------|
|
|
88
|
+
| `value` | `string` | `undefined` | Controlled value (JSON string of Slate nodes) |
|
|
89
|
+
| `defaultValue` | `string` | `'[]'` | Initial value for uncontrolled component |
|
|
90
|
+
| `onChange` | `(value: string) => void` | `undefined` | Callback when content changes |
|
|
91
|
+
| `placeholder` | `string` | `"Start typing..."` | Placeholder text |
|
|
92
|
+
|
|
93
|
+
#### Styling
|
|
94
|
+
|
|
95
|
+
| Prop | Type | Default | Description |
|
|
96
|
+
|------|------|---------|-------------|
|
|
97
|
+
| `width` | `string \| number` | `"100%"` | Editor width |
|
|
98
|
+
| `minHeight` | `string \| number` | `"200px"` | Minimum height |
|
|
99
|
+
| `maxHeight` | `string \| number` | `"400px"` | Maximum height |
|
|
100
|
+
| `borderColor` | `string` | `"#ddd"` | Border color |
|
|
101
|
+
| `borderRadius` | `string \| number` | `"4px"` | Border radius |
|
|
102
|
+
| `backgroundColor` | `string` | `"#ffffff"` | Background color |
|
|
103
|
+
| `textColor` | `string` | `"inherit"` | Text color |
|
|
104
|
+
|
|
105
|
+
#### Features
|
|
106
|
+
|
|
107
|
+
| Prop | Type | Default | Description |
|
|
108
|
+
|------|------|---------|-------------|
|
|
109
|
+
| `features` | `EditorFeatures` | `{}` | Object to enable/disable features |
|
|
110
|
+
|
|
111
|
+
#### Features Object
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
{
|
|
115
|
+
textFormatting?: boolean; // Enable text formatting
|
|
116
|
+
headings?: boolean; // Enable H1, H2, H3
|
|
117
|
+
bold?: boolean; // Enable bold
|
|
118
|
+
italic?: boolean; // Enable italic
|
|
119
|
+
underline?: boolean; // Enable underline
|
|
120
|
+
strikethrough?: boolean; // Enable strikethrough
|
|
121
|
+
textColor?: boolean; // Enable text color
|
|
122
|
+
highlightColor?: boolean; // Enable highlight
|
|
123
|
+
bulletList?: boolean; // Enable bulleted lists
|
|
124
|
+
numberedList?: boolean; // Enable numbered lists
|
|
125
|
+
links?: boolean; // Enable link insertion
|
|
126
|
+
mediaUpload?: boolean; // Enable media upload
|
|
127
|
+
mentions?: boolean; // Enable @mentions
|
|
128
|
+
emoji?: boolean; // Enable emoji picker
|
|
129
|
+
codeBlock?: boolean; // Enable code blocks
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### Mentions
|
|
134
|
+
|
|
135
|
+
| Prop | Type | Description |
|
|
136
|
+
|------|------|-------------|
|
|
137
|
+
| `mentionUsers` | `User[]` | Array of users for @mentions |
|
|
138
|
+
| `onMentionSelect` | `(user: User) => void` | Callback when user is mentioned |
|
|
139
|
+
|
|
140
|
+
**User Type:**
|
|
141
|
+
```typescript
|
|
142
|
+
interface User {
|
|
143
|
+
id: string;
|
|
144
|
+
name: string;
|
|
145
|
+
avatar?: string;
|
|
146
|
+
email?: string;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Tags/Variables
|
|
151
|
+
|
|
152
|
+
| Prop | Type | Description |
|
|
153
|
+
|------|------|-------------|
|
|
154
|
+
| `tags` | `Tag[]` | Array of tags/variables |
|
|
155
|
+
| `onTagSelect` | `(tag: Tag) => void` | Callback when tag is inserted |
|
|
156
|
+
| `tagPlaceholder` | `string` | Placeholder for tag search |
|
|
157
|
+
|
|
158
|
+
**Tag Type:**
|
|
159
|
+
```typescript
|
|
160
|
+
interface Tag {
|
|
161
|
+
id: string;
|
|
162
|
+
label: string; // Display name
|
|
163
|
+
value: string; // Actual value (e.g., "{{userName}}")
|
|
164
|
+
description?: string; // Optional description
|
|
165
|
+
color?: string; // Text color
|
|
166
|
+
backgroundColor?: string; // Background color
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Media Upload
|
|
171
|
+
|
|
172
|
+
| Prop | Type | Description |
|
|
173
|
+
|------|------|-------------|
|
|
174
|
+
| `onMediaUpload` | `(file: File) => Promise<string \| void>` | Async function to handle file upload |
|
|
175
|
+
|
|
176
|
+
#### Character Counter
|
|
177
|
+
|
|
178
|
+
| Prop | Type | Default | Description |
|
|
179
|
+
|------|------|---------|-------------|
|
|
180
|
+
| `showCharCount` | `boolean` | `false` | Show character count |
|
|
181
|
+
| `maxCharCount` | `number` | `undefined` | Maximum characters allowed |
|
|
182
|
+
| `charCountPosition` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Position of counter |
|
|
183
|
+
|
|
184
|
+
#### Toolbar Configuration
|
|
185
|
+
|
|
186
|
+
| Prop | Type | Default | Description |
|
|
187
|
+
|------|------|---------|-------------|
|
|
188
|
+
| `toolbarPosition` | `'top' \| 'bottom' \| 'both'` | `'top'` | Toolbar position |
|
|
189
|
+
| `topToolbarButtons` | `string[]` | `[]` | Buttons for top toolbar |
|
|
190
|
+
| `bottomToolbarButtons` | `string[]` | `[]` | Buttons for bottom toolbar |
|
|
191
|
+
|
|
192
|
+
**Available Toolbar Buttons:**
|
|
193
|
+
`'headings'`, `'bold'`, `'italic'`, `'underline'`, `'strikethrough'`, `'bulletList'`, `'numberedList'`, `'link'`, `'mediaUpload'`, `'mentions'`, `'tags'`, `'emoji'`, `'codeBlock'`, `'more'`
|
|
194
|
+
|
|
195
|
+
#### Action Buttons
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
|------|------|---------|-------------|
|
|
199
|
+
| `actionButtonsPosition` | `'top-right' \| 'bottom-right' \| 'none'` | `'none'` | Position of action buttons |
|
|
200
|
+
| `cancelButton` | `CancelButtonConfig` | `undefined` | Cancel button configuration |
|
|
201
|
+
| `submitButton` | `SubmitButtonConfig` | `undefined` | Submit button configuration |
|
|
202
|
+
|
|
203
|
+
**Button Configuration:**
|
|
204
|
+
```typescript
|
|
205
|
+
interface CancelButtonConfig {
|
|
206
|
+
show?: boolean;
|
|
207
|
+
label?: string; // Max 15 characters
|
|
208
|
+
position?: 1 | 2; // Order (1=first, 2=second)
|
|
209
|
+
style?: React.CSSProperties;
|
|
210
|
+
onClick?: () => void;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interface SubmitButtonConfig {
|
|
214
|
+
show?: boolean;
|
|
215
|
+
label?: string;
|
|
216
|
+
position?: 1 | 2;
|
|
217
|
+
style?: React.CSSProperties;
|
|
218
|
+
onClick?: (content: string) => void; // Receives JSON string
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## 💡 Usage Examples
|
|
223
|
+
|
|
224
|
+
### Basic Editor
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
import RichTextEditor from '@zencemarketing/text-editor-sdk';
|
|
228
|
+
|
|
229
|
+
function BasicEditor() {
|
|
230
|
+
const [content, setContent] = useState('');
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<RichTextEditor
|
|
234
|
+
value={content}
|
|
235
|
+
onChange={setContent}
|
|
236
|
+
features={{
|
|
237
|
+
bold: true,
|
|
238
|
+
italic: true,
|
|
239
|
+
underline: true
|
|
240
|
+
}}
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### With Mentions & Tags
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
const users = [
|
|
250
|
+
{ id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
251
|
+
{ id: '2', name: 'Jane Smith', email: 'jane@example.com' }
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
const tags = [
|
|
255
|
+
{
|
|
256
|
+
id: '1',
|
|
257
|
+
label: 'User Name',
|
|
258
|
+
value: '{{userName}}',
|
|
259
|
+
backgroundColor: '#fff3cd',
|
|
260
|
+
color: '#856404'
|
|
261
|
+
}
|
|
262
|
+
];
|
|
263
|
+
|
|
264
|
+
function EditorWithMentions() {
|
|
265
|
+
const [content, setContent] = useState('');
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<RichTextEditor
|
|
269
|
+
value={content}
|
|
270
|
+
onChange={setContent}
|
|
271
|
+
mentionUsers={users}
|
|
272
|
+
onMentionSelect={(user) => console.log('Mentioned:', user)}
|
|
273
|
+
tags={tags}
|
|
274
|
+
onTagSelect={(tag) => console.log('Tag inserted:', tag)}
|
|
275
|
+
features={{
|
|
276
|
+
mentions: true,
|
|
277
|
+
bold: true,
|
|
278
|
+
italic: true
|
|
279
|
+
}}
|
|
280
|
+
/>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### With Image Upload
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
function EditorWithUpload() {
|
|
289
|
+
const [content, setContent] = useState('');
|
|
290
|
+
|
|
291
|
+
const handleUpload = async (file: File) => {
|
|
292
|
+
const formData = new FormData();
|
|
293
|
+
formData.append('file', file);
|
|
294
|
+
|
|
295
|
+
const response = await fetch('/api/upload', {
|
|
296
|
+
method: 'POST',
|
|
297
|
+
body: formData
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const { url } = await response.json();
|
|
301
|
+
return url;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<RichTextEditor
|
|
306
|
+
value={content}
|
|
307
|
+
onChange={setContent}
|
|
308
|
+
onMediaUpload={handleUpload}
|
|
309
|
+
features={{
|
|
310
|
+
mediaUpload: true,
|
|
311
|
+
bold: true,
|
|
312
|
+
italic: true
|
|
313
|
+
}}
|
|
314
|
+
/>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### With Character Limit
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
function EditorWithLimit() {
|
|
323
|
+
const [content, setContent] = useState('');
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<RichTextEditor
|
|
327
|
+
value={content}
|
|
328
|
+
onChange={setContent}
|
|
329
|
+
showCharCount={true}
|
|
330
|
+
maxCharCount={1000}
|
|
331
|
+
charCountPosition="bottom-right"
|
|
332
|
+
features={{
|
|
333
|
+
bold: true,
|
|
334
|
+
italic: true
|
|
335
|
+
}}
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### With Custom Toolbars
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
function EditorWithCustomToolbars() {
|
|
345
|
+
const [content, setContent] = useState('');
|
|
346
|
+
|
|
347
|
+
return (
|
|
348
|
+
<RichTextEditor
|
|
349
|
+
value={content}
|
|
350
|
+
onChange={setContent}
|
|
351
|
+
toolbarPosition="both"
|
|
352
|
+
topToolbarButtons={['headings', 'bold', 'italic', 'link']}
|
|
353
|
+
bottomToolbarButtons={['emoji', 'mentions', 'mediaUpload']}
|
|
354
|
+
features={{
|
|
355
|
+
headings: true,
|
|
356
|
+
bold: true,
|
|
357
|
+
italic: true,
|
|
358
|
+
links: true,
|
|
359
|
+
emoji: true,
|
|
360
|
+
mentions: true,
|
|
361
|
+
mediaUpload: true
|
|
362
|
+
}}
|
|
363
|
+
/>
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### With Submit/Cancel Buttons
|
|
369
|
+
|
|
370
|
+
```tsx
|
|
371
|
+
function EditorWithActions() {
|
|
372
|
+
const [content, setContent] = useState('');
|
|
373
|
+
|
|
374
|
+
const handleSubmit = (editorContent: string) => {
|
|
375
|
+
const data = JSON.parse(editorContent);
|
|
376
|
+
console.log('Submitting:', data);
|
|
377
|
+
// Send to API
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
return (
|
|
381
|
+
<RichTextEditor
|
|
382
|
+
value={content}
|
|
383
|
+
onChange={setContent}
|
|
384
|
+
actionButtonsPosition="bottom-right"
|
|
385
|
+
cancelButton={{
|
|
386
|
+
show: true,
|
|
387
|
+
label: 'Cancel',
|
|
388
|
+
onClick: () => console.log('Cancelled')
|
|
389
|
+
}}
|
|
390
|
+
submitButton={{
|
|
391
|
+
show: true,
|
|
392
|
+
label: 'Send',
|
|
393
|
+
onClick: handleSubmit,
|
|
394
|
+
style: {
|
|
395
|
+
backgroundColor: '#28a745',
|
|
396
|
+
color: '#fff'
|
|
397
|
+
}
|
|
398
|
+
}}
|
|
399
|
+
features={{
|
|
400
|
+
bold: true,
|
|
401
|
+
italic: true,
|
|
402
|
+
emoji: true
|
|
403
|
+
}}
|
|
404
|
+
/>
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Complete Example (Kitchen Sink)
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
function CompleteEditor() {
|
|
413
|
+
const [content, setContent] = useState('');
|
|
414
|
+
|
|
415
|
+
const users = [
|
|
416
|
+
{ id: '1', name: 'John Doe', email: 'john@example.com' },
|
|
417
|
+
{ id: '2', name: 'Jane Smith', email: 'jane@example.com' }
|
|
418
|
+
];
|
|
419
|
+
|
|
420
|
+
const tags = [
|
|
421
|
+
{
|
|
422
|
+
id: '1',
|
|
423
|
+
label: 'User Name',
|
|
424
|
+
value: '{{userName}}',
|
|
425
|
+
description: 'Current user name',
|
|
426
|
+
backgroundColor: '#fff3cd',
|
|
427
|
+
color: '#856404'
|
|
428
|
+
}
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
const handleMediaUpload = async (file: File) => {
|
|
432
|
+
// Upload logic
|
|
433
|
+
return 'https://example.com/uploaded-image.jpg';
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const handleSubmit = (content: string) => {
|
|
437
|
+
console.log('Content:', JSON.parse(content));
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
return (
|
|
441
|
+
<RichTextEditor
|
|
442
|
+
value={content}
|
|
443
|
+
onChange={setContent}
|
|
444
|
+
placeholder="Start typing..."
|
|
445
|
+
|
|
446
|
+
// Styling
|
|
447
|
+
minHeight="200px"
|
|
448
|
+
maxHeight="500px"
|
|
449
|
+
width="100%"
|
|
450
|
+
borderRadius="8px"
|
|
451
|
+
backgroundColor="#ffffff"
|
|
452
|
+
|
|
453
|
+
// Features
|
|
454
|
+
features={{
|
|
455
|
+
headings: true,
|
|
456
|
+
bold: true,
|
|
457
|
+
italic: true,
|
|
458
|
+
underline: true,
|
|
459
|
+
strikethrough: true,
|
|
460
|
+
bulletList: true,
|
|
461
|
+
numberedList: true,
|
|
462
|
+
links: true,
|
|
463
|
+
mediaUpload: true,
|
|
464
|
+
mentions: true,
|
|
465
|
+
emoji: true,
|
|
466
|
+
codeBlock: true
|
|
467
|
+
}}
|
|
468
|
+
|
|
469
|
+
// Mentions
|
|
470
|
+
mentionUsers={users}
|
|
471
|
+
onMentionSelect={(user) => console.log('Mentioned:', user)}
|
|
472
|
+
|
|
473
|
+
// Tags
|
|
474
|
+
tags={tags}
|
|
475
|
+
onTagSelect={(tag) => console.log('Tag:', tag)}
|
|
476
|
+
tagPlaceholder="Search variables..."
|
|
477
|
+
|
|
478
|
+
// Media
|
|
479
|
+
onMediaUpload={handleMediaUpload}
|
|
480
|
+
|
|
481
|
+
// Character count
|
|
482
|
+
showCharCount={true}
|
|
483
|
+
maxCharCount={5000}
|
|
484
|
+
charCountPosition="bottom-right"
|
|
485
|
+
|
|
486
|
+
// Toolbar
|
|
487
|
+
toolbarPosition="both"
|
|
488
|
+
topToolbarButtons={[
|
|
489
|
+
'headings', 'bold', 'italic', 'underline',
|
|
490
|
+
'bulletList', 'numberedList', 'link'
|
|
491
|
+
]}
|
|
492
|
+
bottomToolbarButtons={[
|
|
493
|
+
'mediaUpload', 'mentions', 'tags', 'emoji', 'codeBlock'
|
|
494
|
+
]}
|
|
495
|
+
|
|
496
|
+
// Action buttons
|
|
497
|
+
actionButtonsPosition="bottom-right"
|
|
498
|
+
cancelButton={{
|
|
499
|
+
show: true,
|
|
500
|
+
label: 'Clear',
|
|
501
|
+
position: 1
|
|
502
|
+
}}
|
|
503
|
+
submitButton={{
|
|
504
|
+
show: true,
|
|
505
|
+
label: 'Send',
|
|
506
|
+
position: 2,
|
|
507
|
+
onClick: handleSubmit,
|
|
508
|
+
style: {
|
|
509
|
+
backgroundColor: '#28a745',
|
|
510
|
+
color: '#fff'
|
|
511
|
+
}
|
|
512
|
+
}}
|
|
513
|
+
/>
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
## 🎨 Styling
|
|
519
|
+
|
|
520
|
+
The editor comes with default styling, but you can customize it extensively:
|
|
521
|
+
|
|
522
|
+
```tsx
|
|
523
|
+
<RichTextEditor
|
|
524
|
+
className="my-custom-editor"
|
|
525
|
+
style={{ border: '2px solid blue' }}
|
|
526
|
+
backgroundColor="#f9f9f9"
|
|
527
|
+
borderColor="#cccccc"
|
|
528
|
+
borderRadius="12px"
|
|
529
|
+
toolbarBackgroundColor="#f0f0f0"
|
|
530
|
+
headerBackgroundColor="#e0e0e0"
|
|
531
|
+
textColor="#333333"
|
|
532
|
+
/>
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
### CSS Classes
|
|
536
|
+
|
|
537
|
+
You can also override styles using CSS:
|
|
538
|
+
|
|
539
|
+
```css
|
|
540
|
+
.my-custom-editor {
|
|
541
|
+
font-family: 'Your Custom Font';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.rte-toolbar {
|
|
545
|
+
/* Toolbar styles */
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.rte-toolbar-button {
|
|
549
|
+
/* Button styles */
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.rte-editor-wrapper {
|
|
553
|
+
/* Editor content area */
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## 📝 Content Format
|
|
558
|
+
|
|
559
|
+
The editor stores content as a JSON string of Slate nodes. Example:
|
|
560
|
+
|
|
561
|
+
```json
|
|
562
|
+
[
|
|
563
|
+
{
|
|
564
|
+
"type": "paragraph",
|
|
565
|
+
"children": [
|
|
566
|
+
{ "text": "Hello " },
|
|
567
|
+
{ "text": "world", "bold": true },
|
|
568
|
+
{ "text": "!" }
|
|
569
|
+
]
|
|
570
|
+
}
|
|
571
|
+
]
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### Converting to HTML
|
|
575
|
+
|
|
576
|
+
To convert editor content to HTML, parse the JSON and process the nodes:
|
|
577
|
+
|
|
578
|
+
```typescript
|
|
579
|
+
const content = JSON.parse(editorContent);
|
|
580
|
+
// Process nodes and convert to HTML based on your needs
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Converting from HTML
|
|
584
|
+
|
|
585
|
+
Use the built-in paste functionality to convert HTML to editor format automatically.
|
|
586
|
+
|
|
587
|
+
## 🔧 Advanced Usage
|
|
588
|
+
|
|
589
|
+
### Programmatically Control Editor
|
|
590
|
+
|
|
591
|
+
```tsx
|
|
592
|
+
function ControlledEditor() {
|
|
593
|
+
const [content, setContent] = useState('');
|
|
594
|
+
|
|
595
|
+
const insertText = () => {
|
|
596
|
+
const nodes = JSON.parse(content || '[]');
|
|
597
|
+
nodes.push({
|
|
598
|
+
type: 'paragraph',
|
|
599
|
+
children: [{ text: 'Programmatically added text' }]
|
|
600
|
+
});
|
|
601
|
+
setContent(JSON.stringify(nodes));
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
return (
|
|
605
|
+
<>
|
|
606
|
+
<button onClick={insertText}>Insert Text</button>
|
|
607
|
+
<RichTextEditor value={content} onChange={setContent} />
|
|
608
|
+
</>
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
## 🐛 Troubleshooting
|
|
614
|
+
|
|
615
|
+
### Editor not showing
|
|
616
|
+
|
|
617
|
+
Make sure you've installed peer dependencies:
|
|
618
|
+
```bash
|
|
619
|
+
npm install react react-dom
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### TypeScript errors
|
|
623
|
+
|
|
624
|
+
Ensure TypeScript is configured correctly and includes node_modules types.
|
|
625
|
+
|
|
626
|
+
### Styles not applying
|
|
627
|
+
|
|
628
|
+
The editor includes its own CSS. Make sure your build tool processes CSS imports.
|
|
629
|
+
|
|
630
|
+
## ⚠️ Alpha Version Notice
|
|
631
|
+
|
|
632
|
+
This is an **alpha release** (0.1.0-alpha.0). This means:
|
|
633
|
+
|
|
634
|
+
- ✅ Core features are implemented and tested
|
|
635
|
+
- ⚠️ API may change before stable 1.0.0 release
|
|
636
|
+
- ⚠️ Some features may have bugs or limitations
|
|
637
|
+
- ⚠️ Not recommended for production use yet
|
|
638
|
+
- 📝 Breaking changes possible in future alpha releases
|
|
639
|
+
|
|
640
|
+
### Roadmap to 1.0.0
|
|
641
|
+
|
|
642
|
+
- [ ] Complete testing across different browsers
|
|
643
|
+
- [ ] Performance optimizations
|
|
644
|
+
- [ ] API stabilization
|
|
645
|
+
- [ ] Additional features (tables, text/highlight colors)
|
|
646
|
+
- [ ] Comprehensive test suite
|
|
647
|
+
- [ ] Migration guides and documentation
|
|
648
|
+
- [ ] Community feedback integration
|
|
649
|
+
|
|
650
|
+
We encourage you to try it out, provide feedback, and report issues!
|
|
651
|
+
|
|
652
|
+
## 📄 License
|
|
653
|
+
|
|
654
|
+
MIT © ZenceMarketing
|
|
655
|
+
|
|
656
|
+
## 🤝 Contributing
|
|
657
|
+
|
|
658
|
+
Contributions are welcome! Please feel free to submit issues and pull requests.
|
|
659
|
+
|
|
660
|
+
## 📞 Support
|
|
661
|
+
|
|
662
|
+
For support, please contact us at support@zencemarketing.com
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
Made with ❤️ by ZenceMarketing
|
package/dist/App.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAGA,OAAO,WAAW,CAAC;AAsDnB,iBAAS,GAAG,4CA8QX;AAED,eAAe,GAAG,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import './ColorPicker.css';
|
|
3
|
+
interface ColorPickerProps {
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (color: string) => void;
|
|
6
|
+
onClose?: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare const ColorPicker: React.FC<ColorPickerProps>;
|
|
9
|
+
export default ColorPicker;
|
|
10
|
+
//# sourceMappingURL=ColorPicker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorPicker.d.ts","sourceRoot":"","sources":["../../src/components/ColorPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,mBAAmB,CAAC;AAE3B,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAqK3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorElement.d.ts","sourceRoot":"","sources":["../../src/components/EditorElement.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAA+B,MAAM,aAAa,CAAC;AAK9E,eAAO,MAAM,aAAa,GAAI,mCAAmC,kBAAkB,KAAG,YAoYrF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorLeaf.d.ts","sourceRoot":"","sources":["../../src/components/EditorLeaf.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,eAAO,MAAM,UAAU,GAAI,gCAAgC,eAAe,KAAG,YA+B5E,CAAC"}
|