UNPKG

react-sprucebot

Version:

React components for your Sprucebot Skill 💪🏼

131 lines (118 loc) 2.97 kB
import React, { Component } from 'react' import PropTypes from 'prop-types' import { Paragraph as P } from '../Typography/Typography' export default class Input extends Component { constructor(props) { super(props) this.state = { hasValue: !!(props.value || props.defaultValue) } } onChange(e) { this.setState({ hasValue: this.input.value.length > 0 }) if (this.props.onChange) { this.props.onChange(this.input.value, e) } if (this.props.multiline) { this.sizeTextarea() } } sizeTextarea() { if (typeof window !== 'undefined') { const style = window.getComputedStyle(this.input) let heightOffset = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom) // Fix when a textarea is not on document body and heightOffset is Not a Number if (isNaN(heightOffset)) { heightOffset = 0 } const height = style.height this.input.style.transition = 'none' this.input.style.height = '1px' const scrollHeight = this.input.scrollHeight this.input.style.height = height if (this._sizeTimeout) { clearTimeout(this._sizeTimeout) } this._sizeTimeout = setTimeout(() => { if (this.input) { this.input.style.transition = this._textAreaTransition this.input.style.height = scrollHeight + heightOffset + 'px' } }, 250) } } handleMultiline(props) { if (props.multiline) { this._textAreaTransition = this.input.style.transition this.sizeTextarea() } } componentDidMount() { this.handleMultiline(this.props) } componentDidUpdate() { this.handleMultiline(this.props) } render() { const props = Object.assign({}, this.props) const { error, label, finePrint, multiline } = props let { tag } = props let labelClass = label ? 'js-show-label' : '' delete props.error delete props.label delete props.onChange delete props.finePrint delete props.tag delete props.multiline // inputs cannot have children if (multiline) { tag = 'textarea' } else if (tag === 'input') { delete props.children } // if this is an empty input, has a label, but no placeholder // make the placeholder match the label and hide the label if ( tag === 'input' && label && !props.placeholder && !this.state.hasValue ) { props.placeholder = label labelClass = '' } const Tag = tag return ( <div className="input__wrapper"> {label && ( <span className={'input__mini__label ' + labelClass}>{label}</span> )} <Tag {...props} onChange={this.onChange.bind(this)} ref={ref => { this.input = ref }} /> {error && ( <span className="input__error error-is-visible">{error}</span> )} {finePrint && <P fine>{finePrint}</P>} </div> ) } } Input.propTypes = { finePrint: PropTypes.string, label: PropTypes.string, error: PropTypes.string, tag: PropTypes.string, multiline: PropTypes.bool } Input.defaultProps = { tag: 'input', multiline: false }