rn-rich-text-editor 1.2.3 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-rich-text-editor",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "A rich text editor component for React Native",
5
5
  "keywords": [
6
6
  "react-native",
package/src/Toolbar.js CHANGED
@@ -105,6 +105,7 @@ export default class Toolbar extends Component {
105
105
  iconTint: '#71787F',
106
106
  iconSize: 20,
107
107
  iconGap: 16,
108
+ separatorStyle: undefined,
108
109
  };
109
110
 
110
111
  constructor(props) {
@@ -169,19 +170,21 @@ export default class Toolbar extends Component {
169
170
  };
170
171
 
171
172
  static getDerivedStateFromProps(nextProps, prevState) {
172
- const { actions } = nextProps;
173
- if (actions !== prevState.actions) {
173
+ const { actions: actionsList } = nextProps;
174
+ if (actionsList !== prevState.actions) {
174
175
  const items = prevState.items || [];
175
176
  const isItemSelected = (action) =>
176
177
  items.includes(action) || items.some(item => item && item.type === action);
177
178
  return {
178
- actions,
179
- data: actions.map(action => ({
179
+ actions: actionsList,
180
+ data: actionsList.map(action => ({
180
181
  action,
181
182
  selected:
182
- action === actions.align
183
- ? ALIGN_ACTIONS.some(a => isItemSelected(a))
184
- : isItemSelected(action),
183
+ action === actions.separator
184
+ ? false // Separators are never selected
185
+ : action === actions.align
186
+ ? ALIGN_ACTIONS.some(a => isItemSelected(a))
187
+ : isItemSelected(action),
185
188
  })),
186
189
  };
187
190
  }
@@ -224,6 +227,9 @@ export default class Toolbar extends Component {
224
227
  items,
225
228
  selectedAlign,
226
229
  data: this.state.actions.map(action => {
230
+ if (action === actions.separator) {
231
+ return { action, selected: false };
232
+ }
227
233
  const isAlignAction = action === actions.align;
228
234
  const selected = isAlignAction
229
235
  ? !!selectedAlign
@@ -277,6 +283,11 @@ export default class Toolbar extends Component {
277
283
  return;
278
284
  }
279
285
 
286
+ // Separators are not clickable
287
+ if (action === actions.separator) {
288
+ return;
289
+ }
290
+
280
291
  if (action === actions.align) {
281
292
  const { selectedAlign } = this.state;
282
293
  // Cycle through alignments: Left -> Center -> Right -> Justify -> Left
@@ -448,7 +459,48 @@ export default class Toolbar extends Component {
448
459
  );
449
460
  }
450
461
 
462
+ _renderSeparator() {
463
+ const { style, separatorStyle, iconGap = 16 } = this.props;
464
+ // Extract separator from style prop (handles both object and array)
465
+ let separatorFromStyleProp = null;
466
+ if (style) {
467
+ if (Array.isArray(style)) {
468
+ for (const styleItem of style) {
469
+ if (styleItem && typeof styleItem === 'object' && styleItem.separator) {
470
+ separatorFromStyleProp = styleItem.separator;
471
+ break;
472
+ }
473
+ }
474
+ } else if (typeof style === 'object' && style.separator) {
475
+ separatorFromStyleProp = style.separator;
476
+ }
477
+ }
478
+ // Merge: defaults, then style.separator, then separatorStyle (later overrides)
479
+ const merged = {
480
+ width: 1,
481
+ height: 24,
482
+ backgroundColor: '#E2E2E4',
483
+ marginHorizontal: iconGap / 2,
484
+ };
485
+ if (separatorFromStyleProp) {
486
+ Object.assign(merged, StyleSheet.flatten(separatorFromStyleProp));
487
+ }
488
+ if (separatorStyle) {
489
+ Object.assign(merged, StyleSheet.flatten(separatorStyle));
490
+ }
491
+ return (
492
+ <View
493
+ key="separator"
494
+ pointerEvents="none"
495
+ style={merged}
496
+ />
497
+ );
498
+ }
499
+
451
500
  _renderAction(action, selected) {
501
+ if (action === actions.separator) {
502
+ return this._renderSeparator();
503
+ }
452
504
  if (action === actions.align) {
453
505
  return this._renderAlignButton(action, selected);
454
506
  }
@@ -463,8 +515,40 @@ export default class Toolbar extends Component {
463
515
  return null;
464
516
  }
465
517
  const disabledStyle = disabled ? { backgroundColor: '#C9CED7' } : {};
466
- const vStyle = [styles.barContainer, disabledStyle, style, disabled && this._getButtonDisabledStyle()];
467
- const barBg = (style && style.backgroundColor) || (disabled && '#C9CED7') || TOOLBAR_BG;
518
+ // Extract separator from style prop if present, keep rest for container
519
+ let containerStyle = style;
520
+ if (style) {
521
+ if (Array.isArray(style)) {
522
+ // Remove separator from any object in the array
523
+ containerStyle = style.map(styleItem => {
524
+ if (styleItem && typeof styleItem === 'object' && styleItem.separator) {
525
+ const { separator, ...rest } = styleItem;
526
+ return rest;
527
+ }
528
+ return styleItem;
529
+ });
530
+ } else if (typeof style === 'object' && style.separator) {
531
+ const { separator, ...rest } = style;
532
+ containerStyle = rest;
533
+ }
534
+ }
535
+ const vStyle = [styles.barContainer, disabledStyle, containerStyle, disabled && this._getButtonDisabledStyle()];
536
+ // Extract backgroundColor from containerStyle (handle array case)
537
+ let barBg = TOOLBAR_BG;
538
+ if (disabled) {
539
+ barBg = '#C9CED7';
540
+ } else if (containerStyle) {
541
+ if (Array.isArray(containerStyle)) {
542
+ for (const styleItem of containerStyle) {
543
+ if (styleItem && typeof styleItem === 'object' && styleItem.backgroundColor) {
544
+ barBg = styleItem.backgroundColor;
545
+ break;
546
+ }
547
+ }
548
+ } else if (typeof containerStyle === 'object' && containerStyle.backgroundColor) {
549
+ barBg = containerStyle.backgroundColor;
550
+ }
551
+ }
468
552
  const showFades = horizontal && !disabled;
469
553
  return (
470
554
  <View style={vStyle}>
@@ -473,7 +557,7 @@ export default class Toolbar extends Component {
473
557
  horizontal={horizontal}
474
558
  style={[flatContainerStyle, showFades && styles.scrollList]}
475
559
  keyboardShouldPersistTaps={'always'}
476
- keyExtractor={(item, index) => item.action + '-' + index}
560
+ keyExtractor={(item, index) => (item.action === actions.separator ? 'separator' : item.action) + '-' + index}
477
561
  data={this.state.data}
478
562
  alwaysBounceHorizontal={false}
479
563
  showsHorizontalScrollIndicator={false}
package/src/actions.js CHANGED
@@ -44,6 +44,7 @@ export const actions = {
44
44
  hiliteColor: 'hiliteColor',
45
45
  blockquote: 'quote',
46
46
  keyboard: 'keyboard',
47
+ separator: 'separator', // Visual separator for toolbar
47
48
  setTitlePlaceholder: 'SET_TITLE_PLACEHOLDER',
48
49
  setContentPlaceholder: 'SET_CONTENT_PLACEHOLDER',
49
50
  setTitleFocusHandler: 'SET_TITLE_FOCUS_HANDLER',
@@ -801,11 +801,22 @@ function createReadOnlyHTML(options = {}) {
801
801
  ${useDefaultFont ? 'font-family: Arial, Helvetica, sans-serif; font-size: 1em;' : ''}
802
802
  color: ${color};
803
803
  padding: 0;
804
+ margin: 0;
804
805
  height: auto !important;
805
806
  min-height: 0 !important;
806
807
  width: 100%;
807
808
  ${contentCSSText}
808
809
  }
810
+ .readonly-container > *:first-child {
811
+ margin-top: 0 !important;
812
+ }
813
+ .readonly-container p {
814
+ margin-top: 0;
815
+ margin-bottom: 0.5em;
816
+ }
817
+ .readonly-container p:last-child {
818
+ margin-bottom: 0;
819
+ }
809
820
  </style>
810
821
  ${getContentCSS()}
811
822
  <style>${cssText}</style>
@@ -822,7 +833,7 @@ function createReadOnlyHTML(options = {}) {
822
833
  var sendHeight = function() {
823
834
  var scrollH = el.scrollHeight;
824
835
  var offsetH = el.offsetHeight;
825
- var h = Math.ceil(Math.max(scrollH, offsetH)) + 8;
836
+ var h = Math.ceil(Math.max(scrollH, offsetH)) + 16;
826
837
  if (h !== lastH && window.ReactNativeWebView) {
827
838
  lastH = h;
828
839
  window.ReactNativeWebView.postMessage(JSON.stringify({type: 'OFFSET_HEIGHT', data: h}));
package/src/index.d.ts CHANGED
@@ -81,6 +81,7 @@ export interface ToolbarProps {
81
81
  selectedButtonStyle?: object;
82
82
  unselectedButtonStyle?: object;
83
83
  disabledButtonStyle?: object;
84
+ separatorStyle?: object;
84
85
  iconMap?: Record<string, unknown>;
85
86
  renderAction?: (action: string, selected: boolean) => React.ReactElement;
86
87
  onPressAddImage?: () => void;
@@ -139,6 +140,7 @@ export const actions: {
139
140
  hiliteColor: string;
140
141
  blockquote: string;
141
142
  keyboard: string;
143
+ separator: string;
142
144
  [key: string]: string;
143
145
  };
144
146