rn-rich-text-editor 0.0.18 → 1.0.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 CHANGED
@@ -1,6 +1,21 @@
1
- # React Native Rich Editor
1
+ # React Native Rich Text Editor
2
2
 
3
- A rich text editor component for React Native using WebView.
3
+ A powerful, feature-rich text editor component for React Native built with WebView. Perfect for creating rich text editing experiences in your React Native applications.
4
+
5
+ ## Features
6
+
7
+ - ✨ **Rich Text Formatting**: Bold, italic, underline, strikethrough, and more
8
+ - 📝 **Text Styling**: Font size, font family, text color, highlight color, line height
9
+ - 📋 **Lists**: Bullet lists, ordered lists, and checkbox lists
10
+ - 🔗 **Media Support**: Insert images and videos
11
+ - 📐 **Alignment**: Left, center, right, and justify alignment
12
+ - 📑 **Headings**: Support for H1-H6 headings
13
+ - 💻 **Code Blocks**: Insert code blocks and inline code
14
+ - 🔄 **Undo/Redo**: Full undo and redo support
15
+ - ⌨️ **Keyboard Management**: Built-in keyboard handling for iOS and Android
16
+ - 🎨 **Customizable**: Fully customizable toolbar and editor styles
17
+ - 📱 **Cross-Platform**: Works on both iOS and Android
18
+ - ♿ **Accessible**: Built with accessibility in mind
4
19
 
5
20
  ## Installation
6
21
 
@@ -8,44 +23,633 @@ A rich text editor component for React Native using WebView.
8
23
  npm install rn-rich-text-editor
9
24
  ```
10
25
 
11
- ## Usage
26
+ ### Peer Dependencies
27
+
28
+ Make sure you have these installed:
29
+
30
+ ```bash
31
+ npm install react react-native react-native-webview
32
+ ```
33
+
34
+ ## Quick Start
12
35
 
13
36
  ```tsx
14
- import { Editor, Toolbar, actions } from 'rn-rich-text-editor';
37
+ import React, { useRef } from 'react';
38
+ import { View } from 'react-native';
39
+ import { Editor, Toolbar } from 'rn-rich-text-editor';
15
40
 
16
41
  function App() {
42
+ const editorRef = useRef(null);
43
+
17
44
  return (
18
- <>
19
- <Editor ref={editorRef} onMessage={handleMessage} />
20
- <Toolbar editorRef={editorRef} />
21
- </>
45
+ <View style={{ flex: 1 }}>
46
+ <Editor
47
+ ref={editorRef}
48
+ placeholder="Start typing..."
49
+ onChange={(html) => console.log('Content changed:', html)}
50
+ />
51
+ <Toolbar editor={editorRef} />
52
+ </View>
22
53
  );
23
54
  }
24
55
  ```
25
56
 
26
- ## API
57
+ ## Components
27
58
 
28
59
  ### Editor
29
60
 
30
- Main editor component.
61
+ The main editor component that provides the rich text editing interface.
31
62
 
32
- **Props:**
33
- - `onMessage?: (event: any) => void` - Callback for editor messages
63
+ #### Props
34
64
 
35
- **Ref Methods:**
36
- - `sendAction(type: string)` - Send action to editor
65
+ | Prop | Type | Default | Description |
66
+ |------|------|---------|-------------|
67
+ | `ref` | `RefObject<EditorRef>` | - | Reference to access editor methods |
68
+ | `contentInset` | `object` | `{}` | Content inset for the editor |
69
+ | `style` | `object` | `{}` | Custom styles for the editor container |
70
+ | `placeholder` | `string` | `''` | Placeholder text shown when editor is empty |
71
+ | `initialContentHTML` | `string` | `''` | Initial HTML content to load |
72
+ | `initialFocus` | `boolean` | `false` | Whether to focus the editor on mount |
73
+ | `disabled` | `boolean` | `false` | Disable the editor |
74
+ | `readOnly` | `boolean` | `false` | Make the editor read-only |
75
+ | `useContainer` | `boolean` | `true` | Use a container wrapper with height |
76
+ | `pasteAsPlainText` | `boolean` | `false` | Paste content as plain text |
77
+ | `autoCapitalize` | `string` | `'off'` | Auto-capitalization setting |
78
+ | `defaultParagraphSeparator` | `string` | `'div'` | Default paragraph separator (`'div'` or `'p'`) |
79
+ | `editorInitializedCallback` | `() => void` | `() => {}` | Callback when editor is initialized |
80
+ | `initialHeight` | `number` | `0` | Initial height of the editor (0 = auto) |
81
+ | `dataDetectorTypes` | `string[]` | `['none']` | Data detector types for links, phone numbers, etc. |
82
+ | `editorStyle` | `object` | - | Custom editor styles (see EditorStyle below) |
83
+ | `html` | `string \| { html: string }` | - | HTML content (alternative to `initialContentHTML`) |
84
+ | `onFocus` | `() => void` | - | Callback when editor gains focus |
85
+ | `onBlur` | `() => void` | - | Callback when editor loses focus |
86
+ | `onChange` | `(html: string) => void` | - | Callback when content changes |
87
+ | `onPaste` | `(data: unknown) => void` | - | Callback when content is pasted |
88
+ | `onKeyUp` | `(data: unknown) => void` | - | Callback on key up event |
89
+ | `onKeyDown` | `(data: unknown) => void` | - | Callback on key down event |
90
+ | `onInput` | `(data: unknown) => void` | - | Callback on input event |
91
+ | `onMessage` | `(message: unknown) => void` | - | Callback for editor messages |
92
+ | `onCursorPosition` | `(offsetY: number) => void` | - | Callback when cursor position changes |
93
+ | `onLink` | `(data: unknown) => void` | - | Callback when a link is clicked |
94
+ | `onHeightChange` | `(height: number) => void` | - | Callback when editor height changes |
95
+ | `errorMessage` | `string` | - | Error message to display |
96
+
97
+ #### EditorStyle Object
98
+
99
+ ```typescript
100
+ {
101
+ backgroundColor?: string; // Editor background color
102
+ color?: string; // Text color
103
+ placeholderColor?: string; // Placeholder text color
104
+ caretColor?: string; // Cursor/caret color
105
+ initialCSSText?: string; // Initial CSS styles
106
+ cssText?: string; // Additional CSS styles
107
+ contentCSSText?: string; // Content area CSS styles
108
+ }
109
+ ```
110
+
111
+ #### EditorRef Methods
112
+
113
+ Access these methods through the editor ref:
114
+
115
+ | Method | Parameters | Description |
116
+ |--------|------------|-------------|
117
+ | `setContentHTML` | `(html: string)` | Set the editor content HTML |
118
+ | `getContentHtml` | `()` | Get the current content HTML (returns Promise) |
119
+ | `setPlaceholder` | `(placeholder: string)` | Set the placeholder text |
120
+ | `setContentStyle` | `(styles: object)` | Update editor styles dynamically |
121
+ | `setDisable` | `(disabled: boolean)` | Enable/disable the editor |
122
+ | `focusContentEditor` | `()` | Focus the editor |
123
+ | `blurContentEditor` | `()` | Blur the editor |
124
+ | `showAndroidKeyboard` | `()` | Show keyboard on Android |
125
+ | `dismissKeyboard` | `()` | Dismiss the keyboard |
126
+ | `insertText` | `(text: string)` | Insert plain text at cursor |
127
+ | `insertHTML` | `(html: string)` | Insert HTML at cursor |
128
+ | `insertImage` | `(attributes: object, style?: object)` | Insert an image |
129
+ | `insertVideo` | `(attributes: object, style?: object)` | Insert a video |
130
+ | `insertLink` | `(title: string, url: string)` | Insert a link |
131
+ | `setFontSize` | `(size: unknown)` | Set font size |
132
+ | `setFontName` | `(name: string)` | Set font family |
133
+ | `setForeColor` | `(color: string)` | Set text color |
134
+ | `setHiliteColor` | `(color: string)` | Set highlight/background color |
135
+ | `setLineHeight` | `(value: number \| string)` | Set line height |
136
+ | `command` | `(command: unknown)` | Execute a command |
137
+ | `commandDOM` | `(command: unknown)` | Execute a DOM command |
138
+ | `injectJavascript` | `(script: string)` | Inject custom JavaScript |
139
+ | `registerToolbar` | `(listener: (items: string[]) => void)` | Register toolbar selection listener |
140
+
141
+ #### Properties
142
+
143
+ | Property | Type | Description |
144
+ |----------|------|-------------|
145
+ | `isKeyboardOpen` | `boolean` | Whether the keyboard is currently open |
37
146
 
38
147
  ### Toolbar
39
148
 
40
- Toolbar component for editor actions.
149
+ A customizable toolbar component that provides formatting buttons for the editor.
150
+
151
+ #### Props
152
+
153
+ | Prop | Type | Default | Description |
154
+ |------|------|---------|-------------|
155
+ | `editor` | `{ current: EditorRef \| null }` | - | Editor ref object (use `editor={editorRef}`) |
156
+ | `getEditor` | `() => EditorRef \| null` | - | Function that returns editor ref (alternative to `editor`) |
157
+ | `actions` | `string[]` | `defaultActions` | Array of action keys to display (see Actions below) |
158
+ | `disabled` | `boolean` | `false` | Disable all toolbar buttons |
159
+ | `readOnly` | `boolean` | `false` | Hide toolbar when read-only |
160
+ | `iconTint` | `string` | `'#71787F'` | Default icon color |
161
+ | `selectedIconTint` | `string` | - | Selected icon color |
162
+ | `disabledIconTint` | `string` | - | Disabled icon color |
163
+ | `iconSize` | `number` | `20` | Size of toolbar icons |
164
+ | `iconGap` | `number` | `16` | Gap between toolbar icons |
165
+ | `style` | `object` | - | Custom styles for toolbar container |
166
+ | `itemStyle` | `object` | - | Custom styles for toolbar items |
167
+ | `selectedButtonStyle` | `object` | - | Styles for selected buttons |
168
+ | `unselectedButtonStyle` | `object` | - | Styles for unselected buttons |
169
+ | `disabledButtonStyle` | `object` | - | Styles for disabled buttons |
170
+ | `iconMap` | `Record<string, unknown>` | - | Custom icon map (override default icons) |
171
+ | `renderAction` | `(action: string, selected: boolean) => React.ReactElement` | - | Custom render function for actions |
172
+ | `onPressAddImage` | `() => void` | - | Callback when image button is pressed |
173
+ | `onInsertLink` | `() => void` | - | Callback when link button is pressed |
174
+ | `insertVideo` | `() => void` | - | Callback when video button is pressed |
175
+ | `flatContainerStyle` | `object` | - | Styles for the FlatList container |
176
+ | `horizontal` | `boolean` | `true` | Whether to display toolbar horizontally |
177
+ | `children` | `React.ReactNode` | - | Additional content to render in toolbar |
178
+
179
+ #### Custom Action Handlers
180
+
181
+ You can provide custom handlers for specific actions by passing them as props:
182
+
183
+ ```tsx
184
+ <Toolbar
185
+ editor={editorRef}
186
+ fontSize={() => {
187
+ // Custom font size handler
188
+ editorRef.current?.setFontSize(18);
189
+ }}
190
+ foreColor={() => {
191
+ // Custom color picker handler
192
+ editorRef.current?.setForeColor('#FF0000');
193
+ }}
194
+ lineHeight={() => {
195
+ // Custom line height handler
196
+ editorRef.current?.setLineHeight(1.5);
197
+ }}
198
+ />
199
+ ```
200
+
201
+ ## Actions
202
+
203
+ The toolbar uses action constants to identify different formatting options. Import them from the package:
204
+
205
+ ```tsx
206
+ import { actions } from 'rn-rich-text-editor';
207
+ ```
208
+
209
+ ### Available Actions
210
+
211
+ | Action | Constant | Description |
212
+ |--------|----------|-------------|
213
+ | **Text Formatting** |
214
+ | Bold | `actions.setBold` | Make text bold |
215
+ | Italic | `actions.setItalic` | Make text italic |
216
+ | Underline | `actions.setUnderline` | Underline text |
217
+ | Strikethrough | `actions.setStrikethrough` | Strikethrough text |
218
+ | Subscript | `actions.setSubscript` | Subscript text |
219
+ | Superscript | `actions.setSuperscript` | Superscript text |
220
+ | Remove Format | `actions.removeFormat` | Remove all formatting |
221
+ | **Headings** |
222
+ | Heading 1 | `actions.heading1` | Apply H1 heading |
223
+ | Heading 2 | `actions.heading2` | Apply H2 heading |
224
+ | Heading 3 | `actions.heading3` | Apply H3 heading |
225
+ | Heading 4 | `actions.heading4` | Apply H4 heading |
226
+ | Heading 5 | `actions.heading5` | Apply H5 heading |
227
+ | Heading 6 | `actions.heading6` | Apply H6 heading |
228
+ | Paragraph | `actions.setParagraph` | Apply paragraph style |
229
+ | **Alignment** |
230
+ | Align Left | `actions.alignLeft` | Align text left |
231
+ | Align Center | `actions.alignCenter` | Align text center |
232
+ | Align Right | `actions.alignRight` | Align text right |
233
+ | Align Full | `actions.alignFull` | Justify text |
234
+ | Align (Cycle) | `actions.align` | Cycle through alignments |
235
+ | **Lists** |
236
+ | Bullet List | `actions.insertBulletsList` | Insert unordered list |
237
+ | Ordered List | `actions.insertOrderedList` | Insert ordered list |
238
+ | Checkbox List | `actions.checkboxList` | Insert checkbox list |
239
+ | Indent | `actions.indent` | Increase indent |
240
+ | Outdent | `actions.outdent` | Decrease indent |
241
+ | **Media** |
242
+ | Insert Image | `actions.insertImage` | Insert image |
243
+ | Insert Video | `actions.insertVideo` | Insert video |
244
+ | Insert Link | `actions.insertLink` | Insert hyperlink |
245
+ | **Text Styling** |
246
+ | Font Size | `actions.fontSize` | Change font size |
247
+ | Font Name | `actions.fontName` | Change font family |
248
+ | Text Color | `actions.foreColor` | Change text color |
249
+ | Highlight Color | `actions.hiliteColor` | Change highlight color |
250
+ | Line Height | `actions.lineHeight` | Change line height |
251
+ | **Other** |
252
+ | Code Block | `actions.code` | Insert code block |
253
+ | Blockquote | `actions.blockquote` | Insert blockquote |
254
+ | Horizontal Rule | `actions.setHR` | Insert horizontal line |
255
+ | Line | `actions.line` | Insert line break |
256
+ | Undo | `actions.undo` | Undo last action |
257
+ | Redo | `actions.redo` | Redo last action |
258
+ | Table | `actions.table` | Insert table |
259
+ | Keyboard | `actions.keyboard` | Toggle keyboard |
260
+
261
+ ### Default Actions
262
+
263
+ The toolbar comes with a default set of actions:
264
+
265
+ ```tsx
266
+ import { defaultActions } from 'rn-rich-text-editor';
267
+
268
+ // Default actions include:
269
+ // - keyboard
270
+ // - setBold
271
+ // - setItalic
272
+ // - setUnderline
273
+ // - removeFormat
274
+ // - insertBulletsList
275
+ // - indent
276
+ // - outdent
277
+ // - insertLink
278
+ // - lineHeight
279
+ ```
280
+
281
+ ## Usage Examples
282
+
283
+ ### Basic Editor with Toolbar
284
+
285
+ ```tsx
286
+ import React, { useRef } from 'react';
287
+ import { View, StyleSheet } from 'react-native';
288
+ import { Editor, Toolbar } from 'rn-rich-text-editor';
289
+
290
+ function RichTextEditor() {
291
+ const editorRef = useRef(null);
292
+
293
+ return (
294
+ <View style={styles.container}>
295
+ <Editor
296
+ ref={editorRef}
297
+ placeholder="Start typing..."
298
+ onChange={(html) => {
299
+ console.log('Content:', html);
300
+ }}
301
+ style={styles.editor}
302
+ />
303
+ <Toolbar editor={editorRef} />
304
+ </View>
305
+ );
306
+ }
307
+
308
+ const styles = StyleSheet.create({
309
+ container: {
310
+ flex: 1,
311
+ backgroundColor: '#fff',
312
+ },
313
+ editor: {
314
+ backgroundColor: '#fff',
315
+ borderColor: '#ddd',
316
+ borderWidth: 1,
317
+ minHeight: 200,
318
+ },
319
+ });
320
+ ```
321
+
322
+ ### Custom Toolbar Actions
323
+
324
+ ```tsx
325
+ import React, { useRef } from 'react';
326
+ import { Editor, Toolbar, actions } from 'rn-rich-text-editor';
327
+
328
+ function CustomToolbar() {
329
+ const editorRef = useRef(null);
41
330
 
42
- **Props:**
43
- - `editorRef: RefObject` - Reference to Editor instance
331
+ const customActions = [
332
+ actions.keyboard,
333
+ actions.setBold,
334
+ actions.setItalic,
335
+ actions.setUnderline,
336
+ actions.heading1,
337
+ actions.insertBulletsList,
338
+ actions.insertOrderedList,
339
+ actions.insertLink,
340
+ actions.insertImage,
341
+ ];
44
342
 
45
- ### Actions
343
+ return (
344
+ <>
345
+ <Editor ref={editorRef} />
346
+ <Toolbar editor={editorRef} actions={customActions} />
347
+ </>
348
+ );
349
+ }
350
+ ```
351
+
352
+ ### Inserting Content Programmatically
353
+
354
+ ```tsx
355
+ import React, { useRef } from 'react';
356
+ import { View, Button } from 'react-native';
357
+ import { Editor } from 'rn-rich-text-editor';
358
+
359
+ function ProgrammaticEditor() {
360
+ const editorRef = useRef(null);
361
+
362
+ const insertImage = () => {
363
+ editorRef.current?.insertImage(
364
+ { src: 'https://example.com/image.jpg', alt: 'Image' },
365
+ { width: '100%', height: 'auto' }
366
+ );
367
+ };
368
+
369
+ const insertLink = () => {
370
+ editorRef.current?.insertLink('Click here', 'https://example.com');
371
+ };
372
+
373
+ const insertText = () => {
374
+ editorRef.current?.insertText('Hello World!');
375
+ };
376
+
377
+ return (
378
+ <View>
379
+ <Editor ref={editorRef} />
380
+ <Button title="Insert Image" onPress={insertImage} />
381
+ <Button title="Insert Link" onPress={insertLink} />
382
+ <Button title="Insert Text" onPress={insertText} />
383
+ </View>
384
+ );
385
+ }
386
+ ```
387
+
388
+ ### Styling the Editor
389
+
390
+ ```tsx
391
+ import React, { useRef } from 'react';
392
+ import { Editor } from 'rn-rich-text-editor';
393
+
394
+ function StyledEditor() {
395
+ const editorRef = useRef(null);
396
+
397
+ return (
398
+ <Editor
399
+ ref={editorRef}
400
+ editorStyle={{
401
+ backgroundColor: '#f5f5f5',
402
+ color: '#333',
403
+ placeholderColor: '#999',
404
+ caretColor: '#007AFF',
405
+ contentCSSText: `
406
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
407
+ font-size: 16px;
408
+ line-height: 1.6;
409
+ `,
410
+ }}
411
+ />
412
+ );
413
+ }
414
+ ```
415
+
416
+ ### Custom Toolbar Styling
417
+
418
+ ```tsx
419
+ import React, { useRef } from 'react';
420
+ import { Editor, Toolbar } from 'rn-rich-text-editor';
46
421
 
47
- Predefined editor actions.
422
+ function CustomStyledToolbar() {
423
+ const editorRef = useRef(null);
424
+
425
+ return (
426
+ <>
427
+ <Editor ref={editorRef} />
428
+ <Toolbar
429
+ editor={editorRef}
430
+ iconTint="#333"
431
+ selectedIconTint="#007AFF"
432
+ iconSize={24}
433
+ iconGap={20}
434
+ style={{
435
+ backgroundColor: '#f0f0f0',
436
+ paddingVertical: 8,
437
+ }}
438
+ selectedButtonStyle={{
439
+ backgroundColor: '#e0e0e0',
440
+ borderRadius: 4,
441
+ }}
442
+ />
443
+ </>
444
+ );
445
+ }
446
+ ```
447
+
448
+ ### Handling Image Insertion
449
+
450
+ ```tsx
451
+ import React, { useRef, useState } from 'react';
452
+ import { Editor, Toolbar, actions } from 'rn-rich-text-editor';
453
+ import { ImagePicker } from 'react-native-image-picker';
454
+
455
+ function ImageEditor() {
456
+ const editorRef = useRef(null);
457
+ const [html, setHtml] = useState('');
458
+
459
+ const handleAddImage = () => {
460
+ ImagePicker.launchImageLibrary({}, (response) => {
461
+ if (response.assets && response.assets[0]) {
462
+ const imageUri = response.assets[0].uri;
463
+ editorRef.current?.insertImage(
464
+ { src: imageUri, alt: 'Image' },
465
+ { width: '100%', height: 'auto' }
466
+ );
467
+ }
468
+ });
469
+ };
470
+
471
+ return (
472
+ <>
473
+ <Editor
474
+ ref={editorRef}
475
+ onChange={setHtml}
476
+ initialContentHTML={html}
477
+ />
478
+ <Toolbar
479
+ editor={editorRef}
480
+ onPressAddImage={handleAddImage}
481
+ />
482
+ </>
483
+ );
484
+ }
485
+ ```
486
+
487
+ ### Read-Only Mode
488
+
489
+ ```tsx
490
+ import React from 'react';
491
+ import { Editor } from 'rn-rich-text-editor';
492
+
493
+ function ReadOnlyViewer() {
494
+ const htmlContent = '<p>This is read-only content</p>';
495
+
496
+ return (
497
+ <Editor
498
+ readOnly={true}
499
+ initialContentHTML={htmlContent}
500
+ editorStyle={{
501
+ backgroundColor: '#fff',
502
+ color: '#333',
503
+ }}
504
+ />
505
+ );
506
+ }
507
+ ```
508
+
509
+ ### Getting Content
510
+
511
+ ```tsx
512
+ import React, { useRef } from 'react';
513
+ import { Button } from 'react-native';
514
+ import { Editor } from 'rn-rich-text-editor';
515
+
516
+ function ContentGetter() {
517
+ const editorRef = useRef(null);
518
+
519
+ const getContent = async () => {
520
+ try {
521
+ const html = await editorRef.current?.getContentHtml();
522
+ console.log('Editor content:', html);
523
+ // Use html for saving, sending, etc.
524
+ } catch (error) {
525
+ console.error('Error getting content:', error);
526
+ }
527
+ };
528
+
529
+ return (
530
+ <>
531
+ <Editor ref={editorRef} />
532
+ <Button title="Get Content" onPress={getContent} />
533
+ </>
534
+ );
535
+ }
536
+ ```
537
+
538
+ ## Advanced Usage
539
+
540
+ ### Custom Icon Map
541
+
542
+ ```tsx
543
+ import React, { useRef } from 'react';
544
+ import { Editor, Toolbar, actions } from 'rn-rich-text-editor';
545
+ import { Image } from 'react-native';
546
+
547
+ function CustomIcons() {
548
+ const editorRef = useRef(null);
549
+
550
+ const iconMap = {
551
+ [actions.setBold]: require('./assets/custom-bold.png'),
552
+ [actions.setItalic]: require('./assets/custom-italic.png'),
553
+ // ... more custom icons
554
+ };
555
+
556
+ return (
557
+ <>
558
+ <Editor ref={editorRef} />
559
+ <Toolbar editor={editorRef} iconMap={iconMap} />
560
+ </>
561
+ );
562
+ }
563
+ ```
564
+
565
+ ### Custom Action Renderer
566
+
567
+ ```tsx
568
+ import React, { useRef } from 'react';
569
+ import { Text, TouchableOpacity } from 'react-native';
570
+ import { Editor, Toolbar, actions } from 'rn-rich-text-editor';
571
+
572
+ function CustomRenderer() {
573
+ const editorRef = useRef(null);
574
+
575
+ const renderAction = (action, selected) => {
576
+ if (action === actions.setBold) {
577
+ return (
578
+ <TouchableOpacity
579
+ style={{
580
+ padding: 8,
581
+ backgroundColor: selected ? '#007AFF' : 'transparent',
582
+ }}
583
+ onPress={() => editorRef.current?.sendAction(action, 'result')}
584
+ >
585
+ <Text style={{ fontWeight: 'bold' }}>B</Text>
586
+ </TouchableOpacity>
587
+ );
588
+ }
589
+ // Return null to use default rendering
590
+ return null;
591
+ };
592
+
593
+ return (
594
+ <>
595
+ <Editor ref={editorRef} />
596
+ <Toolbar editor={editorRef} renderAction={renderAction} />
597
+ </>
598
+ );
599
+ }
600
+ ```
601
+
602
+ ## TypeScript Support
603
+
604
+ This package includes TypeScript definitions. Import types as needed:
605
+
606
+ ```typescript
607
+ import { Editor, Toolbar, EditorRef, EditorProps, ToolbarProps, actions } from 'rn-rich-text-editor';
608
+
609
+ const editorRef = useRef<EditorRef>(null);
610
+
611
+ const editorProps: EditorProps = {
612
+ placeholder: 'Type here...',
613
+ onChange: (html) => console.log(html),
614
+ };
615
+ ```
616
+
617
+ ## Platform-Specific Notes
618
+
619
+ ### iOS
620
+ - Uses WebKit WebView
621
+ - Keyboard handling is automatic
622
+ - Supports all features
623
+
624
+ ### Android
625
+ - Uses Android WebView
626
+ - May require additional keyboard handling
627
+ - All features supported
628
+
629
+ ## Troubleshooting
630
+
631
+ ### Editor not focusing
632
+ - Ensure `initialFocus` is set to `true` if needed
633
+ - Call `editorRef.current?.focusContentEditor()` programmatically
634
+ - On Android, use `showAndroidKeyboard()` before focusing
635
+
636
+ ### Content not updating
637
+ - Use `onChange` callback instead of polling `getContentHtml()`
638
+ - Ensure `initialContentHTML` is set correctly on mount
639
+
640
+ ### Toolbar not responding
641
+ - Verify `editor` prop is correctly passed with ref object
642
+ - Check that editor is initialized before toolbar interactions
643
+ - Ensure `disabled` prop is not set to `true`
644
+
645
+ ## Contributing
646
+
647
+ Contributions are welcome! Please feel free to submit a Pull Request.
48
648
 
49
649
  ## License
50
650
 
51
651
  MIT
652
+
653
+ ## Support
654
+
655
+ For issues and feature requests, please visit the [GitHub repository](https://github.com/vishaal2002/rn-rich-text-editor).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-rich-text-editor",
3
- "version": "0.0.18",
3
+ "version": "1.0.0",
4
4
  "description": "A rich text editor component for React Native",
5
5
  "keywords": [
6
6
  "react-native",
@@ -757,12 +757,15 @@ function createHTML(options = {}) {
757
757
 
758
758
  /**
759
759
  * Escapes a string for safe embedding inside a JavaScript double-quoted string in HTML.
760
+ * Newlines and quotes must be escaped or the script will be invalid.
760
761
  */
761
762
  function escapeForScript(s) {
762
763
  if (s == null) return '';
763
764
  return String(s)
764
765
  .replace(/\\/g, '\\\\')
765
766
  .replace(/"/g, '\\"')
767
+ .replace(/\r/g, '\\r')
768
+ .replace(/\n/g, '\\n')
766
769
  .replace(/\u2028/g, '\\u2028')
767
770
  .replace(/\u2029/g, '\\u2029')
768
771
  .replace(/<\/script/gi, '<\\/script');