UNPKG

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