@lobehub/ui 5.10.5 → 5.11.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.
@@ -1,263 +1,63 @@
1
1
  "use client";
2
- import { useAppElement } from "../../ThemeProvider/AppElementContext.mjs";
3
- import Icon from "../../Icon/Icon.mjs";
4
2
  import { styles } from "../../Menu/sharedStyle.mjs";
5
3
  import { styles as styles$1, triggerVariants } from "./style.mjs";
6
- import { isValidElement, memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import { isValueEmpty } from "./helpers.mjs";
5
+ import { usePortalContainer, useSelectOpen, useSelectSearch, useSelectValue, useSelectVirtual } from "./hooks.mjs";
6
+ import { EmptyContent, SelectListSection, SelectSearchInput, SelectTriggerSuffix, createTriggerValueRenderer, resolveIconNode, resolveSuffixIcon } from "./parts.mjs";
7
+ import { renderOptions } from "./renderOptions.mjs";
8
+ import { memo, useCallback, useEffect, useMemo, useState } from "react";
7
9
  import { jsx, jsxs } from "react/jsx-runtime";
8
10
  import { cx, useThemeMode } from "antd-style";
9
- import { Check, ChevronDown, Loader2, X } from "lucide-react";
10
11
  import { Select } from "@base-ui/react/select";
11
- import { Virtualizer } from "virtua";
12
12
  //#region src/base-ui/Select/Select.tsx
13
- const isGroupOption = (option) => Boolean(option.options);
14
- const getOptionSearchText = (option) => {
15
- if (typeof option.label === "string" || typeof option.label === "number") return String(option.label);
16
- if (typeof option.value === "string" || typeof option.value === "number") return String(option.value);
17
- if (option.title) return option.title;
18
- return "";
19
- };
20
- const escapeRegExp = (value) => value.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&");
21
- const splitBySeparators = (value, separators) => {
22
- if (!separators || separators.length === 0) return [value];
23
- const pattern = separators.map(escapeRegExp).join("|");
24
- return value.split(new RegExp(pattern, "g"));
25
- };
26
- const countVirtualItems = (items) => items.reduce((count, item) => {
27
- if (isGroupOption(item)) return count + item.options.length + 1;
28
- return count + 1;
29
- }, 0);
30
- const isValueEmpty = (value) => value === null || value === void 0 || value === "";
31
13
  const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOpen, defaultValue, disabled, id, labelRender, listHeight = 512, listItemHeight, loading, mode, name, onChange, onOpenChange, onSelect, open, optionRender, options, placeholder, popupClassName, popupMatchSelectWidth, prefix, readOnly, required, behaviorVariant = "default", selectedIndicatorVariant = "check", shadow, showSearch, size = "middle", style, suffixIcon, suffixIconProps, tokenSeparators, value, variant, virtual }) => {
32
14
  const { isDarkMode } = useThemeMode();
33
15
  const resolvedVariant = variant ?? (isDarkMode ? "filled" : "outlined");
34
16
  const isMultiple = mode === "multiple" || mode === "tags";
35
17
  const isItemAligned = behaviorVariant === "item-aligned";
36
- const [uncontrolledValue, setUncontrolledValue] = useState(() => {
37
- if (defaultValue !== void 0) return defaultValue;
38
- return isMultiple ? [] : null;
39
- });
40
- const normalizeValue = useCallback((nextValue) => {
41
- if (isMultiple) {
42
- if (Array.isArray(nextValue)) return nextValue;
43
- if (nextValue === null || nextValue === void 0) return [];
44
- return [nextValue];
45
- }
46
- if (Array.isArray(nextValue)) return nextValue[0] ?? null;
47
- return nextValue === void 0 ? null : nextValue;
48
- }, [isMultiple]);
49
- const mergedValue = value !== void 0 ? value : uncontrolledValue;
50
- const normalizedValue = useMemo(() => normalizeValue(mergedValue), [mergedValue, normalizeValue]);
51
- const valueArray = useMemo(() => isMultiple ? normalizedValue : isValueEmpty(normalizedValue) ? [] : [normalizedValue], [isMultiple, normalizedValue]);
52
18
  const [extraOptions, setExtraOptions] = useState([]);
53
19
  useEffect(() => {
54
20
  if (mode !== "tags" && extraOptions.length > 0) setExtraOptions([]);
55
21
  }, [mode, extraOptions.length]);
56
- const { resolvedOptions, optionMap } = useMemo(() => {
57
- const baseOptions = options ?? [];
58
- const optionValueMap = /* @__PURE__ */ new Map();
59
- const addOption = (item) => {
60
- if (!optionValueMap.has(item.value)) optionValueMap.set(item.value, item);
61
- };
62
- const walkOptions = (items) => {
63
- items.forEach((item) => {
64
- if (isGroupOption(item)) item.options.forEach(addOption);
65
- else addOption(item);
66
- });
67
- };
68
- walkOptions(baseOptions);
69
- const filteredExtraOptions = extraOptions.filter((item) => !optionValueMap.has(item.value));
70
- filteredExtraOptions.forEach(addOption);
71
- const mergedOptions = [...baseOptions, ...filteredExtraOptions];
72
- const missingValueOptions = valueArray.filter((val) => !optionValueMap.has(val)).map((val) => ({
73
- label: String(val),
74
- value: val
75
- }));
76
- missingValueOptions.forEach(addOption);
77
- return {
78
- optionMap: optionValueMap,
79
- resolvedOptions: missingValueOptions.length ? [...mergedOptions, ...missingValueOptions] : mergedOptions
80
- };
81
- }, [
22
+ const { appendTagValues, getOption, handleValueChange, normalizedValue, normalizeValue, resolvedOptions, valueArray } = useSelectValue({
23
+ defaultValue,
82
24
  extraOptions,
83
- options,
84
- valueArray
85
- ]);
86
- const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen));
87
- useEffect(() => {
88
- if (open !== void 0) setUncontrolledOpen(open);
89
- }, [open]);
90
- const mergedOpen = open ?? uncontrolledOpen;
91
- const handleOpenChange = useCallback((nextOpen, eventDetails) => {
92
- onOpenChange?.(nextOpen, eventDetails);
93
- if (open === void 0) setUncontrolledOpen(nextOpen);
94
- }, [onOpenChange, open]);
95
- const [searchValue, setSearchValue] = useState("");
96
- const shouldShowSearch = Boolean(showSearch || mode === "tags");
97
- useEffect(() => {
98
- if (!mergedOpen) setSearchValue("");
99
- }, [mergedOpen]);
100
- const getOption = useCallback((optionValue) => {
101
- const matched = optionMap.get(optionValue);
102
- if (matched) return matched;
103
- if (optionValue && typeof optionValue === "object" && "label" in optionValue) return {
104
- label: optionValue.label,
105
- value: optionValue
106
- };
107
- return {
108
- label: String(optionValue),
109
- value: optionValue
110
- };
111
- }, [optionMap]);
112
- const previousValueRef = useRef(normalizedValue);
113
- useEffect(() => {
114
- previousValueRef.current = normalizedValue;
115
- }, [normalizedValue]);
116
- const handleValueChange = useCallback((nextValue) => {
117
- const normalizedNextValue = normalizeValue(nextValue);
118
- const previousValue = previousValueRef.current;
119
- if (isMultiple) {
120
- const prevValues = Array.isArray(previousValue) ? previousValue : [];
121
- const nextValues = Array.isArray(normalizedNextValue) ? normalizedNextValue : [];
122
- nextValues.filter((val) => !prevValues.some((prev) => Object.is(prev, val))).forEach((val) => {
123
- onSelect?.(val, getOption(val));
124
- });
125
- if (value === void 0) setUncontrolledValue(nextValues);
126
- onChange?.(nextValues, nextValues.map((val) => getOption(val)));
127
- } else {
128
- if (!isValueEmpty(normalizedNextValue) && !Object.is(previousValue, normalizedNextValue)) onSelect?.(normalizedNextValue, getOption(normalizedNextValue));
129
- if (value === void 0) setUncontrolledValue(normalizedNextValue);
130
- onChange?.(normalizedNextValue, isValueEmpty(normalizedNextValue) ? void 0 : getOption(normalizedNextValue));
131
- }
132
- previousValueRef.current = normalizedNextValue;
133
- }, [
134
- getOption,
135
25
  isMultiple,
136
- normalizeValue,
137
26
  onChange,
138
27
  onSelect,
28
+ options,
29
+ setExtraOptions,
139
30
  value
140
- ]);
141
- const appendTagValues = useCallback((rawValues) => {
142
- const valuesToAdd = rawValues.map((val) => val.trim()).filter(Boolean);
143
- if (!valuesToAdd.length) return;
144
- const nextValues = [...valueArray];
145
- const newOptionValues = valuesToAdd.filter((val) => !optionMap.has(val));
146
- if (newOptionValues.length > 0) setExtraOptions((prev) => {
147
- const existingValues = new Set(prev.map((item) => item.value));
148
- const merged = [...prev];
149
- newOptionValues.forEach((val) => {
150
- if (!existingValues.has(val)) merged.push({
151
- label: val,
152
- value: val
153
- });
154
- });
155
- return merged;
156
- });
157
- valuesToAdd.forEach((val) => {
158
- if (!nextValues.some((item) => Object.is(item, val))) nextValues.push(val);
159
- });
160
- if (nextValues.length !== valueArray.length) handleValueChange(nextValues);
161
- }, [
162
- handleValueChange,
163
- optionMap,
164
- valueArray
165
- ]);
166
- const handleSearchChange = useCallback((event) => {
167
- const nextValue = event.target.value;
168
- if (mode === "tags") {
169
- const parts = splitBySeparators(nextValue, tokenSeparators);
170
- if (parts.length > 1) {
171
- const pending = parts.pop() ?? "";
172
- appendTagValues(parts.filter(Boolean));
173
- setSearchValue(pending);
174
- return;
175
- }
176
- }
177
- setSearchValue(nextValue);
178
- }, [
179
- appendTagValues,
180
- mode,
181
- tokenSeparators
182
- ]);
183
- const handleSearchKeyDown = useCallback((event) => {
184
- event.stopPropagation();
185
- if (event.key === "Escape") {
186
- handleOpenChange(false);
187
- return;
188
- }
189
- if (mode !== "tags") return;
190
- if (event.key === "Enter") {
191
- event.preventDefault();
192
- event.stopPropagation();
193
- appendTagValues([searchValue]);
194
- setSearchValue("");
195
- return;
196
- }
197
- if (tokenSeparators?.includes(event.key)) {
198
- event.preventDefault();
199
- event.stopPropagation();
200
- appendTagValues([searchValue]);
201
- setSearchValue("");
202
- }
203
- }, [
31
+ });
32
+ const { handleOpenChange, mergedOpen } = useSelectOpen({
33
+ defaultOpen,
34
+ onOpenChange,
35
+ open
36
+ });
37
+ const { filteredOptions, handleSearchChange, handleSearchKeyDown, searchValue, shouldShowSearch, stopSearchPropagation } = useSelectSearch({
204
38
  appendTagValues,
205
39
  handleOpenChange,
40
+ mergedOpen,
206
41
  mode,
207
- searchValue,
208
- tokenSeparators
209
- ]);
210
- const filteredOptions = useMemo(() => {
211
- if (!shouldShowSearch || !searchValue.trim()) return resolvedOptions;
212
- const query = searchValue.trim().toLowerCase();
213
- const filterItems = (items) => {
214
- return items.map((item) => {
215
- if (isGroupOption(item)) {
216
- const groupItems = item.options.filter((option) => getOptionSearchText(option).toLowerCase().includes(query));
217
- if (!groupItems.length) return null;
218
- return {
219
- ...item,
220
- options: groupItems
221
- };
222
- }
223
- return getOptionSearchText(item).toLowerCase().includes(query) ? item : null;
224
- }).filter(Boolean);
225
- };
226
- return filterItems(resolvedOptions);
227
- }, [
228
42
  resolvedOptions,
229
- searchValue,
230
- shouldShowSearch
231
- ]);
232
- const renderValue = useCallback((currentValue) => {
233
- const resolved = normalizeValue(currentValue);
234
- const placeholderNode = placeholder === void 0 ? null : /* @__PURE__ */ jsx("span", {
235
- className: styles$1.valueText,
236
- children: placeholder
237
- });
238
- if (isMultiple) {
239
- const values = Array.isArray(resolved) ? resolved : [];
240
- if (values.length === 0) return placeholderNode;
241
- return /* @__PURE__ */ jsx("span", {
242
- className: styles$1.tags,
243
- children: values.map((val, index) => {
244
- const option = getOption(val);
245
- const content = labelRender ? labelRender(option) : option.label ?? String(val);
246
- return /* @__PURE__ */ jsx("span", {
247
- className: styles$1.tag,
248
- children: content
249
- }, `${String(val)}-${index}`);
250
- })
251
- });
252
- }
253
- if (isValueEmpty(resolved)) return placeholderNode;
254
- const option = getOption(resolved);
255
- const content = labelRender ? labelRender(option) : option.label ?? String(resolved);
256
- return /* @__PURE__ */ jsx("span", {
257
- className: styles$1.valueText,
258
- children: content
259
- });
260
- }, [
43
+ showSearch,
44
+ tokenSeparators
45
+ });
46
+ const virtualState = useSelectVirtual({
47
+ filteredOptions,
48
+ listItemHeight,
49
+ size,
50
+ valueArray,
51
+ virtual
52
+ });
53
+ const portalContainer = usePortalContainer();
54
+ const renderValue = useMemo(() => createTriggerValueRenderer({
55
+ getOption,
56
+ isMultiple,
57
+ labelRender,
58
+ normalizeValue,
59
+ placeholder
60
+ }), [
261
61
  getOption,
262
62
  isMultiple,
263
63
  labelRender,
@@ -271,32 +71,8 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
271
71
  event.stopPropagation();
272
72
  handleValueChange(isMultiple ? [] : null);
273
73
  }, [handleValueChange, isMultiple]);
274
- const prefixNode = useMemo(() => {
275
- if (prefix === void 0 || prefix === null) return null;
276
- if (isValidElement(prefix) || typeof prefix === "string" || typeof prefix === "number") return prefix;
277
- return /* @__PURE__ */ jsx(Icon, {
278
- icon: prefix,
279
- size: "small"
280
- });
281
- }, [prefix]);
282
- const suffixIconNode = useMemo(() => {
283
- if (loading) return /* @__PURE__ */ jsx(Icon, {
284
- spin: true,
285
- icon: Loader2,
286
- size: "small"
287
- });
288
- if (suffixIcon === null) return null;
289
- if (isValidElement(suffixIcon) || typeof suffixIcon === "string" || typeof suffixIcon === "number") return suffixIcon;
290
- return /* @__PURE__ */ jsx(Icon, {
291
- icon: suffixIcon || ChevronDown,
292
- size: "small",
293
- ...suffixIconProps,
294
- style: {
295
- pointerEvents: "none",
296
- ...suffixIconProps?.style
297
- }
298
- });
299
- }, [
74
+ const prefixNode = useMemo(() => resolveIconNode(prefix), [prefix]);
75
+ const suffixIconNode = useMemo(() => resolveSuffixIcon(suffixIcon, suffixIconProps, loading), [
300
76
  loading,
301
77
  suffixIcon,
302
78
  suffixIconProps
@@ -329,133 +105,19 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
329
105
  size,
330
106
  variant: resolvedVariant
331
107
  }), className, classNames?.root, classNames?.trigger);
332
- const listRef = useRef(null);
333
- const pointerScrollRef = useRef(false);
334
- const pointerScrollTimeoutRef = useRef(null);
335
- const renderVirtualItem = useCallback((props) => {
336
- const { ref, ...rest } = props;
337
- return /* @__PURE__ */ jsx("div", {
338
- ...rest,
339
- ref: (node) => {
340
- if (node) node.scrollIntoView = (...args) => {
341
- if (!pointerScrollRef.current) HTMLElement.prototype.scrollIntoView.call(node, ...args);
342
- };
343
- if (typeof ref === "function") ref(node);
344
- else if (ref && "current" in ref) ref.current = node;
345
- }
346
- });
347
- }, []);
348
- const markPointerScroll = useCallback(() => {
349
- pointerScrollRef.current = true;
350
- if (pointerScrollTimeoutRef.current) clearTimeout(pointerScrollTimeoutRef.current);
351
- pointerScrollTimeoutRef.current = setTimeout(() => {
352
- pointerScrollRef.current = false;
353
- }, 120);
354
- }, []);
355
- const handleListScroll = useCallback(() => {
356
- if (!virtual || !pointerScrollRef.current) return;
357
- const listElement = listRef.current;
358
- const activeElement = document.activeElement;
359
- if (listElement && activeElement && listElement.contains(activeElement)) listElement.focus({ preventScroll: true });
360
- }, [virtual]);
361
- useEffect(() => {
362
- return () => {
363
- if (pointerScrollTimeoutRef.current) clearTimeout(pointerScrollTimeoutRef.current);
364
- };
365
- }, []);
366
- const virtualListStyle = useMemo(() => {
367
- if (!virtual) return void 0;
368
- const rowCount = countVirtualItems(filteredOptions);
369
- return { height: `min(${Math.min(Math.max(rowCount, 1), 6) * (listItemHeight ?? (size === "large" ? 40 : size === "small" ? 28 : 32)) + 8}px, var(--lobe-select-available-height, var(--available-height)))` };
370
- }, [
371
- filteredOptions,
108
+ const isBoldIndicator = selectedIndicatorVariant === "bold";
109
+ const itemTextClassName = cx(optionRender ? styles.itemContent : styles.label, styles$1.itemText, classNames?.itemText);
110
+ const isEmpty = filteredOptions.length === 0;
111
+ const listContent = isEmpty ? /* @__PURE__ */ jsx(EmptyContent, { classNames }) : renderOptions({
112
+ classNames,
113
+ isBoldIndicator,
114
+ items: filteredOptions,
115
+ itemTextClassName,
372
116
  listItemHeight,
373
- size,
117
+ optionRender,
118
+ renderVirtualItem: virtualState.renderVirtualItem,
374
119
  virtual
375
- ]);
376
- const keepMountedIndices = useMemo(() => {
377
- if (!virtual || valueArray.length === 0) return void 0;
378
- const selectedSet = new Set(valueArray);
379
- const indices = [];
380
- let index = 0;
381
- filteredOptions.forEach((item) => {
382
- if (isGroupOption(item)) {
383
- if (item.options.some((option) => selectedSet.has(option.value))) indices.push(index);
384
- index += 1;
385
- return;
386
- }
387
- if (selectedSet.has(item.value)) indices.push(index);
388
- index += 1;
389
- });
390
- return indices.length ? indices : void 0;
391
- }, [
392
- filteredOptions,
393
- valueArray,
394
- virtual
395
- ]);
396
- const itemTextClassName = cx(optionRender ? styles.itemContent : styles.label, styles$1.itemText, classNames?.itemText);
397
- const isBoldIndicator = selectedIndicatorVariant === "bold";
398
- let optionIndex = 0;
399
- const renderOptions = (items) => items.map((item, index) => {
400
- if (isGroupOption(item)) return /* @__PURE__ */ jsxs(Select.Group, {
401
- className: cx(styles$1.group, classNames?.group),
402
- children: [/* @__PURE__ */ jsx(Select.GroupLabel, {
403
- className: cx(styles.groupLabel, styles$1.groupLabel, classNames?.groupLabel),
404
- children: item.label
405
- }), item.options.map((option) => {
406
- const currentIndex = optionIndex++;
407
- return /* @__PURE__ */ jsxs(Select.Item, {
408
- disabled: option.disabled,
409
- label: getOptionSearchText(option),
410
- render: virtual ? renderVirtualItem : void 0,
411
- value: option.value,
412
- className: cx(styles.item, styles$1.item, isBoldIndicator && styles$1.itemBoldSelected, classNames?.item, classNames?.option, option.className),
413
- style: {
414
- minHeight: listItemHeight,
415
- ...option.style
416
- },
417
- children: [/* @__PURE__ */ jsx(Select.ItemText, {
418
- className: itemTextClassName,
419
- children: optionRender ? optionRender(option, { index: currentIndex }) : option.label
420
- }), !isBoldIndicator && /* @__PURE__ */ jsx(Select.ItemIndicator, {
421
- className: cx(styles$1.itemIndicator, classNames?.itemIndicator),
422
- children: /* @__PURE__ */ jsx(Icon, {
423
- icon: Check,
424
- size: "small"
425
- })
426
- })]
427
- }, `${String(option.value)}-${currentIndex}`);
428
- })]
429
- }, `group-${index}`);
430
- const currentIndex = optionIndex++;
431
- return /* @__PURE__ */ jsxs(Select.Item, {
432
- disabled: item.disabled,
433
- label: getOptionSearchText(item),
434
- render: virtual ? renderVirtualItem : void 0,
435
- value: item.value,
436
- className: cx(styles.item, styles$1.item, isBoldIndicator && styles$1.itemBoldSelected, classNames?.item, classNames?.option, item.className),
437
- style: {
438
- minHeight: listItemHeight,
439
- ...item.style
440
- },
441
- children: [/* @__PURE__ */ jsx(Select.ItemText, {
442
- className: itemTextClassName,
443
- children: optionRender ? optionRender(item, { index: currentIndex }) : item.label
444
- }), !isBoldIndicator && /* @__PURE__ */ jsx(Select.ItemIndicator, {
445
- className: cx(styles$1.itemIndicator, classNames?.itemIndicator),
446
- children: /* @__PURE__ */ jsx(Icon, {
447
- icon: Check,
448
- size: "small"
449
- })
450
- })]
451
- }, `${String(item.value)}-${currentIndex}`);
452
120
  });
453
- const appElement = useAppElement();
454
- const portalContainer = useMemo(() => {
455
- if (typeof window === "undefined") return appElement;
456
- if (!(appElement instanceof HTMLElement)) return void 0;
457
- return window.getComputedStyle(appElement).display === "contents" ? document.body : appElement;
458
- }, [appElement]);
459
121
  return /* @__PURE__ */ jsxs(Select.Root, {
460
122
  disabled,
461
123
  id,
@@ -482,20 +144,11 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
482
144
  className: cx(styles$1.value, classNames?.value),
483
145
  children: renderValue
484
146
  }),
485
- /* @__PURE__ */ jsxs("span", {
486
- className: cx(styles$1.suffix, classNames?.suffix),
487
- children: [showClear && /* @__PURE__ */ jsx("span", {
488
- className: cx(styles$1.clear, classNames?.clear),
489
- "data-role": "lobe-select-clear",
490
- onClick: handleClear,
491
- children: /* @__PURE__ */ jsx(Icon, {
492
- icon: X,
493
- size: "small"
494
- })
495
- }), suffixIconNode !== null && suffixIconNode !== void 0 && /* @__PURE__ */ jsx(Select.Icon, {
496
- className: cx(styles$1.icon, classNames?.icon),
497
- children: suffixIconNode
498
- })]
147
+ /* @__PURE__ */ jsx(SelectTriggerSuffix, {
148
+ classNames,
149
+ showClear,
150
+ suffixIconNode,
151
+ onClear: handleClear
499
152
  })
500
153
  ]
501
154
  }), /* @__PURE__ */ jsx(Select.Portal, {
@@ -509,42 +162,21 @@ const Select$1 = memo(({ allowClear, autoFocus, className, classNames, defaultOp
509
162
  children: /* @__PURE__ */ jsxs(Select.Popup, {
510
163
  style: popupStyle,
511
164
  className: cx(styles.popup, styles$1.popup, popupClassName, classNames?.popup, classNames?.dropdown),
512
- children: [shouldShowSearch && /* @__PURE__ */ jsx("div", {
513
- className: cx(styles$1.search, classNames?.search),
514
- children: /* @__PURE__ */ jsx("input", {
515
- className: styles$1.searchInput,
516
- placeholder: typeof placeholder === "string" ? placeholder : void 0,
517
- value: searchValue,
518
- onChange: handleSearchChange,
519
- onKeyDown: handleSearchKeyDown
520
- })
521
- }), (() => {
522
- const content = filteredOptions.length > 0 ? renderOptions(filteredOptions) : /* @__PURE__ */ jsx("div", {
523
- className: cx(styles.item, styles.empty, styles$1.empty, classNames?.empty),
524
- children: "No data"
525
- });
526
- if (!virtual || filteredOptions.length === 0) return /* @__PURE__ */ jsx(Select.List, {
527
- className: cx(styles$1.list, classNames?.list),
528
- "data-virtual": virtual || void 0,
529
- children: content
530
- });
531
- return /* @__PURE__ */ jsx(Select.List, {
532
- className: cx(styles$1.list, classNames?.list),
533
- "data-virtual": virtual || void 0,
534
- ref: listRef,
535
- style: virtualListStyle,
536
- tabIndex: virtual ? -1 : void 0,
537
- onPointerDown: virtual ? markPointerScroll : void 0,
538
- onScroll: virtual ? handleListScroll : void 0,
539
- onTouchMove: virtual ? markPointerScroll : void 0,
540
- onWheel: virtual ? markPointerScroll : void 0,
541
- children: /* @__PURE__ */ jsx(Virtualizer, {
542
- itemSize: listItemHeight,
543
- keepMounted: keepMountedIndices,
544
- children: content
545
- })
546
- });
547
- })()]
165
+ children: [shouldShowSearch && /* @__PURE__ */ jsx(SelectSearchInput, {
166
+ classNames,
167
+ placeholder,
168
+ stopPropagation: stopSearchPropagation,
169
+ value: searchValue,
170
+ onChange: handleSearchChange,
171
+ onKeyDown: handleSearchKeyDown
172
+ }), /* @__PURE__ */ jsx(SelectListSection, {
173
+ classNames,
174
+ isEmpty,
175
+ listContent,
176
+ listItemHeight,
177
+ virtual,
178
+ virtualState
179
+ })]
548
180
  })
549
181
  })
550
182
  })]