UNPKG

34.4 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
7Object.defineProperty(exports, "__esModule", {
8 value: true
9});
10exports.default = generateSelector;
11
12var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
14var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
15
16var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
17
18var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
19
20var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
21
22var React = _interopRequireWildcard(require("react"));
23
24var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode"));
25
26var _classnames = _interopRequireDefault(require("classnames"));
27
28var _useMergedState5 = _interopRequireDefault(require("rc-util/lib/hooks/useMergedState"));
29
30var _Selector = _interopRequireDefault(require("./Selector"));
31
32var _SelectTrigger = _interopRequireDefault(require("./SelectTrigger"));
33
34var _generator = require("./interface/generator");
35
36var _commonUtil = require("./utils/commonUtil");
37
38var _TransBtn = _interopRequireDefault(require("./TransBtn"));
39
40var _useLock3 = _interopRequireDefault(require("./hooks/useLock"));
41
42var _useDelayReset3 = _interopRequireDefault(require("./hooks/useDelayReset"));
43
44var _useLayoutEffect = _interopRequireDefault(require("./hooks/useLayoutEffect"));
45
46var _valueUtil = require("./utils/valueUtil");
47
48var _useSelectTriggerControl = _interopRequireDefault(require("./hooks/useSelectTriggerControl"));
49
50var _useCacheDisplayValue = _interopRequireDefault(require("./hooks/useCacheDisplayValue"));
51
52var _useCacheOptions = _interopRequireDefault(require("./hooks/useCacheOptions"));
53
54/**
55 * To match accessibility requirement, we always provide an input in the component.
56 * Other element will not set `tabIndex` to avoid `onBlur` sequence problem.
57 * For focused select, we set `aria-live="polite"` to update the accessibility content.
58 *
59 * ref:
60 * - keyboard: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role#Keyboard_interactions
61 */
62var DEFAULT_OMIT_PROPS = ['removeIcon', 'placeholder', 'autoFocus', 'maxTagCount', 'maxTagTextLength', 'maxTagPlaceholder', 'choiceTransitionName', 'onInputKeyDown'];
63/**
64 * This function is in internal usage.
65 * Do not use it in your prod env since we may refactor this.
66 */
67
68function generateSelector(config) {
69 var defaultPrefixCls = config.prefixCls,
70 OptionList = config.components.optionList,
71 convertChildrenToData = config.convertChildrenToData,
72 flattenOptions = config.flattenOptions,
73 getLabeledValue = config.getLabeledValue,
74 filterOptions = config.filterOptions,
75 isValueDisabled = config.isValueDisabled,
76 findValueOption = config.findValueOption,
77 warningProps = config.warningProps,
78 fillOptionsWithMissingValue = config.fillOptionsWithMissingValue,
79 omitDOMProps = config.omitDOMProps; // Use raw define since `React.FC` not support generic
80
81 function Select(props, ref) {
82 var _classNames2;
83
84 var _props$prefixCls = props.prefixCls,
85 prefixCls = _props$prefixCls === void 0 ? defaultPrefixCls : _props$prefixCls,
86 className = props.className,
87 id = props.id,
88 open = props.open,
89 defaultOpen = props.defaultOpen,
90 options = props.options,
91 children = props.children,
92 mode = props.mode,
93 value = props.value,
94 defaultValue = props.defaultValue,
95 labelInValue = props.labelInValue,
96 showSearch = props.showSearch,
97 inputValue = props.inputValue,
98 searchValue = props.searchValue,
99 filterOption = props.filterOption,
100 _props$optionFilterPr = props.optionFilterProp,
101 optionFilterProp = _props$optionFilterPr === void 0 ? 'value' : _props$optionFilterPr,
102 _props$autoClearSearc = props.autoClearSearchValue,
103 autoClearSearchValue = _props$autoClearSearc === void 0 ? true : _props$autoClearSearc,
104 onSearch = props.onSearch,
105 allowClear = props.allowClear,
106 clearIcon = props.clearIcon,
107 showArrow = props.showArrow,
108 inputIcon = props.inputIcon,
109 menuItemSelectedIcon = props.menuItemSelectedIcon,
110 disabled = props.disabled,
111 loading = props.loading,
112 defaultActiveFirstOption = props.defaultActiveFirstOption,
113 _props$notFoundConten = props.notFoundContent,
114 notFoundContent = _props$notFoundConten === void 0 ? 'Not Found' : _props$notFoundConten,
115 optionLabelProp = props.optionLabelProp,
116 backfill = props.backfill,
117 getInputElement = props.getInputElement,
118 getPopupContainer = props.getPopupContainer,
119 _props$listHeight = props.listHeight,
120 listHeight = _props$listHeight === void 0 ? 200 : _props$listHeight,
121 _props$listItemHeight = props.listItemHeight,
122 listItemHeight = _props$listItemHeight === void 0 ? 20 : _props$listItemHeight,
123 animation = props.animation,
124 transitionName = props.transitionName,
125 virtual = props.virtual,
126 dropdownStyle = props.dropdownStyle,
127 dropdownClassName = props.dropdownClassName,
128 dropdownMatchSelectWidth = props.dropdownMatchSelectWidth,
129 dropdownRender = props.dropdownRender,
130 dropdownAlign = props.dropdownAlign,
131 _props$showAction = props.showAction,
132 showAction = _props$showAction === void 0 ? [] : _props$showAction,
133 direction = props.direction,
134 tokenSeparators = props.tokenSeparators,
135 tagRender = props.tagRender,
136 onPopupScroll = props.onPopupScroll,
137 onDropdownVisibleChange = props.onDropdownVisibleChange,
138 onFocus = props.onFocus,
139 onBlur = props.onBlur,
140 onKeyUp = props.onKeyUp,
141 onKeyDown = props.onKeyDown,
142 onMouseDown = props.onMouseDown,
143 onChange = props.onChange,
144 onSelect = props.onSelect,
145 onDeselect = props.onDeselect,
146 onClear = props.onClear,
147 _props$internalProps = props.internalProps,
148 internalProps = _props$internalProps === void 0 ? {} : _props$internalProps,
149 restProps = (0, _objectWithoutProperties2.default)(props, ["prefixCls", "className", "id", "open", "defaultOpen", "options", "children", "mode", "value", "defaultValue", "labelInValue", "showSearch", "inputValue", "searchValue", "filterOption", "optionFilterProp", "autoClearSearchValue", "onSearch", "allowClear", "clearIcon", "showArrow", "inputIcon", "menuItemSelectedIcon", "disabled", "loading", "defaultActiveFirstOption", "notFoundContent", "optionLabelProp", "backfill", "getInputElement", "getPopupContainer", "listHeight", "listItemHeight", "animation", "transitionName", "virtual", "dropdownStyle", "dropdownClassName", "dropdownMatchSelectWidth", "dropdownRender", "dropdownAlign", "showAction", "direction", "tokenSeparators", "tagRender", "onPopupScroll", "onDropdownVisibleChange", "onFocus", "onBlur", "onKeyUp", "onKeyDown", "onMouseDown", "onChange", "onSelect", "onDeselect", "onClear", "internalProps"]);
150 var useInternalProps = internalProps.mark === _generator.INTERNAL_PROPS_MARK;
151 var domProps = omitDOMProps ? omitDOMProps(restProps) : restProps;
152 DEFAULT_OMIT_PROPS.forEach(function (prop) {
153 delete domProps[prop];
154 });
155 var containerRef = (0, React.useRef)(null);
156 var triggerRef = (0, React.useRef)(null);
157 var selectorRef = (0, React.useRef)(null);
158 var listRef = (0, React.useRef)(null);
159 var tokenWithEnter = (0, React.useMemo)(function () {
160 return (tokenSeparators || []).some(function (tokenSeparator) {
161 return ['\n', '\r\n'].includes(tokenSeparator);
162 });
163 }, [tokenSeparators]);
164 /** Used for component focused management */
165
166 var _useDelayReset = (0, _useDelayReset3.default)(),
167 _useDelayReset2 = (0, _slicedToArray2.default)(_useDelayReset, 3),
168 mockFocused = _useDelayReset2[0],
169 setMockFocused = _useDelayReset2[1],
170 cancelSetMockFocused = _useDelayReset2[2]; // Inner id for accessibility usage. Only work in client side
171
172
173 var _useState = (0, React.useState)(),
174 _useState2 = (0, _slicedToArray2.default)(_useState, 2),
175 innerId = _useState2[0],
176 setInnerId = _useState2[1];
177
178 (0, React.useEffect)(function () {
179 setInnerId("rc_select_".concat((0, _commonUtil.getUUID)()));
180 }, []);
181 var mergedId = id || innerId; // optionLabelProp
182
183 var mergedOptionLabelProp = optionLabelProp;
184
185 if (mergedOptionLabelProp === undefined) {
186 mergedOptionLabelProp = options ? 'label' : 'children';
187 } // labelInValue
188
189
190 var mergedLabelInValue = mode === 'combobox' ? false : labelInValue;
191 var isMultiple = mode === 'tags' || mode === 'multiple';
192 var mergedShowSearch = showSearch !== undefined ? showSearch : isMultiple || mode === 'combobox'; // ============================== Ref ===============================
193
194 var selectorDomRef = (0, React.useRef)(null);
195 React.useImperativeHandle(ref, function () {
196 return {
197 focus: selectorRef.current.focus,
198 blur: selectorRef.current.blur
199 };
200 }); // ============================= Value ==============================
201
202 var _useMergedState = (0, _useMergedState5.default)(defaultValue, {
203 value: value
204 }),
205 _useMergedState2 = (0, _slicedToArray2.default)(_useMergedState, 2),
206 mergedValue = _useMergedState2[0],
207 setMergedValue = _useMergedState2[1];
208 /** Unique raw values */
209
210
211 var mergedRawValue = (0, React.useMemo)(function () {
212 return (0, _commonUtil.toInnerValue)(mergedValue, {
213 labelInValue: mergedLabelInValue,
214 combobox: mode === 'combobox'
215 });
216 }, [mergedValue, mergedLabelInValue]);
217 /** We cache a set of raw values to speed up check */
218
219 var rawValues = (0, React.useMemo)(function () {
220 return new Set(mergedRawValue);
221 }, [mergedRawValue]); // ============================= Option =============================
222 // Set by option list active, it will merge into search input when mode is `combobox`
223
224 var _useState3 = (0, React.useState)(null),
225 _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
226 activeValue = _useState4[0],
227 setActiveValue = _useState4[1];
228
229 var _useState5 = (0, React.useState)(''),
230 _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
231 innerSearchValue = _useState6[0],
232 setInnerSearchValue = _useState6[1];
233
234 var mergedSearchValue = innerSearchValue;
235
236 if (mode === 'combobox' && mergedValue !== undefined) {
237 mergedSearchValue = mergedValue;
238 } else if (searchValue !== undefined) {
239 mergedSearchValue = searchValue;
240 } else if (inputValue) {
241 mergedSearchValue = inputValue;
242 }
243
244 var mergedOptions = (0, React.useMemo)(function () {
245 var newOptions = options;
246
247 if (newOptions === undefined) {
248 newOptions = convertChildrenToData(children);
249 }
250 /**
251 * `tags` should fill un-list item.
252 * This is not cool here since TreeSelect do not need this
253 */
254
255
256 if (mode === 'tags' && fillOptionsWithMissingValue) {
257 newOptions = fillOptionsWithMissingValue(newOptions, mergedValue, mergedOptionLabelProp, labelInValue);
258 }
259
260 return newOptions || [];
261 }, [options, children, mode, mergedValue]);
262 var mergedFlattenOptions = (0, React.useMemo)(function () {
263 return flattenOptions(mergedOptions, props);
264 }, [mergedOptions]);
265 var getValueOption = (0, _useCacheOptions.default)(mergedRawValue, mergedFlattenOptions); // Display options for OptionList
266
267 var displayOptions = (0, React.useMemo)(function () {
268 if (!mergedSearchValue || !mergedShowSearch) {
269 return (0, _toConsumableArray2.default)(mergedOptions);
270 }
271
272 var filteredOptions = filterOptions(mergedSearchValue, mergedOptions, {
273 optionFilterProp: optionFilterProp,
274 filterOption: mode === 'combobox' && filterOption === undefined ? function () {
275 return true;
276 } : filterOption
277 });
278
279 if (mode === 'tags' && filteredOptions.every(function (opt) {
280 return opt[optionFilterProp] !== mergedSearchValue;
281 })) {
282 filteredOptions.unshift({
283 value: mergedSearchValue,
284 label: mergedSearchValue,
285 key: '__RC_SELECT_TAG_PLACEHOLDER__'
286 });
287 }
288
289 return filteredOptions;
290 }, [mergedOptions, mergedSearchValue, mode, mergedShowSearch]);
291 var displayFlattenOptions = (0, React.useMemo)(function () {
292 return flattenOptions(displayOptions, props);
293 }, [displayOptions]);
294 (0, React.useEffect)(function () {
295 if (listRef.current && listRef.current.scrollTo) {
296 listRef.current.scrollTo(0);
297 }
298 }, [mergedSearchValue]); // ============================ Selector ============================
299
300 var displayValues = (0, React.useMemo)(function () {
301 var tmpValues = mergedRawValue.map(function (val) {
302 var valueOptions = getValueOption([val]);
303 var displayValue = getLabeledValue(val, {
304 options: valueOptions,
305 prevValue: mergedValue,
306 labelInValue: mergedLabelInValue,
307 optionLabelProp: mergedOptionLabelProp
308 });
309 return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, displayValue), {}, {
310 disabled: isValueDisabled(val, valueOptions)
311 });
312 });
313
314 if (!mode && tmpValues.length === 1 && tmpValues[0].value === null && tmpValues[0].label === null) {
315 return [];
316 }
317
318 return tmpValues;
319 }, [mergedValue, mergedOptions, mode]); // Polyfill with cache label
320
321 displayValues = (0, _useCacheDisplayValue.default)(displayValues);
322
323 var triggerSelect = function triggerSelect(newValue, isSelect, source) {
324 var newValueOption = getValueOption([newValue]);
325 var outOption = findValueOption([newValue], newValueOption)[0];
326
327 if (!internalProps.skipTriggerSelect) {
328 // Skip trigger `onSelect` or `onDeselect` if configured
329 var selectValue = mergedLabelInValue ? getLabeledValue(newValue, {
330 options: newValueOption,
331 prevValue: mergedValue,
332 labelInValue: mergedLabelInValue,
333 optionLabelProp: mergedOptionLabelProp
334 }) : newValue;
335
336 if (isSelect && onSelect) {
337 onSelect(selectValue, outOption);
338 } else if (!isSelect && onDeselect) {
339 onDeselect(selectValue, outOption);
340 }
341 } // Trigger internal event
342
343
344 if (useInternalProps) {
345 if (isSelect && internalProps.onRawSelect) {
346 internalProps.onRawSelect(newValue, outOption, source);
347 } else if (!isSelect && internalProps.onRawDeselect) {
348 internalProps.onRawDeselect(newValue, outOption, source);
349 }
350 }
351 }; // We need cache options here in case user update the option list
352
353
354 var _useState7 = (0, React.useState)([]),
355 _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
356 prevValueOptions = _useState8[0],
357 setPrevValueOptions = _useState8[1];
358
359 var triggerChange = function triggerChange(newRawValues) {
360 if (useInternalProps && internalProps.skipTriggerChange) {
361 return;
362 }
363
364 var newRawValuesOptions = getValueOption(newRawValues);
365 var outValues = (0, _commonUtil.toOuterValues)(Array.from(newRawValues), {
366 labelInValue: mergedLabelInValue,
367 options: newRawValuesOptions,
368 getLabeledValue: getLabeledValue,
369 prevValue: mergedValue,
370 optionLabelProp: mergedOptionLabelProp
371 });
372 var outValue = isMultiple ? outValues : outValues[0]; // Skip trigger if prev & current value is both empty
373
374 if (onChange && (mergedRawValue.length !== 0 || outValues.length !== 0)) {
375 var outOptions = findValueOption(newRawValues, newRawValuesOptions, {
376 prevValueOptions: prevValueOptions
377 }); // We will cache option in case it removed by ajax
378
379 setPrevValueOptions(outOptions.map(function (option, index) {
380 var clone = (0, _objectSpread2.default)({}, option);
381 Object.defineProperty(clone, '_INTERNAL_OPTION_VALUE_', {
382 get: function get() {
383 return newRawValues[index];
384 }
385 });
386 return clone;
387 }));
388 onChange(outValue, isMultiple ? outOptions : outOptions[0]);
389 }
390
391 setMergedValue(outValue);
392 };
393
394 var onInternalSelect = function onInternalSelect(newValue, _ref) {
395 var selected = _ref.selected,
396 source = _ref.source;
397
398 if (disabled) {
399 return;
400 }
401
402 var newRawValue;
403
404 if (isMultiple) {
405 newRawValue = new Set(mergedRawValue);
406
407 if (selected) {
408 newRawValue.add(newValue);
409 } else {
410 newRawValue.delete(newValue);
411 }
412 } else {
413 newRawValue = new Set();
414 newRawValue.add(newValue);
415 } // Multiple always trigger change and single should change if value changed
416
417
418 if (isMultiple || !isMultiple && Array.from(mergedRawValue)[0] !== newValue) {
419 triggerChange(Array.from(newRawValue));
420 } // Trigger `onSelect`. Single mode always trigger select
421
422
423 triggerSelect(newValue, !isMultiple || selected, source); // Clean search value if single or configured
424
425 if (mode === 'combobox') {
426 setInnerSearchValue(String(newValue));
427 setActiveValue('');
428 } else if (!isMultiple || autoClearSearchValue) {
429 setInnerSearchValue('');
430 setActiveValue('');
431 }
432 };
433
434 var onInternalOptionSelect = function onInternalOptionSelect(newValue, info) {
435 onInternalSelect(newValue, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, info), {}, {
436 source: 'option'
437 }));
438 };
439
440 var onInternalSelectionSelect = function onInternalSelectionSelect(newValue, info) {
441 onInternalSelect(newValue, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, info), {}, {
442 source: 'selection'
443 }));
444 }; // ============================= Input ==============================
445 // Only works in `combobox`
446
447
448 var customizeInputElement = mode === 'combobox' && getInputElement && getInputElement() || null; // ============================== Open ==============================
449
450 var _useMergedState3 = (0, _useMergedState5.default)(undefined, {
451 defaultValue: defaultOpen,
452 value: open
453 }),
454 _useMergedState4 = (0, _slicedToArray2.default)(_useMergedState3, 2),
455 innerOpen = _useMergedState4[0],
456 setInnerOpen = _useMergedState4[1];
457
458 var mergedOpen = innerOpen; // Not trigger `open` in `combobox` when `notFoundContent` is empty
459
460 var emptyListContent = !notFoundContent && !displayOptions.length;
461
462 if (disabled || emptyListContent && mergedOpen && mode === 'combobox') {
463 mergedOpen = false;
464 }
465
466 var triggerOpen = emptyListContent ? false : mergedOpen;
467
468 var onToggleOpen = function onToggleOpen(newOpen) {
469 var nextOpen = newOpen !== undefined ? newOpen : !mergedOpen;
470
471 if (innerOpen !== nextOpen && !disabled) {
472 setInnerOpen(nextOpen);
473
474 if (onDropdownVisibleChange) {
475 onDropdownVisibleChange(nextOpen);
476 }
477 }
478 };
479
480 (0, _useSelectTriggerControl.default)([containerRef.current, triggerRef.current && triggerRef.current.getPopupElement()], triggerOpen, onToggleOpen); // ============================= Search =============================
481
482 var triggerSearch = function triggerSearch(searchText, fromTyping, isCompositing) {
483 var ret = true;
484 var newSearchText = searchText;
485 setActiveValue(null); // Check if match the `tokenSeparators`
486
487 var patchLabels = isCompositing ? null : (0, _valueUtil.getSeparatedContent)(searchText, tokenSeparators);
488 var patchRawValues = patchLabels;
489
490 if (mode === 'combobox') {
491 // Only typing will trigger onChange
492 if (fromTyping) {
493 triggerChange([newSearchText]);
494 }
495 } else if (patchLabels) {
496 newSearchText = '';
497
498 if (mode !== 'tags') {
499 patchRawValues = patchLabels.map(function (label) {
500 var item = mergedFlattenOptions.find(function (_ref2) {
501 var data = _ref2.data;
502 return data[mergedOptionLabelProp] === label;
503 });
504 return item ? item.data.value : null;
505 }).filter(function (val) {
506 return val !== null;
507 });
508 }
509
510 var newRawValues = Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue), (0, _toConsumableArray2.default)(patchRawValues))));
511 triggerChange(newRawValues);
512 newRawValues.forEach(function (newRawValue) {
513 triggerSelect(newRawValue, true, 'input');
514 }); // Should close when paste finish
515
516 onToggleOpen(false); // Tell Selector that break next actions
517
518 ret = false;
519 }
520
521 setInnerSearchValue(newSearchText);
522
523 if (onSearch && mergedSearchValue !== newSearchText) {
524 onSearch(newSearchText);
525 }
526
527 return ret;
528 }; // Only triggered when menu is closed & mode is tags
529 // If menu is open, OptionList will take charge
530 // If mode isn't tags, press enter is not meaningful when you can't see any option
531
532
533 var onSearchSubmit = function onSearchSubmit(searchText) {
534 var newRawValues = Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue), [searchText])));
535 triggerChange(newRawValues);
536 newRawValues.forEach(function (newRawValue) {
537 triggerSelect(newRawValue, true, 'input');
538 });
539 setInnerSearchValue('');
540 }; // Close dropdown when disabled change
541
542
543 (0, React.useEffect)(function () {
544 if (innerOpen && !!disabled) {
545 setInnerOpen(false);
546 }
547 }, [disabled]); // Close will clean up single mode search text
548
549 (0, React.useEffect)(function () {
550 if (!mergedOpen && !isMultiple && mode !== 'combobox') {
551 triggerSearch('', false, false);
552 }
553 }, [mergedOpen]); // ============================ Keyboard ============================
554
555 /**
556 * We record input value here to check if can press to clean up by backspace
557 * - null: Key is not down, this is reset by key up
558 * - true: Search text is empty when first time backspace down
559 * - false: Search text is not empty when first time backspace down
560 */
561
562 var _useLock = (0, _useLock3.default)(),
563 _useLock2 = (0, _slicedToArray2.default)(_useLock, 2),
564 getClearLock = _useLock2[0],
565 setClearLock = _useLock2[1]; // KeyDown
566
567
568 var onInternalKeyDown = function onInternalKeyDown(event) {
569 var clearLock = getClearLock();
570 var which = event.which; // We only manage open state here, close logic should handle by list component
571
572 if (!mergedOpen && which === _KeyCode.default.ENTER) {
573 onToggleOpen(true);
574 }
575
576 setClearLock(!!mergedSearchValue); // Remove value by `backspace`
577
578 if (which === _KeyCode.default.BACKSPACE && !clearLock && isMultiple && !mergedSearchValue && mergedRawValue.length) {
579 var removeInfo = (0, _commonUtil.removeLastEnabledValue)(displayValues, mergedRawValue);
580
581 if (removeInfo.removedValue !== null) {
582 triggerChange(removeInfo.values);
583 triggerSelect(removeInfo.removedValue, false, 'input');
584 }
585 }
586
587 for (var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
588 rest[_key - 1] = arguments[_key];
589 }
590
591 if (mergedOpen && listRef.current) {
592 var _listRef$current;
593
594 (_listRef$current = listRef.current).onKeyDown.apply(_listRef$current, [event].concat(rest));
595 }
596
597 if (onKeyDown) {
598 onKeyDown.apply(void 0, [event].concat(rest));
599 }
600 }; // KeyUp
601
602
603 var onInternalKeyUp = function onInternalKeyUp(event) {
604 for (var _len2 = arguments.length, rest = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
605 rest[_key2 - 1] = arguments[_key2];
606 }
607
608 if (mergedOpen && listRef.current) {
609 var _listRef$current2;
610
611 (_listRef$current2 = listRef.current).onKeyUp.apply(_listRef$current2, [event].concat(rest));
612 }
613
614 if (onKeyUp) {
615 onKeyUp.apply(void 0, [event].concat(rest));
616 }
617 }; // ========================== Focus / Blur ==========================
618
619 /** Record real focus status */
620
621
622 var focusRef = (0, React.useRef)(false);
623
624 var onContainerFocus = function onContainerFocus() {
625 setMockFocused(true);
626
627 if (!disabled) {
628 if (onFocus && !focusRef.current) {
629 onFocus.apply(void 0, arguments);
630 } // `showAction` should handle `focus` if set
631
632
633 if (showAction.includes('focus')) {
634 onToggleOpen(true);
635 }
636 }
637
638 focusRef.current = true;
639 };
640
641 var onContainerBlur = function onContainerBlur() {
642 setMockFocused(false, function () {
643 focusRef.current = false;
644 onToggleOpen(false);
645 });
646
647 if (disabled) {
648 return;
649 }
650
651 if (mergedSearchValue) {
652 // `tags` mode should move `searchValue` into values
653 if (mode === 'tags') {
654 triggerSearch('', false, false);
655 triggerChange(Array.from(new Set([].concat((0, _toConsumableArray2.default)(mergedRawValue), [mergedSearchValue]))));
656 } else if (mode === 'multiple') {
657 // `multiple` mode only clean the search value but not trigger event
658 setInnerSearchValue('');
659 }
660 }
661
662 if (onBlur) {
663 onBlur.apply(void 0, arguments);
664 }
665 };
666
667 var activeTimeoutIds = [];
668 (0, React.useEffect)(function () {
669 return function () {
670 activeTimeoutIds.forEach(function (timeoutId) {
671 return clearTimeout(timeoutId);
672 });
673 activeTimeoutIds.splice(0, activeTimeoutIds.length);
674 };
675 }, []);
676
677 var onInternalMouseDown = function onInternalMouseDown(event) {
678 var target = event.target;
679 var popupElement = triggerRef.current && triggerRef.current.getPopupElement(); // We should give focus back to selector if clicked item is not focusable
680
681 if (popupElement && popupElement.contains(target)) {
682 var timeoutId = setTimeout(function () {
683 var index = activeTimeoutIds.indexOf(timeoutId);
684
685 if (index !== -1) {
686 activeTimeoutIds.splice(index, 1);
687 }
688
689 cancelSetMockFocused();
690
691 if (!popupElement.contains(document.activeElement)) {
692 selectorRef.current.focus();
693 }
694 });
695 activeTimeoutIds.push(timeoutId);
696 }
697
698 if (onMouseDown) {
699 for (var _len3 = arguments.length, restArgs = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
700 restArgs[_key3 - 1] = arguments[_key3];
701 }
702
703 onMouseDown.apply(void 0, [event].concat(restArgs));
704 }
705 }; // ========================= Accessibility ==========================
706
707
708 var _useState9 = (0, React.useState)(0),
709 _useState10 = (0, _slicedToArray2.default)(_useState9, 2),
710 accessibilityIndex = _useState10[0],
711 setAccessibilityIndex = _useState10[1];
712
713 var mergedDefaultActiveFirstOption = defaultActiveFirstOption !== undefined ? defaultActiveFirstOption : mode !== 'combobox';
714
715 var onActiveValue = function onActiveValue(active, index) {
716 setAccessibilityIndex(index);
717
718 if (backfill && mode === 'combobox' && active !== null) {
719 setActiveValue(String(active));
720 }
721 }; // ============================= Popup ==============================
722
723
724 var _useState11 = (0, React.useState)(null),
725 _useState12 = (0, _slicedToArray2.default)(_useState11, 2),
726 containerWidth = _useState12[0],
727 setContainerWidth = _useState12[1];
728
729 var _useState13 = (0, React.useState)({}),
730 _useState14 = (0, _slicedToArray2.default)(_useState13, 2),
731 forceUpdate = _useState14[1]; // We need force update here since popup dom is render async
732
733
734 function onPopupMouseEnter() {
735 forceUpdate({});
736 }
737
738 (0, _useLayoutEffect.default)(function () {
739 if (triggerOpen) {
740 var newWidth = Math.ceil(containerRef.current.offsetWidth);
741
742 if (containerWidth !== newWidth) {
743 setContainerWidth(newWidth);
744 }
745 }
746 }, [triggerOpen]);
747 var popupNode = React.createElement(OptionList, {
748 ref: listRef,
749 prefixCls: prefixCls,
750 id: mergedId,
751 open: mergedOpen,
752 childrenAsData: !options,
753 options: displayOptions,
754 flattenOptions: displayFlattenOptions,
755 multiple: isMultiple,
756 values: rawValues,
757 height: listHeight,
758 itemHeight: listItemHeight,
759 onSelect: onInternalOptionSelect,
760 onToggleOpen: onToggleOpen,
761 onActiveValue: onActiveValue,
762 defaultActiveFirstOption: mergedDefaultActiveFirstOption,
763 notFoundContent: notFoundContent,
764 onScroll: onPopupScroll,
765 searchValue: mergedSearchValue,
766 menuItemSelectedIcon: menuItemSelectedIcon,
767 virtual: virtual !== false && dropdownMatchSelectWidth !== false,
768 onMouseEnter: onPopupMouseEnter
769 }); // ============================= Clear ==============================
770
771 var clearNode;
772
773 var onClearMouseDown = function onClearMouseDown() {
774 // Trigger internal `onClear` event
775 if (useInternalProps && internalProps.onClear) {
776 internalProps.onClear();
777 }
778
779 if (onClear) {
780 onClear();
781 }
782
783 triggerChange([]);
784 triggerSearch('', false, false);
785 };
786
787 if (!disabled && allowClear && (mergedRawValue.length || mergedSearchValue)) {
788 clearNode = React.createElement(_TransBtn.default, {
789 className: "".concat(prefixCls, "-clear"),
790 onMouseDown: onClearMouseDown,
791 customizeIcon: clearIcon
792 }, "\xD7");
793 } // ============================= Arrow ==============================
794
795
796 var mergedShowArrow = showArrow !== undefined ? showArrow : loading || !isMultiple && mode !== 'combobox';
797 var arrowNode;
798
799 if (mergedShowArrow) {
800 arrowNode = React.createElement(_TransBtn.default, {
801 className: (0, _classnames.default)("".concat(prefixCls, "-arrow"), (0, _defineProperty2.default)({}, "".concat(prefixCls, "-arrow-loading"), loading)),
802 customizeIcon: inputIcon,
803 customizeIconProps: {
804 loading: loading,
805 searchValue: mergedSearchValue,
806 open: mergedOpen,
807 focused: mockFocused,
808 showSearch: mergedShowSearch
809 }
810 });
811 } // ============================ Warning =============================
812
813
814 if (process.env.NODE_ENV !== 'production' && warningProps) {
815 warningProps(props);
816 } // ============================= Render =============================
817
818
819 var mergedClassName = (0, _classnames.default)(prefixCls, className, (_classNames2 = {}, (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-focused"), mockFocused), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-multiple"), isMultiple), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-single"), !isMultiple), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-allow-clear"), allowClear), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-show-arrow"), mergedShowArrow), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-disabled"), disabled), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-loading"), loading), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-open"), mergedOpen), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-customize-input"), customizeInputElement), (0, _defineProperty2.default)(_classNames2, "".concat(prefixCls, "-show-search"), mergedShowSearch), _classNames2));
820 return React.createElement("div", Object.assign({
821 className: mergedClassName
822 }, domProps, {
823 ref: containerRef,
824 onMouseDown: onInternalMouseDown,
825 onKeyDown: onInternalKeyDown,
826 onKeyUp: onInternalKeyUp,
827 onFocus: onContainerFocus,
828 onBlur: onContainerBlur
829 }), mockFocused && !mergedOpen && React.createElement("span", {
830 style: {
831 width: 0,
832 height: 0,
833 display: 'flex',
834 overflow: 'hidden',
835 opacity: 0
836 },
837 "aria-live": "polite"
838 }, "".concat(mergedRawValue.join(', '))), React.createElement(_SelectTrigger.default, {
839 ref: triggerRef,
840 disabled: disabled,
841 prefixCls: prefixCls,
842 visible: triggerOpen,
843 popupElement: popupNode,
844 containerWidth: containerWidth,
845 animation: animation,
846 transitionName: transitionName,
847 dropdownStyle: dropdownStyle,
848 dropdownClassName: dropdownClassName,
849 direction: direction,
850 dropdownMatchSelectWidth: dropdownMatchSelectWidth,
851 dropdownRender: dropdownRender,
852 dropdownAlign: dropdownAlign,
853 getPopupContainer: getPopupContainer,
854 empty: !mergedOptions.length,
855 getTriggerDOMNode: function getTriggerDOMNode() {
856 return selectorDomRef.current;
857 }
858 }, React.createElement(_Selector.default, Object.assign({}, props, {
859 domRef: selectorDomRef,
860 prefixCls: prefixCls,
861 inputElement: customizeInputElement,
862 ref: selectorRef,
863 id: mergedId,
864 showSearch: mergedShowSearch,
865 mode: mode,
866 accessibilityIndex: accessibilityIndex,
867 multiple: isMultiple,
868 tagRender: tagRender,
869 values: displayValues,
870 open: mergedOpen,
871 onToggleOpen: onToggleOpen,
872 searchValue: mergedSearchValue,
873 activeValue: activeValue,
874 onSearch: triggerSearch,
875 onSearchSubmit: onSearchSubmit,
876 onSelect: onInternalSelectionSelect,
877 tokenWithEnter: tokenWithEnter
878 }))), arrowNode, clearNode);
879 }
880
881 var RefSelect = React.forwardRef(Select);
882 return RefSelect;
883}
\No newline at end of file