react-input-autosize
Version:
Auto-resizing Input Component for React
129 lines (123 loc) • 4.65 kB
JavaScript
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require('react');
var sizerStyle = { position: 'absolute', top: 0, left: 0, visibility: 'hidden', height: 0, overflow: 'scroll', whiteSpace: 'pre' };
var AutosizeInput = React.createClass({
displayName: 'AutosizeInput',
propTypes: {
className: React.PropTypes.string, // className for the outer element
defaultValue: React.PropTypes.any, // default field value
inputClassName: React.PropTypes.string, // className for the input element
inputStyle: React.PropTypes.object, // css styles for the input element
minWidth: React.PropTypes.oneOfType([// minimum width for input element
React.PropTypes.number, React.PropTypes.string]),
onChange: React.PropTypes.func, // onChange handler: function(newValue) {}
placeholder: React.PropTypes.string, // placeholder text
placeholderIsMinWidth: React.PropTypes.bool, // don't collapse size to less than the placeholder
style: React.PropTypes.object, // css styles for the outer element
value: React.PropTypes.any },
// field value
getDefaultProps: function getDefaultProps() {
return {
minWidth: 1
};
},
getInitialState: function getInitialState() {
return {
inputWidth: this.props.minWidth
};
},
componentDidMount: function componentDidMount() {
this.copyInputStyles();
this.updateInputWidth();
},
componentDidUpdate: function componentDidUpdate() {
this.updateInputWidth();
},
copyInputStyles: function copyInputStyles() {
if (!this.isMounted() || !window.getComputedStyle) {
return;
}
var inputStyle = window.getComputedStyle(this.refs.input);
if (!inputStyle) {
return;
}
var widthNode = this.refs.sizer;
widthNode.style.fontSize = inputStyle.fontSize;
widthNode.style.fontFamily = inputStyle.fontFamily;
widthNode.style.fontWeight = inputStyle.fontWeight;
widthNode.style.fontStyle = inputStyle.fontStyle;
widthNode.style.letterSpacing = inputStyle.letterSpacing;
if (this.props.placeholder) {
var placeholderNode = this.refs.placeholderSizer;
placeholderNode.style.fontSize = inputStyle.fontSize;
placeholderNode.style.fontFamily = inputStyle.fontFamily;
placeholderNode.style.fontWeight = inputStyle.fontWeight;
placeholderNode.style.fontStyle = inputStyle.fontStyle;
placeholderNode.style.letterSpacing = inputStyle.letterSpacing;
}
},
updateInputWidth: function updateInputWidth() {
if (!this.isMounted() || typeof this.refs.sizer.scrollWidth === 'undefined') {
return;
}
var newInputWidth = undefined;
if (this.props.placeholder && (!this.props.value || this.props.value && this.props.placeholderIsMinWidth)) {
newInputWidth = Math.max(this.refs.sizer.scrollWidth, this.refs.placeholderSizer.scrollWidth) + 2;
} else {
newInputWidth = this.refs.sizer.scrollWidth + 2;
}
if (newInputWidth < this.props.minWidth) {
newInputWidth = this.props.minWidth;
}
if (newInputWidth !== this.state.inputWidth) {
this.setState({
inputWidth: newInputWidth
});
}
},
getInput: function getInput() {
return this.refs.input;
},
focus: function focus() {
this.refs.input.focus();
},
blur: function blur() {
this.refs.input.blur();
},
select: function select() {
this.refs.input.select();
},
render: function render() {
var sizerValue = this.props.defaultValue || this.props.value || '';
var wrapperStyle = this.props.style || {};
if (!wrapperStyle.display) wrapperStyle.display = 'inline-block';
var inputStyle = _extends({}, this.props.inputStyle);
inputStyle.width = this.state.inputWidth + 'px';
inputStyle.boxSizing = 'content-box';
var inputProps = _extends({}, this.props);
inputProps.className = this.props.inputClassName;
inputProps.style = inputStyle;
// ensure props meant for `AutosizeInput` don't end up on the `input`
delete inputProps.inputClassName;
delete inputProps.inputStyle;
delete inputProps.minWidth;
delete inputProps.placeholderIsMinWidth;
return React.createElement(
'div',
{ className: this.props.className, style: wrapperStyle },
React.createElement('input', _extends({}, inputProps, { ref: 'input' })),
React.createElement(
'div',
{ ref: 'sizer', style: sizerStyle },
sizerValue
),
this.props.placeholder ? React.createElement(
'div',
{ ref: 'placeholderSizer', style: sizerStyle },
this.props.placeholder
) : null
);
}
});
module.exports = AutosizeInput;