Skip to content

Instantly share code, notes, and snippets.

@nuc
Forked from Schniz/plaintext-contenteditable.css
Last active April 18, 2019 01:24
Show Gist options
  • Save nuc/1463bb41c5200a23e88cd7fc11b1f996 to your computer and use it in GitHub Desktop.
Save nuc/1463bb41c5200a23e88cd7fc11b1f996 to your computer and use it in GitHub Desktop.
Plain-Text ContentEditable div for React.js
.comPlainTextContentEditable {
-webkit-user-modify: read-write-plaintext-only;
}
.comPlainTextContentEditable--has-placeholder::before {
content: attr(placeholder);
opacity: 0.5;
color: inherit;
cursor: text;
}
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
class ContentEditable extends Component {
static propTypes = {
initialValue: PropTypes.string,
placeholder: PropTypes.string,
onChange: PropTypes.func.isRequired,
onEnter: PropTypes.func,
className: PropTypes.string,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
}
constructor(props) {
super(props)
const { initialValue } = this.props
this.state = {
text: initialValue || ''
}
}
dispatchOnEnter = event => {
const { onEnter } = this.props
if ((event.key === 'Enter' || event.keyCode === 13)
&& typeof onEnter === 'function') {
event.preventDefault()
onEnter()
}
}
getText = element => {
return element.innerText || this.getTextForFirefox(element)
}
getTextForFirefox(el) {
// Taken from http://stackoverflow.com/a/3908094
let text = ''
if (typeof window.getSelection != 'undefined') {
const sel = window.getSelection()
const tempRange = sel.getRangeAt(0)
sel.removeAllRanges()
const range = document.createRange()
range.selectNodeContents(el)
sel.addRange(range)
text = sel.toString()
sel.removeAllRanges()
sel.addRange(tempRange)
}
return text
}
onTextChange = event => {
const text = this.getText(event.target)
this.setState({ text })
this.props.onChange(text)
}
onPaste = event => {
event.preventDefault()
const text = event.clipboardData.getData('text')
document.execCommand('insertText', false, text)
}
// Chrome collapses an inline element with no content to zero width,
// and subsequently is unable to draw a cursor. For this, we need to
// set the display to block when the value is not present.
get additionalStyles() {
return this.state.text.length === 0 ? { display: 'block' } : {}
}
get classname() {
const { className } = this.props
return classnames(
className,
'comPlainTextContentEditable', {
'comPlainTextContentEditable--has-placeholder': this.state.text === '',
}
)
}
render() {
const { onFocus, onBlur, placeholder } = this.props
return (
<span
ref="content"
contentEditable
className={this.classname}
style={this.additionalStyles}
onPaste={this.onPaste}
onInput={this.onTextChange}
onKeyDown={this.dispatchOnEnter}
onBlur={onBlur}
onFocus={onFocus}
placeholder={placeholder}
/>
)
}
}
export default ContentEditable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment