import React from 'react'; import './index.less'; const stripNbsp = str => str.replace(/ |\u202F|\u00A0/g, ' '); export default class ContentEditable extends React.Component { shouldComponentUpdate(nextProps) { let { props, htmlEl } = this; if (JSON.stringify(this.props.style) === JSON.stringify(nextProps.style)) { return false; }; // We need not rerender if the change of props simply reflects the user's edits. // Rerendering in this case would make the cursor/caret jump // Rerender if there is no element yet... (somehow?) if (!htmlEl) { return true; }; // ...or if html really changed... (programmatically, not by user edit) if ( stripNbsp(nextProps.html) !== stripNbsp(htmlEl.innerHTML) && nextProps.html !== props.html ) { return true; }; let optional = ['style', 'className', 'disabled', 'tagName']; // Handle additional properties return optional.some(name => props[name] !== nextProps[name]); } componentDidUpdate() { if (this.htmlEl && this.props.html !== this.htmlEl.innerHTML) { // Perhaps React (whose VDOM gets outdated because we often prevent // rerendering) did not update the DOM. So we update it manually now. this.htmlEl.innerHTML = this.props.html; }; } emitChange = (evt) => { if (!this.htmlEl) return; var name = evt.target.dataset.name; var html = this.htmlEl.innerHTML; if (this.props.onChange && html !== this.lastHtml) { // Clone event with Object.assign to avoid // "Cannot assign to read only property 'target' of object" var evt = Object.assign({}, evt, { target: { value: html, name: name, }, }); this.props.onChange(evt); } this.lastHtml = html; } render() { var { tagName, name, html, style, onKeyPress, ...otherProps } = this.props; return ( // React.createElement( // tagName || 'div', // { // ...props, // ref: (e) => this.htmlEl = e, // onInput: this.emitChange, // onBlur: this.props.onBlur || this.emitChange, // contentEditable: !this.props.disabled, // dangerouslySetInnerHTML: {__html: html} // }, // this.props.children);
this.htmlEl = e} onInput={this.emitChange} onKeyPress={onKeyPress} //onBlur={this.props.onBlur || this.emitChange} contentEditable={!this.props.disabled} dangerouslySetInnerHTML={{__html: html}}> {this.props.children}
); } }