UNPKG

react-mdl

Version:

React Components for Material Design Lite

126 lines (113 loc) 4.56 kB
import React from 'react'; import PropTypes from 'prop-types'; import { findDOMNode } from 'react-dom'; import classNames from 'classnames'; import mdlUpgrade from './utils/mdlUpgrade'; const propTypes = { className: PropTypes.string, disabled: PropTypes.bool, error: PropTypes.node, expandable: PropTypes.bool, expandableIcon: PropTypes.string, floatingLabel: PropTypes.bool, id: (props, propName, componentName) => { const { id } = props; if (id && typeof id !== 'string') { return new Error(`Invalid prop \`${propName}\` supplied to \`${componentName}\`. \`${propName}\` should be a string. Validation failed.`); } if (!id && typeof props.label !== 'string') { return new Error(`Invalid prop \`${propName}\` supplied to \`${componentName}\`. \`${propName}\` is required when label is an element. Validation failed.`); } return null; }, inputClassName: PropTypes.string, label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, maxRows: PropTypes.number, onChange: PropTypes.func, pattern: PropTypes.string, required: PropTypes.bool, rows: PropTypes.number, style: PropTypes.object, value: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]) }; class Textfield extends React.Component { componentDidMount() { if (this.props.error && !this.props.pattern) { this.setAsInvalid(); } } componentDidUpdate(prevProps) { if ( this.props.required !== prevProps.required || this.props.pattern !== prevProps.pattern || this.props.error !== prevProps.error ) { findDOMNode(this).MaterialTextfield.checkValidity(); } if (this.props.disabled !== prevProps.disabled) { findDOMNode(this).MaterialTextfield.checkDisabled(); } if (this.props.value !== prevProps.value && this.inputRef !== document.activeElement) { findDOMNode(this).MaterialTextfield.change(this.props.value); } if (this.props.error && !this.props.pattern) { // Every time the input gets updated by MDL (checkValidity() or change()) // its invalid class gets reset. We have to put it again if the input is specifically set as "invalid" this.setAsInvalid(); } } setAsInvalid() { const elt = findDOMNode(this); if (elt.className.indexOf('is-invalid') < 0) { elt.className = classNames(elt.className, 'is-invalid'); } } render() { const { className, inputClassName, id, error, expandable, expandableIcon, floatingLabel, label, maxRows, rows, style, children, ...otherProps } = this.props; const hasRows = !!rows; const customId = id || `textfield-${label.replace(/[^a-z0-9]/gi, '')}`; const inputTag = hasRows || maxRows > 1 ? 'textarea' : 'input'; const inputProps = { className: classNames('mdl-textfield__input', inputClassName), id: customId, rows, ref: (c) => (this.inputRef = c), ...otherProps }; const input = React.createElement(inputTag, inputProps); const labelContainer = <label className="mdl-textfield__label" htmlFor={customId}>{label}</label>; const errorContainer = !!error && <span className="mdl-textfield__error">{error}</span>; const containerClasses = classNames('mdl-textfield mdl-js-textfield', { 'mdl-textfield--floating-label': floatingLabel, 'mdl-textfield--expandable': expandable }, className); return expandable ? ( <div className={containerClasses} style={style}> <label className="mdl-button mdl-js-button mdl-button--icon" htmlFor={customId}> <i className="material-icons">{expandableIcon}</i> </label> <div className="mdl-textfield__expandable-holder"> {input} {labelContainer} {errorContainer} </div> {children} </div> ) : ( <div className={containerClasses} style={style}> {input} {labelContainer} {errorContainer} {children} </div> ); } } Textfield.propTypes = propTypes; export default mdlUpgrade(Textfield);