UNPKG

material-ui-chip-input

Version:
546 lines (475 loc) 21.5 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 _react = require('react'); var _react2 = _interopRequireDefault(_react); var _TextFieldUnderline = require('material-ui/TextField/TextFieldUnderline'); var _TextFieldUnderline2 = _interopRequireDefault(_TextFieldUnderline); var _TextFieldHint = require('material-ui/TextField/TextFieldHint'); var _TextFieldHint2 = _interopRequireDefault(_TextFieldHint); var _TextFieldLabel = require('material-ui/TextField/TextFieldLabel'); var _TextFieldLabel2 = _interopRequireDefault(_TextFieldLabel); var _AutoComplete = require('material-ui/AutoComplete/AutoComplete'); var _AutoComplete2 = _interopRequireDefault(_AutoComplete); var _transitions = require('material-ui/styles/transitions'); var _transitions2 = _interopRequireDefault(_transitions); var _Chip = require('material-ui/Chip'); var _Chip2 = _interopRequireDefault(_Chip); var _colors = require('material-ui/styles/colors'); var _colorManipulator = require('material-ui/utils/colorManipulator'); 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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 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; } /** * Notice: Some code was adapted from Material-UI's text field. * Copyright (c) 2014 Call-Em-All (https://github.com/callemall/material-ui) */ 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, display: 'inline-block', position: 'relative', backgroundColor: backgroundColor, fontFamily: baseTheme.fontFamily, transition: _transitions2.default.easeOut('200ms', 'height'), cursor: 'text' }, input: { padding: 0, marginTop: 0, marginBottom: 24, lineHeight: '32px', height: 32, position: 'relative', display: 'inline-block', border: 'none', outline: 'none', backgroundColor: 'rgba(0,0,0,0)', color: props.disabled ? disabledTextColor : textColor, cursor: props.disabled ? 'not-allowed' : 'initial', font: 'inherit', appearance: 'textfield', // Improve type search style. WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated style). float: 'left' }, floatingLabel: { color: hintColor, pointerEvents: 'none', top: 28 }, floatingLabelFocusStyle: { transform: 'scale(0.75) translate(0, -36px)' } }; var hasValue = (props.value || state.chips).length > 0 || state.inputValue.length > 0; if (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 (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; }; var defaultChipRenderer = function defaultChipRenderer(_ref, key) { var value = _ref.value; var isFocused = _ref.isFocused; var isDisabled = _ref.isDisabled; var handleClick = _ref.handleClick; var handleRequestDelete = _ref.handleRequestDelete; return _react2.default.createElement( _Chip2.default, { key: key, style: { margin: '8px 8px 0 0', float: 'left', pointerEvents: isDisabled ? 'none' : undefined }, backgroundColor: isFocused ? _colors.blue300 : null, onTouchTap: handleClick, onRequestDelete: handleRequestDelete }, value ); }; var ChipInput = function (_React$Component) { _inherits(ChipInput, _React$Component); function ChipInput(props) { _classCallCheck(this, ChipInput); var _this = _possibleConstructorReturn(this, (ChipInput.__proto__ || Object.getPrototypeOf(ChipInput)).call(this, props)); _this.state = { isFocused: false, errorText: undefined, isClean: true, chips: [], focusedChip: null, inputValue: '' }; _this.handleInputBlur = function (event) { if (!_this.autoComplete.refs.menu) { _this.setState({ isFocused: false, inputValue: '' }); if (_this.props.onBlur) _this.props.onBlur(event); } }; _this.handleInputFocus = function (event) { if (_this.props.disabled) { return; } _this.setState({ isFocused: true }); if (_this.props.onFocus) { _this.props.onFocus(event); } }; _this.handleKeyDown = function (event) { if (event.keyCode === 13) { // enter _this.handleAddChip(event.target.value); } else if (event.keyCode === 8 || event.keyCode === 46) { if (event.target.value === '') { var chips = _this.props.value || _this.state.chips; if (_this.state.focusedChip == null && event.keyCode === 8) { _this.setState({ focusedChip: chips[chips.length - 1] }); } else if (_this.state.focusedChip) { var index = chips.indexOf(_this.state.focusedChip); _this.handleDeleteChip(_this.state.focusedChip); if (event.keyCode === 8 && index > 0) { _this.setState({ focusedChip: chips[index - 1] }); } else if (event.keyCode === 46 && index < chips.length - 1) { _this.setState({ focusedChip: chips[index + 1] }); } } } } else if (event.keyCode === 37) { var _chips = _this.props.value || _this.state.chips; var _index = _chips.indexOf(_this.state.focusedChip); if (_index > 0) { _this.setState({ focusedChip: _chips[_index - 1] }); } } else if (event.keyCode === 39) { var _chips2 = _this.props.value || _this.state.chips; var _index2 = _chips2.indexOf(_this.state.focusedChip); if (_index2 >= 0 && _index2 < _chips2.length - 1) { _this.setState({ focusedChip: _chips2[_index2 + 1] }); } else { _this.setState({ focusedChip: null }); } } else { _this.setState({ focusedChip: null }); } }; if (props.defaultValue) { _this.state.chips = props.defaultValue; } return _this; } _createClass(ChipInput, [{ key: 'componentWillMount', value: function componentWillMount() { var _props = this.props; var name = _props.name; var hintText = _props.hintText; var floatingLabelText = _props.floatingLabelText; var uniqueId = name + '-' + hintText + '-' + floatingLabelText + '-' + Math.floor(Math.random() * 0xFFFF); this.uniqueId = uniqueId.replace(/[^A-Za-z0-9-]/gi, ''); } }, { key: 'componentDidMount', value: function componentDidMount() { var _this2 = this; var handleKeyDown = this.autoComplete.handleKeyDown; this.autoComplete.handleKeyDown = function (event) { if (event.keyCode === 13) { _this2.handleAddChip(event.target.value); _this2.autoComplete.setState({ searchText: '' }); _this2.autoComplete.forceUpdate(); } else { handleKeyDown(event); } }; this.autoComplete.handleItemTouchTap = function (event, child) { var dataSource = _this2.autoComplete.props.dataSource; var index = parseInt(child.key, 10); var chosenRequest = dataSource[index]; var searchText = _this2.autoComplete.chosenRequestText(chosenRequest); _this2.autoComplete.setState({ searchText: '' }); _this2.autoComplete.forceUpdate(); _this2.autoComplete.close(); setTimeout(function () { return _this2.focus(); }, 1); }; } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.disabled) { this.setState({ focusedChip: null }); } } }, { key: 'blur', value: function blur() { if (this.input) this.getInputNode().blur(); } }, { key: 'focus', value: function focus() { if (this.autoComplete) this.getInputNode().focus(); if (this.state.focusedChip) { this.setState({ focusedChip: null }); } } }, { 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.autoComplete.refs.searchTextField.getInputNode(); } }, { key: 'handleAddChip', value: function handleAddChip(chip) { var chips = this.props.value || this.state.chips; if (chip.trim().length > 0 && chips.indexOf(chip) === -1) { if (this.props.value) { if (this.props.onRequestAdd) { this.props.onRequestAdd(chip); } } else { this.setState({ chips: [].concat(_toConsumableArray(this.state.chips), [chip]) }); if (this.props.onChange) { this.props.onChange([].concat(_toConsumableArray(this.state.chips), [chip])); } } } } }, { key: 'handleDeleteChip', value: function handleDeleteChip(chip) { if (this.props.value) { if (this.props.onRequestDelete) { this.props.onRequestDelete(chip); } } else { var chips = this.state.chips.filter(function (c) { return c !== chip; }); if (chips.length !== this.state.chips.length) { this.setState({ chips: chips, focusedChip: this.state.focusedChip === chip ? null : this.state.focusedChip }); if (this.props.onChange) { this.props.onChange(chips); } } } } }, { key: 'render', value: function render() { var _this3 = this; var _props2 = this.props; var children = _props2.children; var className = _props2.className; var disabled = _props2.disabled; var errorStyle = _props2.errorStyle; var errorText = _props2.errorText; var fullWidth = _props2.fullWidth; var hintText = _props2.hintText; var hintStyle = _props2.hintStyle; var inputStyle = _props2.inputStyle; var onBlur = _props2.onBlur; var onChange = _props2.onChange; var onFocus = _props2.onFocus; var style = _props2.style; var underlineDisabledStyle = _props2.underlineDisabledStyle; var underlineFocusStyle = _props2.underlineFocusStyle; var underlineShow = _props2.underlineShow; var underlineStyle = _props2.underlineStyle; var _props2$defaultValue = _props2.defaultValue; var defaultValue = _props2$defaultValue === undefined ? [] : _props2$defaultValue; var filter = _props2.filter; var value = _props2.value; var dataSource = _props2.dataSource; var floatingLabelFixed = _props2.floatingLabelFixed; var floatingLabelFocusStyle = _props2.floatingLabelFocusStyle; var floatingLabelStyle = _props2.floatingLabelStyle; var floatingLabelText = _props2.floatingLabelText; var onRequestAdd = _props2.onRequestAdd; var onRequestDelete = _props2.onRequestDelete; var _props2$chipRenderer = _props2.chipRenderer; var chipRenderer = _props2$chipRenderer === undefined ? defaultChipRenderer : _props2$chipRenderer; var other = _objectWithoutProperties(_props2, ['children', 'className', 'disabled', 'errorStyle', 'errorText', 'fullWidth', 'hintText', 'hintStyle', 'inputStyle', 'onBlur', 'onChange', 'onFocus', 'style', 'underlineDisabledStyle', 'underlineFocusStyle', 'underlineShow', 'underlineStyle', 'defaultValue', 'filter', 'value', 'dataSource', 'floatingLabelFixed', 'floatingLabelFocusStyle', 'floatingLabelStyle', 'floatingLabelText', 'onRequestAdd', 'onRequestDelete', 'chipRenderer']); var prepareStyles = this.context.muiTheme.prepareStyles; var styles = getStyles(this.props, this.context, this.state); var inputId = this.uniqueId; var inputProps = { id: inputId, ref: function ref(elem) { return _this3.input = elem; }, disabled: this.props.disabled, onBlur: this.handleInputBlur, onFocus: this.handleInputFocus, onKeyDown: this.handleKeyDown }; var inputStyleMerged = Object.assign(styles.input, inputStyle); var hasInput = (this.props.value || this.state.chips).length > 0 || this.state.inputValue.length > 0; var showHintText = hintText && !hasInput; var shrinkFloatingLabel = floatingLabelText && (hasInput || this.state.isFocused); var floatingLabelTextElement = floatingLabelText && _react2.default.createElement( _TextFieldLabel2.default, { muiTheme: this.context.muiTheme, style: Object.assign(styles.floatingLabel, this.props.floatingLabelStyle), shrinkStyle: Object.assign(styles.floatingLabelFocusStyle, this.props.floatingLabelFocusStyle), htmlFor: inputId, shrink: shrinkFloatingLabel, disabled: disabled }, floatingLabelText ); var overrideRootStyles = {}; if (floatingLabelText) { overrideRootStyles.marginTop = 14; } if (fullWidth) { overrideRootStyles.width = '100%'; } if (disabled) { overrideRootStyles.cursor = 'not-allowed'; } var chips = this.props.value || this.state.chips; var autoCompleteData = (dataSource || []).filter(function (value) { return chips.indexOf(value) < 0; }); var actualFilter = other.openOnFocus ? function (search, key) { return search === '' || filter(search, key); } : filter; return _react2.default.createElement( 'div', { style: prepareStyles(Object.assign(styles.root, style, overrideRootStyles)), onTouchTap: function onTouchTap() { return _this3.focus(); } }, _react2.default.createElement( 'div', null, floatingLabelTextElement, _react2.default.createElement( 'div', { style: { marginTop: floatingLabelText ? 12 : 0 } }, chips.map(function (tag, i) { return chipRenderer({ value: tag, isDisabled: disabled, isFocused: _this3.state.focusedChip === tag, handleClick: function handleClick() { return _this3.setState({ focusedChip: tag }); }, handleRequestDelete: function handleRequestDelete() { return _this3.handleDeleteChip(tag); } }, i); }) ) ), hintText ? _react2.default.createElement(_TextFieldHint2.default, { muiTheme: this.context.muiTheme, show: showHintText && !(floatingLabelText && !this.state.isFocused), style: Object.assign({ bottom: 20, pointerEvents: 'none' }, hintStyle), text: hintText }) : null, _react2.default.createElement(_AutoComplete2.default, _extends({}, other, inputProps, { filter: actualFilter, style: inputStyleMerged, dataSource: autoCompleteData, menuProps: { onChange: function onChange(event, input) { return _this3.handleAddChip(input); } }, searchText: this.state.inputValue, underlineShow: false, onKeyUp: function onKeyUp(event) { return _this3.setState({ inputValue: event.target.value }); }, ref: function ref(_ref2) { return _this3.autoComplete = _ref2; } })), _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 }) ); } }]); return ChipInput; }(_react2.default.Component); ChipInput.contextTypes = { muiTheme: _react2.default.PropTypes.object.isRequired }; ChipInput.propTypes = { style: _react.PropTypes.object, floatingLabelText: _react.PropTypes.node, hintText: _react.PropTypes.node, disabled: _react.PropTypes.bool, defaultValue: _react.PropTypes.arrayOf(_react.PropTypes.string), onChange: _react.PropTypes.func, value: _react.PropTypes.arrayOf(_react.PropTypes.string), onRequestAdd: _react.PropTypes.func, onRequestDelete: _react.PropTypes.func, dataSource: _react.PropTypes.arrayOf(_react.PropTypes.string), onUpdateInput: _react.PropTypes.func, openOnFocus: _react.PropTypes.bool, chipRenderer: _react.PropTypes.func }; ChipInput.defaultProps = { filter: _AutoComplete2.default.caseInsensitiveFilter }; exports.default = ChipInput;