Skip to content

Instantly share code, notes, and snippets.

@rarous
Created October 26, 2015 13:27
Show Gist options
  • Save rarous/44e03e1f2dd52d13cc31 to your computer and use it in GitHub Desktop.
Save rarous/44e03e1f2dd52d13cc31 to your computer and use it in GitHub Desktop.
.host {
display: inline-block;
position: relative;
width: 400px;
border: 1px solid;
padding: 2px;
-moz-appearance: textarea;
-webkit-appearance: textarea;
}
.host .mirrorText {
visibility: hidden;
word-wrap: break-word;
}
.host textarea {
position: relative;
outline: 0;
border: 0;
resize: none;
background: inherit;
/* see comments in template */
width: 100%;
height: 100%;
font-size: inherit;
font-family: inherit;
}
.host textarea:invalid {
box-shadow: none;
}
.textareaContainer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
import React, {Component, PropTypes} from 'react';
import classNames from 'classnames';
import styles from './iron-autogrow-textarea.css';
const NBSP = '\u00a0';
function constraint(tokens, rows, maxRows) {
const ts = tokens || [''];
const result = (maxRows > 0 && ts.length > maxRows) ? ts.slice(0, maxRows) : ts.slice(0);
while (rows > 0 && result.length < rows) {
result.push('');
}
return result.join('<br />') + NBSP;
}
function tokenize(input) {
if (!input.value) return [''];
return input.value
.replace(/&/gm, '&amp;')
.replace(/"/gm, '&quot;')
.replace(/'/gm, '&#39;')
.replace(/</gm, '&lt;')
.replace(/>/gm, '&gt;')
.split('\n');
}
function valueForMirror(input, rows, maxRows) {
if (!input) return;
return constraint(tokenize(input), rows, maxRows);
}
export class IronAutogrowTextArea extends Component {
static displayName = 'IronAutogrowTextArea';
static propTypes = {
maxRows: PropTypes.number,
rows: PropTypes.number,
value: PropTypes.string,
required: PropTypes.bool
};
constructor(props) {
super(props);
const isInvalid = !props.value && props.required;
const mirror = valueForMirror(props, props.rows, props.maxRows) || NBSP;
this.state = {mirror, isValid: !isInvalid};
}
update(e) {
const {rows, maxRows} = this.props;
const textarea = e.nativeEvent.target;
const isValid = textarea.validity.valid;
this.setState({mirror: valueForMirror(textarea, rows, maxRows), isValid});
}
render() {
const {maxRows, ...props} = this.props;
const {mirror, isValid} = this.state;
props.rows = props.rows || 1;
const classes = classNames('iron-autogrow-textarea', styles.host);
return (
<div className={classes} onChange={::this.update} aria-invalid={!isValid}>
<div className={styles.mirrorText} aria-hidden dangerouslySetInnerHTML={{__html: mirror}} />
<div className={styles.textareaContainer}>
<textarea {...props}></textarea>
</div>
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment