import React, { HTMLProps } from 'react'; import classnames from 'classnames'; import './Input.scss'; interface OwnProps extends HTMLProps { isValid?: boolean; showInvalidBeforeBlur?: boolean; showInvalidWithoutValue?: boolean; showValidAsPlain?: boolean; setInnerRef?(ref: HTMLInputElement | null): void; } interface State { hasBlurred: boolean; /** * @description when the input has not had any values inputted yet * e.g. "Pristine" condition */ isStateless: boolean; } type Props = OwnProps & HTMLProps; class Input extends React.Component { public state: State = { hasBlurred: false, isStateless: true }; public render() { const { setInnerRef, showInvalidBeforeBlur, showInvalidWithoutValue, showValidAsPlain, isValid, ...htmlProps } = this.props; const { hasBlurred, isStateless } = this.state; const hasValue = !!this.props.value && this.props.value.toString().length > 0; // Currently we don't ever highlight valid, so go empty string instead let validClass = isValid ? '' : 'invalid'; if (isStateless) { validClass = ''; } if (!hasValue && !showInvalidWithoutValue) { validClass = ''; } else if (!hasBlurred && !showInvalidBeforeBlur) { validClass = ''; } if ((!isStateless || showInvalidBeforeBlur) && !hasValue && showInvalidWithoutValue) { validClass = 'invalid'; } const classname = classnames('input-group-input', this.props.className, validClass); return ( setInnerRef && setInnerRef(node)} onBlur={e => { this.setState({ hasBlurred: true }); if (this.props && this.props.onBlur) { this.props.onBlur(e); } }} onChange={this.handleOnChange} onWheel={this.props.type === 'number' ? this.preventNumberScroll : undefined} className={classname} /> ); } private handleOnChange = (args: React.FormEvent) => { if (this.state.isStateless) { this.setState({ isStateless: false }); } if (this.props.onChange) { this.props.onChange(args); } }; // When number inputs are scrolled on while in focus, the number changes. So we blur // it if it's focused to prevent that behavior, without preventing the scroll. private preventNumberScroll(ev: React.WheelEvent) { if (document.activeElement === ev.currentTarget) { ev.currentTarget.blur(); } } } export default Input;