rn-rich-text-editor 1.2.2 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-rich-text-editor",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "A rich text editor component for React Native",
5
5
  "keywords": [
6
6
  "react-native",
package/src/Toolbar.js CHANGED
@@ -169,19 +169,21 @@ export default class Toolbar extends Component {
169
169
  };
170
170
 
171
171
  static getDerivedStateFromProps(nextProps, prevState) {
172
- const { actions } = nextProps;
173
- if (actions !== prevState.actions) {
172
+ const { actions: actionsList } = nextProps;
173
+ if (actionsList !== prevState.actions) {
174
174
  const items = prevState.items || [];
175
175
  const isItemSelected = (action) =>
176
176
  items.includes(action) || items.some(item => item && item.type === action);
177
177
  return {
178
- actions,
179
- data: actions.map(action => ({
178
+ actions: actionsList,
179
+ data: actionsList.map(action => ({
180
180
  action,
181
181
  selected:
182
- action === actions.align
183
- ? ALIGN_ACTIONS.some(a => isItemSelected(a))
184
- : isItemSelected(action),
182
+ action === actions.separator
183
+ ? false // Separators are never selected
184
+ : action === actions.align
185
+ ? ALIGN_ACTIONS.some(a => isItemSelected(a))
186
+ : isItemSelected(action),
185
187
  })),
186
188
  };
187
189
  }
@@ -224,6 +226,9 @@ export default class Toolbar extends Component {
224
226
  items,
225
227
  selectedAlign,
226
228
  data: this.state.actions.map(action => {
229
+ if (action === actions.separator) {
230
+ return { action, selected: false };
231
+ }
227
232
  const isAlignAction = action === actions.align;
228
233
  const selected = isAlignAction
229
234
  ? !!selectedAlign
@@ -277,6 +282,11 @@ export default class Toolbar extends Component {
277
282
  return;
278
283
  }
279
284
 
285
+ // Separators are not clickable
286
+ if (action === actions.separator) {
287
+ return;
288
+ }
289
+
280
290
  if (action === actions.align) {
281
291
  const { selectedAlign } = this.state;
282
292
  // Cycle through alignments: Left -> Center -> Right -> Justify -> Left
@@ -448,7 +458,33 @@ export default class Toolbar extends Component {
448
458
  );
449
459
  }
450
460
 
461
+ _renderSeparator() {
462
+ const { style, separatorStyle, iconGap = 16 } = this.props;
463
+ const separatorStylesFromStyle = style && typeof style === 'object' && !Array.isArray(style) && style.separator
464
+ ? style.separator
465
+ : null;
466
+ return (
467
+ <View
468
+ key="separator"
469
+ pointerEvents="none"
470
+ style={[
471
+ {
472
+ width: 1,
473
+ height: 24,
474
+ backgroundColor: '#E2E2E4', // Fallback color
475
+ marginHorizontal: iconGap / 2,
476
+ },
477
+ separatorStylesFromStyle, // From style.separator
478
+ separatorStyle, // From separatorStyle prop (for backward compatibility)
479
+ ]}
480
+ />
481
+ );
482
+ }
483
+
451
484
  _renderAction(action, selected) {
485
+ if (action === actions.separator) {
486
+ return this._renderSeparator();
487
+ }
452
488
  if (action === actions.align) {
453
489
  return this._renderAlignButton(action, selected);
454
490
  }
@@ -463,8 +499,14 @@ export default class Toolbar extends Component {
463
499
  return null;
464
500
  }
465
501
  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;
502
+ // Extract separator styles from style prop if present, keep rest for container
503
+ let containerStyle = style;
504
+ if (style && typeof style === 'object' && !Array.isArray(style) && style.separator) {
505
+ const { separator, ...rest } = style;
506
+ containerStyle = rest;
507
+ }
508
+ const vStyle = [styles.barContainer, disabledStyle, containerStyle, disabled && this._getButtonDisabledStyle()];
509
+ const barBg = (containerStyle && typeof containerStyle === 'object' && !Array.isArray(containerStyle) && containerStyle.backgroundColor) || (disabled && '#C9CED7') || TOOLBAR_BG;
468
510
  const showFades = horizontal && !disabled;
469
511
  return (
470
512
  <View style={vStyle}>
@@ -473,7 +515,7 @@ export default class Toolbar extends Component {
473
515
  horizontal={horizontal}
474
516
  style={[flatContainerStyle, showFades && styles.scrollList]}
475
517
  keyboardShouldPersistTaps={'always'}
476
- keyExtractor={(item, index) => item.action + '-' + index}
518
+ keyExtractor={(item, index) => (item.action === actions.separator ? 'separator' : item.action) + '-' + index}
477
519
  data={this.state.data}
478
520
  alwaysBounceHorizontal={false}
479
521
  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>
@@ -820,7 +831,9 @@ function createReadOnlyHTML(options = {}) {
820
831
  el.innerHTML = content;
821
832
  var lastH = 0;
822
833
  var sendHeight = function() {
823
- var h = Math.ceil(el.scrollHeight);
834
+ var scrollH = el.scrollHeight;
835
+ var offsetH = el.offsetHeight;
836
+ var h = Math.ceil(Math.max(scrollH, offsetH)) + 16;
824
837
  if (h !== lastH && window.ReactNativeWebView) {
825
838
  lastH = h;
826
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