@rc-component/select 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +191 -0
  3. package/assets/index.css +306 -0
  4. package/assets/index.less +397 -0
  5. package/es/BaseSelect/Polite.d.ts +7 -0
  6. package/es/BaseSelect/Polite.js +26 -0
  7. package/es/BaseSelect/index.d.ts +118 -0
  8. package/es/BaseSelect/index.js +569 -0
  9. package/es/OptGroup.d.ts +12 -0
  10. package/es/OptGroup.js +6 -0
  11. package/es/Option.d.ts +14 -0
  12. package/es/Option.js +6 -0
  13. package/es/OptionList.d.ts +10 -0
  14. package/es/OptionList.js +379 -0
  15. package/es/Select.d.ts +114 -0
  16. package/es/Select.js +480 -0
  17. package/es/SelectContext.d.ts +23 -0
  18. package/es/SelectContext.js +6 -0
  19. package/es/SelectTrigger.d.ts +30 -0
  20. package/es/SelectTrigger.js +138 -0
  21. package/es/Selector/Input.d.ts +27 -0
  22. package/es/Selector/Input.js +114 -0
  23. package/es/Selector/MultipleSelector.d.ts +16 -0
  24. package/es/Selector/MultipleSelector.js +185 -0
  25. package/es/Selector/SingleSelector.d.ts +8 -0
  26. package/es/Selector/SingleSelector.js +104 -0
  27. package/es/Selector/index.d.ts +85 -0
  28. package/es/Selector/index.js +184 -0
  29. package/es/TransBtn.d.ts +12 -0
  30. package/es/TransBtn.js +30 -0
  31. package/es/hooks/useAllowClear.d.ts +8 -0
  32. package/es/hooks/useAllowClear.js +26 -0
  33. package/es/hooks/useBaseProps.d.ts +13 -0
  34. package/es/hooks/useBaseProps.js +10 -0
  35. package/es/hooks/useCache.d.ts +7 -0
  36. package/es/hooks/useCache.js +40 -0
  37. package/es/hooks/useDelayReset.d.ts +5 -0
  38. package/es/hooks/useDelayReset.js +24 -0
  39. package/es/hooks/useFilterOptions.d.ts +3 -0
  40. package/es/hooks/useFilterOptions.js +57 -0
  41. package/es/hooks/useId.d.ts +5 -0
  42. package/es/hooks/useId.js +29 -0
  43. package/es/hooks/useLayoutEffect.d.ts +5 -0
  44. package/es/hooks/useLayoutEffect.js +17 -0
  45. package/es/hooks/useLock.d.ts +7 -0
  46. package/es/hooks/useLock.js +27 -0
  47. package/es/hooks/useOptions.d.ts +12 -0
  48. package/es/hooks/useOptions.js +45 -0
  49. package/es/hooks/useRefFunc.d.ts +5 -0
  50. package/es/hooks/useRefFunc.js +14 -0
  51. package/es/hooks/useSelectTriggerControl.d.ts +1 -0
  52. package/es/hooks/useSelectTriggerControl.js +27 -0
  53. package/es/index.d.ts +10 -0
  54. package/es/index.js +7 -0
  55. package/es/interface.d.ts +23 -0
  56. package/es/interface.js +1 -0
  57. package/es/utils/__mocks__/platformUtil.d.ts +1 -0
  58. package/es/utils/__mocks__/platformUtil.js +3 -0
  59. package/es/utils/commonUtil.d.ts +9 -0
  60. package/es/utils/commonUtil.js +32 -0
  61. package/es/utils/keyUtil.d.ts +2 -0
  62. package/es/utils/keyUtil.js +16 -0
  63. package/es/utils/legacyUtil.d.ts +3 -0
  64. package/es/utils/legacyUtil.js +44 -0
  65. package/es/utils/platformUtil.d.ts +1 -0
  66. package/es/utils/platformUtil.js +4 -0
  67. package/es/utils/valueUtil.d.ts +24 -0
  68. package/es/utils/valueUtil.js +128 -0
  69. package/es/utils/warningPropsUtil.d.ts +4 -0
  70. package/es/utils/warningPropsUtil.js +119 -0
  71. package/lib/BaseSelect/Polite.d.ts +7 -0
  72. package/lib/BaseSelect/Polite.js +34 -0
  73. package/lib/BaseSelect/index.d.ts +118 -0
  74. package/lib/BaseSelect/index.js +579 -0
  75. package/lib/OptGroup.d.ts +12 -0
  76. package/lib/OptGroup.js +12 -0
  77. package/lib/Option.d.ts +14 -0
  78. package/lib/Option.js +12 -0
  79. package/lib/OptionList.d.ts +10 -0
  80. package/lib/OptionList.js +387 -0
  81. package/lib/Select.d.ts +114 -0
  82. package/lib/Select.js +487 -0
  83. package/lib/SelectContext.d.ts +23 -0
  84. package/lib/SelectContext.js +13 -0
  85. package/lib/SelectTrigger.d.ts +30 -0
  86. package/lib/SelectTrigger.js +147 -0
  87. package/lib/Selector/Input.d.ts +27 -0
  88. package/lib/Selector/Input.js +123 -0
  89. package/lib/Selector/MultipleSelector.d.ts +16 -0
  90. package/lib/Selector/MultipleSelector.js +194 -0
  91. package/lib/Selector/SingleSelector.d.ts +8 -0
  92. package/lib/Selector/SingleSelector.js +113 -0
  93. package/lib/Selector/index.d.ts +85 -0
  94. package/lib/Selector/index.js +191 -0
  95. package/lib/TransBtn.d.ts +12 -0
  96. package/lib/TransBtn.js +39 -0
  97. package/lib/hooks/useAllowClear.d.ts +8 -0
  98. package/lib/hooks/useAllowClear.js +34 -0
  99. package/lib/hooks/useBaseProps.d.ts +13 -0
  100. package/lib/hooks/useBaseProps.js +19 -0
  101. package/lib/hooks/useCache.d.ts +7 -0
  102. package/lib/hooks/useCache.js +49 -0
  103. package/lib/hooks/useDelayReset.d.ts +5 -0
  104. package/lib/hooks/useDelayReset.js +31 -0
  105. package/lib/hooks/useFilterOptions.d.ts +3 -0
  106. package/lib/hooks/useFilterOptions.js +66 -0
  107. package/lib/hooks/useId.d.ts +5 -0
  108. package/lib/hooks/useId.js +40 -0
  109. package/lib/hooks/useLayoutEffect.d.ts +5 -0
  110. package/lib/hooks/useLayoutEffect.js +25 -0
  111. package/lib/hooks/useLock.d.ts +7 -0
  112. package/lib/hooks/useLock.js +34 -0
  113. package/lib/hooks/useOptions.d.ts +12 -0
  114. package/lib/hooks/useOptions.js +52 -0
  115. package/lib/hooks/useRefFunc.d.ts +5 -0
  116. package/lib/hooks/useRefFunc.js +21 -0
  117. package/lib/hooks/useSelectTriggerControl.d.ts +1 -0
  118. package/lib/hooks/useSelectTriggerControl.js +35 -0
  119. package/lib/index.d.ts +10 -0
  120. package/lib/index.js +37 -0
  121. package/lib/interface.d.ts +23 -0
  122. package/lib/interface.js +5 -0
  123. package/lib/utils/__mocks__/platformUtil.d.ts +1 -0
  124. package/lib/utils/__mocks__/platformUtil.js +9 -0
  125. package/lib/utils/commonUtil.d.ts +9 -0
  126. package/lib/utils/commonUtil.js +42 -0
  127. package/lib/utils/keyUtil.d.ts +2 -0
  128. package/lib/utils/keyUtil.js +22 -0
  129. package/lib/utils/legacyUtil.d.ts +3 -0
  130. package/lib/utils/legacyUtil.js +53 -0
  131. package/lib/utils/platformUtil.d.ts +1 -0
  132. package/lib/utils/platformUtil.js +10 -0
  133. package/lib/utils/valueUtil.d.ts +24 -0
  134. package/lib/utils/valueUtil.js +140 -0
  135. package/lib/utils/warningPropsUtil.d.ts +4 -0
  136. package/lib/utils/warningPropsUtil.js +129 -0
  137. package/package.json +86 -0
@@ -0,0 +1,569 @@
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+ import classNames from 'classnames';
3
+ import useLayoutEffect from "@rc-component/util/es/hooks/useLayoutEffect";
4
+ import useMergedState from "@rc-component/util/es/hooks/useMergedState";
5
+ import isMobile from "@rc-component/util/es/isMobile";
6
+ import { useComposeRef } from "@rc-component/util/es/ref";
7
+ import * as React from 'react';
8
+ import { useAllowClear } from "../hooks/useAllowClear";
9
+ import { BaseSelectContext } from "../hooks/useBaseProps";
10
+ import useDelayReset from "../hooks/useDelayReset";
11
+ import useLock from "../hooks/useLock";
12
+ import useSelectTriggerControl from "../hooks/useSelectTriggerControl";
13
+ import Selector from "../Selector";
14
+ import SelectTrigger from "../SelectTrigger";
15
+ import TransBtn from "../TransBtn";
16
+ import { getSeparatedContent, isValidCount } from "../utils/valueUtil";
17
+ import SelectContext from "../SelectContext";
18
+ import Polite from "./Polite";
19
+ const DEFAULT_OMIT_PROPS = ['value', 'onChange', 'removeIcon', 'placeholder', 'autoFocus', 'maxTagCount', 'maxTagTextLength', 'maxTagPlaceholder', 'choiceTransitionName', 'onInputKeyDown', 'onPopupScroll', 'tabIndex'];
20
+ export const isMultiple = mode => mode === 'tags' || mode === 'multiple';
21
+ const BaseSelect = /*#__PURE__*/React.forwardRef((props, ref) => {
22
+ const {
23
+ id,
24
+ prefixCls,
25
+ className,
26
+ showSearch,
27
+ tagRender,
28
+ showScrollBar = 'optional',
29
+ direction,
30
+ omitDomProps,
31
+ // Value
32
+ displayValues,
33
+ onDisplayValuesChange,
34
+ emptyOptions,
35
+ notFoundContent = 'Not Found',
36
+ onClear,
37
+ // Mode
38
+ mode,
39
+ // Status
40
+ disabled,
41
+ loading,
42
+ // Customize Input
43
+ getInputElement,
44
+ getRawInputElement,
45
+ // Open
46
+ open,
47
+ defaultOpen,
48
+ onPopupVisibleChange,
49
+ // Active
50
+ activeValue,
51
+ onActiveValueChange,
52
+ activeDescendantId,
53
+ // Search
54
+ searchValue,
55
+ autoClearSearchValue,
56
+ onSearch,
57
+ onSearchSplit,
58
+ tokenSeparators,
59
+ // Icons
60
+ allowClear,
61
+ prefix,
62
+ suffixIcon,
63
+ clearIcon,
64
+ // Dropdown
65
+ OptionList,
66
+ animation,
67
+ transitionName,
68
+ popupStyle,
69
+ popupClassName,
70
+ popupMatchSelectWidth,
71
+ popupRender,
72
+ popupAlign,
73
+ placement,
74
+ builtinPlacements,
75
+ getPopupContainer,
76
+ // Focus
77
+ showAction = [],
78
+ onFocus,
79
+ onBlur,
80
+ // Rest Events
81
+ onKeyUp,
82
+ onKeyDown,
83
+ onMouseDown,
84
+ // Rest Props
85
+ ...restProps
86
+ } = props;
87
+
88
+ // ============================== MISC ==============================
89
+ const multiple = isMultiple(mode);
90
+ const mergedShowSearch = (showSearch !== undefined ? showSearch : multiple) || mode === 'combobox';
91
+ const domProps = {
92
+ ...restProps
93
+ };
94
+ DEFAULT_OMIT_PROPS.forEach(propName => {
95
+ delete domProps[propName];
96
+ });
97
+ omitDomProps?.forEach(propName => {
98
+ delete domProps[propName];
99
+ });
100
+
101
+ // ============================= Mobile =============================
102
+ const [mobile, setMobile] = React.useState(false);
103
+ React.useEffect(() => {
104
+ // Only update on the client side
105
+ setMobile(isMobile());
106
+ }, []);
107
+
108
+ // ============================== Refs ==============================
109
+ const containerRef = React.useRef(null);
110
+ const selectorDomRef = React.useRef(null);
111
+ const triggerRef = React.useRef(null);
112
+ const selectorRef = React.useRef(null);
113
+ const listRef = React.useRef(null);
114
+ const blurRef = React.useRef(false);
115
+
116
+ /** Used for component focused management */
117
+ const [mockFocused, setMockFocused, cancelSetMockFocused] = useDelayReset();
118
+
119
+ // =========================== Imperative ===========================
120
+ React.useImperativeHandle(ref, () => ({
121
+ focus: selectorRef.current?.focus,
122
+ blur: selectorRef.current?.blur,
123
+ scrollTo: arg => listRef.current?.scrollTo(arg),
124
+ nativeElement: containerRef.current || selectorDomRef.current
125
+ }));
126
+
127
+ // ========================== Search Value ==========================
128
+ const mergedSearchValue = React.useMemo(() => {
129
+ if (mode !== 'combobox') {
130
+ return searchValue;
131
+ }
132
+ const val = displayValues[0]?.value;
133
+ return typeof val === 'string' || typeof val === 'number' ? String(val) : '';
134
+ }, [searchValue, mode, displayValues]);
135
+
136
+ // ========================== Custom Input ==========================
137
+ // Only works in `combobox`
138
+ const customizeInputElement = mode === 'combobox' && typeof getInputElement === 'function' && getInputElement() || null;
139
+
140
+ // Used for customize replacement for `rc-cascader`
141
+ const customizeRawInputElement = typeof getRawInputElement === 'function' && getRawInputElement();
142
+ const customizeRawInputRef = useComposeRef(selectorDomRef, customizeRawInputElement?.props?.ref);
143
+
144
+ // ============================== Open ==============================
145
+ // SSR not support Portal which means we need delay `open` for the first time render
146
+ const [rendered, setRendered] = React.useState(false);
147
+ useLayoutEffect(() => {
148
+ setRendered(true);
149
+ }, []);
150
+ const [innerOpen, setInnerOpen] = useMergedState(false, {
151
+ defaultValue: defaultOpen,
152
+ value: open
153
+ });
154
+ let mergedOpen = rendered ? innerOpen : false;
155
+
156
+ // Not trigger `open` in `combobox` when `notFoundContent` is empty
157
+ const emptyListContent = !notFoundContent && emptyOptions;
158
+ if (disabled || emptyListContent && mergedOpen && mode === 'combobox') {
159
+ mergedOpen = false;
160
+ }
161
+ const triggerOpen = emptyListContent ? false : mergedOpen;
162
+ const onToggleOpen = React.useCallback(newOpen => {
163
+ const nextOpen = newOpen !== undefined ? newOpen : !mergedOpen;
164
+ if (!disabled) {
165
+ setInnerOpen(nextOpen);
166
+ if (mergedOpen !== nextOpen) {
167
+ onPopupVisibleChange?.(nextOpen);
168
+ }
169
+ }
170
+ }, [disabled, mergedOpen, setInnerOpen, onPopupVisibleChange]);
171
+
172
+ // ============================= Search =============================
173
+ const tokenWithEnter = React.useMemo(() => (tokenSeparators || []).some(tokenSeparator => ['\n', '\r\n'].includes(tokenSeparator)), [tokenSeparators]);
174
+ const {
175
+ maxCount,
176
+ rawValues
177
+ } = React.useContext(SelectContext) || {};
178
+ const onInternalSearch = (searchText, fromTyping, isCompositing) => {
179
+ if (multiple && isValidCount(maxCount) && rawValues?.size >= maxCount) {
180
+ return;
181
+ }
182
+ let ret = true;
183
+ let newSearchText = searchText;
184
+ onActiveValueChange?.(null);
185
+ const separatedList = getSeparatedContent(searchText, tokenSeparators, isValidCount(maxCount) ? maxCount - rawValues.size : undefined);
186
+
187
+ // Check if match the `tokenSeparators`
188
+ const patchLabels = isCompositing ? null : separatedList;
189
+
190
+ // Ignore combobox since it's not split-able
191
+ if (mode !== 'combobox' && patchLabels) {
192
+ newSearchText = '';
193
+ onSearchSplit?.(patchLabels);
194
+
195
+ // Should close when paste finish
196
+ onToggleOpen(false);
197
+
198
+ // Tell Selector that break next actions
199
+ ret = false;
200
+ }
201
+ if (onSearch && mergedSearchValue !== newSearchText) {
202
+ onSearch(newSearchText, {
203
+ source: fromTyping ? 'typing' : 'effect'
204
+ });
205
+ }
206
+ return ret;
207
+ };
208
+
209
+ // Only triggered when menu is closed & mode is tags
210
+ // If menu is open, OptionList will take charge
211
+ // If mode isn't tags, press enter is not meaningful when you can't see any option
212
+ const onInternalSearchSubmit = searchText => {
213
+ // prevent empty tags from appearing when you click the Enter button
214
+ if (!searchText || !searchText.trim()) {
215
+ return;
216
+ }
217
+ onSearch(searchText, {
218
+ source: 'submit'
219
+ });
220
+ };
221
+
222
+ // Close will clean up single mode search text
223
+ React.useEffect(() => {
224
+ if (!mergedOpen && !multiple && mode !== 'combobox') {
225
+ onInternalSearch('', false, false);
226
+ }
227
+ }, [mergedOpen]);
228
+
229
+ // ============================ Disabled ============================
230
+ // Close dropdown & remove focus state when disabled change
231
+ React.useEffect(() => {
232
+ if (innerOpen && disabled) {
233
+ setInnerOpen(false);
234
+ }
235
+
236
+ // After onBlur is triggered, the focused does not need to be reset
237
+ if (disabled && !blurRef.current) {
238
+ setMockFocused(false);
239
+ }
240
+ }, [disabled]);
241
+
242
+ // ============================ Keyboard ============================
243
+ /**
244
+ * We record input value here to check if can press to clean up by backspace
245
+ * - null: Key is not down, this is reset by key up
246
+ * - true: Search text is empty when first time backspace down
247
+ * - false: Search text is not empty when first time backspace down
248
+ */
249
+ const [getClearLock, setClearLock] = useLock();
250
+ const keyLockRef = React.useRef(false);
251
+
252
+ // KeyDown
253
+ const onInternalKeyDown = (event, ...rest) => {
254
+ const clearLock = getClearLock();
255
+ const {
256
+ key
257
+ } = event;
258
+ const isEnterKey = key === 'Enter';
259
+ if (isEnterKey) {
260
+ // Do not submit form when type in the input
261
+ if (mode !== 'combobox') {
262
+ event.preventDefault();
263
+ }
264
+
265
+ // We only manage open state here, close logic should handle by list component
266
+ if (!mergedOpen) {
267
+ onToggleOpen(true);
268
+ }
269
+ }
270
+ setClearLock(!!mergedSearchValue);
271
+
272
+ // Remove value by `backspace`
273
+ if (key === 'Backspace' && !clearLock && multiple && !mergedSearchValue && displayValues.length) {
274
+ const cloneDisplayValues = [...displayValues];
275
+ let removedDisplayValue = null;
276
+ for (let i = cloneDisplayValues.length - 1; i >= 0; i -= 1) {
277
+ const current = cloneDisplayValues[i];
278
+ if (!current.disabled) {
279
+ cloneDisplayValues.splice(i, 1);
280
+ removedDisplayValue = current;
281
+ break;
282
+ }
283
+ }
284
+ if (removedDisplayValue) {
285
+ onDisplayValuesChange(cloneDisplayValues, {
286
+ type: 'remove',
287
+ values: [removedDisplayValue]
288
+ });
289
+ }
290
+ }
291
+ if (mergedOpen && (!isEnterKey || !keyLockRef.current)) {
292
+ // Lock the Enter key after it is pressed to avoid repeated triggering of the onChange event.
293
+ if (isEnterKey) {
294
+ keyLockRef.current = true;
295
+ }
296
+ listRef.current?.onKeyDown(event, ...rest);
297
+ }
298
+ onKeyDown?.(event, ...rest);
299
+ };
300
+
301
+ // KeyUp
302
+ const onInternalKeyUp = (event, ...rest) => {
303
+ if (mergedOpen) {
304
+ listRef.current?.onKeyUp(event, ...rest);
305
+ }
306
+ if (event.key === 'Enter') {
307
+ keyLockRef.current = false;
308
+ }
309
+ onKeyUp?.(event, ...rest);
310
+ };
311
+
312
+ // ============================ Selector ============================
313
+ const onSelectorRemove = val => {
314
+ const newValues = displayValues.filter(i => i !== val);
315
+ onDisplayValuesChange(newValues, {
316
+ type: 'remove',
317
+ values: [val]
318
+ });
319
+ };
320
+ const onInputBlur = () => {
321
+ // Unlock the Enter key after the input blur; otherwise, the Enter key needs to be pressed twice to trigger the correct effect.
322
+ keyLockRef.current = false;
323
+ };
324
+
325
+ // ========================== Focus / Blur ==========================
326
+ /** Record real focus status */
327
+ const focusRef = React.useRef(false);
328
+ const onContainerFocus = (...args) => {
329
+ setMockFocused(true);
330
+ if (!disabled) {
331
+ if (onFocus && !focusRef.current) {
332
+ onFocus(...args);
333
+ }
334
+
335
+ // `showAction` should handle `focus` if set
336
+ if (showAction.includes('focus')) {
337
+ onToggleOpen(true);
338
+ }
339
+ }
340
+ focusRef.current = true;
341
+ };
342
+ const onContainerBlur = (...args) => {
343
+ blurRef.current = true;
344
+ setMockFocused(false, () => {
345
+ focusRef.current = false;
346
+ blurRef.current = false;
347
+ onToggleOpen(false);
348
+ });
349
+ if (disabled) {
350
+ return;
351
+ }
352
+ if (mergedSearchValue) {
353
+ // `tags` mode should move `searchValue` into values
354
+ if (mode === 'tags') {
355
+ onSearch(mergedSearchValue, {
356
+ source: 'submit'
357
+ });
358
+ } else if (mode === 'multiple') {
359
+ // `multiple` mode only clean the search value but not trigger event
360
+ onSearch('', {
361
+ source: 'blur'
362
+ });
363
+ }
364
+ }
365
+ if (onBlur) {
366
+ onBlur(...args);
367
+ }
368
+ };
369
+
370
+ // Give focus back of Select
371
+ const activeTimeoutIds = [];
372
+ React.useEffect(() => () => {
373
+ activeTimeoutIds.forEach(timeoutId => clearTimeout(timeoutId));
374
+ activeTimeoutIds.splice(0, activeTimeoutIds.length);
375
+ }, []);
376
+ const onInternalMouseDown = (event, ...restArgs) => {
377
+ const {
378
+ target
379
+ } = event;
380
+ const popupElement = triggerRef.current?.getPopupElement();
381
+
382
+ // We should give focus back to selector if clicked item is not focusable
383
+ if (popupElement && popupElement.contains(target)) {
384
+ const timeoutId = setTimeout(() => {
385
+ const index = activeTimeoutIds.indexOf(timeoutId);
386
+ if (index !== -1) {
387
+ activeTimeoutIds.splice(index, 1);
388
+ }
389
+ cancelSetMockFocused();
390
+ if (!mobile && !popupElement.contains(document.activeElement)) {
391
+ selectorRef.current?.focus();
392
+ }
393
+ });
394
+ activeTimeoutIds.push(timeoutId);
395
+ }
396
+ onMouseDown?.(event, ...restArgs);
397
+ };
398
+
399
+ // ============================ Dropdown ============================
400
+ const [, forceUpdate] = React.useState({});
401
+ // We need force update here since popup dom is render async
402
+ function onPopupMouseEnter() {
403
+ forceUpdate({});
404
+ }
405
+
406
+ // Used for raw custom input trigger
407
+ let onTriggerVisibleChange;
408
+ if (customizeRawInputElement) {
409
+ onTriggerVisibleChange = newOpen => {
410
+ onToggleOpen(newOpen);
411
+ };
412
+ }
413
+
414
+ // Close when click on non-select element
415
+ useSelectTriggerControl(() => [containerRef.current, triggerRef.current?.getPopupElement()], triggerOpen, onToggleOpen, !!customizeRawInputElement);
416
+
417
+ // ============================ Context =============================
418
+ const baseSelectContext = React.useMemo(() => ({
419
+ ...props,
420
+ notFoundContent,
421
+ open: mergedOpen,
422
+ triggerOpen,
423
+ id,
424
+ showSearch: mergedShowSearch,
425
+ multiple,
426
+ toggleOpen: onToggleOpen,
427
+ showScrollBar
428
+ }), [props, notFoundContent, triggerOpen, mergedOpen, id, mergedShowSearch, multiple, onToggleOpen, showScrollBar]);
429
+
430
+ // ==================================================================
431
+ // == Render ==
432
+ // ==================================================================
433
+
434
+ // ============================= Arrow ==============================
435
+ const showSuffixIcon = !!suffixIcon || loading;
436
+ let arrowNode;
437
+ if (showSuffixIcon) {
438
+ arrowNode = /*#__PURE__*/React.createElement(TransBtn, {
439
+ className: classNames(`${prefixCls}-arrow`, {
440
+ [`${prefixCls}-arrow-loading`]: loading
441
+ }),
442
+ customizeIcon: suffixIcon,
443
+ customizeIconProps: {
444
+ loading,
445
+ searchValue: mergedSearchValue,
446
+ open: mergedOpen,
447
+ focused: mockFocused,
448
+ showSearch: mergedShowSearch
449
+ }
450
+ });
451
+ }
452
+
453
+ // ============================= Clear ==============================
454
+ const onClearMouseDown = () => {
455
+ onClear?.();
456
+ selectorRef.current?.focus();
457
+ onDisplayValuesChange([], {
458
+ type: 'clear',
459
+ values: displayValues
460
+ });
461
+ onInternalSearch('', false, false);
462
+ };
463
+ const {
464
+ allowClear: mergedAllowClear,
465
+ clearIcon: clearNode
466
+ } = useAllowClear(prefixCls, onClearMouseDown, displayValues, allowClear, clearIcon, disabled, mergedSearchValue, mode);
467
+
468
+ // =========================== OptionList ===========================
469
+ const optionList = /*#__PURE__*/React.createElement(OptionList, {
470
+ ref: listRef
471
+ });
472
+
473
+ // ============================= Select =============================
474
+ const mergedClassName = classNames(prefixCls, className, {
475
+ [`${prefixCls}-focused`]: mockFocused,
476
+ [`${prefixCls}-multiple`]: multiple,
477
+ [`${prefixCls}-single`]: !multiple,
478
+ [`${prefixCls}-allow-clear`]: allowClear,
479
+ [`${prefixCls}-show-arrow`]: showSuffixIcon,
480
+ [`${prefixCls}-disabled`]: disabled,
481
+ [`${prefixCls}-loading`]: loading,
482
+ [`${prefixCls}-open`]: mergedOpen,
483
+ [`${prefixCls}-customize-input`]: customizeInputElement,
484
+ [`${prefixCls}-show-search`]: mergedShowSearch
485
+ });
486
+
487
+ // >>> Selector
488
+ const selectorNode = /*#__PURE__*/React.createElement(SelectTrigger, {
489
+ ref: triggerRef,
490
+ disabled: disabled,
491
+ prefixCls: prefixCls,
492
+ visible: triggerOpen,
493
+ popupElement: optionList,
494
+ animation: animation,
495
+ transitionName: transitionName,
496
+ popupStyle: popupStyle,
497
+ popupClassName: popupClassName,
498
+ direction: direction,
499
+ popupMatchSelectWidth: popupMatchSelectWidth,
500
+ popupRender: popupRender,
501
+ popupAlign: popupAlign,
502
+ placement: placement,
503
+ builtinPlacements: builtinPlacements,
504
+ getPopupContainer: getPopupContainer,
505
+ empty: emptyOptions,
506
+ getTriggerDOMNode: node =>
507
+ // TODO: This is workaround and should be removed in `rc-select`
508
+ // And use new standard `nativeElement` for ref.
509
+ // But we should update `rc-resize-observer` first.
510
+ selectorDomRef.current || node,
511
+ onPopupVisibleChange: onTriggerVisibleChange,
512
+ onPopupMouseEnter: onPopupMouseEnter
513
+ }, customizeRawInputElement ? ( /*#__PURE__*/React.cloneElement(customizeRawInputElement, {
514
+ ref: customizeRawInputRef
515
+ })) : /*#__PURE__*/React.createElement(Selector, _extends({}, props, {
516
+ domRef: selectorDomRef,
517
+ prefixCls: prefixCls,
518
+ inputElement: customizeInputElement,
519
+ ref: selectorRef,
520
+ id: id,
521
+ prefix: prefix,
522
+ showSearch: mergedShowSearch,
523
+ autoClearSearchValue: autoClearSearchValue,
524
+ mode: mode,
525
+ activeDescendantId: activeDescendantId,
526
+ tagRender: tagRender,
527
+ values: displayValues,
528
+ open: mergedOpen,
529
+ onToggleOpen: onToggleOpen,
530
+ activeValue: activeValue,
531
+ searchValue: mergedSearchValue,
532
+ onSearch: onInternalSearch,
533
+ onSearchSubmit: onInternalSearchSubmit,
534
+ onRemove: onSelectorRemove,
535
+ tokenWithEnter: tokenWithEnter,
536
+ onInputBlur: onInputBlur
537
+ })));
538
+
539
+ // >>> Render
540
+ let renderNode;
541
+
542
+ // Render raw
543
+ if (customizeRawInputElement) {
544
+ renderNode = selectorNode;
545
+ } else {
546
+ renderNode = /*#__PURE__*/React.createElement("div", _extends({
547
+ className: mergedClassName
548
+ }, domProps, {
549
+ ref: containerRef,
550
+ onMouseDown: onInternalMouseDown,
551
+ onKeyDown: onInternalKeyDown,
552
+ onKeyUp: onInternalKeyUp,
553
+ onFocus: onContainerFocus,
554
+ onBlur: onContainerBlur
555
+ }), /*#__PURE__*/React.createElement(Polite, {
556
+ visible: mockFocused && !mergedOpen,
557
+ values: displayValues
558
+ }), selectorNode, arrowNode, mergedAllowClear && clearNode);
559
+ }
560
+ return /*#__PURE__*/React.createElement(BaseSelectContext.Provider, {
561
+ value: baseSelectContext
562
+ }, renderNode);
563
+ });
564
+
565
+ // Set display name for dev
566
+ if (process.env.NODE_ENV !== 'production') {
567
+ BaseSelect.displayName = 'BaseSelect';
568
+ }
569
+ export default BaseSelect;
@@ -0,0 +1,12 @@
1
+ import type * as React from 'react';
2
+ import type { DefaultOptionType } from './Select';
3
+ export interface OptGroupProps extends Omit<DefaultOptionType, 'options'> {
4
+ children?: React.ReactNode;
5
+ }
6
+ export interface OptionGroupFC extends React.FC<OptGroupProps> {
7
+ /** Legacy for check if is a Option Group */
8
+ isSelectOptGroup: boolean;
9
+ }
10
+ /** This is a placeholder, not real render in dom */
11
+ declare const OptGroup: OptionGroupFC;
12
+ export default OptGroup;
package/es/OptGroup.js ADDED
@@ -0,0 +1,6 @@
1
+ /* istanbul ignore file */
2
+
3
+ /** This is a placeholder, not real render in dom */
4
+ const OptGroup = () => null;
5
+ OptGroup.isSelectOptGroup = true;
6
+ export default OptGroup;
package/es/Option.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type * as React from 'react';
2
+ import type { DefaultOptionType } from './Select';
3
+ export interface OptionProps extends Omit<DefaultOptionType, 'label'> {
4
+ children: React.ReactNode;
5
+ /** Save for customize data */
6
+ [prop: string]: any;
7
+ }
8
+ export interface OptionFC extends React.FC<OptionProps> {
9
+ /** Legacy for check if is a Option Group */
10
+ isSelectOption: boolean;
11
+ }
12
+ /** This is a placeholder, not real render in dom */
13
+ declare const Option: OptionFC;
14
+ export default Option;
package/es/Option.js ADDED
@@ -0,0 +1,6 @@
1
+ /* istanbul ignore file */
2
+
3
+ /** This is a placeholder, not real render in dom */
4
+ const Option = () => null;
5
+ Option.isSelectOption = true;
6
+ export default Option;
@@ -0,0 +1,10 @@
1
+ import type { ScrollConfig } from 'rc-virtual-list/lib/List';
2
+ import * as React from 'react';
3
+ export type OptionListProps = Record<string, never>;
4
+ export interface RefOptionListProps {
5
+ onKeyDown: React.KeyboardEventHandler;
6
+ onKeyUp: React.KeyboardEventHandler;
7
+ scrollTo?: (args: number | ScrollConfig) => void;
8
+ }
9
+ declare const RefOptionList: React.ForwardRefExoticComponent<React.RefAttributes<RefOptionListProps>>;
10
+ export default RefOptionList;