rn-rich-text-editor 0.0.16 → 0.0.18
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 +1 -1
- package/src/Editor.js +69 -34
- package/src/Toolbar.js +5 -1
- package/src/editor/createHTML.js +65 -1
- package/src/index.d.ts +2 -0
package/package.json
CHANGED
package/src/Editor.js
CHANGED
|
@@ -3,7 +3,7 @@ import { WebView } from 'react-native-webview';
|
|
|
3
3
|
import { actions } from './actions';
|
|
4
4
|
import { messages } from './messages';
|
|
5
5
|
import { Keyboard, Platform, StyleSheet, TextInput, View, Linking } from 'react-native';
|
|
6
|
-
import { createHTML } from './editor/createHTML';
|
|
6
|
+
import { createHTML, createReadOnlyHTML } from './editor/createHTML';
|
|
7
7
|
|
|
8
8
|
const PlatformIOS = Platform.OS === 'ios';
|
|
9
9
|
|
|
@@ -18,6 +18,7 @@ export default class Editor extends Component {
|
|
|
18
18
|
initialContentHTML: '',
|
|
19
19
|
initialFocus: false,
|
|
20
20
|
disabled: false,
|
|
21
|
+
readOnly: false,
|
|
21
22
|
useContainer: true,
|
|
22
23
|
pasteAsPlainText: false,
|
|
23
24
|
autoCapitalize: 'off',
|
|
@@ -69,39 +70,49 @@ export default class Editor extends Component {
|
|
|
69
70
|
initialHeight,
|
|
70
71
|
initialFocus,
|
|
71
72
|
disabled,
|
|
73
|
+
readOnly,
|
|
72
74
|
styleWithCSS,
|
|
73
75
|
useCharacter,
|
|
74
76
|
defaultHttps,
|
|
77
|
+
initialContentHTML,
|
|
75
78
|
} = props;
|
|
79
|
+
const contentForReadOnly = initialContentHTML || (typeof html === 'string' ? html : (html && html.html)) || '';
|
|
76
80
|
that.state = {
|
|
77
81
|
html: {
|
|
78
|
-
html:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
82
|
+
html: readOnly
|
|
83
|
+
? createReadOnlyHTML({
|
|
84
|
+
content: contentForReadOnly,
|
|
85
|
+
backgroundColor,
|
|
86
|
+
color,
|
|
87
|
+
initialCSSText,
|
|
88
|
+
cssText,
|
|
89
|
+
contentCSSText,
|
|
90
|
+
})
|
|
91
|
+
: (html ||
|
|
92
|
+
createHTML({
|
|
93
|
+
backgroundColor,
|
|
94
|
+
color,
|
|
95
|
+
caretColor,
|
|
96
|
+
placeholderColor,
|
|
97
|
+
initialCSSText,
|
|
98
|
+
cssText,
|
|
99
|
+
contentCSSText,
|
|
100
|
+
pasteAsPlainText,
|
|
101
|
+
pasteListener: !!onPaste,
|
|
102
|
+
keyUpListener: !!onKeyUp,
|
|
103
|
+
keyDownListener: !!onKeyDown,
|
|
104
|
+
inputListener: !!onInput,
|
|
105
|
+
enterKeyHint,
|
|
106
|
+
autoCapitalize,
|
|
107
|
+
autoCorrect,
|
|
108
|
+
initialFocus: initialFocus && !disabled,
|
|
109
|
+
defaultParagraphSeparator,
|
|
110
|
+
firstFocusEnd,
|
|
111
|
+
useContainer,
|
|
112
|
+
styleWithCSS,
|
|
113
|
+
useCharacter,
|
|
114
|
+
defaultHttps,
|
|
115
|
+
})),
|
|
105
116
|
},
|
|
106
117
|
keyboardHeight: 0,
|
|
107
118
|
height: initialHeight > 0 ? initialHeight : DEFAULT_EDITOR_HEIGHT,
|
|
@@ -240,7 +251,27 @@ export default class Editor extends Component {
|
|
|
240
251
|
}
|
|
241
252
|
|
|
242
253
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
243
|
-
const { editorStyle, disabled, placeholder } = this.props;
|
|
254
|
+
const { editorStyle, disabled, placeholder, readOnly, initialContentHTML, html } = this.props;
|
|
255
|
+
if (readOnly) {
|
|
256
|
+
const contentChanged = initialContentHTML !== prevProps.initialContentHTML || html !== prevProps.html;
|
|
257
|
+
if (prevProps.readOnly !== readOnly || contentChanged || prevProps.editorStyle !== editorStyle) {
|
|
258
|
+
const contentForReadOnly = initialContentHTML || (typeof html === 'string' ? html : (html?.html)) || '';
|
|
259
|
+
const { backgroundColor, color, initialCSSText, cssText, contentCSSText } = editorStyle || {};
|
|
260
|
+
this.setState({
|
|
261
|
+
html: {
|
|
262
|
+
html: createReadOnlyHTML({
|
|
263
|
+
content: contentForReadOnly,
|
|
264
|
+
backgroundColor,
|
|
265
|
+
color,
|
|
266
|
+
initialCSSText,
|
|
267
|
+
cssText,
|
|
268
|
+
contentCSSText,
|
|
269
|
+
}),
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
244
275
|
if (prevProps.editorStyle !== editorStyle) {
|
|
245
276
|
editorStyle && this.setContentStyle(editorStyle);
|
|
246
277
|
}
|
|
@@ -258,16 +289,16 @@ export default class Editor extends Component {
|
|
|
258
289
|
|
|
259
290
|
renderWebView() {
|
|
260
291
|
let that = this;
|
|
261
|
-
const { html, editorStyle, useContainer, style, onLink, dataDetectorTypes, ...rest } = that.props;
|
|
292
|
+
const { html, editorStyle, useContainer, style, onLink, dataDetectorTypes, readOnly, ...rest } = that.props;
|
|
262
293
|
const { html: viewHTML } = that.state;
|
|
263
294
|
return (
|
|
264
295
|
<>
|
|
265
296
|
<WebView
|
|
266
297
|
useWebKit={true}
|
|
267
298
|
scrollEnabled={false}
|
|
268
|
-
hideKeyboardAccessoryView={
|
|
299
|
+
hideKeyboardAccessoryView={!readOnly}
|
|
269
300
|
keyboardDisplayRequiresUserAction={false}
|
|
270
|
-
nestedScrollEnabled={!useContainer}
|
|
301
|
+
nestedScrollEnabled={readOnly || !useContainer}
|
|
271
302
|
style={[styles.webview, style]}
|
|
272
303
|
{...rest}
|
|
273
304
|
ref={that.setRef}
|
|
@@ -288,7 +319,7 @@ export default class Editor extends Component {
|
|
|
288
319
|
return true;
|
|
289
320
|
}}
|
|
290
321
|
/>
|
|
291
|
-
{Platform.OS === 'android' && <TextInput ref={ref => (that._input = ref)} style={styles._input} />}
|
|
322
|
+
{!readOnly && Platform.OS === 'android' && <TextInput ref={ref => (that._input = ref)} style={styles._input} />}
|
|
292
323
|
</>
|
|
293
324
|
);
|
|
294
325
|
}
|
|
@@ -452,7 +483,11 @@ export default class Editor extends Component {
|
|
|
452
483
|
|
|
453
484
|
init() {
|
|
454
485
|
let that = this;
|
|
455
|
-
const { initialFocus, initialContentHTML, placeholder, editorInitializedCallback, disabled } = that.props;
|
|
486
|
+
const { initialFocus, initialContentHTML, placeholder, editorInitializedCallback, disabled, readOnly } = that.props;
|
|
487
|
+
if (readOnly) {
|
|
488
|
+
editorInitializedCallback();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
456
491
|
initialContentHTML && that.setContentHTML(initialContentHTML);
|
|
457
492
|
placeholder && that.setPlaceholder(placeholder);
|
|
458
493
|
that.setDisable(disabled);
|
package/src/Toolbar.js
CHANGED
|
@@ -63,6 +63,7 @@ export default class Toolbar extends Component {
|
|
|
63
63
|
static defaultProps = {
|
|
64
64
|
actions: defaultActions,
|
|
65
65
|
disabled: false,
|
|
66
|
+
readOnly: false,
|
|
66
67
|
iconTint: '#71787F',
|
|
67
68
|
iconSize: 20,
|
|
68
69
|
iconGap: 16,
|
|
@@ -373,7 +374,10 @@ export default class Toolbar extends Component {
|
|
|
373
374
|
}
|
|
374
375
|
|
|
375
376
|
render() {
|
|
376
|
-
const { style, disabled, children, flatContainerStyle, horizontal = true } = this.props;
|
|
377
|
+
const { style, disabled, readOnly, children, flatContainerStyle, horizontal = true } = this.props;
|
|
378
|
+
if (readOnly) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
377
381
|
const vStyle = [styles.barContainer, style, disabled && this._getButtonDisabledStyle()];
|
|
378
382
|
return (
|
|
379
383
|
<View style={vStyle}>
|
package/src/editor/createHTML.js
CHANGED
|
@@ -755,5 +755,69 @@ function createHTML(options = {}) {
|
|
|
755
755
|
`;
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Escapes a string for safe embedding inside a JavaScript double-quoted string in HTML.
|
|
760
|
+
*/
|
|
761
|
+
function escapeForScript(s) {
|
|
762
|
+
if (s == null) return '';
|
|
763
|
+
return String(s)
|
|
764
|
+
.replace(/\\/g, '\\\\')
|
|
765
|
+
.replace(/"/g, '\\"')
|
|
766
|
+
.replace(/\u2028/g, '\\u2028')
|
|
767
|
+
.replace(/\u2029/g, '\\u2029')
|
|
768
|
+
.replace(/<\/script/gi, '<\\/script');
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Creates minimal HTML for read-only display: content in a fixed-height scrollable box.
|
|
773
|
+
* No editor, no toolbar. Content is escaped and embedded in the template.
|
|
774
|
+
*/
|
|
775
|
+
function createReadOnlyHTML(options = {}) {
|
|
776
|
+
const {
|
|
777
|
+
content = '',
|
|
778
|
+
backgroundColor = '#FFF',
|
|
779
|
+
color = '#000033',
|
|
780
|
+
contentCSSText = '',
|
|
781
|
+
cssText = '',
|
|
782
|
+
initialCSSText = '',
|
|
783
|
+
} = options;
|
|
784
|
+
const escapedContent = escapeForScript(content);
|
|
785
|
+
return `
|
|
786
|
+
<!DOCTYPE html>
|
|
787
|
+
<html>
|
|
788
|
+
<head>
|
|
789
|
+
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
|
790
|
+
<style>
|
|
791
|
+
${initialCSSText}
|
|
792
|
+
* { outline: 0; -webkit-tap-highlight-color: rgba(0,0,0,0); box-sizing: border-box; }
|
|
793
|
+
html, body { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; font-size: 1em; height: 100%; }
|
|
794
|
+
body { background-color: ${backgroundColor}; color: ${color}; }
|
|
795
|
+
.readonly-container {
|
|
796
|
+
height: 100%;
|
|
797
|
+
overflow-y: auto;
|
|
798
|
+
-webkit-overflow-scrolling: touch;
|
|
799
|
+
padding: 10px;
|
|
800
|
+
${contentCSSText}
|
|
801
|
+
}
|
|
802
|
+
</style>
|
|
803
|
+
${getContentCSS()}
|
|
804
|
+
<style>${cssText}</style>
|
|
805
|
+
</head>
|
|
806
|
+
<body>
|
|
807
|
+
<div id="readonly-content" class="readonly-container"></div>
|
|
808
|
+
<script>
|
|
809
|
+
(function() {
|
|
810
|
+
var content = "${escapedContent}";
|
|
811
|
+
var el = document.getElementById('readonly-content');
|
|
812
|
+
if (el) {
|
|
813
|
+
el.innerHTML = content;
|
|
814
|
+
}
|
|
815
|
+
})();
|
|
816
|
+
</script>
|
|
817
|
+
</body>
|
|
818
|
+
</html>
|
|
819
|
+
`;
|
|
820
|
+
}
|
|
821
|
+
|
|
758
822
|
const HTML = createHTML();
|
|
759
|
-
export { HTML, createHTML };
|
|
823
|
+
export { HTML, createHTML, createReadOnlyHTML };
|
package/src/index.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export interface EditorProps {
|
|
|
39
39
|
initialContentHTML?: string;
|
|
40
40
|
initialFocus?: boolean;
|
|
41
41
|
disabled?: boolean;
|
|
42
|
+
readOnly?: boolean;
|
|
42
43
|
useContainer?: boolean;
|
|
43
44
|
pasteAsPlainText?: boolean;
|
|
44
45
|
autoCapitalize?: string;
|
|
@@ -69,6 +70,7 @@ export interface ToolbarProps {
|
|
|
69
70
|
getEditor?: () => EditorRef | null;
|
|
70
71
|
actions?: string[];
|
|
71
72
|
disabled?: boolean;
|
|
73
|
+
readOnly?: boolean;
|
|
72
74
|
iconTint?: string;
|
|
73
75
|
selectedIconTint?: string;
|
|
74
76
|
disabledIconTint?: string;
|