UNPKG

42.5 kBJavaScriptView Raw
1'use strict';
2
3exports.__esModule = true;
4
5var _typeof2 = require('babel-runtime/helpers/typeof');
6
7var _typeof3 = _interopRequireDefault(_typeof2);
8
9var _extends2 = require('babel-runtime/helpers/extends');
10
11var _extends3 = _interopRequireDefault(_extends2);
12
13var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
14
15var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
16
17var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
18
19var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
20
21var _inherits2 = require('babel-runtime/helpers/inherits');
22
23var _inherits3 = _interopRequireDefault(_inherits2);
24
25var _class, _temp; /* eslint-disable valid-jsdoc */
26
27
28var _react = require('react');
29
30var _react2 = _interopRequireDefault(_react);
31
32var _propTypes = require('prop-types');
33
34var _propTypes2 = _interopRequireDefault(_propTypes);
35
36var _classnames = require('classnames');
37
38var _classnames2 = _interopRequireDefault(_classnames);
39
40var _reactLifecyclesCompat = require('react-lifecycles-compat');
41
42var _util = require('../util');
43
44var _tag = require('../tag');
45
46var _tag2 = _interopRequireDefault(_tag);
47
48var _input = require('../input');
49
50var _input2 = _interopRequireDefault(_input);
51
52var _icon = require('../icon');
53
54var _icon2 = _interopRequireDefault(_icon);
55
56var _zhCn = require('../locale/zh-cn');
57
58var _zhCn2 = _interopRequireDefault(_zhCn);
59
60var _base = require('./base');
61
62var _base2 = _interopRequireDefault(_base);
63
64var _util2 = require('./util');
65
66function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
67
68var bindCtx = _util.func.bindCtx,
69 noop = _util.func.noop;
70
71var isIE9 = _util.env.ieVersion === 9;
72
73/**
74 * 无障碍化注意事项:
75 * 1. Select 无搜索情况下,不应该让 Input 可focus,此时外层wrap必须可focus,并且需要相应focus事件让外边框发生变化
76 *
77 * TODO: hightLight 后续改造注意点
78 * 1. hightLight 跟随点击变化(fixed) 2. 弹窗打开时根据 是否高亮第一个选项的 api开关设置是否hightLight 第一项
79 */
80
81// 自定义弹层:1. 不需要关心Menu的点击事件 2. 不需要关心dataSource变化
82
83/**
84 * Select
85 */
86var Select = (_temp = _class = function (_Base) {
87 (0, _inherits3.default)(Select, _Base);
88
89 function Select(props) {
90 (0, _classCallCheck3.default)(this, Select);
91
92 // because dataSource maybe updated while select a item, so we should cache choosen value's item
93 var _this = (0, _possibleConstructorReturn3.default)(this, _Base.call(this, props));
94
95 _this.handleWrapClick = function (e) {
96 // ignore click on input to choose text
97 if (e.target.nodeName !== 'INPUT') {
98 e.preventDefault();
99 }
100 _this.focusInput();
101 };
102
103 _this.handleArrowClick = function (e) {
104 e.preventDefault();
105 _this.focusInput();
106
107 // because of can not close Popup by click Input while hasSearch.
108 // so when Popup open and hasSearch, we should close Popup intentionally
109 _this.state.visible && _this.hasSearch() && _this.setVisible(false);
110 };
111
112 _this.handleClear = function (e) {
113 e.stopPropagation();
114 _this.selectAllYet = false;
115 _this.handleChange(undefined, 'clear');
116 };
117
118 _this.valueDataSource = {
119 valueDS: [], // [{value,label}]
120 mapValueDS: {} // {value: {value,label}}
121 };
122
123 var searchValue = 'searchValue' in props ? props.searchValue : '';
124
125 _this.dataStore.setOptions({
126 key: searchValue,
127 addonKey: props.mode === 'tag' // tag 模式手动输入的数据
128 });
129
130 (0, _extends3.default)(_this.state, {
131 searchValue: searchValue,
132 dataSource: _this.setDataSource(props)
133 });
134
135 // 根据value和计算后的dataSource,更新value对应的详细数据valueDataSource
136 if (typeof _this.state.value !== 'undefined') {
137 _this.valueDataSource = (0, _util2.getValueDataSource)(_this.state.value, _this.valueDataSource.mapValueDS, _this.dataStore.getMapDS());
138 }
139
140 bindCtx(_this, ['handleMenuSelect', 'handleItemClick', 'handleSearch', 'handleSearchKeyDown', 'handleSelectAll', 'maxTagPlaceholder']);
141 return _this;
142 }
143
144 Select.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
145 var state = {};
146
147 if ('value' in nextProps && nextProps.value !== prevState.value) {
148 (0, _extends3.default)(state, {
149 value: nextProps.value
150 });
151 }
152
153 if ('highlightKey' in nextProps && nextProps.highlightKey !== prevState.highlightKey) {
154 (0, _extends3.default)(state, {
155 highlightKey: nextProps.highlightKey
156 });
157 } else if ('value' in nextProps && nextProps.value !== prevState.value && nextProps.mode === 'single') {
158 (0, _extends3.default)(state, {
159 highlightKey: nextProps.value
160 });
161 }
162
163 if ('searchValue' in nextProps && nextProps.searchValue !== prevState.searchValue) {
164 var searchValue = nextProps.searchValue;
165 (0, _extends3.default)(state, {
166 searchValue: searchValue === undefined || searchValue === null ? '' : searchValue
167 });
168 }
169
170 if ('visible' in nextProps && nextProps.visible !== prevState.visible) {
171 (0, _extends3.default)(state, {
172 visible: nextProps.visible
173 });
174 }
175
176 if (Object.keys(state).length) {
177 return state;
178 }
179
180 return null;
181 };
182
183 Select.prototype.componentDidUpdate = function componentDidUpdate(prevProps, prevState) {
184 var props = this.props;
185 if ('searchValue' in props && this.state.searchValue !== prevState.searchValue) {
186 this.dataStore.setOptions({ key: this.state.searchValue });
187 }
188
189 if (props.mode !== prevProps.mode) {
190 this.dataStore.setOptions({
191 addonKey: props.mode === 'tag'
192 });
193 }
194 if (props.mode !== prevProps.mode) {
195 this.dataStore.setOptions({
196 addonKey: props.mode === 'tag'
197 });
198 }
199 if (props.filter !== prevProps.filter) {
200 this.dataStore.setOptions({
201 filter: props.filter
202 });
203 }
204 if (props.filterLocal !== prevProps.filterLocal) {
205 this.dataStore.setOptions({
206 filterLocal: props.filterLocal
207 });
208 }
209
210 if (prevProps.children !== props.children || prevProps.dataSource !== props.dataSource) {
211 /* eslint-disable react/no-did-update-set-state */
212 this.setState({
213 dataSource: this.setDataSource(props)
214 });
215
216 if (!props.popupContent) {
217 this.setFirstHightLightKeyForMenu(this.state.searchValue);
218 }
219 }
220
221 if ('value' in props) {
222 this.valueDataSource = (0, _util2.getValueDataSource)(props.value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS());
223 this.updateSelectAllYet(this.valueDataSource.value);
224 } else if ('defaultValue' in props && props.defaultValue === this.valueDataSource.value && (props.children !== prevProps.children || props.dataSource !== prevProps.dataSource)) {
225 // has defaultValue and value not changed and dataSource changed
226 // fix: set defaultValue first, then update dataSource.
227 this.valueDataSource = (0, _util2.getValueDataSource)(props.defaultValue, this.valueDataSource.mapValueDS, this.dataStore.getMapDS());
228 }
229
230 if (prevProps.label !== this.props.label || prevState.value !== this.state.value || props.searchValue !== this.state.searchValue) {
231 this.syncWidth();
232 }
233 };
234
235 Select.prototype.componentDidMount = function componentDidMount() {
236 if (isIE9) {
237 this.ie9Hack();
238 }
239 _Base.prototype.componentDidMount.call(this);
240 };
241
242 // ie9 下 table-cell 布局不支持宽度超出隐藏
243
244
245 Select.prototype.ie9Hack = function ie9Hack() {
246 try {
247 var width = this.selectDOM.currentStyle.width;
248 this.setState({
249 fixWidth: width !== 'auto'
250 });
251 } catch (e) {
252 //
253 }
254 };
255
256 Select.prototype.useDetailValue = function useDetailValue() {
257 var _props = this.props,
258 popupContent = _props.popupContent,
259 useDetailValue = _props.useDetailValue,
260 dataSource = _props.dataSource;
261
262 return useDetailValue || popupContent && !dataSource;
263 };
264
265 Select.prototype.hasSearch = function hasSearch() {
266 var _props2 = this.props,
267 showSearch = _props2.showSearch,
268 mode = _props2.mode;
269
270 return showSearch || mode === 'tag';
271 };
272
273 Select.prototype.getTagSize = function getTagSize() {
274 var _props3 = this.props,
275 size = _props3.size,
276 adjustTagSize = _props3.adjustTagSize;
277
278 if (adjustTagSize) {
279 return size;
280 }
281 return size === 'large' ? 'medium' : 'small';
282 };
283
284 /**
285 * Menu.Item onSelect
286 * @private
287 * @param {Array<string>} keys
288 * @
289 */
290
291
292 Select.prototype.handleMenuSelect = function handleMenuSelect(keys, item) {
293 var _props4 = this.props,
294 mode = _props4.mode,
295 readOnly = _props4.readOnly,
296 disabled = _props4.disabled;
297
298
299 if (readOnly || disabled) {
300 return false;
301 }
302
303 var isSingle = mode === 'single';
304
305 if (isSingle) {
306 // 单选
307 return this.handleSingleSelect(keys[0], 'itemClick');
308 } else {
309 // 正常多选
310 return this.handleMultipleSelect(keys, 'itemClick', item.props && item.props._key);
311 }
312 };
313
314 Select.prototype.handleItemClick = function handleItemClick(key) {
315 if (!this.props.popupAutoFocus) {
316 this.focusInput();
317 }
318
319 if (this.props.mode === 'single' && key === this.state.value) {
320 this.setVisible(false, 'itemClick');
321 }
322 };
323
324 /**
325 * 单选模式
326 */
327
328
329 Select.prototype.handleSingleSelect = function handleSingleSelect(key, triggerType) {
330 // TODO: 这里 cacheValue=false 有问题,dataSource 更新的时候就应该处理
331 var cacheValue = this.props.cacheValue;
332 // get data only from dataStore while cacheValue=false
333
334 var itemObj = (0, _util2.getValueDataSource)(key, cacheValue ? this.valueDataSource.mapValueDS : {}, this.dataStore.getMapDS());
335 this.valueDataSource = itemObj;
336
337 this.setVisible(false, triggerType);
338
339 // 应在return之前传出highlightKey
340 this.setState({
341 highlightKey: key
342 });
343
344 if (this.useDetailValue()) {
345 return this.handleChange(itemObj.valueDS, triggerType);
346 } else {
347 this.handleChange(itemObj.value, triggerType, itemObj.valueDS);
348 }
349
350 // 清空搜索
351 if (!('searchValue' in this.props) && this.state.searchValue) {
352 this.handleSearchClear(triggerType);
353 }
354 };
355
356 /**
357 * 多选模式 multiple/tag
358 */
359
360
361 Select.prototype.handleMultipleSelect = function handleMultipleSelect(keys, triggerType, key, keepSearchValue) {
362 var _this2 = this;
363
364 var itemObj = (0, _util2.getValueDataSource)(keys, this.valueDataSource.mapValueDS, this.dataStore.getMapDS());
365
366 var _props5 = this.props,
367 cacheValue = _props5.cacheValue,
368 mode = _props5.mode,
369 hiddenSelected = _props5.hiddenSelected;
370
371 // cache those value maybe not exists in dataSource
372
373 if (cacheValue || mode === 'tag') {
374 this.valueDataSource = itemObj;
375 }
376
377 if (hiddenSelected) {
378 this.setVisible(false, triggerType);
379 }
380
381 // 因为搜索后会设置 hightLight 为第一个item,menu渲染会自动滚动到 hightLight 的元素上面。
382 // 所以设置 hightLight 为当前选中项避免滚动
383 key && this.state.visible && this.setState({
384 highlightKey: key
385 });
386
387 if (this.useDetailValue()) {
388 this.handleChange(itemObj.valueDS, triggerType);
389 } else {
390 this.handleChange(itemObj.value, triggerType, itemObj.valueDS);
391 }
392
393 this.updateSelectAllYet(itemObj.value);
394
395 // 清空搜索
396 if (!('searchValue' in this.props) && this.state.searchValue && !keepSearchValue) {
397 // 因为 SearchValue 被 clear 后会重新渲染 Menu,所以在 Overlay 检测 safeNode 的时候 e.target 可能会找不到导致弹窗关闭
398 setTimeout(function () {
399 _this2.handleSearchClear(triggerType);
400 });
401 }
402 };
403
404 Select.prototype.updateSelectAllYet = function updateSelectAllYet(value) {
405 var _this3 = this;
406
407 // multiple mode
408 // is current state select all or not
409 this.selectAllYet = false;
410 if (this.props.hasSelectAll && Array.isArray(value)) {
411 var selectAllValues = this.dataStore.getEnableDS().map(function (item) {
412 return item.value;
413 });
414
415 if (selectAllValues.length <= value.length) {
416 this.selectAllYet = true;
417
418 selectAllValues.forEach(function (val) {
419 if (value.indexOf(val) === -1) {
420 _this3.selectAllYet = false;
421 return;
422 }
423 });
424 }
425 }
426 };
427
428 Select.prototype.handleSearchValue = function handleSearchValue(value) {
429 if (this.state.searchValue === value) {
430 return;
431 }
432
433 var filterLocal = this.props.filterLocal;
434
435
436 if (filterLocal) {
437 if (!('searchValue' in this.props)) {
438 this.setState({
439 searchValue: value,
440 dataSource: this.dataStore.updateByKey(value)
441 });
442 this.setFirstHightLightKeyForMenu(value);
443 }
444 } else if (!('searchValue' in this.props)) {
445 this.setState({
446 searchValue: value
447 });
448 }
449 };
450
451 /**
452 * Handle search input change event
453 * @param {String} value search text
454 * @param {Event} e change Event
455 */
456
457
458 Select.prototype.handleSearch = function handleSearch(value, e) {
459 this.handleSearchValue(value);
460
461 // inputing should trigger popup open
462 if (!this.state.visible && value) {
463 this.setVisible(true);
464 }
465
466 this.props.onSearch(value, e);
467 };
468
469 Select.prototype.handleSearchClear = function handleSearchClear(triggerType) {
470 this.handleSearchValue('');
471 this.props.onSearchClear(triggerType);
472 };
473
474 // 搜索框 keyDown 事件
475
476
477 Select.prototype.handleSearchKeyDown = function handleSearchKeyDown(e) {
478 var _props6 = this.props,
479 popupContent = _props6.popupContent,
480 onKeyDown = _props6.onKeyDown,
481 showSearch = _props6.showSearch,
482 mode = _props6.mode,
483 hasClear = _props6.hasClear,
484 onToggleHighlightItem = _props6.onToggleHighlightItem,
485 readOnly = _props6.readOnly,
486 disabled = _props6.disabled;
487
488
489 var hasSearch = this.hasSearch();
490
491 if (popupContent) {
492 // 搜索的时候不阻止冒泡会无法输入
493 if (hasSearch && e.keyCode === _util.KEYCODE.SPACE) {
494 e.stopPropagation();
495 }
496 return onKeyDown(e);
497 }
498
499 var proxy = 'search';
500
501 switch (e.keyCode) {
502 case _util.KEYCODE.UP:
503 e.preventDefault();
504 onToggleHighlightItem(this.toggleHighlightItem(-1, e), 'up');
505 break;
506 case _util.KEYCODE.DOWN:
507 e.preventDefault();
508 onToggleHighlightItem(this.toggleHighlightItem(1, e), 'down');
509 break;
510 case _util.KEYCODE.ENTER:
511 e.preventDefault();
512 if (readOnly || disabled) {
513 break;
514 }
515 this.chooseHighlightItem(proxy, e);
516 break;
517 case _util.KEYCODE.ESC:
518 e.preventDefault();
519 this.state.visible && this.setVisible(false, 'keyDown');
520 break;
521 case _util.KEYCODE.SPACE:
522 e.stopPropagation();
523 !hasSearch && e.preventDefault();
524 break;
525 case _util.KEYCODE.BACKSPACE:
526 if (readOnly || disabled) {
527 break;
528 }
529 if (mode === 'multiple' && showSearch || mode === 'tag') {
530 // 在多选并且有搜索的情况下,删除最后一个 tag
531 var valueDS = this.valueDataSource.valueDS;
532 if (valueDS && valueDS.length && !valueDS[valueDS.length - 1].disabled) {
533 this.handleDeleteTag(e);
534 }
535 } else if (mode === 'single' && hasClear && !this.state.visible) {
536 // 单选、非展开、并且可清除的情况,允许按删除键清除
537 this.handleClear(e);
538 }
539 break;
540 default:
541 break;
542 }
543
544 onKeyDown(e);
545 };
546
547 Select.prototype.chooseMultipleItem = function chooseMultipleItem(key) {
548 var value = this.state.value || [];
549 var keys = value.map(function (v) {
550 return (0, _util2.valueToSelectKey)(v);
551 });
552
553 var keepSearchValue = false;
554
555 var index = keys.map(function (v) {
556 return '' + v;
557 }).indexOf(key);
558
559 if (index > -1) {
560 // unselect
561 keys.splice(index, 1);
562 keepSearchValue = true; // 回车反选保留搜索值
563 } else {
564 // select
565 keys.push(key);
566 }
567
568 this.handleMultipleSelect(keys, 'enter', null, keepSearchValue);
569 };
570
571 // 回车 选择高亮的 item
572
573
574 Select.prototype.chooseHighlightItem = function chooseHighlightItem(proxy, e) {
575 var mode = this.props.mode;
576
577
578 if (!this.state.visible) {
579 // input tag by itself
580 if (mode === 'tag' && this.state.searchValue) {
581 this.chooseMultipleItem(this.state.searchValue);
582 }
583 return false;
584 }
585
586 var highlightKey = this.state.highlightKey;
587
588 // 没有高亮选项 或者 没有可选菜单
589
590 if (highlightKey === null || !this.dataStore.getMenuDS().length) {
591 return;
592 }
593
594 if (mode === 'single') {
595 this.handleSingleSelect(highlightKey, 'enter');
596 } else {
597 this.chooseMultipleItem(highlightKey);
598 // 阻止事件冒泡到最外层,让Popup 监听到触发弹层关闭
599 e && e.stopPropagation();
600 }
601 };
602
603 /**
604 * Handle Tag close event
605 * @param {Object} item
606 * @return {Boolean} false return false to prevent auto close
607 * ----
608 * It MUST be multiple mode, needn't additional judgement
609 */
610
611
612 Select.prototype.handleTagClose = function handleTagClose(item) {
613 var readOnly = this.props.readOnly;
614
615 if (readOnly) return false;
616 if (this.useDetailValue()) {
617 var value = this.state.value.filter(function (v) {
618 return item.value !== v.value;
619 });
620
621 this.handleChange(value, 'tag');
622 } else {
623 // filter out current item, and then call handleMenuSelect
624 var _value = this.state.value.filter(function (v) {
625 return item.value !== v;
626 });
627
628 this.handleMultipleSelect(_value, 'tag');
629 }
630
631 this.props.onRemove(item);
632
633 // prevent tag close
634 return false;
635 };
636
637 // eslint-disable-next-line valid-jsdoc
638 /**
639 * Handle BACKSPACE key event
640 * @param {Event} e keyDown event
641 * ---
642 * It MUST be multiple mode
643 */
644
645
646 Select.prototype.handleDeleteTag = function handleDeleteTag(e) {
647 var value = this.state.value;
648 var searchValue = this.state.searchValue;
649
650 if (searchValue || !value || !value.length) {
651 return false;
652 }
653
654 e.preventDefault();
655
656 var nextValues = value.slice(0, value.length - 1);
657 // 手动调用 handleMenuSelect 时直接传入原生的 value,可以减少 toString 的操作
658
659 if (this.useDetailValue()) {
660 this.handleChange(nextValues, 'tag');
661 } else {
662 this.handleMultipleSelect(nextValues, 'tag');
663 }
664 };
665
666 /**
667 * Handle SelectAll span click event
668 * @param {Event} e click event
669 */
670
671
672 Select.prototype.handleSelectAll = function handleSelectAll(e) {
673 e && e.preventDefault();
674 var nextValues = void 0;
675
676 if (this.selectAllYet) {
677 nextValues = [];
678 } else {
679 nextValues = this.dataStore.getEnableDS().map(function (item) {
680 return item.value;
681 });
682 }
683
684 // 直接传 values,减少 toString 操作
685 this.handleMultipleSelect(nextValues, 'selectAll');
686 };
687
688 Select.prototype.handleVisibleChange = function handleVisibleChange(visible, type) {
689 this.setVisible(visible, type);
690 };
691
692 Select.prototype.afterClose = function afterClose() {
693 // 关闭的时候清空搜索值
694 if (this.hasSearch()) {
695 this.handleSearchClear('popupClose');
696 }
697 };
698
699 Select.prototype.maxTagPlaceholder = function maxTagPlaceholder(selectedValues, totalValues) {
700 var locale = this.props.locale;
701
702
703 return '' + _util.str.template(locale.maxTagPlaceholder, {
704 selected: selectedValues.length,
705 total: totalValues.length
706 });
707 };
708
709 /**
710 * 如果用户是自定义的弹层,则直接以 value 为准,不再校验 dataSource
711 * TODO: 2.0 中 value 接受 string/object{value,label} 两种类型的数据,自动做识别,可以避免用户去转换,也和 date-picker 对齐
712 * 此外 onChange 第一个参数根据 api 来控制类型是 [string] 还是 [object{value,label}]
713 * @param {object} props
714 */
715
716
717 Select.prototype.renderValues = function renderValues() {
718 var _this4 = this;
719
720 var _props7 = this.props,
721 prefix = _props7.prefix,
722 mode = _props7.mode,
723 valueRender = _props7.valueRender,
724 fillProps = _props7.fillProps,
725 disabled = _props7.disabled,
726 maxTagCount = _props7.maxTagCount,
727 maxTagPlaceholder = _props7.maxTagPlaceholder,
728 tagInline = _props7.tagInline,
729 tagClosable = _props7.tagClosable;
730
731 var tagSize = this.getTagSize();
732 var value = this.state.value;
733
734 if ((0, _util2.isNull)(value)) {
735 return null;
736 }
737
738 // get detail value
739 if (!this.useDetailValue()) {
740 if (value === this.valueDataSource.value) {
741 value = this.valueDataSource.valueDS;
742 } else {
743 value = (0, _util2.getValueDataSource)(value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()).valueDS;
744 }
745 }
746
747 if (mode === 'single') {
748 if (!value) {
749 return null;
750 }
751
752 var retvalue = fillProps && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object' && fillProps in value ? value[fillProps] : valueRender(value);
753 // 0 => '0'
754 return typeof retvalue === 'number' ? retvalue.toString() : retvalue;
755 } else if (value) {
756 var limitedCountValue = value;
757 var maxTagPlaceholderEl = void 0;
758 var totalValue = this.dataStore.getFlattenDS();
759 var holder = 'maxTagPlaceholder' in this.props ? maxTagPlaceholder : this.maxTagPlaceholder;
760
761 if (maxTagCount !== undefined && value.length > maxTagCount && !tagInline) {
762 limitedCountValue = limitedCountValue.slice(0, maxTagCount);
763 maxTagPlaceholderEl = _react2.default.createElement(
764 _tag2.default,
765 { key: '_count', type: 'primary', size: tagSize, animation: false },
766 holder(value, totalValue)
767 );
768 }
769
770 if (value.length > 0 && tagInline) {
771 maxTagPlaceholderEl = _react2.default.createElement(
772 'div',
773 { className: prefix + 'select-tag-compact', key: '_count' },
774 holder(value, totalValue)
775 );
776 }
777
778 value = limitedCountValue;
779 if (!Array.isArray(value)) {
780 value = [value];
781 }
782
783 var selectedValueNodes = value.map(function (v) {
784 if (!v) {
785 return null;
786 }
787 var labelNode = fillProps ? v[fillProps] : valueRender(v);
788
789 return _react2.default.createElement(
790 _tag2.default,
791 {
792 key: v.value,
793 disabled: disabled || v.disabled,
794 type: 'primary',
795 size: tagSize,
796 animation: false,
797 onClose: _this4.handleTagClose.bind(_this4, v),
798 closable: tagClosable
799 },
800 labelNode
801 );
802 });
803
804 if (maxTagPlaceholderEl) {
805 if (tagInline) {
806 selectedValueNodes.unshift(maxTagPlaceholderEl);
807 } else {
808 selectedValueNodes.push(maxTagPlaceholderEl);
809 }
810 }
811 return selectedValueNodes;
812 }
813
814 return null;
815 };
816 /**
817 * 1. fix flash while click <label/>
818 * 2. fix onBlur while has clear
819 * @returns
820 */
821
822
823 Select.prototype.hasClear = function hasClear() {
824 var _props8 = this.props,
825 hasClear = _props8.hasClear,
826 readOnly = _props8.readOnly,
827 disabled = _props8.disabled,
828 showSearch = _props8.showSearch;
829 var _state = this.state,
830 value = _state.value,
831 visible = _state.visible;
832
833
834 return typeof value !== 'undefined' && value !== null && hasClear && !readOnly && !disabled && !(showSearch && visible);
835 };
836
837 /**
838 * render arrow
839 * @param {object} props
840 * @param {function} [clickHandler]
841 */
842
843
844 Select.prototype.renderExtraNode = function renderExtraNode() {
845 var _props9 = this.props,
846 hasArrow = _props9.hasArrow,
847 hasClear = _props9.hasClear,
848 prefix = _props9.prefix;
849
850
851 var ret = [];
852
853 if (hasArrow) {
854 ret.push(_react2.default.createElement(
855 'span',
856 { key: 'arrow', 'aria-hidden': true, onClick: this.handleArrowClick, className: prefix + 'select-arrow' },
857 _react2.default.createElement(_icon2.default, { type: 'arrow-down', className: prefix + 'select-symbol-fold' })
858 ));
859 }
860
861 // do not use this.hasClear() here, to make sure clear btn always exists, can not influenced by apis like `disabled` `readOnly`
862 if (hasClear) {
863 ret.push(_react2.default.createElement(
864 'span',
865 { key: 'clear', 'aria-hidden': true, onClick: this.handleClear, className: prefix + 'select-clear' },
866 _react2.default.createElement(_icon2.default, { type: 'delete-filling' })
867 ));
868 }
869
870 return ret;
871 };
872
873 /**
874 * 选择器
875 * @override
876 * @param {object} props
877 */
878
879
880 Select.prototype.renderSelect = function renderSelect() {
881 var _classNames,
882 _this5 = this;
883
884 var _props10 = this.props,
885 prefix = _props10.prefix,
886 showSearch = _props10.showSearch,
887 placeholder = _props10.placeholder,
888 mode = _props10.mode,
889 size = _props10.size,
890 className = _props10.className,
891 style = _props10.style,
892 readOnly = _props10.readOnly,
893 disabled = _props10.disabled,
894 hasBorder = _props10.hasBorder,
895 label = _props10.label,
896 locale = _props10.locale,
897 state = _props10.state,
898 onBlur = _props10.onBlur,
899 onFocus = _props10.onFocus,
900 onMouseEnter = _props10.onMouseEnter,
901 onMouseLeave = _props10.onMouseLeave,
902 rtl = _props10.rtl;
903
904 var others = _util.obj.pickOthers(Select.propTypes, this.props);
905 var othersData = _util.obj.pickAttrsWith(others, 'data-');
906
907 var visible = this.state.visible;
908 var isSingle = mode === 'single';
909 var hasSearch = this.hasSearch();
910 var valueNodes = this.renderValues();
911
912 // compatible with selectPlaceHolder. TODO: removed in 2.0 version
913 var _placeholder = placeholder || locale.selectPlaceholder || locale.selectPlaceHolder;
914 if (valueNodes && valueNodes.length) {
915 _placeholder = null;
916 }
917
918 // 弹窗展开时将当前的值作为 placeholder,这个功能的前提是 valueNode 必须是一个字符串
919 if (showSearch && visible && isSingle && typeof valueNodes === 'string') {
920 _placeholder = valueNodes;
921 }
922
923 // 下拉箭头
924 var extra = this.renderExtraNode();
925
926 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));
927
928 var valuetext = this.valueDataSource.valueDS ? this.valueDataSource.valueDS.label : '';
929 return _react2.default.createElement(
930 'span',
931 (0, _extends3.default)({}, othersData, {
932 className: triggerClazz,
933 style: style,
934 dir: rtl ? 'rtl' : undefined,
935 ref: this.saveSelectRef,
936 onClick: this.handleWrapClick,
937 onMouseEnter: onMouseEnter,
938 onMouseLeave: onMouseLeave,
939 onMouseDown: this.handleWrapClick
940 }),
941 _react2.default.createElement(_input2.default, (0, _extends3.default)({
942 'aria-valuetext': valuetext
943 }, _util.obj.pickOthers(othersData, others), {
944 role: 'combobox',
945 tabIndex: 0,
946 'aria-expanded': this.state.visible,
947 'aria-disabled': disabled,
948 state: state,
949 label: label,
950 extra: extra,
951 value: this.state.searchValue,
952 size: size,
953 readOnly: !this.hasSearch() || readOnly,
954 disabled: disabled,
955 placeholder: _placeholder,
956 hasBorder: hasBorder,
957 hasClear: false,
958 htmlSize: '1',
959 inputRender: function inputRender(inputEl) {
960 return _this5.renderSearchInput(valueNodes, _placeholder, inputEl);
961 },
962 onChange: this.handleSearch,
963 onKeyDown: this.handleSearchKeyDown,
964 onFocus: onFocus,
965 onBlur: onBlur,
966 className: prefix + 'select-inner',
967 ref: this.saveInputRef
968 })),
969 _react2.default.createElement(
970 'span',
971 { className: prefix + 'sr-only', 'aria-live': 'polite' },
972 this.state.srReader
973 )
974 );
975 };
976
977 Select.prototype.renderSearchInput = function renderSearchInput(valueNodes, placeholder, inputEl) {
978 var _classNames2;
979
980 var _props11 = this.props,
981 prefix = _props11.prefix,
982 mode = _props11.mode,
983 tagInline = _props11.tagInline;
984
985 var isSingle = mode === 'single';
986
987 var mirrorText = this.state.searchValue;
988
989 var cls = (0, _classnames2.default)((_classNames2 = {}, _classNames2[prefix + 'select-values'] = true, _classNames2[prefix + 'input-text-field'] = true, _classNames2[prefix + 'select-compact'] = !isSingle && tagInline, _classNames2));
990 var title = typeof valueNodes === 'string' ? valueNodes : '';
991 var searchInput = [isSingle && valueNodes ? _react2.default.createElement(
992 'em',
993 { title: title, key: 'select-value' },
994 valueNodes
995 ) : valueNodes];
996 var triggerSearch = _react2.default.createElement(
997 'span',
998 { key: 'trigger-search', className: prefix + 'select-trigger-search' },
999 inputEl,
1000 _react2.default.createElement(
1001 'span',
1002 { 'aria-hidden': true },
1003 _react2.default.createElement(
1004 'span',
1005 null,
1006 mirrorText || placeholder
1007 ),
1008 _react2.default.createElement(
1009 'span',
1010 { style: { display: 'inline-block', width: 1 } },
1011 '\xA0'
1012 )
1013 )
1014 );
1015
1016 if (!isSingle && tagInline) {
1017 searchInput.unshift(triggerSearch);
1018 } else {
1019 searchInput.push(triggerSearch);
1020 }
1021
1022 return _react2.default.createElement(
1023 'span',
1024 { className: cls },
1025 searchInput
1026 );
1027 };
1028
1029 /**
1030 * 渲染弹层的 header 内容
1031 * @override
1032 * @param {object} props
1033 */
1034
1035
1036 Select.prototype.renderMenuHeader = function renderMenuHeader() {
1037 var _classNames3, _classNames4;
1038
1039 var _props12 = this.props,
1040 prefix = _props12.prefix,
1041 hasSelectAll = _props12.hasSelectAll,
1042 mode = _props12.mode,
1043 locale = _props12.locale,
1044 menuProps = _props12.menuProps;
1045
1046
1047 if (menuProps && 'header' in menuProps) {
1048 return menuProps.header;
1049 }
1050
1051 var sourceCount = this.dataStore.getEnableDS().length;
1052 // 多选模式下才有全选
1053 if (!hasSelectAll || mode === 'single' || !sourceCount) {
1054 return null;
1055 }
1056
1057 var text = typeof hasSelectAll === 'boolean' ? locale.selectAll : hasSelectAll;
1058
1059 var selectAllYet = this.selectAllYet;
1060
1061 var cls = (0, _classnames2.default)((_classNames3 = {}, _classNames3[prefix + 'select-all'] = true, _classNames3[prefix + 'selected'] = selectAllYet, _classNames3));
1062
1063 var clsInner = (0, _classnames2.default)((_classNames4 = {}, _classNames4[prefix + 'select-all-inner'] = true, _classNames4));
1064
1065 // remove style={{'lineHeight': 'unset'}} in next Y
1066 // remove style={{'display': 'none'}} in next Y
1067 return _react2.default.createElement(
1068 'div',
1069 { key: 'all', onClick: this.handleSelectAll, className: cls, style: { lineHeight: 'unset' } },
1070 selectAllYet ? _react2.default.createElement(_icon2.default, { className: prefix + 'menu-icon-selected', style: { display: 'none' }, type: 'select' }) : null,
1071 _react2.default.createElement(
1072 'span',
1073 { className: clsInner },
1074 text
1075 )
1076 );
1077 };
1078
1079 Select.prototype.render = function render() {
1080 var mode = this.props.mode;
1081
1082 var props = (0, _extends3.default)({}, this.props);
1083
1084 // forbid to close Popup by click Input while hasSearch
1085 if (this.hasSearch()) {
1086 props.canCloseByTrigger = false;
1087 }
1088 if (mode === 'single') {
1089 props.cache = true;
1090 }
1091 return _Base.prototype.render.call(this, props);
1092 };
1093
1094 return Select;
1095}(_base2.default), _class.propTypes = (0, _extends3.default)({}, _base2.default.propTypes, {
1096 /**
1097 * 选择器模式
1098 */
1099 mode: _propTypes2.default.oneOf(['single', 'multiple', 'tag']),
1100 /**
1101 * 当前值,用于受控模式
1102 */
1103 value: _propTypes2.default.any,
1104 /**
1105 * 初始的默认值
1106 */
1107 defaultValue: _propTypes2.default.any,
1108 /**
1109 * Select发生改变时触发的回调
1110 * @param {*} value 选中的值
1111 * @param {String} actionType 触发的方式, 'itemClick', 'enter', 'tag'
1112 * @param {*} item 选中的值的对象数据 (useDetailValue=false有效)
1113 */
1114 onChange: _propTypes2.default.func,
1115 /**
1116 * 传入的数据源,可以动态渲染子项,详见 [dataSource的使用](#dataSource的使用)
1117 */
1118 dataSource: _propTypes2.default.arrayOf(_propTypes2.default.oneOfType([_propTypes2.default.shape({
1119 value: _propTypes2.default.any,
1120 label: _propTypes2.default.any,
1121 disabled: _propTypes2.default.bool,
1122 children: _propTypes2.default.array
1123 }), _propTypes2.default.bool, _propTypes2.default.number, _propTypes2.default.string])),
1124 /**
1125 * 是否有边框
1126 */
1127 hasBorder: _propTypes2.default.bool,
1128 /**
1129 * 是否有下拉箭头
1130 */
1131 hasArrow: _propTypes2.default.bool,
1132 /**
1133 * 展开后是否能搜索(tag 模式下固定为true)
1134 */
1135 showSearch: _propTypes2.default.bool,
1136 /**
1137 * 当搜索框值变化时回调
1138 * @param {String} value 数据
1139 */
1140 onSearch: _propTypes2.default.func,
1141 /**
1142 * 当搜索框值被(选择、弹窗关闭)导致清空时候的回调
1143 * @param {String} actionType 触发的方式, 'select'(选择清空), 'popupClose'(弹窗关闭清空)
1144 */
1145 onSearchClear: _propTypes2.default.func,
1146 /**
1147 * 多选模式下是否有全选功能
1148 */
1149 hasSelectAll: _propTypes2.default.oneOfType([_propTypes2.default.bool, _propTypes2.default.string]),
1150 /**
1151 * 填充到选择框里的值的 key
1152 */
1153 fillProps: _propTypes2.default.string,
1154 /**
1155 * value 使用对象类型 `{value, label}`, 同时 onChange 第一个参数返回也修改为 dataSource 中的对象
1156 */
1157 useDetailValue: _propTypes2.default.bool,
1158 /**
1159 * dataSource 变化的时是否保留已选的内容
1160 */
1161 cacheValue: _propTypes2.default.bool,
1162 /**
1163 * 渲染 Select 展现内容的方法
1164 * @param {Object} item 渲染节点的item
1165 * @return {ReactNode} 展现内容
1166 * @default item => `item.label || item.value`
1167 */
1168 valueRender: _propTypes2.default.func,
1169 /**
1170 * 渲染 MenuItem 内容的方法
1171 * @param {Object} item 渲染节点的item
1172 * @param {String} searchValue 搜索关键字(如果开启搜索)
1173 * @return {ReactNode} item node
1174 */
1175 itemRender: _propTypes2.default.func,
1176 /**
1177 * 弹层内容为空的文案
1178 */
1179 notFoundContent: _propTypes2.default.node,
1180 style: _propTypes2.default.object,
1181 /**
1182 * 受控搜索值,一般不需要设置
1183 * @type {[type]}
1184 */
1185 searchValue: _propTypes2.default.string,
1186 /**
1187 * 是否一行显示,仅在 mode 为 multiple 的时候生效
1188 * @version 1.15
1189 */
1190 tagInline: _propTypes2.default.bool,
1191 /**
1192 * tag 是否可关闭
1193 * @version 1.20
1194 */
1195 tagClosable: _propTypes2.default.bool,
1196 /**
1197 * tag 尺寸是否和 select 保持一致(mode=multiple/tag 模式生效),默认false
1198 * @version 1.24
1199 */
1200 adjustTagSize: _propTypes2.default.bool,
1201 /**
1202 * 最多显示多少个 tag
1203 * @version 1.15
1204 */
1205 maxTagCount: _propTypes2.default.number,
1206 /**
1207 * 隐藏多余 tag 时显示的内容,在 maxTagCount 生效时起作用
1208 * @param {object} selectedValues 当前已选中的元素
1209 * @param {object} totalValues 总待选元素
1210 * @version 1.15
1211 */
1212 maxTagPlaceholder: _propTypes2.default.func,
1213 /**
1214 * 选择后是否立即隐藏菜单 (mode=multiple/tag 模式生效)
1215 */
1216 hiddenSelected: _propTypes2.default.bool,
1217 /**
1218 * tag 删除回调
1219 * @param {object} item 渲染节点的item
1220 */
1221 onRemove: _propTypes2.default.func,
1222 /**
1223 * 焦点事件
1224 */
1225 onFocus: _propTypes2.default.func,
1226 /**
1227 * 是否自动高亮第一个选项
1228 */
1229 // highlightFirstItem: PropTypes.bool,
1230 /**
1231 * 失去焦点事件
1232 */
1233 onBlur: _propTypes2.default.func,
1234 onMouseEnter: _propTypes2.default.func,
1235 onMouseLeave: _propTypes2.default.func,
1236 onKeyDown: _propTypes2.default.func,
1237 locale: _propTypes2.default.object,
1238 /**
1239 * 展开下拉菜单时是否自动焦点到弹层
1240 */
1241 popupAutoFocus: _propTypes2.default.bool,
1242 /**
1243 * 是否展示 dataSource 中 children
1244 */
1245 showDataSourceChildren: _propTypes2.default.bool
1246}), _class.defaultProps = (0, _extends3.default)({}, _base2.default.defaultProps, {
1247 locale: _zhCn2.default.Select,
1248 mode: 'single',
1249 showSearch: false,
1250 cacheValue: true,
1251 tagInline: false,
1252 adjustTagSize: false,
1253 onSearch: noop,
1254 onSearchClear: noop,
1255 hasArrow: true,
1256 onRemove: noop,
1257 // highlightFirstItem: true,
1258 valueRender: function valueRender(item) {
1259 return item.label || item.value;
1260 },
1261 onKeyDown: noop,
1262 onFocus: noop,
1263 onBlur: noop,
1264 onMouseEnter: noop,
1265 onMouseLeave: noop,
1266 popupAutoFocus: false,
1267 tagClosable: true
1268}), _class.displayName = 'Select', _temp);
1269exports.default = (0, _reactLifecyclesCompat.polyfill)(Select);
1270module.exports = exports['default'];
\No newline at end of file