UNPKG

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