@xsolla/xui-select 0.179.0 → 0.181.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.
- package/README.md +31 -6
- package/native/index.d.mts +4 -0
- package/native/index.d.ts +4 -0
- package/native/index.js +72 -19
- package/native/index.js.map +1 -1
- package/native/index.mjs +72 -19
- package/native/index.mjs.map +1 -1
- package/package.json +5 -5
- package/web/index.d.mts +4 -0
- package/web/index.d.ts +4 -0
- package/web/index.js +72 -19
- package/web/index.js.map +1 -1
- package/web/index.mjs +72 -19
- package/web/index.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -344,6 +344,29 @@ export default function FormWithSelect() {
|
|
|
344
344
|
}
|
|
345
345
|
```
|
|
346
346
|
|
|
347
|
+
### Dropdown Positioning
|
|
348
|
+
|
|
349
|
+
By default the dropdown always opens on the `side` (default `"bottom"`). Pass `autoFlip` to let it flip to the opposite side when there isn't enough viewport space.
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
import * as React from "react";
|
|
353
|
+
import { Select } from "@xsolla/xui-select";
|
|
354
|
+
|
|
355
|
+
const options = ["Option 1", "Option 2", "Option 3"];
|
|
356
|
+
|
|
357
|
+
// Always opens below (default — no surprises for existing layouts)
|
|
358
|
+
<Select options={options} placeholder="Default" />
|
|
359
|
+
|
|
360
|
+
// Always opens above
|
|
361
|
+
<Select side="top" options={options} placeholder="Opens above" />
|
|
362
|
+
|
|
363
|
+
// Opens below, flips above when near the bottom of the viewport
|
|
364
|
+
<Select autoFlip options={options} placeholder="Auto-flip enabled" />
|
|
365
|
+
|
|
366
|
+
// Opens above, flips below when near the top of the viewport
|
|
367
|
+
<Select side="top" autoFlip options={options} placeholder="Prefers top, flips if needed" />
|
|
368
|
+
```
|
|
369
|
+
|
|
347
370
|
## API Reference
|
|
348
371
|
|
|
349
372
|
### Select
|
|
@@ -378,6 +401,8 @@ The main select component. Renders a button trigger with dropdown menu.
|
|
|
378
401
|
| fullWidth | `boolean` | `true` | Whether the select should stretch to fill the full width of its container. |
|
|
379
402
|
| overlayThemeMode | `ThemeMode` | `themeMode` | Theme mode for the dropdown overlay. |
|
|
380
403
|
| overlayThemeProductContext | `ProductContext` | `themeProductContext` | Product context for the dropdown overlay. |
|
|
404
|
+
| side | `"top" \| "bottom"` | `"bottom"` | Preferred side for the dropdown. |
|
|
405
|
+
| autoFlip | `boolean` | `false` | When true, the dropdown flips to the opposite side when there isn't enough viewport space on the preferred side. |
|
|
381
406
|
|
|
382
407
|
**SelectOption Type:**
|
|
383
408
|
|
|
@@ -403,10 +428,10 @@ The Select component works on React Native with the following differences:
|
|
|
403
428
|
|
|
404
429
|
## Accessibility
|
|
405
430
|
|
|
406
|
-
-
|
|
407
|
-
-
|
|
408
|
-
-
|
|
409
|
-
-
|
|
410
|
-
-
|
|
411
|
-
-
|
|
431
|
+
- Trigger has `role="combobox"`, `aria-haspopup="listbox"`, and `aria-expanded` (updates on open/close)
|
|
432
|
+
- Trigger links to its label via `aria-labelledby` when the `label` prop is set
|
|
433
|
+
- Dropdown has `role="listbox"`; each option has `role="option"` and `aria-selected`
|
|
434
|
+
- Disabled trigger and disabled options expose `aria-disabled="true"`
|
|
435
|
+
- Search input has `aria-label` matching `searchPlaceholder`
|
|
436
|
+
- Selected item auto-scrolls into view when the dropdown opens (web only)
|
|
412
437
|
- Disabled state properly communicated to assistive technology
|
package/native/index.d.mts
CHANGED
|
@@ -35,6 +35,10 @@ interface SelectProps extends ThemeOverrideProps {
|
|
|
35
35
|
overlayThemeMode?: ThemeMode;
|
|
36
36
|
/** Product context for the dropdown overlay. Defaults to themeProductContext when not set. */
|
|
37
37
|
overlayThemeProductContext?: ProductContext;
|
|
38
|
+
/** Preferred side for the dropdown. Default: "bottom". */
|
|
39
|
+
side?: "top" | "bottom";
|
|
40
|
+
/** When true, the dropdown flips to the opposite side when there isn't enough viewport space. Default: false. */
|
|
41
|
+
autoFlip?: boolean;
|
|
38
42
|
}
|
|
39
43
|
declare const Select: React.FC<SelectProps>;
|
|
40
44
|
|
package/native/index.d.ts
CHANGED
|
@@ -35,6 +35,10 @@ interface SelectProps extends ThemeOverrideProps {
|
|
|
35
35
|
overlayThemeMode?: ThemeMode;
|
|
36
36
|
/** Product context for the dropdown overlay. Defaults to themeProductContext when not set. */
|
|
37
37
|
overlayThemeProductContext?: ProductContext;
|
|
38
|
+
/** Preferred side for the dropdown. Default: "bottom". */
|
|
39
|
+
side?: "top" | "bottom";
|
|
40
|
+
/** When true, the dropdown flips to the opposite side when there isn't enough viewport space. Default: false. */
|
|
41
|
+
autoFlip?: boolean;
|
|
38
42
|
}
|
|
39
43
|
declare const Select: React.FC<SelectProps>;
|
|
40
44
|
|
package/native/index.js
CHANGED
|
@@ -347,7 +347,9 @@ var Select = ({
|
|
|
347
347
|
themeMode,
|
|
348
348
|
themeProductContext,
|
|
349
349
|
overlayThemeMode,
|
|
350
|
-
overlayThemeProductContext
|
|
350
|
+
overlayThemeProductContext,
|
|
351
|
+
side = "bottom",
|
|
352
|
+
autoFlip = false
|
|
351
353
|
}) => {
|
|
352
354
|
const { theme: rawTheme } = (0, import_xui_core.useResolvedTheme)({
|
|
353
355
|
themeMode,
|
|
@@ -369,6 +371,11 @@ var Select = ({
|
|
|
369
371
|
const dropdownRef = (0, import_react2.useRef)(null);
|
|
370
372
|
const selectedItemRef = (0, import_react2.useRef)(null);
|
|
371
373
|
const searchInputRef = (0, import_react2.useRef)(null);
|
|
374
|
+
const [baseId] = (0, import_react2.useState)(
|
|
375
|
+
() => `xui-select-${Math.random().toString(36).slice(2, 9)}`
|
|
376
|
+
);
|
|
377
|
+
const labelId = `${baseId}-label`;
|
|
378
|
+
const listboxId = `${baseId}-listbox`;
|
|
372
379
|
const isDisable = externalState === "disable" || disabled;
|
|
373
380
|
const isError = externalState === "error" || !!errorMessage;
|
|
374
381
|
const isFocus = externalState === "focus" || isOpen;
|
|
@@ -376,14 +383,35 @@ var Select = ({
|
|
|
376
383
|
const inputColors = theme.colors.control.input;
|
|
377
384
|
const overlayInputColors = overlayTheme.colors.control.input;
|
|
378
385
|
const updateDropdownPosition = (0, import_react2.useCallback)(() => {
|
|
379
|
-
if (!isWeb || !triggerRef.current) return;
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
386
|
+
if (!isWeb || !triggerRef.current || !dropdownRef.current) return;
|
|
387
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
388
|
+
const dropH = dropdownRef.current.getBoundingClientRect().height;
|
|
389
|
+
const gap = sizeStyles.fieldGap;
|
|
390
|
+
const viewportHeight = window.innerHeight;
|
|
391
|
+
const spaceBelow = viewportHeight - triggerRect.bottom - gap;
|
|
392
|
+
const spaceAbove = triggerRect.top - gap;
|
|
393
|
+
const placeBelow = () => setDropdownPosition({
|
|
394
|
+
left: triggerRect.left,
|
|
395
|
+
top: triggerRect.bottom + gap,
|
|
396
|
+
width: triggerRect.width,
|
|
397
|
+
visible: true
|
|
398
|
+
});
|
|
399
|
+
const placeAbove = () => setDropdownPosition({
|
|
400
|
+
left: triggerRect.left,
|
|
401
|
+
bottom: viewportHeight - triggerRect.top + gap,
|
|
402
|
+
width: triggerRect.width,
|
|
403
|
+
visible: true
|
|
385
404
|
});
|
|
386
|
-
|
|
405
|
+
if (!autoFlip) {
|
|
406
|
+
side === "top" ? placeAbove() : placeBelow();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (side === "top") {
|
|
410
|
+
spaceAbove >= dropH || spaceAbove >= spaceBelow ? placeAbove() : placeBelow();
|
|
411
|
+
} else {
|
|
412
|
+
spaceBelow >= dropH || spaceBelow >= spaceAbove ? placeBelow() : placeAbove();
|
|
413
|
+
}
|
|
414
|
+
}, [sizeStyles.fieldGap, side, autoFlip]);
|
|
387
415
|
(0, import_react2.useEffect)(() => {
|
|
388
416
|
if (value !== void 0) setSelectedValue(value);
|
|
389
417
|
}, [value]);
|
|
@@ -401,12 +429,17 @@ var Select = ({
|
|
|
401
429
|
if (!isWeb || !isFocus) return;
|
|
402
430
|
updateDropdownPosition();
|
|
403
431
|
window.addEventListener("resize", updateDropdownPosition);
|
|
404
|
-
window.
|
|
405
|
-
return () => {
|
|
406
|
-
window.removeEventListener("resize", updateDropdownPosition);
|
|
407
|
-
window.removeEventListener("scroll", updateDropdownPosition, true);
|
|
408
|
-
};
|
|
432
|
+
return () => window.removeEventListener("resize", updateDropdownPosition);
|
|
409
433
|
}, [isFocus, updateDropdownPosition]);
|
|
434
|
+
(0, import_react2.useEffect)(() => {
|
|
435
|
+
if (!isWeb || !isOpen) return;
|
|
436
|
+
const closeOnScroll = (e) => {
|
|
437
|
+
if (dropdownRef.current?.contains(e.target)) return;
|
|
438
|
+
setIsOpen(false);
|
|
439
|
+
};
|
|
440
|
+
window.addEventListener("scroll", closeOnScroll, true);
|
|
441
|
+
return () => window.removeEventListener("scroll", closeOnScroll, true);
|
|
442
|
+
}, [isOpen]);
|
|
410
443
|
(0, import_react2.useEffect)(() => {
|
|
411
444
|
if (isFocus && searchable) searchInputRef.current?.focus();
|
|
412
445
|
}, [isFocus, searchable]);
|
|
@@ -476,22 +509,31 @@ var Select = ({
|
|
|
476
509
|
const textColor = isDisable ? inputColors.textDisable : selectedValue ? inputColors.text : inputColors.placeholder;
|
|
477
510
|
const iconColor = isDisable ? inputColors.textDisable : inputColors.text;
|
|
478
511
|
const dropdownTop = sizeStyles.height + (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) + sizeStyles.fieldGap;
|
|
479
|
-
const dropdown = isFocus && options.length > 0 &&
|
|
512
|
+
const dropdown = isFocus && options.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
480
513
|
Box,
|
|
481
514
|
{
|
|
482
515
|
ref: dropdownRef,
|
|
516
|
+
id: listboxId,
|
|
517
|
+
role: "listbox",
|
|
518
|
+
"aria-label": label || placeholder,
|
|
483
519
|
"data-modal-id": modalId,
|
|
484
|
-
position: isNative ? "absolute" :
|
|
485
|
-
top: isNative ? dropdownTop :
|
|
486
|
-
left: isNative ? void 0 : dropdownPosition?.left,
|
|
487
|
-
width: isNative ? "100%" : dropdownPosition?.width,
|
|
520
|
+
position: isNative ? "absolute" : void 0,
|
|
521
|
+
top: isNative ? dropdownTop : void 0,
|
|
488
522
|
backgroundColor: overlayTheme.colors.background.secondary,
|
|
489
523
|
borderColor: overlayTheme.colors.border.secondary,
|
|
490
524
|
borderWidth: 1,
|
|
491
525
|
borderRadius: overlayTheme.shape.contextMenu[size].borderRadius,
|
|
492
526
|
style: {
|
|
493
527
|
zIndex: 2e3,
|
|
494
|
-
...isNative ? { elevation: 4 } : {
|
|
528
|
+
...isNative ? { elevation: 4 } : {
|
|
529
|
+
position: "fixed",
|
|
530
|
+
top: dropdownPosition?.top != null ? dropdownPosition.top : void 0,
|
|
531
|
+
bottom: dropdownPosition?.bottom != null ? dropdownPosition.bottom : void 0,
|
|
532
|
+
left: dropdownPosition?.left,
|
|
533
|
+
width: dropdownPosition?.width,
|
|
534
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
|
|
535
|
+
visibility: dropdownPosition?.visible ? "visible" : "hidden"
|
|
536
|
+
},
|
|
495
537
|
minWidth: iconOnly ? sizeStyles.height * 3 : void 0
|
|
496
538
|
},
|
|
497
539
|
children: [
|
|
@@ -525,6 +567,7 @@ var Select = ({
|
|
|
525
567
|
ref: searchInputRef,
|
|
526
568
|
flex: 1,
|
|
527
569
|
type: "text",
|
|
570
|
+
"aria-label": searchPlaceholder,
|
|
528
571
|
value: searchValue,
|
|
529
572
|
onChange: (e) => setSearchValue(e.target.value),
|
|
530
573
|
placeholder: searchPlaceholder,
|
|
@@ -578,6 +621,9 @@ var Select = ({
|
|
|
578
621
|
Box,
|
|
579
622
|
{
|
|
580
623
|
testID,
|
|
624
|
+
role: "option",
|
|
625
|
+
"aria-selected": isSelected,
|
|
626
|
+
"aria-disabled": isOptionDisabled || void 0,
|
|
581
627
|
ref: isSelected ? selectedItemRef : void 0,
|
|
582
628
|
paddingVertical: sizeStyles.paddingVertical,
|
|
583
629
|
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
@@ -624,6 +670,7 @@ var Select = ({
|
|
|
624
670
|
label && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
625
671
|
Text,
|
|
626
672
|
{
|
|
673
|
+
id: labelId,
|
|
627
674
|
color: theme.colors.content.secondary,
|
|
628
675
|
fontSize: sizeStyles.fontSize - 2,
|
|
629
676
|
fontWeight: "500",
|
|
@@ -635,6 +682,12 @@ var Select = ({
|
|
|
635
682
|
{
|
|
636
683
|
ref: triggerRef,
|
|
637
684
|
onPress: handlePress,
|
|
685
|
+
role: "combobox",
|
|
686
|
+
"aria-haspopup": "listbox",
|
|
687
|
+
"aria-expanded": isFocus && options.length > 0,
|
|
688
|
+
"aria-controls": listboxId,
|
|
689
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
690
|
+
"aria-disabled": isDisable || void 0,
|
|
638
691
|
backgroundColor,
|
|
639
692
|
borderColor,
|
|
640
693
|
borderWidth: borderColor !== "transparent" ? 1 : 0,
|
package/native/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.tsx","../../src/Select.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/Icon.tsx","../../../../foundation/primitives-native/src/index.tsx","../../src/Portal.native.tsx"],"sourcesContent":["export * from \"./Select\";\n","import React, { useState, useRef, useEffect, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, Icon, isWeb, isNative } from \"@xsolla/xui-primitives\";\nimport {\n useModalId,\n useResolvedTheme,\n type ThemeOverrideProps,\n type ThemeMode,\n type ProductContext,\n} from \"@xsolla/xui-core\";\nimport { useClickOutside } from \"@xsolla/xui-hooks\";\nimport {\n ChevronDown,\n ChevronUp,\n ExclamationMarkCr,\n Remove,\n Search as SearchIcon,\n} from \"@xsolla/xui-icons-base\";\nimport { Portal } from \"./Portal\";\n\nexport interface SelectOption {\n label: string;\n value: any;\n disabled?: boolean;\n}\n\nexport interface SelectProps extends ThemeOverrideProps {\n value?: string;\n placeholder?: string;\n onPress?: () => void;\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n state?: \"default\" | \"hover\" | \"focus\" | \"disable\" | \"error\";\n disabled?: boolean;\n label?: string;\n errorMessage?: string;\n iconLeft?: React.ReactNode;\n iconRight?: React.ReactNode;\n filled?: boolean;\n iconOnly?: boolean;\n options?: (string | SelectOption)[];\n onChange?: (value: string) => void;\n searchable?: boolean;\n searchPlaceholder?: string;\n noOptionsMessage?: string;\n /** Show a clear button to reset the selected value (field variant only) */\n clearable?: boolean;\n /** Called when the clear button is pressed */\n onClear?: () => void;\n maxHeight?: number;\n fullWidth?: boolean;\n testID?: string;\n /** Theme mode for the dropdown overlay. Defaults to themeMode when not set. */\n overlayThemeMode?: ThemeMode;\n /** Product context for the dropdown overlay. Defaults to themeProductContext when not set. */\n overlayThemeProductContext?: ProductContext;\n}\n\ninterface DropdownPosition {\n left: number;\n top: number;\n width: number;\n}\n\nexport const Select: React.FC<SelectProps> = ({\n value,\n placeholder = \"Select\",\n onPress,\n size = \"md\",\n state: externalState,\n disabled = false,\n label,\n errorMessage,\n iconLeft,\n iconRight,\n filled = true,\n iconOnly = false,\n options = [],\n onChange,\n searchable = false,\n searchPlaceholder = \"Search\",\n noOptionsMessage = \"No results\",\n clearable = false,\n onClear,\n maxHeight = 300,\n fullWidth = true,\n testID,\n themeMode,\n themeProductContext,\n overlayThemeMode,\n overlayThemeProductContext,\n}) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\n const { theme: rawOverlayTheme } = useResolvedTheme({\n themeMode: overlayThemeMode ?? themeMode,\n themeProductContext: overlayThemeProductContext ?? themeProductContext,\n });\n const overlayTheme = rawOverlayTheme as any;\n const modalId = useModalId();\n const [isOpen, setIsOpen] = useState(false);\n const [selectedValue, setSelectedValue] = useState<string | undefined>(value);\n const [searchValue, setSearchValue] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] =\n useState<DropdownPosition | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const selectedItemRef = useRef<HTMLDivElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n const isDisable = externalState === \"disable\" || disabled;\n const isError = externalState === \"error\" || !!errorMessage;\n const isFocus = externalState === \"focus\" || isOpen;\n\n // 1. Resolve Config from Theme\n const sizeStyles = theme.sizing.input(size);\n const inputColors = theme.colors.control.input;\n const overlayInputColors = overlayTheme.colors.control.input;\n\n const updateDropdownPosition = useCallback(() => {\n if (!isWeb || !triggerRef.current) return;\n\n const rect = triggerRef.current.getBoundingClientRect();\n setDropdownPosition({\n left: rect.left,\n top: rect.bottom + sizeStyles.fieldGap,\n width: rect.width,\n });\n }, [sizeStyles.fieldGap]);\n\n useEffect(() => {\n if (value !== undefined) setSelectedValue(value);\n }, [value]);\n\n useEffect(() => {\n if (isFocus && selectedItemRef.current && dropdownRef.current) {\n const timeoutId = setTimeout(() => {\n const selectedItem = selectedItemRef.current;\n if (selectedItem && isWeb)\n selectedItem.scrollIntoView({ block: \"nearest\" });\n }, 0);\n return () => clearTimeout(timeoutId);\n }\n }, [isFocus]);\n\n // Keep the portaled dropdown anchored to the trigger (web only)\n useEffect(() => {\n if (!isWeb || !isFocus) return;\n\n updateDropdownPosition();\n window.addEventListener(\"resize\", updateDropdownPosition);\n window.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n return () => {\n window.removeEventListener(\"resize\", updateDropdownPosition);\n window.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }, [isFocus, updateDropdownPosition]);\n\n useEffect(() => {\n if (isFocus && searchable) searchInputRef.current?.focus();\n }, [isFocus, searchable]);\n\n useEffect(() => {\n if (!isFocus) setSearchValue(\"\");\n }, [isFocus]);\n\n // Dropdown is portaled outside containerRef, so spare clicks that land in it\n useClickOutside(\n containerRef,\n useCallback((event: MouseEvent) => {\n const dropdownEl = dropdownRef.current;\n if (dropdownEl) {\n const path =\n typeof event.composedPath === \"function\"\n ? event.composedPath()\n : [];\n const insideDropdown = path.length\n ? path.includes(dropdownEl)\n : dropdownEl.contains(event.target as Node);\n if (insideDropdown) return;\n }\n setIsOpen(false);\n }, []),\n isWeb && isOpen\n );\n\n const getOptionLabel = (option: string | SelectOption) =>\n typeof option === \"string\" ? option : option.label;\n const getOptionValue = (option: string | SelectOption) =>\n typeof option === \"string\" ? option : option.value;\n const getOptionDisabled = (option: string | SelectOption) =>\n typeof option === \"string\" ? false : option.disabled || false;\n\n const filteredOptions =\n searchable && searchValue\n ? options.filter((option) =>\n getOptionLabel(option)\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n : options;\n\n const handlePress = () => {\n if (!isDisable) {\n if (onPress) onPress();\n setIsOpen(!isOpen);\n }\n };\n\n const handleSelect = (option: string | SelectOption) => {\n if (getOptionDisabled(option)) return;\n const val = getOptionValue(option);\n setSelectedValue(val);\n setIsOpen(false);\n if (onChange) onChange(val);\n };\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (isDisable) return;\n setSelectedValue(undefined);\n if (onChange) onChange(\"\");\n if (onClear) onClear();\n };\n\n const isHover = externalState === \"hover\";\n let backgroundColor = inputColors.bg;\n let borderColor = inputColors.border;\n\n if (isDisable) {\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n } else if (isFocus) {\n backgroundColor = theme.colors.control.focus.bg;\n borderColor = isError\n ? theme.colors.border.alert\n : theme.colors.border.brand;\n } else if (isError) {\n borderColor = theme.colors.border.alert;\n } else if (isHover) {\n backgroundColor = inputColors.bgHover;\n borderColor = inputColors.borderHover;\n }\n\n if (filled === false && !isFocus && !isError && !isHover) {\n backgroundColor = \"transparent\";\n }\n\n const currentLabel = selectedValue\n ? getOptionLabel(\n options.find((o) => getOptionValue(o) === selectedValue) ||\n selectedValue\n )\n : placeholder;\n\n const textColor = isDisable\n ? inputColors.textDisable\n : selectedValue\n ? inputColors.text\n : inputColors.placeholder;\n const iconColor = isDisable ? inputColors.textDisable : inputColors.text;\n\n const dropdownTop =\n sizeStyles.height +\n (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) +\n sizeStyles.fieldGap;\n\n const dropdown = isFocus &&\n options.length > 0 &&\n (isNative || dropdownPosition) && (\n <Box\n ref={dropdownRef}\n data-modal-id={modalId}\n position={isNative ? \"absolute\" : \"fixed\"}\n top={isNative ? dropdownTop : dropdownPosition?.top}\n left={isNative ? undefined : dropdownPosition?.left}\n width={isNative ? \"100%\" : dropdownPosition?.width}\n backgroundColor={overlayTheme.colors.background.secondary}\n borderColor={overlayTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={overlayTheme.shape.contextMenu[size].borderRadius}\n style={{\n zIndex: 2000,\n ...(isNative\n ? { elevation: 4 }\n : { boxShadow: \"0 4px 12px rgba(0,0,0,0.1)\" }),\n minWidth: iconOnly ? sizeStyles.height * 3 : undefined,\n }}\n >\n {/* Search Input - Outside scrollable area (web only) */}\n {searchable && !isNative && (\n <Box\n paddingHorizontal={sizeStyles.paddingHorizontal}\n paddingVertical={sizeStyles.paddingVertical}\n borderBottomWidth={1}\n borderColor={overlayTheme.colors.border.secondary}\n >\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={sizeStyles.paddingHorizontal / 2}\n paddingHorizontal={4}\n >\n <Icon\n size={sizeStyles.iconSize - 2}\n color={overlayInputColors.placeholder}\n >\n <SearchIcon />\n </Icon>\n <Box\n as=\"input\"\n ref={searchInputRef}\n flex={1}\n type=\"text\"\n value={searchValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setSearchValue(e.target.value)\n }\n placeholder={searchPlaceholder}\n style={{\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n color: overlayInputColors.text,\n fontSize: sizeStyles.fontSize,\n width: \"100%\",\n }}\n />\n </Box>\n </Box>\n )}\n\n {/* Options List - Scrollable */}\n <Box\n paddingVertical={4}\n overflow=\"scroll\"\n style={{\n maxHeight: searchable ? maxHeight - 60 : maxHeight,\n ...(isWeb ? { overflowY: \"auto\" } : {}),\n }}\n >\n {filteredOptions.length === 0 ? (\n <Box\n paddingVertical={sizeStyles.paddingVertical * 2}\n paddingHorizontal={sizeStyles.paddingHorizontal}\n alignItems=\"center\"\n >\n <Text\n color={overlayTheme.colors.content.tertiary}\n fontSize={sizeStyles.fontSize}\n >\n {noOptionsMessage}\n </Text>\n </Box>\n ) : (\n filteredOptions.map((option, index) => {\n const optionValue = getOptionValue(option);\n const optionLabel = getOptionLabel(option);\n const isOptionDisabled = getOptionDisabled(option);\n const isSelected = optionValue === selectedValue;\n const brandColors = overlayTheme.colors.control.brand.primary;\n const contentColors = overlayTheme.colors.content;\n return (\n <Box\n testID={testID}\n key={index}\n ref={isSelected ? selectedItemRef : undefined}\n paddingVertical={sizeStyles.paddingVertical}\n paddingHorizontal={sizeStyles.paddingHorizontal}\n onPress={\n isOptionDisabled ? undefined : () => handleSelect(option)\n }\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n backgroundColor={isSelected ? brandColors.bg : \"transparent\"}\n style={{\n ...(isWeb\n ? {\n cursor: isOptionDisabled ? \"not-allowed\" : \"pointer\",\n }\n : {}),\n opacity: isOptionDisabled ? 0.5 : 1,\n }}\n hoverStyle={\n !isSelected && !isOptionDisabled\n ? { backgroundColor: overlayInputColors.bgHover }\n : undefined\n }\n >\n <Text\n color={\n isSelected\n ? contentColors.on.brand\n : overlayTheme.colors.content.secondary\n }\n fontSize={sizeStyles.fontSize}\n fontWeight=\"400\"\n >\n {optionLabel}\n </Text>\n </Box>\n );\n })\n )}\n </Box>\n </Box>\n );\n\n return (\n <Box\n testID={testID}\n ref={containerRef}\n flexDirection=\"column\"\n gap={sizeStyles.fieldGap}\n width={fullWidth ? \"100%\" : undefined}\n position=\"relative\"\n >\n {label && (\n <Text\n color={theme.colors.content.secondary}\n fontSize={sizeStyles.fontSize - 2}\n fontWeight=\"500\"\n >\n {label}\n </Text>\n )}\n <Box\n ref={triggerRef}\n onPress={handlePress}\n backgroundColor={backgroundColor}\n borderColor={borderColor}\n borderWidth={borderColor !== \"transparent\" ? 1 : 0}\n borderRadius={sizeStyles.radius}\n height={sizeStyles.height}\n width={iconOnly ? sizeStyles.height : \"100%\"}\n paddingHorizontal={iconOnly ? 0 : sizeStyles.paddingHorizontal}\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent={iconOnly ? \"center\" : \"flex-start\"}\n gap={iconOnly ? 4 : 12}\n position=\"relative\"\n hoverStyle={\n !isDisable && !isFocus && !isError\n ? {\n backgroundColor: inputColors.bgHover,\n borderColor: inputColors.borderHover,\n }\n : undefined\n }\n >\n {iconLeft && (\n <Box alignItems=\"center\" justifyContent=\"center\">\n <Icon size={sizeStyles.iconSize} color={iconColor}>\n {iconLeft}\n </Icon>\n </Box>\n )}\n {!iconOnly && (\n <Box\n flex={1}\n height=\"100%\"\n justifyContent=\"center\"\n overflow=\"hidden\"\n overflowX=\"hidden\"\n >\n <Text\n color={textColor}\n fontSize={sizeStyles.fontSize}\n numberOfLines={1}\n style={{ whiteSpace: \"nowrap\" }}\n >\n {currentLabel}\n </Text>\n </Box>\n )}\n <Box flexDirection=\"row\" alignItems=\"center\" gap={4}>\n {/* Clear button (field variant only) */}\n {clearable && !iconOnly && !isDisable && selectedValue && (\n <Box\n onPress={handleClear}\n alignItems=\"center\"\n justifyContent=\"center\"\n style={isWeb ? { cursor: \"pointer\" } : undefined}\n >\n <Remove\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n </Box>\n )}\n\n {/* Error icon */}\n {isError && (\n <Icon\n size={sizeStyles.iconSize}\n color={theme.colors.content.alert.primary}\n >\n <ExclamationMarkCr />\n </Icon>\n )}\n {iconRight !== undefined ? (\n <Icon size={sizeStyles.iconSize} color={iconColor}>\n {iconRight}\n </Icon>\n ) : isFocus ? (\n <ChevronUp\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n ) : (\n <ChevronDown\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n )}\n </Box>\n </Box>\n\n {/* Dropdown Menu */}\n {isNative ? dropdown : <Portal>{dropdown}</Portal>}\n\n {isError && errorMessage && (\n <Text\n color={theme.colors.content.alert.primary}\n fontSize={sizeStyles.fontSize - 2}\n style={{ lineHeight: sizeStyles.lineHeight + \"px\" }}\n >\n {errorMessage}\n </Text>\n )}\n </Box>\n );\n};\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\nimport { View, ViewStyle } from \"react-native\";\nimport { IconProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Icon: React.FC<IconProps> = ({\n children,\n color,\n size,\n testID,\n \"data-testid\": dataTestId,\n}) => {\n const style: ViewStyle = {\n width: typeof size === \"number\" ? size : undefined,\n height: typeof size === \"number\" ? size : undefined,\n alignItems: \"center\",\n justifyContent: \"center\",\n };\n\n // On native, we try to pass the color down to children (like Text primitives)\n // to mimic the CSS inheritance behavior of the web version.\n const childrenWithProps = React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n color: child.props.color || color,\n // Also pass size if child seems to be an icon that needs it\n size: child.props.size || size,\n });\n }\n return child;\n });\n\n return (\n <View style={style} testID={dataTestId || testID}>\n {childrenWithProps}\n </View>\n );\n};\n","export * from \"./Box\";\nexport * from \"./Text\";\nexport * from \"./Spinner\";\nexport * from \"./Icon\";\nexport * from \"./Divider\";\nexport * from \"./Input\";\nexport * from \"./TextArea\";\nexport * from \"./LinearGradient\";\n\nexport const isWeb = false;\nexport const isNative = true;\n","import { ReactNode } from \"react\";\n\ninterface PortalProps {\n children: ReactNode;\n}\n\nexport const Portal = ({ children }: PortalProps) => <>{children}</>;\n"],"mappings":"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","names":["import_react","import_react_native","import_jsx_runtime","RNText","import_react_native","import_jsx_runtime","React","import_jsx_runtime","import_jsx_runtime","SearchIcon"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.tsx","../../src/Select.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/Icon.tsx","../../../../foundation/primitives-native/src/index.tsx","../../src/Portal.native.tsx"],"sourcesContent":["export * from \"./Select\";\n","import React, { useState, useRef, useEffect, useCallback } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, Icon, isWeb, isNative } from \"@xsolla/xui-primitives\";\nimport {\n useModalId,\n useResolvedTheme,\n type ThemeOverrideProps,\n type ThemeMode,\n type ProductContext,\n} from \"@xsolla/xui-core\";\nimport { useClickOutside } from \"@xsolla/xui-hooks\";\nimport {\n ChevronDown,\n ChevronUp,\n ExclamationMarkCr,\n Remove,\n Search as SearchIcon,\n} from \"@xsolla/xui-icons-base\";\nimport { Portal } from \"./Portal\";\n\nexport interface SelectOption {\n label: string;\n value: any;\n disabled?: boolean;\n}\n\nexport interface SelectProps extends ThemeOverrideProps {\n value?: string;\n placeholder?: string;\n onPress?: () => void;\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n state?: \"default\" | \"hover\" | \"focus\" | \"disable\" | \"error\";\n disabled?: boolean;\n label?: string;\n errorMessage?: string;\n iconLeft?: React.ReactNode;\n iconRight?: React.ReactNode;\n filled?: boolean;\n iconOnly?: boolean;\n options?: (string | SelectOption)[];\n onChange?: (value: string) => void;\n searchable?: boolean;\n searchPlaceholder?: string;\n noOptionsMessage?: string;\n /** Show a clear button to reset the selected value (field variant only) */\n clearable?: boolean;\n /** Called when the clear button is pressed */\n onClear?: () => void;\n maxHeight?: number;\n fullWidth?: boolean;\n testID?: string;\n /** Theme mode for the dropdown overlay. Defaults to themeMode when not set. */\n overlayThemeMode?: ThemeMode;\n /** Product context for the dropdown overlay. Defaults to themeProductContext when not set. */\n overlayThemeProductContext?: ProductContext;\n /** Preferred side for the dropdown. Default: \"bottom\". */\n side?: \"top\" | \"bottom\";\n /** When true, the dropdown flips to the opposite side when there isn't enough viewport space. Default: false. */\n autoFlip?: boolean;\n}\n\ninterface DropdownPosition {\n left: number;\n top?: number;\n bottom?: number;\n width: number;\n visible: boolean;\n}\n\nexport const Select: React.FC<SelectProps> = ({\n value,\n placeholder = \"Select\",\n onPress,\n size = \"md\",\n state: externalState,\n disabled = false,\n label,\n errorMessage,\n iconLeft,\n iconRight,\n filled = true,\n iconOnly = false,\n options = [],\n onChange,\n searchable = false,\n searchPlaceholder = \"Search\",\n noOptionsMessage = \"No results\",\n clearable = false,\n onClear,\n maxHeight = 300,\n fullWidth = true,\n testID,\n themeMode,\n themeProductContext,\n overlayThemeMode,\n overlayThemeProductContext,\n side = \"bottom\",\n autoFlip = false,\n}) => {\n const { theme: rawTheme } = useResolvedTheme({\n themeMode,\n themeProductContext,\n });\n const theme = rawTheme as any;\n const { theme: rawOverlayTheme } = useResolvedTheme({\n themeMode: overlayThemeMode ?? themeMode,\n themeProductContext: overlayThemeProductContext ?? themeProductContext,\n });\n const overlayTheme = rawOverlayTheme as any;\n const modalId = useModalId();\n const [isOpen, setIsOpen] = useState(false);\n const [selectedValue, setSelectedValue] = useState<string | undefined>(value);\n const [searchValue, setSearchValue] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] =\n useState<DropdownPosition | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const selectedItemRef = useRef<HTMLDivElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n // Stable IDs for ARIA relationships — lazy useState so it's computed once\n const [baseId] = useState(\n () => `xui-select-${Math.random().toString(36).slice(2, 9)}`\n );\n const labelId = `${baseId}-label`;\n const listboxId = `${baseId}-listbox`;\n\n const isDisable = externalState === \"disable\" || disabled;\n const isError = externalState === \"error\" || !!errorMessage;\n const isFocus = externalState === \"focus\" || isOpen;\n\n // 1. Resolve Config from Theme\n const sizeStyles = theme.sizing.input(size);\n const inputColors = theme.colors.control.input;\n const overlayInputColors = overlayTheme.colors.control.input;\n\n const updateDropdownPosition = useCallback(() => {\n if (!isWeb || !triggerRef.current || !dropdownRef.current) return;\n\n const triggerRect = triggerRef.current.getBoundingClientRect();\n // Read the actual rendered height — dropdown is in DOM (visibility: hidden) at this point\n const dropH = dropdownRef.current.getBoundingClientRect().height;\n const gap = sizeStyles.fieldGap;\n const viewportHeight = window.innerHeight;\n const spaceBelow = viewportHeight - triggerRect.bottom - gap;\n const spaceAbove = triggerRect.top - gap;\n\n const placeBelow = () =>\n setDropdownPosition({\n left: triggerRect.left,\n top: triggerRect.bottom + gap,\n width: triggerRect.width,\n visible: true,\n });\n\n const placeAbove = () =>\n setDropdownPosition({\n left: triggerRect.left,\n bottom: viewportHeight - triggerRect.top + gap,\n width: triggerRect.width,\n visible: true,\n });\n\n if (!autoFlip) {\n side === \"top\" ? placeAbove() : placeBelow();\n return;\n }\n\n // Auto-flip: prefer the requested side, flip only when there isn't enough room\n if (side === \"top\") {\n spaceAbove >= dropH || spaceAbove >= spaceBelow\n ? placeAbove()\n : placeBelow();\n } else {\n spaceBelow >= dropH || spaceBelow >= spaceAbove\n ? placeBelow()\n : placeAbove();\n }\n }, [sizeStyles.fieldGap, side, autoFlip]);\n\n useEffect(() => {\n if (value !== undefined) setSelectedValue(value);\n }, [value]);\n\n useEffect(() => {\n if (isFocus && selectedItemRef.current && dropdownRef.current) {\n const timeoutId = setTimeout(() => {\n const selectedItem = selectedItemRef.current;\n if (selectedItem && isWeb)\n selectedItem.scrollIntoView({ block: \"nearest\" });\n }, 0);\n return () => clearTimeout(timeoutId);\n }\n }, [isFocus]);\n\n // Keep the portaled dropdown anchored to the trigger (web only)\n // Positioning: runs whenever the dropdown becomes visible (covers both normal open\n // and forced-focus via the state prop). Resize repositions an already-open dropdown.\n useEffect(() => {\n if (!isWeb || !isFocus) return;\n updateDropdownPosition();\n window.addEventListener(\"resize\", updateDropdownPosition);\n return () => window.removeEventListener(\"resize\", updateDropdownPosition);\n }, [isFocus, updateDropdownPosition]);\n\n // Close-on-scroll: only active when the user has explicitly opened the dropdown\n // (isOpen=true), NOT when isFocus is forced via the state prop. This prevents\n // Storybook / forced-focus stories from closing immediately on ambient scroll events.\n // Scrolling inside the dropdown (the options list) is ignored.\n useEffect(() => {\n if (!isWeb || !isOpen) return;\n const closeOnScroll = (e: Event) => {\n if (dropdownRef.current?.contains(e.target as Node)) return;\n setIsOpen(false);\n };\n window.addEventListener(\"scroll\", closeOnScroll, true);\n return () => window.removeEventListener(\"scroll\", closeOnScroll, true);\n }, [isOpen]);\n\n useEffect(() => {\n if (isFocus && searchable) searchInputRef.current?.focus();\n }, [isFocus, searchable]);\n\n useEffect(() => {\n if (!isFocus) setSearchValue(\"\");\n }, [isFocus]);\n\n // Dropdown is portaled outside containerRef, so spare clicks that land in it\n useClickOutside(\n containerRef,\n useCallback((event: MouseEvent) => {\n const dropdownEl = dropdownRef.current;\n if (dropdownEl) {\n const path =\n typeof event.composedPath === \"function\" ? event.composedPath() : [];\n const insideDropdown = path.length\n ? path.includes(dropdownEl)\n : dropdownEl.contains(event.target as Node);\n if (insideDropdown) return;\n }\n setIsOpen(false);\n }, []),\n isWeb && isOpen\n );\n\n const getOptionLabel = (option: string | SelectOption) =>\n typeof option === \"string\" ? option : option.label;\n const getOptionValue = (option: string | SelectOption) =>\n typeof option === \"string\" ? option : option.value;\n const getOptionDisabled = (option: string | SelectOption) =>\n typeof option === \"string\" ? false : option.disabled || false;\n\n const filteredOptions =\n searchable && searchValue\n ? options.filter((option) =>\n getOptionLabel(option)\n .toLowerCase()\n .includes(searchValue.toLowerCase())\n )\n : options;\n\n const handlePress = () => {\n if (!isDisable) {\n if (onPress) onPress();\n setIsOpen(!isOpen);\n }\n };\n\n const handleSelect = (option: string | SelectOption) => {\n if (getOptionDisabled(option)) return;\n const val = getOptionValue(option);\n setSelectedValue(val);\n setIsOpen(false);\n if (onChange) onChange(val);\n };\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (isDisable) return;\n setSelectedValue(undefined);\n if (onChange) onChange(\"\");\n if (onClear) onClear();\n };\n\n const isHover = externalState === \"hover\";\n let backgroundColor = inputColors.bg;\n let borderColor = inputColors.border;\n\n if (isDisable) {\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n } else if (isFocus) {\n backgroundColor = theme.colors.control.focus.bg;\n borderColor = isError\n ? theme.colors.border.alert\n : theme.colors.border.brand;\n } else if (isError) {\n borderColor = theme.colors.border.alert;\n } else if (isHover) {\n backgroundColor = inputColors.bgHover;\n borderColor = inputColors.borderHover;\n }\n\n if (filled === false && !isFocus && !isError && !isHover) {\n backgroundColor = \"transparent\";\n }\n\n const currentLabel = selectedValue\n ? getOptionLabel(\n options.find((o) => getOptionValue(o) === selectedValue) ||\n selectedValue\n )\n : placeholder;\n\n const textColor = isDisable\n ? inputColors.textDisable\n : selectedValue\n ? inputColors.text\n : inputColors.placeholder;\n const iconColor = isDisable ? inputColors.textDisable : inputColors.text;\n\n const dropdownTop =\n sizeStyles.height +\n (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) +\n sizeStyles.fieldGap;\n\n const dropdown = isFocus && options.length > 0 && (\n <Box\n ref={dropdownRef}\n id={listboxId}\n role=\"listbox\"\n aria-label={label || placeholder}\n data-modal-id={modalId}\n position={isNative ? \"absolute\" : undefined}\n top={isNative ? dropdownTop : undefined}\n backgroundColor={overlayTheme.colors.background.secondary}\n borderColor={overlayTheme.colors.border.secondary}\n borderWidth={1}\n borderRadius={overlayTheme.shape.contextMenu[size].borderRadius}\n style={{\n zIndex: 2000,\n ...(isNative\n ? { elevation: 4 }\n : {\n position: \"fixed\",\n top:\n dropdownPosition?.top != null\n ? dropdownPosition.top\n : undefined,\n bottom:\n dropdownPosition?.bottom != null\n ? dropdownPosition.bottom\n : undefined,\n left: dropdownPosition?.left,\n width: dropdownPosition?.width,\n boxShadow: \"0 4px 12px rgba(0,0,0,0.1)\",\n visibility: dropdownPosition?.visible ? \"visible\" : \"hidden\",\n }),\n minWidth: iconOnly ? sizeStyles.height * 3 : undefined,\n }}\n >\n {/* Search Input - Outside scrollable area (web only) */}\n {searchable && !isNative && (\n <Box\n paddingHorizontal={sizeStyles.paddingHorizontal}\n paddingVertical={sizeStyles.paddingVertical}\n borderBottomWidth={1}\n borderColor={overlayTheme.colors.border.secondary}\n >\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n gap={sizeStyles.paddingHorizontal / 2}\n paddingHorizontal={4}\n >\n <Icon\n size={sizeStyles.iconSize - 2}\n color={overlayInputColors.placeholder}\n >\n <SearchIcon />\n </Icon>\n <Box\n as=\"input\"\n ref={searchInputRef}\n flex={1}\n type=\"text\"\n aria-label={searchPlaceholder}\n value={searchValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setSearchValue(e.target.value)\n }\n placeholder={searchPlaceholder}\n style={{\n border: \"none\",\n outline: \"none\",\n background: \"transparent\",\n color: overlayInputColors.text,\n fontSize: sizeStyles.fontSize,\n width: \"100%\",\n }}\n />\n </Box>\n </Box>\n )}\n\n {/* Options List - Scrollable */}\n <Box\n paddingVertical={4}\n overflow=\"scroll\"\n style={{\n maxHeight: searchable ? maxHeight - 60 : maxHeight,\n ...(isWeb ? { overflowY: \"auto\" } : {}),\n }}\n >\n {filteredOptions.length === 0 ? (\n <Box\n paddingVertical={sizeStyles.paddingVertical * 2}\n paddingHorizontal={sizeStyles.paddingHorizontal}\n alignItems=\"center\"\n >\n <Text\n color={overlayTheme.colors.content.tertiary}\n fontSize={sizeStyles.fontSize}\n >\n {noOptionsMessage}\n </Text>\n </Box>\n ) : (\n filteredOptions.map((option, index) => {\n const optionValue = getOptionValue(option);\n const optionLabel = getOptionLabel(option);\n const isOptionDisabled = getOptionDisabled(option);\n const isSelected = optionValue === selectedValue;\n const brandColors = overlayTheme.colors.control.brand.primary;\n const contentColors = overlayTheme.colors.content;\n return (\n <Box\n testID={testID}\n key={index}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={isOptionDisabled || undefined}\n ref={isSelected ? selectedItemRef : undefined}\n paddingVertical={sizeStyles.paddingVertical}\n paddingHorizontal={sizeStyles.paddingHorizontal}\n onPress={\n isOptionDisabled ? undefined : () => handleSelect(option)\n }\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n backgroundColor={isSelected ? brandColors.bg : \"transparent\"}\n style={{\n ...(isWeb\n ? {\n cursor: isOptionDisabled ? \"not-allowed\" : \"pointer\",\n }\n : {}),\n opacity: isOptionDisabled ? 0.5 : 1,\n }}\n hoverStyle={\n !isSelected && !isOptionDisabled\n ? { backgroundColor: overlayInputColors.bgHover }\n : undefined\n }\n >\n <Text\n color={\n isSelected\n ? contentColors.on.brand\n : overlayTheme.colors.content.secondary\n }\n fontSize={sizeStyles.fontSize}\n fontWeight=\"400\"\n >\n {optionLabel}\n </Text>\n </Box>\n );\n })\n )}\n </Box>\n </Box>\n );\n\n return (\n <Box\n testID={testID}\n ref={containerRef}\n flexDirection=\"column\"\n gap={sizeStyles.fieldGap}\n width={fullWidth ? \"100%\" : undefined}\n position=\"relative\"\n >\n {label && (\n <Text\n id={labelId}\n color={theme.colors.content.secondary}\n fontSize={sizeStyles.fontSize - 2}\n fontWeight=\"500\"\n >\n {label}\n </Text>\n )}\n <Box\n ref={triggerRef}\n onPress={handlePress}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded={isFocus && options.length > 0}\n aria-controls={listboxId}\n aria-labelledby={label ? labelId : undefined}\n aria-disabled={isDisable || undefined}\n backgroundColor={backgroundColor}\n borderColor={borderColor}\n borderWidth={borderColor !== \"transparent\" ? 1 : 0}\n borderRadius={sizeStyles.radius}\n height={sizeStyles.height}\n width={iconOnly ? sizeStyles.height : \"100%\"}\n paddingHorizontal={iconOnly ? 0 : sizeStyles.paddingHorizontal}\n flexDirection=\"row\"\n alignItems=\"center\"\n justifyContent={iconOnly ? \"center\" : \"flex-start\"}\n gap={iconOnly ? 4 : 12}\n position=\"relative\"\n hoverStyle={\n !isDisable && !isFocus && !isError\n ? {\n backgroundColor: inputColors.bgHover,\n borderColor: inputColors.borderHover,\n }\n : undefined\n }\n >\n {iconLeft && (\n <Box alignItems=\"center\" justifyContent=\"center\">\n <Icon size={sizeStyles.iconSize} color={iconColor}>\n {iconLeft}\n </Icon>\n </Box>\n )}\n {!iconOnly && (\n <Box\n flex={1}\n height=\"100%\"\n justifyContent=\"center\"\n overflow=\"hidden\"\n overflowX=\"hidden\"\n >\n <Text\n color={textColor}\n fontSize={sizeStyles.fontSize}\n numberOfLines={1}\n style={{ whiteSpace: \"nowrap\" }}\n >\n {currentLabel}\n </Text>\n </Box>\n )}\n <Box flexDirection=\"row\" alignItems=\"center\" gap={4}>\n {/* Clear button (field variant only) */}\n {clearable && !iconOnly && !isDisable && selectedValue && (\n <Box\n onPress={handleClear}\n alignItems=\"center\"\n justifyContent=\"center\"\n style={isWeb ? { cursor: \"pointer\" } : undefined}\n >\n <Remove\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n </Box>\n )}\n\n {/* Error icon */}\n {isError && (\n <Icon\n size={sizeStyles.iconSize}\n color={theme.colors.content.alert.primary}\n >\n <ExclamationMarkCr />\n </Icon>\n )}\n {iconRight !== undefined ? (\n <Icon size={sizeStyles.iconSize} color={iconColor}>\n {iconRight}\n </Icon>\n ) : isFocus ? (\n <ChevronUp\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n ) : (\n <ChevronDown\n size={sizeStyles.iconSize}\n color={iconColor}\n variant=\"line\"\n />\n )}\n </Box>\n </Box>\n\n {/* Dropdown Menu */}\n {isNative ? dropdown : <Portal>{dropdown}</Portal>}\n\n {isError && errorMessage && (\n <Text\n color={theme.colors.content.alert.primary}\n fontSize={sizeStyles.fontSize - 2}\n style={{ lineHeight: sizeStyles.lineHeight + \"px\" }}\n >\n {errorMessage}\n </Text>\n )}\n </Box>\n );\n};\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\nimport { View, ViewStyle } from \"react-native\";\nimport { IconProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Icon: React.FC<IconProps> = ({\n children,\n color,\n size,\n testID,\n \"data-testid\": dataTestId,\n}) => {\n const style: ViewStyle = {\n width: typeof size === \"number\" ? size : undefined,\n height: typeof size === \"number\" ? size : undefined,\n alignItems: \"center\",\n justifyContent: \"center\",\n };\n\n // On native, we try to pass the color down to children (like Text primitives)\n // to mimic the CSS inheritance behavior of the web version.\n const childrenWithProps = React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n color: child.props.color || color,\n // Also pass size if child seems to be an icon that needs it\n size: child.props.size || size,\n });\n }\n return child;\n });\n\n return (\n <View style={style} testID={dataTestId || testID}>\n {childrenWithProps}\n </View>\n );\n};\n","export * from \"./Box\";\nexport * from \"./Text\";\nexport * from \"./Spinner\";\nexport * from \"./Icon\";\nexport * from \"./Divider\";\nexport * from \"./Input\";\nexport * from \"./TextArea\";\nexport * from \"./LinearGradient\";\n\nexport const isWeb = false;\nexport const isNative = true;\n","import { ReactNode } from \"react\";\n\ninterface PortalProps {\n children: ReactNode;\n}\n\nexport const Portal = ({ children }: PortalProps) => <>{children}</>;\n"],"mappings":"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","names":["import_react","import_react_native","import_jsx_runtime","RNText","import_react_native","import_jsx_runtime","React","import_jsx_runtime","import_jsx_runtime","SearchIcon"]}
|
package/native/index.mjs
CHANGED
|
@@ -327,7 +327,9 @@ var Select = ({
|
|
|
327
327
|
themeMode,
|
|
328
328
|
themeProductContext,
|
|
329
329
|
overlayThemeMode,
|
|
330
|
-
overlayThemeProductContext
|
|
330
|
+
overlayThemeProductContext,
|
|
331
|
+
side = "bottom",
|
|
332
|
+
autoFlip = false
|
|
331
333
|
}) => {
|
|
332
334
|
const { theme: rawTheme } = useResolvedTheme({
|
|
333
335
|
themeMode,
|
|
@@ -349,6 +351,11 @@ var Select = ({
|
|
|
349
351
|
const dropdownRef = useRef(null);
|
|
350
352
|
const selectedItemRef = useRef(null);
|
|
351
353
|
const searchInputRef = useRef(null);
|
|
354
|
+
const [baseId] = useState(
|
|
355
|
+
() => `xui-select-${Math.random().toString(36).slice(2, 9)}`
|
|
356
|
+
);
|
|
357
|
+
const labelId = `${baseId}-label`;
|
|
358
|
+
const listboxId = `${baseId}-listbox`;
|
|
352
359
|
const isDisable = externalState === "disable" || disabled;
|
|
353
360
|
const isError = externalState === "error" || !!errorMessage;
|
|
354
361
|
const isFocus = externalState === "focus" || isOpen;
|
|
@@ -356,14 +363,35 @@ var Select = ({
|
|
|
356
363
|
const inputColors = theme.colors.control.input;
|
|
357
364
|
const overlayInputColors = overlayTheme.colors.control.input;
|
|
358
365
|
const updateDropdownPosition = useCallback(() => {
|
|
359
|
-
if (!isWeb || !triggerRef.current) return;
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
366
|
+
if (!isWeb || !triggerRef.current || !dropdownRef.current) return;
|
|
367
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
368
|
+
const dropH = dropdownRef.current.getBoundingClientRect().height;
|
|
369
|
+
const gap = sizeStyles.fieldGap;
|
|
370
|
+
const viewportHeight = window.innerHeight;
|
|
371
|
+
const spaceBelow = viewportHeight - triggerRect.bottom - gap;
|
|
372
|
+
const spaceAbove = triggerRect.top - gap;
|
|
373
|
+
const placeBelow = () => setDropdownPosition({
|
|
374
|
+
left: triggerRect.left,
|
|
375
|
+
top: triggerRect.bottom + gap,
|
|
376
|
+
width: triggerRect.width,
|
|
377
|
+
visible: true
|
|
378
|
+
});
|
|
379
|
+
const placeAbove = () => setDropdownPosition({
|
|
380
|
+
left: triggerRect.left,
|
|
381
|
+
bottom: viewportHeight - triggerRect.top + gap,
|
|
382
|
+
width: triggerRect.width,
|
|
383
|
+
visible: true
|
|
365
384
|
});
|
|
366
|
-
|
|
385
|
+
if (!autoFlip) {
|
|
386
|
+
side === "top" ? placeAbove() : placeBelow();
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (side === "top") {
|
|
390
|
+
spaceAbove >= dropH || spaceAbove >= spaceBelow ? placeAbove() : placeBelow();
|
|
391
|
+
} else {
|
|
392
|
+
spaceBelow >= dropH || spaceBelow >= spaceAbove ? placeBelow() : placeAbove();
|
|
393
|
+
}
|
|
394
|
+
}, [sizeStyles.fieldGap, side, autoFlip]);
|
|
367
395
|
useEffect(() => {
|
|
368
396
|
if (value !== void 0) setSelectedValue(value);
|
|
369
397
|
}, [value]);
|
|
@@ -381,12 +409,17 @@ var Select = ({
|
|
|
381
409
|
if (!isWeb || !isFocus) return;
|
|
382
410
|
updateDropdownPosition();
|
|
383
411
|
window.addEventListener("resize", updateDropdownPosition);
|
|
384
|
-
window.
|
|
385
|
-
return () => {
|
|
386
|
-
window.removeEventListener("resize", updateDropdownPosition);
|
|
387
|
-
window.removeEventListener("scroll", updateDropdownPosition, true);
|
|
388
|
-
};
|
|
412
|
+
return () => window.removeEventListener("resize", updateDropdownPosition);
|
|
389
413
|
}, [isFocus, updateDropdownPosition]);
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
if (!isWeb || !isOpen) return;
|
|
416
|
+
const closeOnScroll = (e) => {
|
|
417
|
+
if (dropdownRef.current?.contains(e.target)) return;
|
|
418
|
+
setIsOpen(false);
|
|
419
|
+
};
|
|
420
|
+
window.addEventListener("scroll", closeOnScroll, true);
|
|
421
|
+
return () => window.removeEventListener("scroll", closeOnScroll, true);
|
|
422
|
+
}, [isOpen]);
|
|
390
423
|
useEffect(() => {
|
|
391
424
|
if (isFocus && searchable) searchInputRef.current?.focus();
|
|
392
425
|
}, [isFocus, searchable]);
|
|
@@ -456,22 +489,31 @@ var Select = ({
|
|
|
456
489
|
const textColor = isDisable ? inputColors.textDisable : selectedValue ? inputColors.text : inputColors.placeholder;
|
|
457
490
|
const iconColor = isDisable ? inputColors.textDisable : inputColors.text;
|
|
458
491
|
const dropdownTop = sizeStyles.height + (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) + sizeStyles.fieldGap;
|
|
459
|
-
const dropdown = isFocus && options.length > 0 &&
|
|
492
|
+
const dropdown = isFocus && options.length > 0 && /* @__PURE__ */ jsxs(
|
|
460
493
|
Box,
|
|
461
494
|
{
|
|
462
495
|
ref: dropdownRef,
|
|
496
|
+
id: listboxId,
|
|
497
|
+
role: "listbox",
|
|
498
|
+
"aria-label": label || placeholder,
|
|
463
499
|
"data-modal-id": modalId,
|
|
464
|
-
position: isNative ? "absolute" :
|
|
465
|
-
top: isNative ? dropdownTop :
|
|
466
|
-
left: isNative ? void 0 : dropdownPosition?.left,
|
|
467
|
-
width: isNative ? "100%" : dropdownPosition?.width,
|
|
500
|
+
position: isNative ? "absolute" : void 0,
|
|
501
|
+
top: isNative ? dropdownTop : void 0,
|
|
468
502
|
backgroundColor: overlayTheme.colors.background.secondary,
|
|
469
503
|
borderColor: overlayTheme.colors.border.secondary,
|
|
470
504
|
borderWidth: 1,
|
|
471
505
|
borderRadius: overlayTheme.shape.contextMenu[size].borderRadius,
|
|
472
506
|
style: {
|
|
473
507
|
zIndex: 2e3,
|
|
474
|
-
...isNative ? { elevation: 4 } : {
|
|
508
|
+
...isNative ? { elevation: 4 } : {
|
|
509
|
+
position: "fixed",
|
|
510
|
+
top: dropdownPosition?.top != null ? dropdownPosition.top : void 0,
|
|
511
|
+
bottom: dropdownPosition?.bottom != null ? dropdownPosition.bottom : void 0,
|
|
512
|
+
left: dropdownPosition?.left,
|
|
513
|
+
width: dropdownPosition?.width,
|
|
514
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
|
|
515
|
+
visibility: dropdownPosition?.visible ? "visible" : "hidden"
|
|
516
|
+
},
|
|
475
517
|
minWidth: iconOnly ? sizeStyles.height * 3 : void 0
|
|
476
518
|
},
|
|
477
519
|
children: [
|
|
@@ -505,6 +547,7 @@ var Select = ({
|
|
|
505
547
|
ref: searchInputRef,
|
|
506
548
|
flex: 1,
|
|
507
549
|
type: "text",
|
|
550
|
+
"aria-label": searchPlaceholder,
|
|
508
551
|
value: searchValue,
|
|
509
552
|
onChange: (e) => setSearchValue(e.target.value),
|
|
510
553
|
placeholder: searchPlaceholder,
|
|
@@ -558,6 +601,9 @@ var Select = ({
|
|
|
558
601
|
Box,
|
|
559
602
|
{
|
|
560
603
|
testID,
|
|
604
|
+
role: "option",
|
|
605
|
+
"aria-selected": isSelected,
|
|
606
|
+
"aria-disabled": isOptionDisabled || void 0,
|
|
561
607
|
ref: isSelected ? selectedItemRef : void 0,
|
|
562
608
|
paddingVertical: sizeStyles.paddingVertical,
|
|
563
609
|
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
@@ -604,6 +650,7 @@ var Select = ({
|
|
|
604
650
|
label && /* @__PURE__ */ jsx5(
|
|
605
651
|
Text,
|
|
606
652
|
{
|
|
653
|
+
id: labelId,
|
|
607
654
|
color: theme.colors.content.secondary,
|
|
608
655
|
fontSize: sizeStyles.fontSize - 2,
|
|
609
656
|
fontWeight: "500",
|
|
@@ -615,6 +662,12 @@ var Select = ({
|
|
|
615
662
|
{
|
|
616
663
|
ref: triggerRef,
|
|
617
664
|
onPress: handlePress,
|
|
665
|
+
role: "combobox",
|
|
666
|
+
"aria-haspopup": "listbox",
|
|
667
|
+
"aria-expanded": isFocus && options.length > 0,
|
|
668
|
+
"aria-controls": listboxId,
|
|
669
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
670
|
+
"aria-disabled": isDisable || void 0,
|
|
618
671
|
backgroundColor,
|
|
619
672
|
borderColor,
|
|
620
673
|
borderWidth: borderColor !== "transparent" ? 1 : 0,
|