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