UNPKG

@alifd/next

Version:

A configurable component library for web built on React.

1,270 lines (1,044 loc) 42.5 kB
'use strict'; exports.__esModule = true; var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _class, _temp; /* eslint-disable valid-jsdoc */ var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _reactLifecyclesCompat = require('react-lifecycles-compat'); var _util = require('../util'); var _tag = require('../tag'); var _tag2 = _interopRequireDefault(_tag); var _input = require('../input'); var _input2 = _interopRequireDefault(_input); var _icon = require('../icon'); var _icon2 = _interopRequireDefault(_icon); var _zhCn = require('../locale/zh-cn'); var _zhCn2 = _interopRequireDefault(_zhCn); var _base = require('./base'); var _base2 = _interopRequireDefault(_base); var _util2 = require('./util'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var bindCtx = _util.func.bindCtx, noop = _util.func.noop; var isIE9 = _util.env.ieVersion === 9; /** * 无障碍化注意事项: * 1. Select 无搜索情况下,不应该让 Input 可focus,此时外层wrap必须可focus,并且需要相应focus事件让外边框发生变化 * * TODO: hightLight 后续改造注意点 * 1. hightLight 跟随点击变化(fixed) 2. 弹窗打开时根据 是否高亮第一个选项的 api开关设置是否hightLight 第一项 */ // 自定义弹层:1. 不需要关心Menu的点击事件 2. 不需要关心dataSource变化 /** * Select */ var Select = (_temp = _class = function (_Base) { (0, _inherits3.default)(Select, _Base); function Select(props) { (0, _classCallCheck3.default)(this, Select); // because dataSource maybe updated while select a item, so we should cache choosen value's item var _this = (0, _possibleConstructorReturn3.default)(this, _Base.call(this, props)); _this.handleWrapClick = function (e) { // ignore click on input to choose text if (e.target.nodeName !== 'INPUT') { e.preventDefault(); } _this.focusInput(); }; _this.handleArrowClick = function (e) { e.preventDefault(); _this.focusInput(); // because of can not close Popup by click Input while hasSearch. // so when Popup open and hasSearch, we should close Popup intentionally _this.state.visible && _this.hasSearch() && _this.setVisible(false); }; _this.handleClear = function (e) { e.stopPropagation(); _this.selectAllYet = false; _this.handleChange(undefined, 'clear'); }; _this.valueDataSource = { valueDS: [], // [{value,label}] mapValueDS: {} // {value: {value,label}} }; var searchValue = 'searchValue' in props ? props.searchValue : ''; _this.dataStore.setOptions({ key: searchValue, addonKey: props.mode === 'tag' // tag 模式手动输入的数据 }); (0, _extends3.default)(_this.state, { searchValue: searchValue, dataSource: _this.setDataSource(props) }); // 根据value和计算后的dataSource,更新value对应的详细数据valueDataSource if (typeof _this.state.value !== 'undefined') { _this.valueDataSource = (0, _util2.getValueDataSource)(_this.state.value, _this.valueDataSource.mapValueDS, _this.dataStore.getMapDS()); } bindCtx(_this, ['handleMenuSelect', 'handleItemClick', 'handleSearch', 'handleSearchKeyDown', 'handleSelectAll', 'maxTagPlaceholder']); return _this; } Select.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) { var state = {}; if ('value' in nextProps && nextProps.value !== prevState.value) { (0, _extends3.default)(state, { value: nextProps.value }); } if ('highlightKey' in nextProps && nextProps.highlightKey !== prevState.highlightKey) { (0, _extends3.default)(state, { highlightKey: nextProps.highlightKey }); } else if ('value' in nextProps && nextProps.value !== prevState.value && nextProps.mode === 'single') { (0, _extends3.default)(state, { highlightKey: nextProps.value }); } if ('searchValue' in nextProps && nextProps.searchValue !== prevState.searchValue) { var searchValue = nextProps.searchValue; (0, _extends3.default)(state, { searchValue: searchValue === undefined || searchValue === null ? '' : searchValue }); } if ('visible' in nextProps && nextProps.visible !== prevState.visible) { (0, _extends3.default)(state, { visible: nextProps.visible }); } if (Object.keys(state).length) { return state; } return null; }; Select.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState) { var props = this.props; if ('searchValue' in props && this.state.searchValue !== prevState.searchValue) { this.dataStore.setOptions({ key: this.state.searchValue }); } if (props.mode !== prevProps.mode) { this.dataStore.setOptions({ addonKey: props.mode === 'tag' }); } if (props.mode !== prevProps.mode) { this.dataStore.setOptions({ addonKey: props.mode === 'tag' }); } if (props.filter !== prevProps.filter) { this.dataStore.setOptions({ filter: props.filter }); } if (props.filterLocal !== prevProps.filterLocal) { this.dataStore.setOptions({ filterLocal: props.filterLocal }); } if (prevProps.children !== props.children || prevProps.dataSource !== props.dataSource) { /* eslint-disable react/no-did-update-set-state */ this.setState({ dataSource: this.setDataSource(props) }); if (!props.popupContent) { this.setFirstHightLightKeyForMenu(this.state.searchValue); } } if ('value' in props) { this.valueDataSource = (0, _util2.getValueDataSource)(props.value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()); this.updateSelectAllYet(this.valueDataSource.value); } else if ('defaultValue' in props && props.defaultValue === this.valueDataSource.value && (props.children !== prevProps.children || props.dataSource !== prevProps.dataSource)) { // has defaultValue and value not changed and dataSource changed // fix: set defaultValue first, then update dataSource. this.valueDataSource = (0, _util2.getValueDataSource)(props.defaultValue, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()); } if (prevProps.label !== this.props.label || prevState.value !== this.state.value || props.searchValue !== this.state.searchValue) { this.syncWidth(); } }; Select.prototype.componentDidMount = function componentDidMount() { if (isIE9) { this.ie9Hack(); } _Base.prototype.componentDidMount.call(this); }; // ie9 下 table-cell 布局不支持宽度超出隐藏 Select.prototype.ie9Hack = function ie9Hack() { try { var width = this.selectDOM.currentStyle.width; this.setState({ fixWidth: width !== 'auto' }); } catch (e) { // } }; Select.prototype.useDetailValue = function useDetailValue() { var _props = this.props, popupContent = _props.popupContent, useDetailValue = _props.useDetailValue, dataSource = _props.dataSource; return useDetailValue || popupContent && !dataSource; }; Select.prototype.hasSearch = function hasSearch() { var _props2 = this.props, showSearch = _props2.showSearch, mode = _props2.mode; return showSearch || mode === 'tag'; }; Select.prototype.getTagSize = function getTagSize() { var _props3 = this.props, size = _props3.size, adjustTagSize = _props3.adjustTagSize; if (adjustTagSize) { return size; } return size === 'large' ? 'medium' : 'small'; }; /** * Menu.Item onSelect * @private * @param {Array<string>} keys * @ */ Select.prototype.handleMenuSelect = function handleMenuSelect(keys, item) { var _props4 = this.props, mode = _props4.mode, readOnly = _props4.readOnly, disabled = _props4.disabled; if (readOnly || disabled) { return false; } var isSingle = mode === 'single'; if (isSingle) { // 单选 return this.handleSingleSelect(keys[0], 'itemClick'); } else { // 正常多选 return this.handleMultipleSelect(keys, 'itemClick', item.props && item.props._key); } }; Select.prototype.handleItemClick = function handleItemClick(key) { if (!this.props.popupAutoFocus) { this.focusInput(); } if (this.props.mode === 'single' && key === this.state.value) { this.setVisible(false, 'itemClick'); } }; /** * 单选模式 */ Select.prototype.handleSingleSelect = function handleSingleSelect(key, triggerType) { // TODO: 这里 cacheValue=false 有问题,dataSource 更新的时候就应该处理 var cacheValue = this.props.cacheValue; // get data only from dataStore while cacheValue=false var itemObj = (0, _util2.getValueDataSource)(key, cacheValue ? this.valueDataSource.mapValueDS : {}, this.dataStore.getMapDS()); this.valueDataSource = itemObj; this.setVisible(false, triggerType); // 应在return之前传出highlightKey this.setState({ highlightKey: key }); if (this.useDetailValue()) { return this.handleChange(itemObj.valueDS, triggerType); } else { this.handleChange(itemObj.value, triggerType, itemObj.valueDS); } // 清空搜索 if (!('searchValue' in this.props) && this.state.searchValue) { this.handleSearchClear(triggerType); } }; /** * 多选模式 multiple/tag */ Select.prototype.handleMultipleSelect = function handleMultipleSelect(keys, triggerType, key, keepSearchValue) { var _this2 = this; var itemObj = (0, _util2.getValueDataSource)(keys, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()); var _props5 = this.props, cacheValue = _props5.cacheValue, mode = _props5.mode, hiddenSelected = _props5.hiddenSelected; // cache those value maybe not exists in dataSource if (cacheValue || mode === 'tag') { this.valueDataSource = itemObj; } if (hiddenSelected) { this.setVisible(false, triggerType); } // 因为搜索后会设置 hightLight 为第一个item,menu渲染会自动滚动到 hightLight 的元素上面。 // 所以设置 hightLight 为当前选中项避免滚动 key && this.state.visible && this.setState({ highlightKey: key }); if (this.useDetailValue()) { this.handleChange(itemObj.valueDS, triggerType); } else { this.handleChange(itemObj.value, triggerType, itemObj.valueDS); } this.updateSelectAllYet(itemObj.value); // 清空搜索 if (!('searchValue' in this.props) && this.state.searchValue && !keepSearchValue) { // 因为 SearchValue 被 clear 后会重新渲染 Menu,所以在 Overlay 检测 safeNode 的时候 e.target 可能会找不到导致弹窗关闭 setTimeout(function () { _this2.handleSearchClear(triggerType); }); } }; Select.prototype.updateSelectAllYet = function updateSelectAllYet(value) { var _this3 = this; // multiple mode // is current state select all or not this.selectAllYet = false; if (this.props.hasSelectAll && Array.isArray(value)) { var selectAllValues = this.dataStore.getEnableDS().map(function (item) { return item.value; }); if (selectAllValues.length <= value.length) { this.selectAllYet = true; selectAllValues.forEach(function (val) { if (value.indexOf(val) === -1) { _this3.selectAllYet = false; return; } }); } } }; Select.prototype.handleSearchValue = function handleSearchValue(value) { if (this.state.searchValue === value) { return; } var filterLocal = this.props.filterLocal; if (filterLocal) { if (!('searchValue' in this.props)) { this.setState({ searchValue: value, dataSource: this.dataStore.updateByKey(value) }); this.setFirstHightLightKeyForMenu(value); } } else if (!('searchValue' in this.props)) { this.setState({ searchValue: value }); } }; /** * Handle search input change event * @param {String} value search text * @param {Event} e change Event */ Select.prototype.handleSearch = function handleSearch(value, e) { this.handleSearchValue(value); // inputing should trigger popup open if (!this.state.visible && value) { this.setVisible(true); } this.props.onSearch(value, e); }; Select.prototype.handleSearchClear = function handleSearchClear(triggerType) { this.handleSearchValue(''); this.props.onSearchClear(triggerType); }; // 搜索框 keyDown 事件 Select.prototype.handleSearchKeyDown = function handleSearchKeyDown(e) { var _props6 = this.props, popupContent = _props6.popupContent, onKeyDown = _props6.onKeyDown, showSearch = _props6.showSearch, mode = _props6.mode, hasClear = _props6.hasClear, onToggleHighlightItem = _props6.onToggleHighlightItem, readOnly = _props6.readOnly, disabled = _props6.disabled; var hasSearch = this.hasSearch(); if (popupContent) { // 搜索的时候不阻止冒泡会无法输入 if (hasSearch && e.keyCode === _util.KEYCODE.SPACE) { e.stopPropagation(); } return onKeyDown(e); } var proxy = 'search'; switch (e.keyCode) { case _util.KEYCODE.UP: e.preventDefault(); onToggleHighlightItem(this.toggleHighlightItem(-1, e), 'up'); break; case _util.KEYCODE.DOWN: e.preventDefault(); onToggleHighlightItem(this.toggleHighlightItem(1, e), 'down'); break; case _util.KEYCODE.ENTER: e.preventDefault(); if (readOnly || disabled) { break; } this.chooseHighlightItem(proxy, e); break; case _util.KEYCODE.ESC: e.preventDefault(); this.state.visible && this.setVisible(false, 'keyDown'); break; case _util.KEYCODE.SPACE: e.stopPropagation(); !hasSearch && e.preventDefault(); break; case _util.KEYCODE.BACKSPACE: if (readOnly || disabled) { break; } if (mode === 'multiple' && showSearch || mode === 'tag') { // 在多选并且有搜索的情况下,删除最后一个 tag var valueDS = this.valueDataSource.valueDS; if (valueDS && valueDS.length && !valueDS[valueDS.length - 1].disabled) { this.handleDeleteTag(e); } } else if (mode === 'single' && hasClear && !this.state.visible) { // 单选、非展开、并且可清除的情况,允许按删除键清除 this.handleClear(e); } break; default: break; } onKeyDown(e); }; Select.prototype.chooseMultipleItem = function chooseMultipleItem(key) { var value = this.state.value || []; var keys = value.map(function (v) { return (0, _util2.valueToSelectKey)(v); }); var keepSearchValue = false; var index = keys.map(function (v) { return '' + v; }).indexOf(key); if (index > -1) { // unselect keys.splice(index, 1); keepSearchValue = true; // 回车反选保留搜索值 } else { // select keys.push(key); } this.handleMultipleSelect(keys, 'enter', null, keepSearchValue); }; // 回车 选择高亮的 item Select.prototype.chooseHighlightItem = function chooseHighlightItem(proxy, e) { var mode = this.props.mode; if (!this.state.visible) { // input tag by itself if (mode === 'tag' && this.state.searchValue) { this.chooseMultipleItem(this.state.searchValue); } return false; } var highlightKey = this.state.highlightKey; // 没有高亮选项 或者 没有可选菜单 if (highlightKey === null || !this.dataStore.getMenuDS().length) { return; } if (mode === 'single') { this.handleSingleSelect(highlightKey, 'enter'); } else { this.chooseMultipleItem(highlightKey); // 阻止事件冒泡到最外层,让Popup 监听到触发弹层关闭 e && e.stopPropagation(); } }; /** * Handle Tag close event * @param {Object} item * @return {Boolean} false return false to prevent auto close * ---- * It MUST be multiple mode, needn't additional judgement */ Select.prototype.handleTagClose = function handleTagClose(item) { var readOnly = this.props.readOnly; if (readOnly) return false; if (this.useDetailValue()) { var value = this.state.value.filter(function (v) { return item.value !== v.value; }); this.handleChange(value, 'tag'); } else { // filter out current item, and then call handleMenuSelect var _value = this.state.value.filter(function (v) { return item.value !== v; }); this.handleMultipleSelect(_value, 'tag'); } this.props.onRemove(item); // prevent tag close return false; }; // eslint-disable-next-line valid-jsdoc /** * Handle BACKSPACE key event * @param {Event} e keyDown event * --- * It MUST be multiple mode */ Select.prototype.handleDeleteTag = function handleDeleteTag(e) { var value = this.state.value; var searchValue = this.state.searchValue; if (searchValue || !value || !value.length) { return false; } e.preventDefault(); var nextValues = value.slice(0, value.length - 1); // 手动调用 handleMenuSelect 时直接传入原生的 value,可以减少 toString 的操作 if (this.useDetailValue()) { this.handleChange(nextValues, 'tag'); } else { this.handleMultipleSelect(nextValues, 'tag'); } }; /** * Handle SelectAll span click event * @param {Event} e click event */ Select.prototype.handleSelectAll = function handleSelectAll(e) { e && e.preventDefault(); var nextValues = void 0; if (this.selectAllYet) { nextValues = []; } else { nextValues = this.dataStore.getEnableDS().map(function (item) { return item.value; }); } // 直接传 values,减少 toString 操作 this.handleMultipleSelect(nextValues, 'selectAll'); }; Select.prototype.handleVisibleChange = function handleVisibleChange(visible, type) { this.setVisible(visible, type); }; Select.prototype.afterClose = function afterClose() { // 关闭的时候清空搜索值 if (this.hasSearch()) { this.handleSearchClear('popupClose'); } }; Select.prototype.maxTagPlaceholder = function maxTagPlaceholder(selectedValues, totalValues) { var locale = this.props.locale; return '' + _util.str.template(locale.maxTagPlaceholder, { selected: selectedValues.length, total: totalValues.length }); }; /** * 如果用户是自定义的弹层,则直接以 value 为准,不再校验 dataSource * TODO: 2.0 中 value 接受 string/object{value,label} 两种类型的数据,自动做识别,可以避免用户去转换,也和 date-picker 对齐 * 此外 onChange 第一个参数根据 api 来控制类型是 [string] 还是 [object{value,label}] * @param {object} props */ Select.prototype.renderValues = function renderValues() { var _this4 = this; var _props7 = this.props, prefix = _props7.prefix, mode = _props7.mode, valueRender = _props7.valueRender, fillProps = _props7.fillProps, disabled = _props7.disabled, maxTagCount = _props7.maxTagCount, maxTagPlaceholder = _props7.maxTagPlaceholder, tagInline = _props7.tagInline, tagClosable = _props7.tagClosable; var tagSize = this.getTagSize(); var value = this.state.value; if ((0, _util2.isNull)(value)) { return null; } // get detail value if (!this.useDetailValue()) { if (value === this.valueDataSource.value) { value = this.valueDataSource.valueDS; } else { value = (0, _util2.getValueDataSource)(value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()).valueDS; } } if (mode === 'single') { if (!value) { return null; } var retvalue = fillProps && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object' && fillProps in value ? value[fillProps] : valueRender(value); // 0 => '0' return typeof retvalue === 'number' ? retvalue.toString() : retvalue; } else if (value) { var limitedCountValue = value; var maxTagPlaceholderEl = void 0; var totalValue = this.dataStore.getFlattenDS(); var holder = 'maxTagPlaceholder' in this.props ? maxTagPlaceholder : this.maxTagPlaceholder; if (maxTagCount !== undefined && value.length > maxTagCount && !tagInline) { limitedCountValue = limitedCountValue.slice(0, maxTagCount); maxTagPlaceholderEl = _react2.default.createElement( _tag2.default, { key: '_count', type: 'primary', size: tagSize, animation: false }, holder(value, totalValue) ); } if (value.length > 0 && tagInline) { maxTagPlaceholderEl = _react2.default.createElement( 'div', { className: prefix + 'select-tag-compact', key: '_count' }, holder(value, totalValue) ); } value = limitedCountValue; if (!Array.isArray(value)) { value = [value]; } var selectedValueNodes = value.map(function (v) { if (!v) { return null; } var labelNode = fillProps ? v[fillProps] : valueRender(v); return _react2.default.createElement( _tag2.default, { key: v.value, disabled: disabled || v.disabled, type: 'primary', size: tagSize, animation: false, onClose: _this4.handleTagClose.bind(_this4, v), closable: tagClosable }, labelNode ); }); if (maxTagPlaceholderEl) { if (tagInline) { selectedValueNodes.unshift(maxTagPlaceholderEl); } else { selectedValueNodes.push(maxTagPlaceholderEl); } } return selectedValueNodes; } return null; }; /** * 1. fix flash while click <label/> * 2. fix onBlur while has clear * @returns */ Select.prototype.hasClear = function hasClear() { var _props8 = this.props, hasClear = _props8.hasClear, readOnly = _props8.readOnly, disabled = _props8.disabled, showSearch = _props8.showSearch; var _state = this.state, value = _state.value, visible = _state.visible; return typeof value !== 'undefined' && value !== null && hasClear && !readOnly && !disabled && !(showSearch && visible); }; /** * render arrow * @param {object} props * @param {function} [clickHandler] */ Select.prototype.renderExtraNode = function renderExtraNode() { var _props9 = this.props, hasArrow = _props9.hasArrow, hasClear = _props9.hasClear, prefix = _props9.prefix; var ret = []; if (hasArrow) { ret.push(_react2.default.createElement( 'span', { key: 'arrow', 'aria-hidden': true, onClick: this.handleArrowClick, className: prefix + 'select-arrow' }, _react2.default.createElement(_icon2.default, { type: 'arrow-down', className: prefix + 'select-symbol-fold' }) )); } // do not use this.hasClear() here, to make sure clear btn always exists, can not influenced by apis like `disabled` `readOnly` if (hasClear) { ret.push(_react2.default.createElement( 'span', { key: 'clear', 'aria-hidden': true, onClick: this.handleClear, className: prefix + 'select-clear' }, _react2.default.createElement(_icon2.default, { type: 'delete-filling' }) )); } return ret; }; /** * 选择器 * @override * @param {object} props */ Select.prototype.renderSelect = function renderSelect() { var _classNames, _this5 = this; var _props10 = this.props, prefix = _props10.prefix, showSearch = _props10.showSearch, placeholder = _props10.placeholder, mode = _props10.mode, size = _props10.size, className = _props10.className, style = _props10.style, readOnly = _props10.readOnly, disabled = _props10.disabled, hasBorder = _props10.hasBorder, label = _props10.label, locale = _props10.locale, state = _props10.state, onBlur = _props10.onBlur, onFocus = _props10.onFocus, onMouseEnter = _props10.onMouseEnter, onMouseLeave = _props10.onMouseLeave, rtl = _props10.rtl; var others = _util.obj.pickOthers(Select.propTypes, this.props); var othersData = _util.obj.pickAttrsWith(others, 'data-'); var visible = this.state.visible; var isSingle = mode === 'single'; var hasSearch = this.hasSearch(); var valueNodes = this.renderValues(); // compatible with selectPlaceHolder. TODO: removed in 2.0 version var _placeholder = placeholder || locale.selectPlaceholder || locale.selectPlaceHolder; if (valueNodes && valueNodes.length) { _placeholder = null; } // 弹窗展开时将当前的值作为 placeholder,这个功能的前提是 valueNode 必须是一个字符串 if (showSearch && visible && isSingle && typeof valueNodes === 'string') { _placeholder = valueNodes; } // 下拉箭头 var extra = this.renderExtraNode(); var triggerClazz = (0, _classnames2.default)([prefix + 'select', prefix + 'select-trigger', prefix + 'select-' + mode, '' + prefix + size, className], (_classNames = {}, _classNames[prefix + 'active'] = visible, _classNames[prefix + 'inactive'] = !visible, _classNames[prefix + 'no-search'] = !hasSearch, _classNames[prefix + 'has-search'] = hasSearch, _classNames[prefix + 'select-in-ie'] = isIE9, _classNames[prefix + 'select-in-ie-fixwidth'] = this.state.fixWidth, _classNames[prefix + 'has-clear'] = this.hasClear(), _classNames)); var valuetext = this.valueDataSource.valueDS ? this.valueDataSource.valueDS.label : ''; return _react2.default.createElement( 'span', (0, _extends3.default)({}, othersData, { className: triggerClazz, style: style, dir: rtl ? 'rtl' : undefined, ref: this.saveSelectRef, onClick: this.handleWrapClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: this.handleWrapClick }), _react2.default.createElement(_input2.default, (0, _extends3.default)({ 'aria-valuetext': valuetext }, _util.obj.pickOthers(othersData, others), { role: 'combobox', tabIndex: 0, 'aria-expanded': this.state.visible, 'aria-disabled': disabled, state: state, label: label, extra: extra, value: this.state.searchValue, size: size, readOnly: !this.hasSearch() || readOnly, disabled: disabled, placeholder: _placeholder, hasBorder: hasBorder, hasClear: false, htmlSize: '1', inputRender: function inputRender(inputEl) { return _this5.renderSearchInput(valueNodes, _placeholder, inputEl); }, onChange: this.handleSearch, onKeyDown: this.handleSearchKeyDown, onFocus: onFocus, onBlur: onBlur, className: prefix + 'select-inner', ref: this.saveInputRef })), _react2.default.createElement( 'span', { className: prefix + 'sr-only', 'aria-live': 'polite' }, this.state.srReader ) ); }; Select.prototype.renderSearchInput = function renderSearchInput(valueNodes, placeholder, inputEl) { var _classNames2; var _props11 = this.props, prefix = _props11.prefix, mode = _props11.mode, tagInline = _props11.tagInline; var isSingle = mode === 'single'; var mirrorText = this.state.searchValue; var cls = (0, _classnames2.default)((_classNames2 = {}, _classNames2[prefix + 'select-values'] = true, _classNames2[prefix + 'input-text-field'] = true, _classNames2[prefix + 'select-compact'] = !isSingle && tagInline, _classNames2)); var title = typeof valueNodes === 'string' ? valueNodes : ''; var searchInput = [isSingle && valueNodes ? _react2.default.createElement( 'em', { title: title, key: 'select-value' }, valueNodes ) : valueNodes]; var triggerSearch = _react2.default.createElement( 'span', { key: 'trigger-search', className: prefix + 'select-trigger-search' }, inputEl, _react2.default.createElement( 'span', { 'aria-hidden': true }, _react2.default.createElement( 'span', null, mirrorText || placeholder ), _react2.default.createElement( 'span', { style: { display: 'inline-block', width: 1 } }, '\xA0' ) ) ); if (!isSingle && tagInline) { searchInput.unshift(triggerSearch); } else { searchInput.push(triggerSearch); } return _react2.default.createElement( 'span', { className: cls }, searchInput ); }; /** * 渲染弹层的 header 内容 * @override * @param {object} props */ Select.prototype.renderMenuHeader = function renderMenuHeader() { var _classNames3, _classNames4; var _props12 = this.props, prefix = _props12.prefix, hasSelectAll = _props12.hasSelectAll, mode = _props12.mode, locale = _props12.locale, menuProps = _props12.menuProps; if (menuProps && 'header' in menuProps) { return menuProps.header; } var sourceCount = this.dataStore.getEnableDS().length; // 多选模式下才有全选 if (!hasSelectAll || mode === 'single' || !sourceCount) { return null; } var text = typeof hasSelectAll === 'boolean' ? locale.selectAll : hasSelectAll; var selectAllYet = this.selectAllYet; var cls = (0, _classnames2.default)((_classNames3 = {}, _classNames3[prefix + 'select-all'] = true, _classNames3[prefix + 'selected'] = selectAllYet, _classNames3)); var clsInner = (0, _classnames2.default)((_classNames4 = {}, _classNames4[prefix + 'select-all-inner'] = true, _classNames4)); // remove style={{'lineHeight': 'unset'}} in next Y // remove style={{'display': 'none'}} in next Y return _react2.default.createElement( 'div', { key: 'all', onClick: this.handleSelectAll, className: cls, style: { lineHeight: 'unset' } }, selectAllYet ? _react2.default.createElement(_icon2.default, { className: prefix + 'menu-icon-selected', style: { display: 'none' }, type: 'select' }) : null, _react2.default.createElement( 'span', { className: clsInner }, text ) ); }; Select.prototype.render = function render() { var mode = this.props.mode; var props = (0, _extends3.default)({}, this.props); // forbid to close Popup by click Input while hasSearch if (this.hasSearch()) { props.canCloseByTrigger = false; } if (mode === 'single') { props.cache = true; } return _Base.prototype.render.call(this, props); }; return Select; }(_base2.default), _class.propTypes = (0, _extends3.default)({}, _base2.default.propTypes, { /** * 选择器模式 */ mode: _propTypes2.default.oneOf(['single', 'multiple', 'tag']), /** * 当前值,用于受控模式 */ value: _propTypes2.default.any, /** * 初始的默认值 */ defaultValue: _propTypes2.default.any, /** * Select发生改变时触发的回调 * @param {*} value 选中的值 * @param {String} actionType 触发的方式, 'itemClick', 'enter', 'tag' * @param {*} item 选中的值的对象数据 (useDetailValue=false有效) */ onChange: _propTypes2.default.func, /** * 传入的数据源,可以动态渲染子项,详见 [dataSource的使用](#dataSource的使用) */ dataSource: _propTypes2.default.arrayOf(_propTypes2.default.oneOfType([_propTypes2.default.shape({ value: _propTypes2.default.any, label: _propTypes2.default.any, disabled: _propTypes2.default.bool, children: _propTypes2.default.array }), _propTypes2.default.bool, _propTypes2.default.number, _propTypes2.default.string])), /** * 是否有边框 */ hasBorder: _propTypes2.default.bool, /** * 是否有下拉箭头 */ hasArrow: _propTypes2.default.bool, /** * 展开后是否能搜索(tag 模式下固定为true) */ showSearch: _propTypes2.default.bool, /** * 当搜索框值变化时回调 * @param {String} value 数据 */ onSearch: _propTypes2.default.func, /** * 当搜索框值被(选择、弹窗关闭)导致清空时候的回调 * @param {String} actionType 触发的方式, 'select'(选择清空), 'popupClose'(弹窗关闭清空) */ onSearchClear: _propTypes2.default.func, /** * 多选模式下是否有全选功能 */ hasSelectAll: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.string]), /** * 填充到选择框里的值的 key */ fillProps: _propTypes2.default.string, /** * value 使用对象类型 `{value, label}`, 同时 onChange 第一个参数返回也修改为 dataSource 中的对象 */ useDetailValue: _propTypes2.default.bool, /** * dataSource 变化的时是否保留已选的内容 */ cacheValue: _propTypes2.default.bool, /** * 渲染 Select 展现内容的方法 * @param {Object} item 渲染节点的item * @return {ReactNode} 展现内容 * @default item => `item.label || item.value` */ valueRender: _propTypes2.default.func, /** * 渲染 MenuItem 内容的方法 * @param {Object} item 渲染节点的item * @param {String} searchValue 搜索关键字(如果开启搜索) * @return {ReactNode} item node */ itemRender: _propTypes2.default.func, /** * 弹层内容为空的文案 */ notFoundContent: _propTypes2.default.node, style: _propTypes2.default.object, /** * 受控搜索值,一般不需要设置 * @type {[type]} */ searchValue: _propTypes2.default.string, /** * 是否一行显示,仅在 mode 为 multiple 的时候生效 * @version 1.15 */ tagInline: _propTypes2.default.bool, /** * tag 是否可关闭 * @version 1.20 */ tagClosable: _propTypes2.default.bool, /** * tag 尺寸是否和 select 保持一致(mode=multiple/tag 模式生效),默认false * @version 1.24 */ adjustTagSize: _propTypes2.default.bool, /** * 最多显示多少个 tag * @version 1.15 */ maxTagCount: _propTypes2.default.number, /** * 隐藏多余 tag 时显示的内容,在 maxTagCount 生效时起作用 * @param {object} selectedValues 当前已选中的元素 * @param {object} totalValues 总待选元素 * @version 1.15 */ maxTagPlaceholder: _propTypes2.default.func, /** * 选择后是否立即隐藏菜单 (mode=multiple/tag 模式生效) */ hiddenSelected: _propTypes2.default.bool, /** * tag 删除回调 * @param {object} item 渲染节点的item */ onRemove: _propTypes2.default.func, /** * 焦点事件 */ onFocus: _propTypes2.default.func, /** * 是否自动高亮第一个选项 */ // highlightFirstItem: PropTypes.bool, /** * 失去焦点事件 */ onBlur: _propTypes2.default.func, onMouseEnter: _propTypes2.default.func, onMouseLeave: _propTypes2.default.func, onKeyDown: _propTypes2.default.func, locale: _propTypes2.default.object, /** * 展开下拉菜单时是否自动焦点到弹层 */ popupAutoFocus: _propTypes2.default.bool, /** * 是否展示 dataSource 中 children */ showDataSourceChildren: _propTypes2.default.bool }), _class.defaultProps = (0, _extends3.default)({}, _base2.default.defaultProps, { locale: _zhCn2.default.Select, mode: 'single', showSearch: false, cacheValue: true, tagInline: false, adjustTagSize: false, onSearch: noop, onSearchClear: noop, hasArrow: true, onRemove: noop, // highlightFirstItem: true, valueRender: function valueRender(item) { return item.label || item.value; }, onKeyDown: noop, onFocus: noop, onBlur: noop, onMouseEnter: noop, onMouseLeave: noop, popupAutoFocus: false, tagClosable: true }), _class.displayName = 'Select', _temp); exports.default = (0, _reactLifecyclesCompat.polyfill)(Select); module.exports = exports['default'];