UNPKG

material-ui

Version:

React Components that Implement Google's Material Design.

591 lines (514 loc) 19.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _simpleAssign = require('simple-assign'); var _simpleAssign2 = _interopRequireDefault(_simpleAssign); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _shallowEqual = require('recompose/shallowEqual'); var _shallowEqual2 = _interopRequireDefault(_shallowEqual); var _transitions = require('../styles/transitions'); var _transitions2 = _interopRequireDefault(_transitions); var _EnhancedTextarea = require('./EnhancedTextarea'); var _EnhancedTextarea2 = _interopRequireDefault(_EnhancedTextarea); var _TextFieldHint = require('./TextFieldHint'); var _TextFieldHint2 = _interopRequireDefault(_TextFieldHint); var _TextFieldLabel = require('./TextFieldLabel'); var _TextFieldLabel2 = _interopRequireDefault(_TextFieldLabel); var _TextFieldUnderline = require('./TextFieldUnderline'); var _TextFieldUnderline2 = _interopRequireDefault(_TextFieldUnderline); var _warning = require('warning'); var _warning2 = _interopRequireDefault(_warning); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var getStyles = function getStyles(props, context, state) { var _context$muiTheme = context.muiTheme, baseTheme = _context$muiTheme.baseTheme, _context$muiTheme$tex = _context$muiTheme.textField, floatingLabelColor = _context$muiTheme$tex.floatingLabelColor, focusColor = _context$muiTheme$tex.focusColor, textColor = _context$muiTheme$tex.textColor, disabledTextColor = _context$muiTheme$tex.disabledTextColor, backgroundColor = _context$muiTheme$tex.backgroundColor, errorColor = _context$muiTheme$tex.errorColor; var styles = { root: { fontSize: 16, lineHeight: '24px', width: props.fullWidth ? '100%' : 256, height: (props.rows - 1) * 24 + (props.floatingLabelText ? 72 : 48), display: 'inline-block', position: 'relative', backgroundColor: backgroundColor, fontFamily: baseTheme.fontFamily, transition: _transitions2.default.easeOut('200ms', 'height'), cursor: props.disabled ? 'not-allowed' : 'auto' }, error: { position: 'relative', bottom: 2, fontSize: 12, lineHeight: '12px', color: errorColor, transition: _transitions2.default.easeOut() }, floatingLabel: { color: props.disabled ? disabledTextColor : floatingLabelColor, pointerEvents: 'none' }, input: { padding: 0, position: 'relative', width: '100%', border: 'none', outline: 'none', backgroundColor: 'rgba(0,0,0,0)', color: props.disabled ? disabledTextColor : textColor, cursor: 'inherit', font: 'inherit', WebkitOpacity: 1, WebkitTapHighlightColor: 'rgba(0,0,0,0)' // Remove mobile color flashing (deprecated style). }, inputNative: { appearance: 'textfield' // Improve type search style. } }; styles.textarea = (0, _simpleAssign2.default)({}, styles.input, { marginTop: props.floatingLabelText ? 36 : 12, marginBottom: props.floatingLabelText ? -36 : -12, boxSizing: 'border-box', font: 'inherit' }); // Do not assign a height to the textarea as he handles it on his own. styles.input.height = '100%'; if (state.isFocused) { styles.floatingLabel.color = focusColor; } if (props.floatingLabelText) { styles.input.boxSizing = 'border-box'; if (!props.multiLine) { styles.input.marginTop = 14; } if (state.errorText) { styles.error.bottom = !props.multiLine ? styles.error.fontSize + 3 : 3; } } if (state.errorText) { if (state.isFocused) { styles.floatingLabel.color = styles.error.color; } } return styles; }; /** * Check if a value is valid to be displayed inside an input. * * @param The value to check. * @returns True if the string provided is valid, false otherwise. */ function isValid(value) { return value !== '' && value !== undefined && value !== null && !(Array.isArray(value) && value.length === 0); } var TextField = function (_Component) { (0, _inherits3.default)(TextField, _Component); function TextField() { var _ref; var _temp, _this, _ret; (0, _classCallCheck3.default)(this, TextField); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_ref = TextField.__proto__ || (0, _getPrototypeOf2.default)(TextField)).call.apply(_ref, [this].concat(args))), _this), _this.state = { isFocused: false, errorText: undefined, hasValue: false }, _this.handleInputBlur = function (event) { _this.setState({ isFocused: false }); if (_this.props.onBlur) { _this.props.onBlur(event); } }, _this.handleInputChange = function (event) { if (!_this.props.hasOwnProperty('value')) { _this.setState({ hasValue: isValid(event.target.value) }); } if (_this.props.onChange) { _this.props.onChange(event, event.target.value); } }, _this.handleInputFocus = function (event) { if (_this.props.disabled) { return; } _this.setState({ isFocused: true }); if (_this.props.onFocus) { _this.props.onFocus(event); } }, _this.handleHeightChange = function (event, height) { var newHeight = height + 24; if (_this.props.floatingLabelText) { newHeight += 24; } _reactDom2.default.findDOMNode(_this).style.height = newHeight + 'px'; }, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret); } (0, _createClass3.default)(TextField, [{ key: 'componentWillMount', value: function componentWillMount() { var _props = this.props, children = _props.children, name = _props.name, hintText = _props.hintText, floatingLabelText = _props.floatingLabelText, id = _props.id; var propsLeaf = children ? children.props : this.props; this.setState({ errorText: this.props.errorText, hasValue: isValid(propsLeaf.value) || isValid(propsLeaf.defaultValue) }); process.env.NODE_ENV !== "production" ? (0, _warning2.default)(name || hintText || floatingLabelText || id, 'Material-UI: We don\'t have enough information\n to build a robust unique id for the TextField component. Please provide an id or a name.') : void 0; var uniqueId = name + '-' + hintText + '-' + floatingLabelText + '-' + Math.floor(Math.random() * 0xFFFF); this.uniqueId = uniqueId.replace(/[^A-Za-z0-9-]/gi, ''); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.disabled && !this.props.disabled) { this.setState({ isFocused: false }); } if (nextProps.errorText !== this.props.errorText) { this.setState({ errorText: nextProps.errorText }); } if (nextProps.children && nextProps.children.props) { nextProps = nextProps.children.props; } if (nextProps.hasOwnProperty('value')) { var hasValue = isValid(nextProps.value); this.setState({ hasValue: hasValue }); } } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState, nextContext) { return !(0, _shallowEqual2.default)(this.props, nextProps) || !(0, _shallowEqual2.default)(this.state, nextState) || !(0, _shallowEqual2.default)(this.context, nextContext); } }, { key: 'blur', value: function blur() { if (this.input) { this.getInputNode().blur(); } } }, { key: 'focus', value: function focus() { if (this.input) { this.getInputNode().focus(); } } }, { key: 'select', value: function select() { if (this.input) { this.getInputNode().select(); } } }, { key: 'getValue', value: function getValue() { return this.input ? this.getInputNode().value : undefined; } }, { key: 'getInputNode', value: function getInputNode() { return this.props.children || this.props.multiLine ? this.input.getInputNode() : _reactDom2.default.findDOMNode(this.input); } }, { key: '_isControlled', value: function _isControlled() { return this.props.hasOwnProperty('value'); } }, { key: 'render', value: function render() { var _this2 = this; var _props2 = this.props, children = _props2.children, className = _props2.className, disabled = _props2.disabled, errorStyle = _props2.errorStyle, errorText = _props2.errorText, floatingLabelFixed = _props2.floatingLabelFixed, floatingLabelFocusStyle = _props2.floatingLabelFocusStyle, floatingLabelShrinkStyle = _props2.floatingLabelShrinkStyle, floatingLabelStyle = _props2.floatingLabelStyle, floatingLabelText = _props2.floatingLabelText, fullWidth = _props2.fullWidth, hintText = _props2.hintText, hintStyle = _props2.hintStyle, id = _props2.id, inputStyle = _props2.inputStyle, multiLine = _props2.multiLine, onBlur = _props2.onBlur, onChange = _props2.onChange, onFocus = _props2.onFocus, style = _props2.style, type = _props2.type, underlineDisabledStyle = _props2.underlineDisabledStyle, underlineFocusStyle = _props2.underlineFocusStyle, underlineShow = _props2.underlineShow, underlineStyle = _props2.underlineStyle, rows = _props2.rows, rowsMax = _props2.rowsMax, textareaStyle = _props2.textareaStyle, other = (0, _objectWithoutProperties3.default)(_props2, ['children', 'className', 'disabled', 'errorStyle', 'errorText', 'floatingLabelFixed', 'floatingLabelFocusStyle', 'floatingLabelShrinkStyle', 'floatingLabelStyle', 'floatingLabelText', 'fullWidth', 'hintText', 'hintStyle', 'id', 'inputStyle', 'multiLine', 'onBlur', 'onChange', 'onFocus', 'style', 'type', 'underlineDisabledStyle', 'underlineFocusStyle', 'underlineShow', 'underlineStyle', 'rows', 'rowsMax', 'textareaStyle']); var prepareStyles = this.context.muiTheme.prepareStyles; var styles = getStyles(this.props, this.context, this.state); var inputId = id || this.uniqueId; var errorTextElement = this.state.errorText && _react2.default.createElement( 'div', { style: prepareStyles((0, _simpleAssign2.default)(styles.error, errorStyle)) }, this.state.errorText ); var floatingLabelTextElement = floatingLabelText && _react2.default.createElement( _TextFieldLabel2.default, { muiTheme: this.context.muiTheme, style: (0, _simpleAssign2.default)(styles.floatingLabel, floatingLabelStyle, this.state.isFocused ? floatingLabelFocusStyle : null), shrinkStyle: floatingLabelShrinkStyle, htmlFor: inputId, shrink: this.state.hasValue || this.state.isFocused || floatingLabelFixed, disabled: disabled }, floatingLabelText ); var inputProps = { id: inputId, ref: function ref(elem) { return _this2.input = elem; }, disabled: this.props.disabled, onBlur: this.handleInputBlur, onChange: this.handleInputChange, onFocus: this.handleInputFocus }; var childStyleMerged = (0, _simpleAssign2.default)(styles.input, inputStyle); var inputElement = void 0; if (children) { inputElement = _react2.default.cloneElement(children, (0, _extends3.default)({}, inputProps, children.props, { style: (0, _simpleAssign2.default)(childStyleMerged, children.props.style) })); } else { inputElement = multiLine ? _react2.default.createElement(_EnhancedTextarea2.default, (0, _extends3.default)({ style: childStyleMerged, textareaStyle: (0, _simpleAssign2.default)(styles.textarea, styles.inputNative, textareaStyle), rows: rows, rowsMax: rowsMax, hintText: hintText }, other, inputProps, { onHeightChange: this.handleHeightChange })) : _react2.default.createElement('input', (0, _extends3.default)({ type: type, style: prepareStyles((0, _simpleAssign2.default)(styles.inputNative, childStyleMerged)) }, other, inputProps)); } var rootProps = {}; if (children) { rootProps = other; } return _react2.default.createElement( 'div', (0, _extends3.default)({}, rootProps, { className: className, style: prepareStyles((0, _simpleAssign2.default)(styles.root, style)) }), floatingLabelTextElement, hintText ? _react2.default.createElement(_TextFieldHint2.default, { muiTheme: this.context.muiTheme, show: !(this.state.hasValue || floatingLabelText && !this.state.isFocused) || !this.state.hasValue && floatingLabelText && floatingLabelFixed && !this.state.isFocused, style: hintStyle, text: hintText }) : null, inputElement, underlineShow ? _react2.default.createElement(_TextFieldUnderline2.default, { disabled: disabled, disabledStyle: underlineDisabledStyle, error: !!this.state.errorText, errorStyle: errorStyle, focus: this.state.isFocused, focusStyle: underlineFocusStyle, muiTheme: this.context.muiTheme, style: underlineStyle }) : null, errorTextElement ); } }]); return TextField; }(_react.Component); TextField.defaultProps = { disabled: false, floatingLabelFixed: false, multiLine: false, fullWidth: false, type: 'text', underlineShow: true, rows: 1 }; TextField.contextTypes = { muiTheme: _propTypes2.default.object.isRequired }; TextField.propTypes = process.env.NODE_ENV !== "production" ? { children: _propTypes2.default.node, /** * The css class name of the root element. */ className: _propTypes2.default.string, /** * The text string to use for the default value. */ defaultValue: _propTypes2.default.any, /** * Disables the text field if set to true. */ disabled: _propTypes2.default.bool, /** * The style object to use to override error styles. */ errorStyle: _propTypes2.default.object, /** * The error content to display. */ errorText: _propTypes2.default.node, /** * If true, the floating label will float even when there is no value. */ floatingLabelFixed: _propTypes2.default.bool, /** * The style object to use to override floating label styles when focused. */ floatingLabelFocusStyle: _propTypes2.default.object, /** * The style object to use to override floating label styles when shrunk. */ floatingLabelShrinkStyle: _propTypes2.default.object, /** * The style object to use to override floating label styles. */ floatingLabelStyle: _propTypes2.default.object, /** * The content to use for the floating label element. */ floatingLabelText: _propTypes2.default.node, /** * If true, the field receives the property width 100%. */ fullWidth: _propTypes2.default.bool, /** * Override the inline-styles of the TextField's hint text element. */ hintStyle: _propTypes2.default.object, /** * The hint content to display. */ hintText: _propTypes2.default.node, /** * The id prop for the text field. */ id: _propTypes2.default.string, /** * Override the inline-styles of the TextField's input element. * When multiLine is false: define the style of the input element. * When multiLine is true: define the style of the container of the textarea. */ inputStyle: _propTypes2.default.object, /** * If true, a textarea element will be rendered. * The textarea also grows and shrinks according to the number of lines. */ multiLine: _propTypes2.default.bool, /** * Name applied to the input. */ name: _propTypes2.default.string, /** @ignore */ onBlur: _propTypes2.default.func, /** * Callback function that is fired when the textfield's value changes. * * @param {object} event Change event targeting the text field. * @param {string} newValue The new value of the text field. */ onChange: _propTypes2.default.func, /** @ignore */ onFocus: _propTypes2.default.func, /** * Number of rows to display when multiLine option is set to true. */ rows: _propTypes2.default.number, /** * Maximum number of rows to display when * multiLine option is set to true. */ rowsMax: _propTypes2.default.number, /** * Override the inline-styles of the root element. */ style: _propTypes2.default.object, /** * Override the inline-styles of the TextField's textarea element. * The TextField use either a textarea or an input, * this property has effects only when multiLine is true. */ textareaStyle: _propTypes2.default.object, /** * Specifies the type of input to display * such as "password" or "text". */ type: _propTypes2.default.string, /** * Override the inline-styles of the * TextField's underline element when disabled. */ underlineDisabledStyle: _propTypes2.default.object, /** * Override the inline-styles of the TextField's * underline element when focussed. */ underlineFocusStyle: _propTypes2.default.object, /** * If true, shows the underline for the text field. */ underlineShow: _propTypes2.default.bool, /** * Override the inline-styles of the TextField's underline element. */ underlineStyle: _propTypes2.default.object, /** * The value of the text field. */ value: _propTypes2.default.any } : {}; exports.default = TextField;