function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _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; }; return _extends.apply(this, arguments); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } import classnames from 'classnames'; import classes from 'component-classes'; import Animate from 'rc-animate'; import { Item as MenuItem, ItemGroup as MenuItemGroup } from 'rc-menu'; import childrenToArray from "rc-util/es/Children/toArray"; import KeyCode from "rc-util/es/KeyCode"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { polyfill } from 'react-lifecycles-compat'; import warning from 'warning'; import Option from './Option'; // Where el is the DOM element you'd like to test for visibility function isHidden(node) { return !node || node.offsetParent === null; } import SelectPropTypes from './PropTypes'; import SelectTrigger from './SelectTrigger'; import { defaultFilterFn, findFirstMenuItem, findIndexInValueBySingleValue, generateUUID, getLabelFromPropsValue, getMapKey, getPropValue, getValuePropValue, includesSeparators, isCombobox, isMultipleOrTags, isMultipleOrTagsOrCombobox, isSingleMode, preventDefaultEvent, saveRef, splitBySeparators, toArray, toTitle, UNSELECTABLE_ATTRIBUTE, UNSELECTABLE_STYLE, validateOptionValue } from './util'; var SELECT_EMPTY_VALUE_KEY = 'RC_SELECT_EMPTY_VALUE_KEY'; var noop = function noop() { return null; }; function chaining() { for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { fns[_key] = arguments[_key]; } return function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } // tslint:disable-next-line:prefer-for-of for (var i = 0; i < fns.length; i++) { if (fns[i] && typeof fns[i] === 'function') { fns[i].apply(chaining, args); } } }; } var Select = /*#__PURE__*/ function (_React$Component) { _inherits(Select, _React$Component); function Select(props) { var _this; _classCallCheck(this, Select); _this = _possibleConstructorReturn(this, _getPrototypeOf(Select).call(this, props)); _this.inputRef = null; _this.inputMirrorRef = null; _this.topCtrlRef = null; _this.selectTriggerRef = null; _this.rootRef = null; _this.selectionRef = null; _this.dropdownContainer = null; _this.blurTimer = null; _this.focusTimer = null; _this.comboboxTimer = null; // tslint:disable-next-line:variable-name _this._focused = false; // tslint:disable-next-line:variable-name _this._mouseDown = false; // tslint:disable-next-line:variable-name _this._options = []; // tslint:disable-next-line:variable-name _this._empty = false; _this.onInputChange = function (event) { var tokenSeparators = _this.props.tokenSeparators; var val = event.target.value; if (isMultipleOrTags(_this.props) && tokenSeparators.length && includesSeparators(val, tokenSeparators)) { var nextValue = _this.getValueByInput(val); if (nextValue !== undefined) { _this.fireChange(nextValue); } _this.setOpenState(false, { needFocus: true }); _this.setInputValue('', false); return; } _this.setInputValue(val); _this.setState({ open: true }); if (isCombobox(_this.props)) { _this.fireChange([val]); } }; _this.onDropdownVisibleChange = function (open) { if (open && !_this._focused) { _this.clearBlurTime(); _this.timeoutFocus(); _this._focused = true; _this.updateFocusClassName(); } _this.setOpenState(open); }; // combobox ignore _this.onKeyDown = function (event) { var open = _this.state.open; var disabled = _this.props.disabled; if (disabled) { return; } var keyCode = event.keyCode; if (open && !_this.getInputDOMNode()) { _this.onInputKeyDown(event); } else if (keyCode === KeyCode.ENTER || keyCode === KeyCode.DOWN) { if (!open) { _this.setOpenState(true); } event.preventDefault(); } else if (keyCode === KeyCode.SPACE) { // Not block space if popup is shown if (!open) { _this.setOpenState(true); event.preventDefault(); } } }; _this.onInputKeyDown = function (event) { var _this$props = _this.props, disabled = _this$props.disabled, combobox = _this$props.combobox, defaultActiveFirstOption = _this$props.defaultActiveFirstOption; if (disabled) { return; } var state = _this.state; var isRealOpen = _this.getRealOpenState(state); // magic code var keyCode = event.keyCode; if (isMultipleOrTags(_this.props) && !event.target.value && keyCode === KeyCode.BACKSPACE) { event.preventDefault(); var value = state.value; if (value.length) { _this.removeSelected(value[value.length - 1]); } return; } if (keyCode === KeyCode.DOWN) { if (!state.open) { _this.openIfHasChildren(); event.preventDefault(); event.stopPropagation(); return; } } else if (keyCode === KeyCode.ENTER && state.open) { // Aviod trigger form submit when select item // https://github.com/ant-design/ant-design/issues/10861 // https://github.com/ant-design/ant-design/issues/14544 if (isRealOpen || !combobox) { event.preventDefault(); } // Hard close popup to avoid lock of non option in combobox mode if (isRealOpen && combobox && defaultActiveFirstOption === false) { _this.comboboxTimer = setTimeout(function () { _this.setOpenState(false); }); } } else if (keyCode === KeyCode.ESC) { if (state.open) { _this.setOpenState(false); event.preventDefault(); event.stopPropagation(); } return; } if (isRealOpen && _this.selectTriggerRef) { var menu = _this.selectTriggerRef.getInnerMenu(); if (menu && menu.onKeyDown(event, _this.handleBackfill)) { event.preventDefault(); event.stopPropagation(); } } }; _this.onMenuSelect = function (_ref) { var item = _ref.item; if (!item) { return; } var value = _this.state.value; var props = _this.props; var selectedValue = getValuePropValue(item); var lastValue = value[value.length - 1]; var skipTrigger = false; if (isMultipleOrTags(props)) { if (findIndexInValueBySingleValue(value, selectedValue) !== -1) { skipTrigger = true; } else { value = value.concat([selectedValue]); } } else { if (!isCombobox(props) && lastValue !== undefined && lastValue === selectedValue && selectedValue !== _this.state.backfillValue) { _this.setOpenState(false, { needFocus: true, fireSearch: false }); skipTrigger = true; } else { value = [selectedValue]; _this.setOpenState(false, { needFocus: true, fireSearch: false }); } } if (!skipTrigger) { _this.fireChange(value); } _this.fireSelect(selectedValue); if (!skipTrigger) { var inputValue = isCombobox(props) ? getPropValue(item, props.optionLabelProp) : ''; if (props.autoClearSearchValue) { _this.setInputValue(inputValue, false); } } }; _this.onMenuDeselect = function (_ref2) { var item = _ref2.item, domEvent = _ref2.domEvent; if (domEvent.type === 'keydown' && domEvent.keyCode === KeyCode.ENTER) { var menuItemDomNode = ReactDOM.findDOMNode(item); // https://github.com/ant-design/ant-design/issues/20465#issuecomment-569033796 if (!isHidden(menuItemDomNode)) { _this.removeSelected(getValuePropValue(item)); } return; } if (domEvent.type === 'click') { _this.removeSelected(getValuePropValue(item)); } var props = _this.props; if (props.autoClearSearchValue) { _this.setInputValue(''); } }; _this.onArrowClick = function (e) { e.stopPropagation(); e.preventDefault(); if (!_this.props.disabled) { _this.setOpenState(!_this.state.open, { needFocus: !_this.state.open }); } }; _this.onPlaceholderClick = function () { if (_this.getInputDOMNode && _this.getInputDOMNode()) { _this.getInputDOMNode().focus(); } }; _this.onOuterFocus = function (e) { if (_this.props.disabled) { e.preventDefault(); return; } _this.clearBlurTime(); // In IE11, onOuterFocus will be trigger twice when focus input // First one: e.target is div // Second one: e.target is input // other browser only trigger second one // https://github.com/ant-design/ant-design/issues/15942 // Here we ignore the first one when e.target is div var inputNode = _this.getInputDOMNode(); if (inputNode && e.target === _this.rootRef) { return; } if (!isMultipleOrTagsOrCombobox(_this.props) && e.target === inputNode) { return; } if (_this._focused) { return; } _this._focused = true; _this.updateFocusClassName(); // only effect multiple or tag mode if (!isMultipleOrTags(_this.props) || !_this._mouseDown) { _this.timeoutFocus(); } }; _this.onPopupFocus = function () { // fix ie scrollbar, focus element again _this.maybeFocus(true, true); }; _this.onOuterBlur = function (e) { if (_this.props.disabled) { e.preventDefault(); return; } _this.blurTimer = window.setTimeout(function () { _this._focused = false; _this.updateFocusClassName(); var props = _this.props; var value = _this.state.value; var inputValue = _this.state.inputValue; if (isSingleMode(props) && props.showSearch && inputValue && props.defaultActiveFirstOption) { var options = _this._options || []; if (options.length) { var firstOption = findFirstMenuItem(options); if (firstOption) { value = [getValuePropValue(firstOption)]; _this.fireChange(value); } } } else if (isMultipleOrTags(props) && inputValue) { if (_this._mouseDown) { // need update dropmenu when not blur _this.setInputValue(''); } else { // why not use setState? // https://github.com/ant-design/ant-design/issues/14262 _this.state.inputValue = ''; if (_this.getInputDOMNode && _this.getInputDOMNode()) { _this.getInputDOMNode().value = ''; } } var tmpValue = _this.getValueByInput(inputValue); if (tmpValue !== undefined) { value = tmpValue; _this.fireChange(value); } } // if click the rest space of Select in multiple mode if (isMultipleOrTags(props) && _this._mouseDown) { _this.maybeFocus(true, true); _this._mouseDown = false; return; } _this.setOpenState(false); if (props.onBlur) { props.onBlur(_this.getVLForOnChange(value)); } }, 10); }; _this.onClearSelection = function (event) { var props = _this.props; var state = _this.state; if (props.disabled) { return; } var inputValue = state.inputValue; var value = state.value; event.stopPropagation(); if (inputValue || value.length) { if (value.length) { _this.fireChange([]); } _this.setOpenState(false, { needFocus: true }); if (inputValue) { _this.setInputValue(''); } } }; _this.onChoiceAnimationLeave = function () { _this.forcePopupAlign(); }; _this.getOptionInfoBySingleValue = function (value, optionsInfo) { var info; optionsInfo = optionsInfo || _this.state.optionsInfo; if (optionsInfo[getMapKey(value)]) { info = optionsInfo[getMapKey(value)]; } if (info) { return info; } var defaultLabel = value; if (_this.props.labelInValue) { var valueLabel = getLabelFromPropsValue(_this.props.value, value); var defaultValueLabel = getLabelFromPropsValue(_this.props.defaultValue, value); if (valueLabel !== undefined) { defaultLabel = valueLabel; } else if (defaultValueLabel !== undefined) { defaultLabel = defaultValueLabel; } } var defaultInfo = { option: React.createElement(Option, { value: value, key: value }, value), value: value, label: defaultLabel }; return defaultInfo; }; _this.getOptionBySingleValue = function (value) { var _this$getOptionInfoBy = _this.getOptionInfoBySingleValue(value), option = _this$getOptionInfoBy.option; return option; }; _this.getOptionsBySingleValue = function (values) { return values.map(function (value) { return _this.getOptionBySingleValue(value); }); }; _this.getValueByLabel = function (label) { if (label === undefined) { return null; } var value = null; Object.keys(_this.state.optionsInfo).forEach(function (key) { var info = _this.state.optionsInfo[key]; var disabled = info.disabled; if (disabled) { return; } var oldLable = toArray(info.label); if (oldLable && oldLable.join('') === label) { value = info.value; } }); return value; }; _this.getVLBySingleValue = function (value) { if (_this.props.labelInValue) { return { key: value, label: _this.getLabelBySingleValue(value) }; } return value; }; _this.getVLForOnChange = function (vlsS) { var vls = vlsS; if (vls !== undefined) { if (!_this.props.labelInValue) { vls = vls.map(function (v) { return v; }); } else { vls = vls.map(function (vl) { return { key: vl, label: _this.getLabelBySingleValue(vl) }; }); } return isMultipleOrTags(_this.props) ? vls : vls[0]; } return vls; }; _this.getLabelBySingleValue = function (value, optionsInfo) { var _this$getOptionInfoBy2 = _this.getOptionInfoBySingleValue(value, optionsInfo), label = _this$getOptionInfoBy2.label; return label; }; _this.getDropdownContainer = function () { if (!_this.dropdownContainer) { _this.dropdownContainer = document.createElement('div'); document.body.appendChild(_this.dropdownContainer); } return _this.dropdownContainer; }; _this.getPlaceholderElement = function () { var props = _this.props; var state = _this.state; var hidden = false; if (state.inputValue) { hidden = true; } var value = state.value; if (value.length) { hidden = true; } if (isCombobox(props) && value.length === 1 && state.value && !state.value[0]) { hidden = false; } var placeholder = props.placeholder; if (placeholder) { return React.createElement("div", _extends({ onMouseDown: preventDefaultEvent, style: _extends({ display: hidden ? 'none' : 'block' }, UNSELECTABLE_STYLE) }, UNSELECTABLE_ATTRIBUTE, { onClick: _this.onPlaceholderClick, className: "".concat(props.prefixCls, "-selection__placeholder") }), placeholder); } return null; }; _this.getInputElement = function () { var props = _this.props; var defaultInput = React.createElement("input", { id: props.id, autoComplete: "off" }); // tslint:disable-next-line:typedef-whitespace var inputElement = props.getInputElement ? props.getInputElement() : defaultInput; var inputCls = classnames(inputElement.props.className, _defineProperty({}, "".concat(props.prefixCls, "-search__field"), true)); // https://github.com/ant-design/ant-design/issues/4992#issuecomment-281542159 // Add space to the end of the inputValue as the width measurement tolerance return React.createElement("div", { className: "".concat(props.prefixCls, "-search__field__wrap") }, React.cloneElement(inputElement, { ref: _this.saveInputRef, onChange: _this.onInputChange, onKeyDown: chaining(_this.onInputKeyDown, inputElement.props.onKeyDown, _this.props.onInputKeyDown), value: _this.state.inputValue, disabled: props.disabled, className: inputCls }), React.createElement("span", { ref: _this.saveInputMirrorRef, className: "".concat(props.prefixCls, "-search__field__mirror") }, _this.state.inputValue, "\xA0")); }; _this.getInputDOMNode = function () { return _this.topCtrlRef ? _this.topCtrlRef.querySelector('input,textarea,div[contentEditable]') : _this.inputRef; }; _this.getInputMirrorDOMNode = function () { return _this.inputMirrorRef; }; _this.getPopupDOMNode = function () { if (_this.selectTriggerRef) { return _this.selectTriggerRef.getPopupDOMNode(); } }; _this.getPopupMenuComponent = function () { if (_this.selectTriggerRef) { return _this.selectTriggerRef.getInnerMenu(); } }; _this.setOpenState = function (open) { var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var needFocus = config.needFocus, fireSearch = config.fireSearch; var props = _this.props; var state = _this.state; if (state.open === open) { _this.maybeFocus(open, !!needFocus); return; } if (_this.props.onDropdownVisibleChange) { _this.props.onDropdownVisibleChange(open); } var nextState = { open: open, backfillValue: '' }; // clear search input value when open is false in singleMode. // https://github.com/ant-design/ant-design/issues/16572 if (!open && isSingleMode(props) && props.showSearch) { _this.setInputValue('', fireSearch); } if (!open) { _this.maybeFocus(open, !!needFocus); } _this.setState(_extends({ open: open }, nextState), function () { if (open) { _this.maybeFocus(open, !!needFocus); } }); }; _this.setInputValue = function (inputValue) { var fireSearch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var onSearch = _this.props.onSearch; if (inputValue !== _this.state.inputValue) { _this.setState(function (prevState) { // Additional check if `inputValue` changed in latest state. if (fireSearch && inputValue !== prevState.inputValue && onSearch) { onSearch(inputValue); } return { inputValue: inputValue }; }, _this.forcePopupAlign); } }; _this.getValueByInput = function (str) { var _this$props2 = _this.props, multiple = _this$props2.multiple, tokenSeparators = _this$props2.tokenSeparators; var nextValue = _this.state.value; var hasNewValue = false; splitBySeparators(str, tokenSeparators).forEach(function (label) { var selectedValue = [label]; if (multiple) { var value = _this.getValueByLabel(label); if (value && findIndexInValueBySingleValue(nextValue, value) === -1) { nextValue = nextValue.concat(value); hasNewValue = true; _this.fireSelect(value); } } else if (findIndexInValueBySingleValue(nextValue, label) === -1) { nextValue = nextValue.concat(selectedValue); hasNewValue = true; _this.fireSelect(label); } }); return hasNewValue ? nextValue : undefined; }; _this.getRealOpenState = function (state) { // tslint:disable-next-line:variable-name var _open = _this.props.open; if (typeof _open === 'boolean') { return _open; } var open = (state || _this.state).open; var options = _this._options || []; if (isMultipleOrTagsOrCombobox(_this.props) || !_this.props.showSearch) { if (open && !options.length) { open = false; } } return open; }; _this.markMouseDown = function () { _this._mouseDown = true; }; _this.markMouseLeave = function () { _this._mouseDown = false; }; _this.handleBackfill = function (item) { if (!_this.props.backfill || !(isSingleMode(_this.props) || isCombobox(_this.props))) { return; } var key = getValuePropValue(item); if (isCombobox(_this.props)) { _this.setInputValue(key, false); } _this.setState({ value: [key], backfillValue: key }); }; _this.filterOption = function (input, child) { var defaultFilter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultFilterFn; var value = _this.state.value; var lastValue = value[value.length - 1]; if (!input || lastValue && lastValue === _this.state.backfillValue) { return true; } var filterFn = _this.props.filterOption; if ('filterOption' in _this.props) { if (filterFn === true) { filterFn = defaultFilter.bind(_assertThisInitialized(_this)); } } else { filterFn = defaultFilter.bind(_assertThisInitialized(_this)); } if (!filterFn) { return true; } else if (typeof filterFn === 'function') { return filterFn.call(_assertThisInitialized(_this), input, child); } else if (child.props.disabled) { return false; } return true; }; _this.timeoutFocus = function () { var onFocus = _this.props.onFocus; if (_this.focusTimer) { _this.clearFocusTime(); } _this.focusTimer = window.setTimeout(function () { if (onFocus) { onFocus(); } }, 10); }; _this.clearFocusTime = function () { if (_this.focusTimer) { clearTimeout(_this.focusTimer); _this.focusTimer = null; } }; _this.clearBlurTime = function () { if (_this.blurTimer) { clearTimeout(_this.blurTimer); _this.blurTimer = null; } }; _this.clearComboboxTime = function () { if (_this.comboboxTimer) { clearTimeout(_this.comboboxTimer); _this.comboboxTimer = null; } }; _this.updateFocusClassName = function () { var rootRef = _this.rootRef; var props = _this.props; // avoid setState and its side effect if (_this._focused) { classes(rootRef).add("".concat(props.prefixCls, "-focused")); } else { classes(rootRef).remove("".concat(props.prefixCls, "-focused")); } }; _this.maybeFocus = function (open, needFocus) { if (needFocus || open) { var input = _this.getInputDOMNode(); var _document = document, activeElement = _document.activeElement; if (input && (open || isMultipleOrTagsOrCombobox(_this.props))) { if (activeElement !== input) { input.focus(); _this._focused = true; } } else if (activeElement !== _this.selectionRef && _this.selectionRef) { _this.selectionRef.focus(); _this._focused = true; } } }; _this.removeSelected = function (selectedKey, e) { var props = _this.props; if (props.disabled || _this.isChildDisabled(selectedKey)) { return; } // Do not trigger Trigger popup if (e && e.stopPropagation) { e.stopPropagation(); } var oldValue = _this.state.value; var value = oldValue.filter(function (singleValue) { return singleValue !== selectedKey; }); var canMultiple = isMultipleOrTags(props); if (canMultiple) { var event = selectedKey; if (props.labelInValue) { event = { key: selectedKey, label: _this.getLabelBySingleValue(selectedKey) }; } if (props.onDeselect) { props.onDeselect(event, _this.getOptionBySingleValue(selectedKey)); } } _this.fireChange(value); }; _this.openIfHasChildren = function () { var props = _this.props; if (React.Children.count(props.children) || isSingleMode(props)) { _this.setOpenState(true); } }; _this.fireSelect = function (value) { if (_this.props.onSelect) { _this.props.onSelect(_this.getVLBySingleValue(value), _this.getOptionBySingleValue(value)); } }; _this.fireChange = function (value) { var props = _this.props; if (!('value' in props)) { _this.setState({ value: value }, _this.forcePopupAlign); } var vls = _this.getVLForOnChange(value); var options = _this.getOptionsBySingleValue(value); if (props.onChange) { props.onChange(vls, isMultipleOrTags(_this.props) ? options : options[0]); } }; _this.isChildDisabled = function (key) { return childrenToArray(_this.props.children).some(function (child) { var childValue = getValuePropValue(child); return childValue === key && child.props && child.props.disabled; }); }; _this.forcePopupAlign = function () { if (!_this.state.open) { return; } if (_this.selectTriggerRef && _this.selectTriggerRef.triggerRef) { _this.selectTriggerRef.triggerRef.forcePopupAlign(); } }; _this.renderFilterOptions = function () { var inputValue = _this.state.inputValue; var _this$props3 = _this.props, children = _this$props3.children, tags = _this$props3.tags, notFoundContent = _this$props3.notFoundContent; var menuItems = []; var childrenKeys = []; var empty = false; var options = _this.renderFilterOptionsFromChildren(children, childrenKeys, menuItems); if (tags) { // tags value must be string var value = _this.state.value; value = value.filter(function (singleValue) { return childrenKeys.indexOf(singleValue) === -1 && (!inputValue || String(singleValue).indexOf(String(inputValue)) > -1); }); // sort by length value.sort(function (val1, val2) { return val1.length - val2.length; }); value.forEach(function (singleValue) { var key = singleValue; var menuItem = React.createElement(MenuItem, { style: UNSELECTABLE_STYLE, role: "option", attribute: UNSELECTABLE_ATTRIBUTE, value: key, key: key }, key); options.push(menuItem); menuItems.push(menuItem); }); // ref: https://github.com/ant-design/ant-design/issues/14090 if (inputValue && menuItems.every(function (option) { return getValuePropValue(option) !== inputValue; })) { options.unshift(React.createElement(MenuItem, { style: UNSELECTABLE_STYLE, role: "option", attribute: UNSELECTABLE_ATTRIBUTE, value: inputValue, key: inputValue }, inputValue)); } } if (!options.length && notFoundContent) { empty = true; options = [React.createElement(MenuItem, { style: UNSELECTABLE_STYLE, attribute: UNSELECTABLE_ATTRIBUTE, disabled: true, role: "option", value: "NOT_FOUND", key: "NOT_FOUND" }, notFoundContent)]; } return { empty: empty, options: options }; }; _this.renderFilterOptionsFromChildren = function (children, childrenKeys, menuItems) { var sel = []; var props = _this.props; var inputValue = _this.state.inputValue; var tags = props.tags; React.Children.forEach(children, function (child) { if (!child) { return; } var type = child.type; if (type.isSelectOptGroup) { var label = child.props.label; var key = child.key; if (!key && typeof label === 'string') { key = label; } else if (!label && key) { label = key; } // Match option group label if (inputValue && _this.filterOption(inputValue, child)) { var innerItems = childrenToArray(child.props.children).map(function (subChild) { var childValueSub = getValuePropValue(subChild) || subChild.key; return React.createElement(MenuItem, _extends({ key: childValueSub, value: childValueSub }, subChild.props)); }); sel.push(React.createElement(MenuItemGroup, { key: key, title: label }, innerItems)); // Not match } else { var _innerItems = _this.renderFilterOptionsFromChildren(child.props.children, childrenKeys, menuItems); if (_innerItems.length) { sel.push(React.createElement(MenuItemGroup, { key: key, title: label }, _innerItems)); } } return; } warning(type.isSelectOption, 'the children of `Select` should be `Select.Option` or `Select.OptGroup`, ' + "instead of `".concat(type.name || type.displayName || child.type, "`.")); var childValue = getValuePropValue(child); validateOptionValue(childValue, _this.props); if (_this.filterOption(inputValue, child)) { var menuItem = React.createElement(MenuItem, _extends({ style: UNSELECTABLE_STYLE, attribute: UNSELECTABLE_ATTRIBUTE, value: childValue, key: childValue, role: "option" }, child.props)); sel.push(menuItem); menuItems.push(menuItem); } if (tags) { childrenKeys.push(childValue); } }); return sel; }; _this.renderTopControlNode = function () { var _this$state = _this.state, open = _this$state.open, inputValue = _this$state.inputValue; var value = _this.state.value; var props = _this.props; var choiceTransitionName = props.choiceTransitionName, prefixCls = props.prefixCls, maxTagTextLength = props.maxTagTextLength, maxTagCount = props.maxTagCount, showSearch = props.showSearch, removeIcon = props.removeIcon; var maxTagPlaceholder = props.maxTagPlaceholder; var className = "".concat(prefixCls, "-selection__rendered"); // search input is inside topControlNode in single, multiple & combobox. 2016/04/13 var innerNode = null; if (isSingleMode(props)) { var selectedValue = null; if (value.length) { var showSelectedValue = false; var opacity = 1; if (!showSearch) { showSelectedValue = true; } else if (open) { showSelectedValue = !inputValue; if (showSelectedValue) { opacity = 0.4; } } else { showSelectedValue = true; } var singleValue = value[0]; var _this$getOptionInfoBy3 = _this.getOptionInfoBySingleValue(singleValue), label = _this$getOptionInfoBy3.label, title = _this$getOptionInfoBy3.title; selectedValue = React.createElement("div", { key: "value", className: "".concat(prefixCls, "-selection-selected-value"), title: toTitle(title || label), style: { display: showSelectedValue ? 'block' : 'none', opacity: opacity } }, label); } if (!showSearch) { innerNode = [selectedValue]; } else { innerNode = [selectedValue, React.createElement("div", { className: "".concat(prefixCls, "-search ").concat(prefixCls, "-search--inline"), key: "input", style: { display: open ? 'block' : 'none' } }, _this.getInputElement())]; } } else { var selectedValueNodes = []; var limitedCountValue = value; var maxTagPlaceholderEl; if (maxTagCount !== undefined && value.length > maxTagCount) { limitedCountValue = limitedCountValue.slice(0, maxTagCount); var omittedValues = _this.getVLForOnChange(value.slice(maxTagCount, value.length)); var content = "+ ".concat(value.length - maxTagCount, " ..."); if (maxTagPlaceholder) { content = typeof maxTagPlaceholder === 'function' ? maxTagPlaceholder(omittedValues) : maxTagPlaceholder; } maxTagPlaceholderEl = React.createElement("li", _extends({ style: UNSELECTABLE_STYLE }, UNSELECTABLE_ATTRIBUTE, { role: "presentation", onMouseDown: preventDefaultEvent, className: "".concat(prefixCls, "-selection__choice ").concat(prefixCls, "-selection__choice__disabled"), key: "maxTagPlaceholder", title: toTitle(content) }), React.createElement("div", { className: "".concat(prefixCls, "-selection__choice__content") }, content)); } if (isMultipleOrTags(props)) { selectedValueNodes = limitedCountValue.map(function (singleValue) { var info = _this.getOptionInfoBySingleValue(singleValue); var content = info.label; var title = info.title || content; if (maxTagTextLength && typeof content === 'string' && content.length > maxTagTextLength) { content = "".concat(content.slice(0, maxTagTextLength), "..."); } var disabled = _this.isChildDisabled(singleValue); var choiceClassName = disabled ? "".concat(prefixCls, "-selection__choice ").concat(prefixCls, "-selection__choice__disabled") : "".concat(prefixCls, "-selection__choice"); return React.createElement("li", _extends({ style: UNSELECTABLE_STYLE }, UNSELECTABLE_ATTRIBUTE, { onMouseDown: preventDefaultEvent, className: choiceClassName, role: "presentation", key: singleValue || SELECT_EMPTY_VALUE_KEY, title: toTitle(title) }), React.createElement("div", { className: "".concat(prefixCls, "-selection__choice__content") }, content), disabled ? null : React.createElement("span", { onClick: function onClick(event) { _this.removeSelected(singleValue, event); }, className: "".concat(prefixCls, "-selection__choice__remove") }, removeIcon || React.createElement("i", { className: "".concat(prefixCls, "-selection__choice__remove-icon") }, "\xD7"))); }); } if (maxTagPlaceholderEl) { selectedValueNodes.push(maxTagPlaceholderEl); } selectedValueNodes.push(React.createElement("li", { className: "".concat(prefixCls, "-search ").concat(prefixCls, "-search--inline"), key: "__input" }, _this.getInputElement())); if (isMultipleOrTags(props) && choiceTransitionName) { innerNode = React.createElement(Animate, { onLeave: _this.onChoiceAnimationLeave, component: "ul", transitionName: choiceTransitionName }, selectedValueNodes); } else { innerNode = React.createElement("ul", null, selectedValueNodes); } } return React.createElement("div", { className: className, ref: _this.saveTopCtrlRef }, _this.getPlaceholderElement(), innerNode); }; var optionsInfo = Select.getOptionsInfoFromProps(props); if (props.tags && typeof props.filterOption !== 'function') { var isDisabledExist = Object.keys(optionsInfo).some(function (key) { return optionsInfo[key].disabled; }); warning(!isDisabledExist, 'Please avoid setting option to disabled in tags mode since user can always type text as tag.'); } _this.state = { value: Select.getValueFromProps(props, true), inputValue: props.combobox ? Select.getInputValueForCombobox(props, optionsInfo, true) : '', open: props.defaultOpen, optionsInfo: optionsInfo, backfillValue: '', // a flag for aviod redundant getOptionsInfoFromProps call skipBuildOptionsInfo: true, ariaId: '' }; _this.saveInputRef = saveRef(_assertThisInitialized(_this), 'inputRef'); _this.saveInputMirrorRef = saveRef(_assertThisInitialized(_this), 'inputMirrorRef'); _this.saveTopCtrlRef = saveRef(_assertThisInitialized(_this), 'topCtrlRef'); _this.saveSelectTriggerRef = saveRef(_assertThisInitialized(_this), 'selectTriggerRef'); _this.saveRootRef = saveRef(_assertThisInitialized(_this), 'rootRef'); _this.saveSelectionRef = saveRef(_assertThisInitialized(_this), 'selectionRef'); return _this; } _createClass(Select, [{ key: "componentDidMount", value: function componentDidMount() { // when defaultOpen is true, we should auto focus search input // https://github.com/ant-design/ant-design/issues/14254 if (this.props.autoFocus || this.state.open) { this.focus(); } this.setState({ ariaId: generateUUID() }); } }, { key: "componentDidUpdate", value: function componentDidUpdate() { if (isMultipleOrTags(this.props)) { var inputNode = this.getInputDOMNode(); var mirrorNode = this.getInputMirrorDOMNode(); if (inputNode && inputNode.value && mirrorNode) { inputNode.style.width = ''; inputNode.style.width = "".concat(mirrorNode.clientWidth, "px"); } else if (inputNode) { inputNode.style.width = ''; } } this.forcePopupAlign(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.clearFocusTime(); this.clearBlurTime(); this.clearComboboxTime(); if (this.dropdownContainer) { ReactDOM.unmountComponentAtNode(this.dropdownContainer); document.body.removeChild(this.dropdownContainer); this.dropdownContainer = null; } } }, { key: "focus", value: function focus() { if (isSingleMode(this.props) && this.selectionRef) { this.selectionRef.focus(); } else if (this.getInputDOMNode()) { this.getInputDOMNode().focus(); } } }, { key: "blur", value: function blur() { if (isSingleMode(this.props) && this.selectionRef) { this.selectionRef.blur(); } else if (this.getInputDOMNode()) { this.getInputDOMNode().blur(); } } }, { key: "renderArrow", value: function renderArrow(multiple) { // showArrow : Set to true if not multiple by default but keep set value. var _this$props4 = this.props, _this$props4$showArro = _this$props4.showArrow, showArrow = _this$props4$showArro === void 0 ? !multiple : _this$props4$showArro, loading = _this$props4.loading, inputIcon = _this$props4.inputIcon, prefixCls = _this$props4.prefixCls; if (!showArrow && !loading) { return null; } // if loading have loading icon var defaultIcon = loading ? React.createElement("i", { className: "".concat(prefixCls, "-arrow-loading") }) : React.createElement("i", { className: "".concat(prefixCls, "-arrow-icon") }); return React.createElement("span", _extends({ key: "arrow", className: "".concat(prefixCls, "-arrow"), style: UNSELECTABLE_STYLE }, UNSELECTABLE_ATTRIBUTE, { onClick: this.onArrowClick }), inputIcon || defaultIcon); } }, { key: "renderClear", value: function renderClear() { var _this$props5 = this.props, prefixCls = _this$props5.prefixCls, allowClear = _this$props5.allowClear, clearIcon = _this$props5.clearIcon; var inputValue = this.state.inputValue; var value = this.state.value; var clear = React.createElement("span", _extends({ key: "clear", className: "".concat(prefixCls, "-selection__clear"), onMouseDown: preventDefaultEvent, style: UNSELECTABLE_STYLE }, UNSELECTABLE_ATTRIBUTE, { onClick: this.onClearSelection }), clearIcon || React.createElement("i", { className: "".concat(prefixCls, "-selection__clear-icon") }, "\xD7")); if (!allowClear) { return null; } if (isCombobox(this.props)) { if (inputValue) { return clear; } return null; } if (inputValue || value.length) { return clear; } return null; } }, { key: "render", value: function render() { var _rootCls; var props = this.props; var multiple = isMultipleOrTags(props); // Default set showArrow to true if not set (not set directly in defaultProps to handle multiple case) var _props$showArrow = props.showArrow, showArrow = _props$showArrow === void 0 ? true : _props$showArrow; var state = this.state; var className = props.className, disabled = props.disabled, prefixCls = props.prefixCls, loading = props.loading; var ctrlNode = this.renderTopControlNode(); var _this$state2 = this.state, open = _this$state2.open, ariaId = _this$state2.ariaId; if (open) { var filterOptions = this.renderFilterOptions(); this._empty = filterOptions.empty; this._options = filterOptions.options; } var realOpen = this.getRealOpenState(); var empty = this._empty; var options = this._options || []; var dataOrAriaAttributeProps = {}; Object.keys(props).forEach(function (key) { if (Object.prototype.hasOwnProperty.call(props, key) && (key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role')) { dataOrAriaAttributeProps[key] = props[key]; } }); // for (const key in props) { // if ( // Object.prototype.hasOwnProperty.call(props, key) && // (key.substr(0, 5) === 'data-' || key.substr(0, 5) === 'aria-' || key === 'role') // ) { // dataOrAriaAttributeProps[key] = props[key]; // } // } var extraSelectionProps = _extends({}, dataOrAriaAttributeProps); if (!isMultipleOrTagsOrCombobox(props)) { extraSelectionProps = _extends(_extends({}, extraSelectionProps), { onKeyDown: this.onKeyDown, tabIndex: props.disabled ? -1 : props.tabIndex }); } var rootCls = (_rootCls = {}, _defineProperty(_rootCls, className, !!className), _defineProperty(_rootCls, prefixCls, 1), _defineProperty(_rootCls, "".concat(prefixCls, "-open"), open), _defineProperty(_rootCls, "".concat(prefixCls, "-focused"), open || !!this._focused), _defineProperty(_rootCls, "".concat(prefixCls, "-combobox"), isCombobox(props)), _defineProperty(_rootCls, "".concat(prefixCls, "-disabled"), disabled), _defineProperty(_rootCls, "".concat(prefixCls, "-enabled"), !disabled), _defineProperty(_rootCls, "".concat(prefixCls, "-allow-clear"), !!props.allowClear), _defineProperty(_rootCls, "".concat(prefixCls, "-no-arrow"), !showArrow), _defineProperty(_rootCls, "".concat(prefixCls, "-loading"), !!loading), _rootCls); return React.createElement(SelectTrigger, { onPopupFocus: this.onPopupFocus, onMouseEnter: this.props.onMouseEnter, onMouseLeave: this.props.onMouseLeave, dropdownAlign: props.dropdownAlign, dropdownClassName: props.dropdownClassName, dropdownMatchSelectWidth: props.dropdownMatchSelectWidth, defaultActiveFirstOption: props.defaultActiveFirstOption, dropdownMenuStyle: props.dropdownMenuStyle, transitionName: props.transitionName, animation: props.animation, prefixCls: props.prefixCls, dropdownStyle: props.dropdownStyle, combobox: props.combobox, showSearch: props.showSearch, options: options, empty: empty, multiple: multiple, disabled: disabled, visible: realOpen, inputValue: state.inputValue, value: state.value, backfillValue: state.backfillValue, firstActiveValue: props.firstActiveValue, onDropdownVisibleChange: this.onDropdownVisibleChange, getPopupContainer: props.getPopupContainer, onMenuSelect: this.onMenuSelect, onMenuDeselect: this.onMenuDeselect, onPopupScroll: props.onPopupScroll, showAction: props.showAction, ref: this.saveSelectTriggerRef, menuItemSelectedIcon: props.menuItemSelectedIcon, dropdownRender: props.dropdownRender, ariaId: ariaId }, React.createElement("div", { id: props.id, style: props.style, ref: this.saveRootRef, onBlur: this.onOuterBlur, onFocus: this.onOuterFocus, className: classnames(rootCls), onMouseDown: this.markMouseDown, onMouseUp: this.markMouseLeave, onMouseOut: this.markMouseLeave }, React.createElement("div", _extends({ ref: this.saveSelectionRef, key: "selection", className: "".concat(prefixCls, "-selection\n ").concat(prefixCls, "-selection--").concat(multiple ? 'multiple' : 'single'), role: "combobox", "aria-autocomplete": "list", "aria-haspopup": "true", "aria-controls": ariaId, "aria-expanded": realOpen }, extraSelectionProps), ctrlNode, this.renderClear(), this.renderArrow(!!multiple)))); } }]); return Select; }(React.Component); Select.propTypes = SelectPropTypes; Select.defaultProps = { prefixCls: 'rc-select', defaultOpen: false, labelInValue: false, defaultActiveFirstOption: true, showSearch: true, allowClear: false, placeholder: '', onChange: noop, onFocus: noop, onBlur: noop, onSelect: noop, onSearch: noop, onDeselect: noop, onInputKeyDown: noop, dropdownMatchSelectWidth: true, dropdownStyle: {}, dropdownMenuStyle: {}, optionFilterProp: 'value', optionLabelProp: 'value', notFoundContent: 'Not Found', backfill: false, showAction: ['click'], tokenSeparators: [], autoClearSearchValue: true, tabIndex: 0, dropdownRender: function dropdownRender(menu) { return menu; } }; Select.getDerivedStateFromProps = function (nextProps, prevState) { var optionsInfo = prevState.skipBuildOptionsInfo ? prevState.optionsInfo : Select.getOptionsInfoFromProps(nextProps, prevState); var newState = { optionsInfo: optionsInfo, skipBuildOptionsInfo: false }; if ('open' in nextProps) { newState.open = nextProps.open; } if (nextProps.disabled && prevState.open) { newState.open = false; } if ('value' in nextProps) { var value = Select.getValueFromProps(nextProps); newState.value = value; if (nextProps.combobox) { newState.inputValue = Select.getInputValueForCombobox(nextProps, optionsInfo); } } return newState; }; Select.getOptionsFromChildren = function (children) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; React.Children.forEach(children, function (child) { if (!child) { return; } var type = child.type; if (type.isSelectOptGroup) { Select.getOptionsFromChildren(child.props.children, options); } else { options.push(child); } }); return options; }; Select.getInputValueForCombobox = function (props, optionsInfo, useDefaultValue) { var value = []; if ('value' in props && !useDefaultValue) { value = toArray(props.value); } if ('defaultValue' in props && useDefaultValue) { value = toArray(props.defaultValue); } if (value.length) { value = value[0]; } else { return ''; } var label = value; if (props.labelInValue) { label = value.label; } else if (optionsInfo[getMapKey(value)]) { label = optionsInfo[getMapKey(value)].label; } if (label === undefined) { label = ''; } return label; }; Select.getLabelFromOption = function (props, option) { return getPropValue(option, props.optionLabelProp); }; Select.getOptionsInfoFromProps = function (props, preState) { var options = Select.getOptionsFromChildren(props.children); var optionsInfo = {}; options.forEach(function (option) { var singleValue = getValuePropValue(option); optionsInfo[getMapKey(singleValue)] = { option: option, value: singleValue, label: Select.getLabelFromOption(props, option), title: option.props.title, disabled: option.props.disabled }; }); if (preState) { // keep option info in pre state value. var oldOptionsInfo = preState.optionsInfo; var value = preState.value; if (value) { value.forEach(function (v) { var key = getMapKey(v); if (!optionsInfo[key] && oldOptionsInfo[key] !== undefined) { optionsInfo[key] = oldOptionsInfo[key]; } }); } } return optionsInfo; }; Select.getValueFromProps = function (props, useDefaultValue) { var value = []; if ('value' in props && !useDefaultValue) { value = toArray(props.value); } if ('defaultValue' in props && useDefaultValue) { value = toArray(props.defaultValue); } if (props.labelInValue) { value = value.map(function (v) { return v.key; }); } return value; }; Select.displayName = 'Select'; polyfill(Select); export default Select;