UNPKG

d2-ui

Version:
563 lines (490 loc) 20 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); 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 _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _simpleAssign = require('simple-assign'); var _simpleAssign2 = _interopRequireDefault(_simpleAssign); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); var _keycode = require('keycode'); var _keycode2 = _interopRequireDefault(_keycode); var _shallowEqual = require('recompose/shallowEqual'); var _shallowEqual2 = _interopRequireDefault(_shallowEqual); var _colorManipulator = require('../utils/colorManipulator'); var _transitions = require('../styles/transitions'); var _transitions2 = _interopRequireDefault(_transitions); var _deprecatedPropType = require('../utils/deprecatedPropType'); var _deprecatedPropType2 = _interopRequireDefault(_deprecatedPropType); 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 }; } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var getStyles = function getStyles(props, context, state) { var _context$muiTheme = context.muiTheme; var baseTheme = _context$muiTheme.baseTheme; var _context$muiTheme$tex = _context$muiTheme.textField; var floatingLabelColor = _context$muiTheme$tex.floatingLabelColor; var focusColor = _context$muiTheme$tex.focusColor; var textColor = _context$muiTheme$tex.textColor; var disabledTextColor = _context$muiTheme$tex.disabledTextColor; var backgroundColor = _context$muiTheme$tex.backgroundColor; var hintColor = _context$muiTheme$tex.hintColor; var 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') }, error: { position: 'relative', bottom: 2, fontSize: 12, lineHeight: '12px', color: errorColor, transition: _transitions2.default.easeOut() }, floatingLabel: { color: hintColor }, input: { WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated) padding: 0, position: 'relative', width: '100%', height: '100%', border: 'none', outline: 'none', backgroundColor: 'rgba(0,0,0,0)', color: props.disabled ? disabledTextColor : textColor, font: 'inherit' }, textarea: {} }; (0, _simpleAssign2.default)(styles.error, props.errorStyle); (0, _simpleAssign2.default)(styles.textarea, styles.input, { marginTop: props.floatingLabelText ? 36 : 12, marginBottom: props.floatingLabelText ? -36 : -12, boxSizing: 'border-box', font: 'inherit' }); if (state.hasValue) { styles.floatingLabel.color = (0, _colorManipulator.fade)(props.disabled ? disabledTextColor : floatingLabelColor, 0.5); } 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 Boolean(value || value === 0); } var TextField = function (_Component) { _inherits(TextField, _Component); function TextField() { var _Object$getPrototypeO; var _temp, _this, _ret; _classCallCheck(this, TextField); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(TextField)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = { isFocused: false, errorText: undefined, hasValue: false, isClean: true }, _this.handleInputBlur = function (event) { _this.setState({ isFocused: false }); if (_this.props.onBlur) _this.props.onBlur(event); }, _this.handleInputChange = function (event) { _this.setState({ hasValue: isValid(event.target.value), isClean: false }); 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.handleInputKeyDown = function (event) { if ((0, _keycode2.default)(event) === 'enter' && _this.props.onEnterKeyDown) _this.props.onEnterKeyDown(event); if (_this.props.onKeyDown) _this.props.onKeyDown(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), _possibleConstructorReturn(_this, _ret); } _createClass(TextField, [{ key: 'componentWillMount', value: function componentWillMount() { var _props = this.props; var children = _props.children; var name = _props.name; var hintText = _props.hintText; var floatingLabelText = _props.floatingLabelText; var 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, '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.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.state.isClean && isValid(nextProps.defaultValue); if (hasValue !== this.state.hasValue) { 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; var className = _props2.className; var disabled = _props2.disabled; var errorStyle = _props2.errorStyle; var errorText = _props2.errorText; var // eslint-disable-line no-unused-vars floatingLabelFixed = _props2.floatingLabelFixed; var floatingLabelText = _props2.floatingLabelText; var fullWidth = _props2.fullWidth; var // eslint-disable-line no-unused-vars hintText = _props2.hintText; var hintStyle = _props2.hintStyle; var id = _props2.id; var inputStyle = _props2.inputStyle; var multiLine = _props2.multiLine; var onBlur = _props2.onBlur; var // eslint-disable-line no-unused-vars onChange = _props2.onChange; var // eslint-disable-line no-unused-vars onFocus = _props2.onFocus; var // eslint-disable-line no-unused-vars style = _props2.style; var type = _props2.type; var underlineDisabledStyle = _props2.underlineDisabledStyle; var underlineFocusStyle = _props2.underlineFocusStyle; var underlineShow = _props2.underlineShow; var underlineStyle = _props2.underlineStyle; var rows = _props2.rows; var rowsMax = _props2.rowsMax; var textareaStyle = _props2.textareaStyle; var other = _objectWithoutProperties(_props2, ['className', 'disabled', 'errorStyle', 'errorText', 'floatingLabelFixed', '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(styles.error) }, this.state.errorText ); var floatingLabelTextElement = floatingLabelText && _react2.default.createElement( _TextFieldLabel2.default, { muiTheme: this.context.muiTheme, style: (0, _simpleAssign2.default)(styles.floatingLabel, this.props.floatingLabelStyle), shrinkStyle: this.props.floatingLabelFocusStyle, 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, onKeyDown: this.handleInputKeyDown }; var inputStyleMerged = (0, _simpleAssign2.default)(styles.input, inputStyle); var inputElement = void 0; if (this.props.children) { inputElement = _react2.default.cloneElement(this.props.children, _extends({}, inputProps, this.props.children.props, { style: (0, _simpleAssign2.default)(inputStyleMerged, this.props.children.props.style) })); } else { inputElement = multiLine ? _react2.default.createElement(_EnhancedTextarea2.default, _extends({}, other, inputProps, { style: inputStyleMerged, rows: rows, rowsMax: rowsMax, onHeightChange: this.handleHeightChange, textareaStyle: (0, _simpleAssign2.default)(styles.textarea, textareaStyle) })) : _react2.default.createElement('input', _extends({}, other, inputProps, { style: prepareStyles(inputStyleMerged), type: type })); } return _react2.default.createElement( 'div', { 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.propTypes = { children: _react.PropTypes.node, /** * The css class name of the root element. */ className: _react.PropTypes.string, /** * The text string to use for the default value. */ defaultValue: _react.PropTypes.any, /** * Disables the text field if set to true. */ disabled: _react.PropTypes.bool, /** * The style object to use to override error styles. */ errorStyle: _react.PropTypes.object, /** * The error content to display. */ errorText: _react.PropTypes.node, /** * If true, the floating label will float even when there is no value. */ floatingLabelFixed: _react.PropTypes.bool, /** * The style object to use to override floating label styles when focused. */ floatingLabelFocusStyle: _react.PropTypes.object, /** * The style object to use to override floating label styles. */ floatingLabelStyle: _react.PropTypes.object, /** * The content to use for the floating label element. */ floatingLabelText: _react.PropTypes.node, /** * If true, the field receives the property width 100%. */ fullWidth: _react.PropTypes.bool, /** * Override the inline-styles of the TextField's hint text element. */ hintStyle: _react.PropTypes.object, /** * The hint content to display. */ hintText: _react.PropTypes.node, /** * The id prop for the text field. */ id: _react.PropTypes.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: _react.PropTypes.object, /** * If true, a textarea element will be rendered. * The textarea also grows and shrinks according to the number of lines. */ multiLine: _react.PropTypes.bool, /** * Name applied to the input. */ name: _react.PropTypes.string, /** * Callback function that is fired when the textfield loses focus. */ onBlur: _react.PropTypes.func, /** * Callback function that is fired when the textfield's value changes. */ onChange: _react.PropTypes.func, /** * The function to call when the user presses the Enter key. */ onEnterKeyDown: (0, _deprecatedPropType2.default)(_react.PropTypes.func, 'Use onKeyDown and check for keycode instead.'), /** * Callback function that is fired when the textfield gains focus. */ onFocus: _react.PropTypes.func, /** * Callback function fired when key is pressed down. */ onKeyDown: _react.PropTypes.func, /** * Number of rows to display when multiLine option is set to true. */ rows: _react.PropTypes.number, /** * Maximum number of rows to display when * multiLine option is set to true. */ rowsMax: _react.PropTypes.number, /** * Override the inline-styles of the root element. */ style: _react.PropTypes.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: _react.PropTypes.object, /** * Specifies the type of input to display * such as "password" or "text". */ type: _react.PropTypes.string, /** * Override the inline-styles of the * TextField's underline element when disabled. */ underlineDisabledStyle: _react.PropTypes.object, /** * Override the inline-styles of the TextField's * underline element when focussed. */ underlineFocusStyle: _react.PropTypes.object, /** * If true, shows the underline for the text field. */ underlineShow: _react.PropTypes.bool, /** * Override the inline-styles of the TextField's underline element. */ underlineStyle: _react.PropTypes.object, /** * The value of the text field. */ value: _react.PropTypes.any }; TextField.defaultProps = { disabled: false, floatingLabelFixed: false, multiLine: false, fullWidth: false, type: 'text', underlineShow: true, rows: 1 }; TextField.contextTypes = { muiTheme: _react.PropTypes.object.isRequired }; exports.default = TextField;