UNPKG

react-native-cn-quill

Version:
219 lines (218 loc) 8.95 kB
import * as React from 'react'; import { WebView } from 'react-native-webview'; import { View, Text, StyleSheet } from 'react-native'; import { createHtml } from '../utils/editor-utils'; import { Loading } from './loading'; export default class QuillEditor extends React.Component { constructor(props) { super(props); this.getInitalHtml = () => { const { initialHtml = '', import3rdParties = 'local', containerId = 'standalone-container', theme = { background: 'white', color: 'rgb(32, 35, 42)', placeholder: 'rgba(0,0,0,0.6)', }, quill = { id: 'editor-container', placeholder: 'write here!', modules: { toolbar: false, }, theme: 'snow', }, customFonts = [], customStyles = [], defaultFontFamily = undefined, customJS = '', } = this.props; return createHtml({ initialHtml, placeholder: quill.placeholder, theme: quill.theme ? quill.theme : 'snow', toolbar: JSON.stringify(quill.modules?.toolbar), libraries: import3rdParties, editorId: quill.id ? quill.id : 'editor-container', defaultFontFamily, containerId, color: theme.color, fonts: customFonts, backgroundColor: theme.background, placeholderColor: theme.placeholder, customStyles, customJS, }); }; this.post = (obj) => { const jsonString = JSON.stringify(obj); this._webview.current?.postMessage(jsonString); }; this.toMessage = (data) => { const message = JSON.parse(data); return message; }; this.onMessage = (event) => { const message = this.toMessage(event.nativeEvent.data); const response = message.key ? this._promises.find((x) => x.key === message.key) : undefined; switch (message.type) { case 'format-change': case 'text-change': case 'selection-change': case 'html-change': case 'editor-change': case 'blur': case 'focus': this._handlers .filter((x) => x.event === message.type) .forEach((item) => item.handler(message.data)); break; case 'has-focus': case 'get-contents': case 'get-text': case 'get-length': case 'get-bounds': case 'get-selection': case 'get-html': if (response) { response.resolve(message.data); this._promises = this._promises.filter((x) => x.key !== message.key); } break; } }; this.blur = () => { this.post({ command: 'blur' }); }; this.focus = () => { this.post({ command: 'focus' }); }; this.hasFocus = () => { return this.postAwait({ command: 'hasFocus' }); }; this.enable = (enable = true) => { this.post({ command: 'enable', value: enable }); }; this.disable = () => { this.post({ command: 'enable', value: false }); }; this.update = () => { this.post({ command: 'update' }); }; this.format = (name, value) => { this.post({ command: 'format', name, value }); }; this.deleteText = (index, length) => { this.post({ command: 'deleteText', index, length }); }; this.getContents = (index, length) => { return this.postAwait({ command: 'getContents', index, length }); }; this.getHtml = () => { return this.postAwait({ command: 'getHtml' }); }; this.getLength = () => { return this.postAwait({ command: 'getLength' }); }; this.getText = (index, length) => { return this.postAwait({ command: 'getText', index, length }); }; this.getBounds = (index, length) => { return this.postAwait({ command: 'getBounds', index, length }); }; this.getSelection = (focus = false) => { return this.postAwait({ command: 'getSelection', focus }); }; this.setSelection = (index, length, source) => { this.post({ command: 'setSelection', index, length, source }); }; this.insertEmbed = (index, type, value) => { this.post({ command: 'insertEmbed', index, type, value }); }; this.insertText = (index, text, formats) => { this.post({ command: 'insertText', index, text, formats }); }; this.setContents = (delta) => { this.post({ command: 'setContents', delta }); }; this.setText = (text) => { this.post({ command: 'setText', text }); }; this.updateContents = (delta) => { this.post({ command: 'updateContents', delta }); }; this.on = (event, handler) => { this._handlers.push({ event, handler }); }; this.off = (event, handler) => { const index = this._handlers.findIndex((x) => x.event === event && x.handler === handler); if (index > -1) { this._handlers.splice(index, 1); } }; this.dangerouslyPasteHTML = (index, html) => { this.post({ command: 'dangerouslyPasteHTML', index, html }); }; this.renderWebview = (content, style, props = {}) => (React.createElement(WebView, Object.assign({ scrollEnabled: false, hideKeyboardAccessoryView: true, keyboardDisplayRequiresUserAction: false, originWhitelist: ['*'], style: style, onError: (syntheticEvent) => { const { nativeEvent } = syntheticEvent; console.warn('WebView error: ', nativeEvent); }, allowFileAccess: true, domStorageEnabled: false, automaticallyAdjustContentInsets: true, bounces: false, dataDetectorTypes: "none" }, props, { javaScriptEnabled: true, source: { html: content }, ref: this._webview, onMessage: this.onMessage }))); this._webview = React.createRef(); this.state = { webviewContent: this.getInitalHtml(), }; this._handlers = []; this._promises = []; const { onSelectionChange, onEditorChange, onTextChange, onHtmlChange, onBlur, onFocus, } = this.props; if (onSelectionChange) { this.on('selection-change', onSelectionChange); } if (onEditorChange) { this.on('editor-change', onEditorChange); } if (onTextChange) { this.on('text-change', onTextChange); } if (onHtmlChange) { this.on('html-change', onHtmlChange); } if (onBlur) { this.on('blur', onBlur); } if (onFocus) { this.on('focus', onFocus); } } getKey() { var timestamp = new Date().getUTCMilliseconds(); return `${timestamp}${Math.random()}`; } postAwait(data) { const key = this.getKey(); let resolveFn; resolveFn = () => { }; const promise = new Promise((resolve) => { resolveFn = resolve; }); const resp = { key, resolve: resolveFn, }; this._promises.push(resp); this.post({ ...data, key }); return promise; } render() { const { webviewContent } = this.state; const { style, webview, container = false, loading = 'Please Wait ...', } = this.props; if (container === false) { if (!webviewContent) return React.createElement(Text, null, "Please wait..."); return this.renderWebview(webviewContent, style, webview); } else { const ContainerComponent = container === true ? View : container; return (React.createElement(ContainerComponent, { style: style }, webviewContent ? (this.renderWebview(webviewContent, styles.webView, webview)) : typeof loading === 'string' ? (React.createElement(Loading, { text: loading })) : (loading))); } } } let styles = StyleSheet.create({ webView: { flexGrow: 1, borderWidth: 0, }, });