rn-rich-text-editor 1.0.1 → 1.0.3

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.
Files changed (73) hide show
  1. package/package.json +1 -1
  2. package/src/Editor.js +14 -2
  3. package/src/Toolbar.js +164 -30
  4. package/src/img/align_center.png +0 -0
  5. package/src/img/align_left.png +0 -0
  6. package/src/img/align_right.png +0 -0
  7. package/src/img/bold.png +0 -0
  8. package/src/img/intdent.png +0 -0
  9. package/src/img/italic.svg +3 -0
  10. package/src/img/list.png +0 -0
  11. package/src/img/numbered_list.png +0 -0
  12. package/src/img/outdent.png +0 -0
  13. package/src/img/redo.png +0 -0
  14. package/src/img/undo.png +0 -0
  15. package/src/img/blockquote@2x.png +0 -0
  16. package/src/img/blockquote@3x.png +0 -0
  17. package/src/img/bold@2x.png +0 -0
  18. package/src/img/bold@3x.png +0 -0
  19. package/src/img/checkbox@2x.png +0 -0
  20. package/src/img/checkbox@3x.png +0 -0
  21. package/src/img/code@2x.png +0 -0
  22. package/src/img/code@3x.png +0 -0
  23. package/src/img/fontSize@2x.png +0 -0
  24. package/src/img/fontSize@3x.png +0 -0
  25. package/src/img/image@2x.png +0 -0
  26. package/src/img/image@3x.png +0 -0
  27. package/src/img/indent.png +0 -0
  28. package/src/img/indent@2x.png +0 -0
  29. package/src/img/indent@3x.png +0 -0
  30. package/src/img/italic@2x.png +0 -0
  31. package/src/img/italic@3x.png +0 -0
  32. package/src/img/justify_center.png +0 -0
  33. package/src/img/justify_center@2x.png +0 -0
  34. package/src/img/justify_center@3x.png +0 -0
  35. package/src/img/justify_full@2x.png +0 -0
  36. package/src/img/justify_full@3x.png +0 -0
  37. package/src/img/justify_left@2x.png +0 -0
  38. package/src/img/justify_left@3x.png +0 -0
  39. package/src/img/justify_right.png +0 -0
  40. package/src/img/justify_right@2x.png +0 -0
  41. package/src/img/justify_right@3x.png +0 -0
  42. package/src/img/keyboard@2x.png +0 -0
  43. package/src/img/keyboard@3x.png +0 -0
  44. package/src/img/line@2x.png +0 -0
  45. package/src/img/line@3x.png +0 -0
  46. package/src/img/link@2x.png +0 -0
  47. package/src/img/link@3x.png +0 -0
  48. package/src/img/ol.png +0 -0
  49. package/src/img/ol@2x.png +0 -0
  50. package/src/img/ol@3x.png +0 -0
  51. package/src/img/outdent@2x.png +0 -0
  52. package/src/img/outdent@3x.png +0 -0
  53. package/src/img/redo@2x.png +0 -0
  54. package/src/img/redo@3x.png +0 -0
  55. package/src/img/remove_format@2x.png +0 -0
  56. package/src/img/remove_format@3x.png +0 -0
  57. package/src/img/strikethrough@2x.png +0 -0
  58. package/src/img/strikethrough@3x.png +0 -0
  59. package/src/img/subscript@2x.png +0 -0
  60. package/src/img/subscript@3x.png +0 -0
  61. package/src/img/superscript@2x.png +0 -0
  62. package/src/img/superscript@3x.png +0 -0
  63. package/src/img/table@2x.png +0 -0
  64. package/src/img/table@3x.png +0 -0
  65. package/src/img/ul.png +0 -0
  66. package/src/img/ul@2x.png +0 -0
  67. package/src/img/ul@3x.png +0 -0
  68. package/src/img/underline@2x.png +0 -0
  69. package/src/img/underline@3x.png +0 -0
  70. package/src/img/undo@2x.png +0 -0
  71. package/src/img/undo@3x.png +0 -0
  72. package/src/img/video@2x.png +0 -0
  73. package/src/img/video@3x.png +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-rich-text-editor",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A rich text editor component for React Native",
5
5
  "keywords": [
6
6
  "react-native",
package/src/Editor.js CHANGED
@@ -339,11 +339,11 @@ export default class Editor extends Component {
339
339
  const errorStyle = errorMessage ? { borderWidth: 1, borderColor: '#d92d20' } : {};
340
340
 
341
341
  return useContainer ? (
342
- <View style={[style, { height }, errorStyle]} onLayout={this.onViewLayout}>
342
+ <View style={[editorBorderStyle, style, { height }, errorStyle]} onLayout={this.onViewLayout}>
343
343
  {this.renderWebView()}
344
344
  </View>
345
345
  ) : (
346
- <View style={errorStyle}>
346
+ <View style={[editorBorderStyle, errorStyle]}>
347
347
  {this.renderWebView()}
348
348
  </View>
349
349
  );
@@ -518,6 +518,18 @@ export default class Editor extends Component {
518
518
  }
519
519
  }
520
520
 
521
+ const BORDER_COLOR = '#C9CED7';
522
+ const BORDER_RADIUS = 6;
523
+
524
+ const editorBorderStyle = {
525
+ borderColor: BORDER_COLOR,
526
+ borderLeftWidth: 1,
527
+ borderRightWidth: 1,
528
+ borderBottomWidth: 1,
529
+ borderBottomLeftRadius: BORDER_RADIUS,
530
+ borderBottomRightRadius: BORDER_RADIUS,
531
+ };
532
+
521
533
  const styles = StyleSheet.create({
522
534
  _input: {
523
535
  position: 'absolute',
package/src/Toolbar.js CHANGED
@@ -2,6 +2,48 @@ import React, { Component } from 'react';
2
2
  import { FlatList, Image, StyleSheet, TouchableOpacity, View } from 'react-native';
3
3
  import { actions } from './actions';
4
4
 
5
+ const FADE_WIDTH = 24;
6
+ const FADE_STRIPS = 5;
7
+ const TOOLBAR_BG = '#efefef';
8
+
9
+ function hexToRgb(hex) {
10
+ const match = hex.replace('#', '').match(/.{2}/g);
11
+ return match ? match.map((x) => parseInt(x, 16)) : [239, 239, 239];
12
+ }
13
+
14
+ function FadeOverlay({ side, visible, backgroundColor }) {
15
+ if (!visible) return null;
16
+ const bg = backgroundColor || TOOLBAR_BG;
17
+ const rgb = bg.startsWith('rgb')
18
+ ? bg.match(/\d+/g)?.map(Number) || [239, 239, 239]
19
+ : hexToRgb(bg);
20
+ const strips = Array.from({ length: FADE_STRIPS }, (_, i) => {
21
+ const alpha = ((i + 1) / FADE_STRIPS) * 0.85;
22
+ const stripWidth = FADE_WIDTH / FADE_STRIPS;
23
+ return (
24
+ <View
25
+ key={i}
26
+ style={[
27
+ styles.fadeStrip,
28
+ {
29
+ width: stripWidth,
30
+ backgroundColor: `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${alpha})`,
31
+ left: side === 'left' ? FADE_WIDTH - (i + 1) * stripWidth : i * stripWidth,
32
+ },
33
+ ]}
34
+ />
35
+ );
36
+ });
37
+ return (
38
+ <View
39
+ style={[styles.fadeOverlay, side === 'right' ? styles.fadeRight : styles.fadeLeft]}
40
+ pointerEvents="none"
41
+ >
42
+ {strips}
43
+ </View>
44
+ );
45
+ }
46
+
5
47
  const ALIGN_ACTIONS = [
6
48
  actions.alignLeft,
7
49
  actions.alignCenter,
@@ -19,7 +61,6 @@ export const defaultActions = [
19
61
  actions.indent,
20
62
  actions.outdent,
21
63
  actions.insertLink,
22
- actions.lineHeight,
23
64
  ];
24
65
 
25
66
  function getDefaultIcon() {
@@ -28,11 +69,11 @@ function getDefaultIcon() {
28
69
  texts[actions.insertImage] = require('./img/image.png');
29
70
  texts[actions.keyboard] = require('./img/keyboard.png');
30
71
  texts[actions.setBold] = require('./img/bold.png');
31
- texts[actions.setItalic] = require('./img/italic.png');
72
+ texts[actions.setItalic] = require('./img/italic.svg');
32
73
  texts[actions.setSubscript] = require('./img/subscript.png');
33
74
  texts[actions.setSuperscript] = require('./img/superscript.png');
34
- texts[actions.insertBulletsList] = require('./img/ul.png');
35
- texts[actions.insertOrderedList] = require('./img/ol.png');
75
+ texts[actions.insertBulletsList] = require('./img/list.png');
76
+ texts[actions.insertOrderedList] = require('./img/numbered_list.png');
36
77
  texts[actions.insertLink] = require('./img/link.png');
37
78
  texts[actions.setStrikethrough] = require('./img/strikethrough.png');
38
79
  texts[actions.setUnderline] = require('./img/underline.png');
@@ -45,16 +86,14 @@ function getDefaultIcon() {
45
86
  texts[actions.table] = require('./img/table.png');
46
87
  texts[actions.code] = require('./img/code.png');
47
88
  texts[actions.outdent] = require('./img/outdent.png');
48
- texts[actions.indent] = require('./img/indent.png');
49
- texts[actions.alignLeft] = require('./img/justify_left.png');
50
- texts[actions.alignCenter] = require('./img/justify_center.png');
51
- texts[actions.alignRight] = require('./img/justify_right.png');
89
+ texts[actions.indent] = require('./img/intdent.png');
90
+ texts[actions.alignLeft] = require('./img/align_left.png');
91
+ texts[actions.alignCenter] = require('./img/align_center.png');
92
+ texts[actions.alignRight] = require('./img/align_right.png');
52
93
  texts[actions.alignFull] = require('./img/justify_full.png');
53
- texts[actions.align] = require('./img/justify_left.png');
94
+ texts[actions.align] = require('./img/align_left.png');
54
95
  texts[actions.blockquote] = require('./img/blockquote.png');
55
96
  texts[actions.line] = require('./img/line.png');
56
- texts[actions.fontSize] = require('./img/fontSize.png');
57
- texts[actions.lineHeight] = require('./img/fontSize.png');
58
97
  return texts;
59
98
  }
60
99
 
@@ -75,6 +114,8 @@ export default class Toolbar extends Component {
75
114
  this.state = {
76
115
  items: [],
77
116
  selectedAlign: null,
117
+ showLeftFade: false,
118
+ showRightFade: false,
78
119
  };
79
120
  }
80
121
 
@@ -85,10 +126,49 @@ export default class Toolbar extends Component {
85
126
  nextState.actions !== that.state.actions ||
86
127
  nextState.data !== that.state.data ||
87
128
  nextState.selectedAlign !== that.state.selectedAlign ||
129
+ nextState.showLeftFade !== that.state.showLeftFade ||
130
+ nextState.showRightFade !== that.state.showRightFade ||
88
131
  nextProps.style !== that.props.style
89
132
  );
90
133
  }
91
134
 
135
+ _scrollWidth = 0;
136
+ _layoutWidth = 0;
137
+
138
+ _onScroll = (e) => {
139
+ const scrollX = e.nativeEvent.contentOffset.x;
140
+ const showLeft = scrollX > 5;
141
+ const showRight = scrollX + this._layoutWidth < this._scrollWidth - 5;
142
+ this.setState((s) =>
143
+ s.showLeftFade !== showLeft || s.showRightFade !== showRight
144
+ ? { showLeftFade: showLeft, showRightFade: showRight }
145
+ : null
146
+ );
147
+ };
148
+
149
+ _onContentSizeChange = (contentWidth) => {
150
+ this._scrollWidth = contentWidth;
151
+ this._updateFades();
152
+ };
153
+
154
+ _onLayout = (e) => {
155
+ this._layoutWidth = e.nativeEvent.layout.width;
156
+ this._updateFades();
157
+ };
158
+
159
+ _updateFades = () => {
160
+ if (this._scrollWidth <= 0 || this._layoutWidth <= 0) return;
161
+ const canScroll = this._scrollWidth > this._layoutWidth;
162
+ this.setState((s) => {
163
+ const showRight = canScroll;
164
+ const showLeft = canScroll && s.showLeftFade;
165
+ if (s.showRightFade !== showRight || (showLeft !== s.showLeftFade && canScroll)) {
166
+ return { showRightFade: showRight, showLeftFade: showLeft };
167
+ }
168
+ return null;
169
+ });
170
+ };
171
+
92
172
  static getDerivedStateFromProps(nextProps, prevState) {
93
173
  const { actions } = nextProps;
94
174
  if (actions !== prevState.actions) {
@@ -250,15 +330,6 @@ export default class Toolbar extends Component {
250
330
  editor.showAndroidKeyboard();
251
331
  editor.sendAction(action, 'result');
252
332
  break;
253
- case actions.lineHeight:
254
- editor.showAndroidKeyboard();
255
- if (this.props[action]) {
256
- this.props[action]();
257
- } else {
258
- editor.sendAction(action, 'result', 1.5);
259
- }
260
- break;
261
- case actions.fontSize:
262
333
  case actions.fontName:
263
334
  case actions.foreColor:
264
335
  case actions.hiliteColor:
@@ -379,33 +450,96 @@ export default class Toolbar extends Component {
379
450
  return null;
380
451
  }
381
452
  const vStyle = [styles.barContainer, style, disabled && this._getButtonDisabledStyle()];
453
+ const barBg = (style && style.backgroundColor) || TOOLBAR_BG;
454
+ const showFades = horizontal;
382
455
  return (
383
456
  <View style={vStyle}>
384
- <FlatList
385
- horizontal={horizontal}
386
- style={flatContainerStyle}
387
- keyboardShouldPersistTaps={'always'}
388
- keyExtractor={(item, index) => item.action + '-' + index}
389
- data={this.state.data}
390
- alwaysBounceHorizontal={false}
391
- showsHorizontalScrollIndicator={false}
392
- renderItem={({ item }) => this._renderAction(item.action, item.selected)}
393
- />
457
+ <View style={styles.scrollWrapper} onLayout={showFades ? this._onLayout : undefined}>
458
+ <FlatList
459
+ horizontal={horizontal}
460
+ style={[flatContainerStyle, showFades && styles.scrollList]}
461
+ keyboardShouldPersistTaps={'always'}
462
+ keyExtractor={(item, index) => item.action + '-' + index}
463
+ data={this.state.data}
464
+ alwaysBounceHorizontal={false}
465
+ showsHorizontalScrollIndicator={false}
466
+ onScroll={showFades ? this._onScroll : undefined}
467
+ onContentSizeChange={showFades ? this._onContentSizeChange : undefined}
468
+ scrollEventThrottle={16}
469
+ renderItem={({ item }) => this._renderAction(item.action, item.selected)}
470
+ />
471
+ {showFades && (
472
+ <>
473
+ <FadeOverlay
474
+ side="left"
475
+ visible={this.state.showLeftFade}
476
+ backgroundColor={barBg}
477
+ />
478
+ <FadeOverlay
479
+ side="right"
480
+ visible={this.state.showRightFade}
481
+ backgroundColor={barBg}
482
+ />
483
+ </>
484
+ )}
485
+ </View>
394
486
  {children}
395
487
  </View>
396
488
  );
397
489
  }
398
490
  }
399
491
 
492
+ const BORDER_COLOR = '#C9CED7';
493
+ const BORDER_RADIUS = 6;
494
+
400
495
  const styles = StyleSheet.create({
401
496
  barContainer: {
402
497
  height: 44,
403
498
  backgroundColor: '#efefef',
404
499
  alignItems: 'center',
500
+ borderColor: BORDER_COLOR,
501
+ borderTopWidth: 1,
502
+ borderLeftWidth: 1,
503
+ borderRightWidth: 1,
504
+ borderBottomWidth: 1,
505
+ borderTopLeftRadius: BORDER_RADIUS,
506
+ borderTopRightRadius: BORDER_RADIUS,
405
507
  },
406
508
 
407
509
  item: {
408
510
  justifyContent: 'center',
409
511
  alignItems: 'center',
410
512
  },
513
+
514
+ scrollWrapper: {
515
+ flex: 1,
516
+ flexDirection: 'row',
517
+ alignSelf: 'stretch',
518
+ position: 'relative',
519
+ },
520
+
521
+ scrollList: {
522
+ flex: 1,
523
+ },
524
+
525
+ fadeOverlay: {
526
+ position: 'absolute',
527
+ top: 0,
528
+ bottom: 0,
529
+ width: FADE_WIDTH,
530
+ },
531
+
532
+ fadeLeft: {
533
+ left: 0,
534
+ },
535
+
536
+ fadeRight: {
537
+ right: 0,
538
+ },
539
+
540
+ fadeStrip: {
541
+ position: 'absolute',
542
+ top: 0,
543
+ bottom: 0,
544
+ },
411
545
  });
Binary file
Binary file
Binary file
package/src/img/bold.png CHANGED
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ <svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M12.5 0C12.9602 0 13.3333 0.373096 13.3333 0.833333C13.3333 1.29357 12.9602 1.66667 12.5 1.66667H9.74447L5.36947 13.3333H8.33333C8.79357 13.3333 9.16667 13.7064 9.16667 14.1667C9.16667 14.6269 8.79357 15 8.33333 15H0.833333C0.373096 15 0 14.6269 0 14.1667C0 13.7064 0.373096 13.3333 0.833333 13.3333H3.58887L7.96387 1.66667H5C4.53976 1.66667 4.16667 1.29357 4.16667 0.833333C4.16667 0.373096 4.53976 0 5 0H12.5Z" fill="#8A8A8C"/>
3
+ </svg>
Binary file
Binary file
Binary file
package/src/img/redo.png CHANGED
Binary file
package/src/img/undo.png CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/src/img/ol.png DELETED
Binary file
package/src/img/ol@2x.png DELETED
Binary file
package/src/img/ol@3x.png DELETED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/src/img/ul.png DELETED
Binary file
package/src/img/ul@2x.png DELETED
Binary file
package/src/img/ul@3x.png DELETED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file