@xsolla/xui-select 0.176.0 → 0.177.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/native/index.js +192 -151
- package/native/index.js.map +1 -1
- package/native/index.mjs +191 -149
- package/native/index.mjs.map +1 -1
- package/package.json +6 -5
- package/web/index.js +196 -149
- package/web/index.js.map +1 -1
- package/web/index.mjs +193 -145
- package/web/index.mjs.map +1 -1
package/web/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/Select.tsx
|
|
2
|
-
import { useState, useRef, useEffect, useCallback } from "react";
|
|
2
|
+
import { useState as useState2, useRef, useEffect as useEffect2, useCallback } from "react";
|
|
3
3
|
|
|
4
4
|
// ../../foundation/primitives-web/src/Box.tsx
|
|
5
5
|
import React2 from "react";
|
|
@@ -323,6 +323,7 @@ var isNative = false;
|
|
|
323
323
|
|
|
324
324
|
// src/Select.tsx
|
|
325
325
|
import {
|
|
326
|
+
useModalId,
|
|
326
327
|
useResolvedTheme
|
|
327
328
|
} from "@xsolla/xui-core";
|
|
328
329
|
import { useClickOutside } from "@xsolla/xui-hooks";
|
|
@@ -333,6 +334,18 @@ import {
|
|
|
333
334
|
Remove,
|
|
334
335
|
Search as SearchIcon
|
|
335
336
|
} from "@xsolla/xui-icons-base";
|
|
337
|
+
|
|
338
|
+
// src/Portal.web.tsx
|
|
339
|
+
import { useEffect, useState } from "react";
|
|
340
|
+
import { createPortal } from "react-dom";
|
|
341
|
+
var Portal = ({ children }) => {
|
|
342
|
+
const [mountNode, setMountNode] = useState(null);
|
|
343
|
+
useEffect(() => setMountNode(document.body), []);
|
|
344
|
+
if (!mountNode) return null;
|
|
345
|
+
return createPortal(children, mountNode);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/Select.tsx
|
|
336
349
|
import { jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
337
350
|
var Select = ({
|
|
338
351
|
value,
|
|
@@ -372,20 +385,35 @@ var Select = ({
|
|
|
372
385
|
themeProductContext: overlayThemeProductContext ?? themeProductContext
|
|
373
386
|
});
|
|
374
387
|
const overlayTheme = rawOverlayTheme;
|
|
375
|
-
const
|
|
376
|
-
const [
|
|
377
|
-
const [
|
|
388
|
+
const modalId = useModalId();
|
|
389
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
390
|
+
const [selectedValue, setSelectedValue] = useState2(value);
|
|
391
|
+
const [searchValue, setSearchValue] = useState2("");
|
|
392
|
+
const [dropdownPosition, setDropdownPosition] = useState2(null);
|
|
378
393
|
const containerRef = useRef(null);
|
|
394
|
+
const triggerRef = useRef(null);
|
|
379
395
|
const dropdownRef = useRef(null);
|
|
380
396
|
const selectedItemRef = useRef(null);
|
|
381
397
|
const searchInputRef = useRef(null);
|
|
382
398
|
const isDisable = externalState === "disable" || disabled;
|
|
383
399
|
const isError = externalState === "error" || !!errorMessage;
|
|
384
400
|
const isFocus = externalState === "focus" || isOpen;
|
|
385
|
-
|
|
401
|
+
const sizeStyles = theme.sizing.input(size);
|
|
402
|
+
const inputColors = theme.colors.control.input;
|
|
403
|
+
const overlayInputColors = overlayTheme.colors.control.input;
|
|
404
|
+
const updateDropdownPosition = useCallback(() => {
|
|
405
|
+
if (!isWeb || !triggerRef.current) return;
|
|
406
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
407
|
+
setDropdownPosition({
|
|
408
|
+
left: rect.left,
|
|
409
|
+
top: rect.bottom + sizeStyles.fieldGap,
|
|
410
|
+
width: rect.width
|
|
411
|
+
});
|
|
412
|
+
}, [sizeStyles.fieldGap]);
|
|
413
|
+
useEffect2(() => {
|
|
386
414
|
if (value !== void 0) setSelectedValue(value);
|
|
387
415
|
}, [value]);
|
|
388
|
-
|
|
416
|
+
useEffect2(() => {
|
|
389
417
|
if (isFocus && selectedItemRef.current && dropdownRef.current) {
|
|
390
418
|
const timeoutId = setTimeout(() => {
|
|
391
419
|
const selectedItem = selectedItemRef.current;
|
|
@@ -395,15 +423,33 @@ var Select = ({
|
|
|
395
423
|
return () => clearTimeout(timeoutId);
|
|
396
424
|
}
|
|
397
425
|
}, [isFocus]);
|
|
398
|
-
|
|
426
|
+
useEffect2(() => {
|
|
427
|
+
if (!isWeb || !isFocus) return;
|
|
428
|
+
updateDropdownPosition();
|
|
429
|
+
window.addEventListener("resize", updateDropdownPosition);
|
|
430
|
+
window.addEventListener("scroll", updateDropdownPosition, true);
|
|
431
|
+
return () => {
|
|
432
|
+
window.removeEventListener("resize", updateDropdownPosition);
|
|
433
|
+
window.removeEventListener("scroll", updateDropdownPosition, true);
|
|
434
|
+
};
|
|
435
|
+
}, [isFocus, updateDropdownPosition]);
|
|
436
|
+
useEffect2(() => {
|
|
399
437
|
if (isFocus && searchable) searchInputRef.current?.focus();
|
|
400
438
|
}, [isFocus, searchable]);
|
|
401
|
-
|
|
439
|
+
useEffect2(() => {
|
|
402
440
|
if (!isFocus) setSearchValue("");
|
|
403
441
|
}, [isFocus]);
|
|
404
442
|
useClickOutside(
|
|
405
443
|
containerRef,
|
|
406
|
-
useCallback(() =>
|
|
444
|
+
useCallback((event) => {
|
|
445
|
+
const dropdownEl = dropdownRef.current;
|
|
446
|
+
if (dropdownEl) {
|
|
447
|
+
const path = typeof event.composedPath === "function" ? event.composedPath() : [];
|
|
448
|
+
const insideDropdown = path.length ? path.includes(dropdownEl) : dropdownEl.contains(event.target);
|
|
449
|
+
if (insideDropdown) return;
|
|
450
|
+
}
|
|
451
|
+
setIsOpen(false);
|
|
452
|
+
}, []),
|
|
407
453
|
isWeb && isOpen
|
|
408
454
|
);
|
|
409
455
|
const getOptionLabel = (option) => typeof option === "string" ? option : option.label;
|
|
@@ -412,9 +458,6 @@ var Select = ({
|
|
|
412
458
|
const filteredOptions = searchable && searchValue ? options.filter(
|
|
413
459
|
(option) => getOptionLabel(option).toLowerCase().includes(searchValue.toLowerCase())
|
|
414
460
|
) : options;
|
|
415
|
-
const sizeStyles = theme.sizing.input(size);
|
|
416
|
-
const inputColors = theme.colors.control.input;
|
|
417
|
-
const overlayInputColors = overlayTheme.colors.control.input;
|
|
418
461
|
const handlePress = () => {
|
|
419
462
|
if (!isDisable) {
|
|
420
463
|
if (onPress) onPress();
|
|
@@ -458,6 +501,142 @@ var Select = ({
|
|
|
458
501
|
) : placeholder;
|
|
459
502
|
const textColor = isDisable ? inputColors.textDisable : selectedValue ? inputColors.text : inputColors.placeholder;
|
|
460
503
|
const iconColor = isDisable ? inputColors.textDisable : inputColors.text;
|
|
504
|
+
const dropdownTop = sizeStyles.height + (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) + sizeStyles.fieldGap;
|
|
505
|
+
const dropdown = isFocus && options.length > 0 && (isNative || dropdownPosition) && /* @__PURE__ */ jsxs(
|
|
506
|
+
Box,
|
|
507
|
+
{
|
|
508
|
+
ref: dropdownRef,
|
|
509
|
+
"data-modal-id": modalId,
|
|
510
|
+
position: isNative ? "absolute" : "fixed",
|
|
511
|
+
top: isNative ? dropdownTop : dropdownPosition?.top,
|
|
512
|
+
left: isNative ? void 0 : dropdownPosition?.left,
|
|
513
|
+
width: isNative ? "100%" : dropdownPosition?.width,
|
|
514
|
+
backgroundColor: overlayTheme.colors.background.secondary,
|
|
515
|
+
borderColor: overlayTheme.colors.border.secondary,
|
|
516
|
+
borderWidth: 1,
|
|
517
|
+
borderRadius: overlayTheme.shape.contextMenu[size].borderRadius,
|
|
518
|
+
style: {
|
|
519
|
+
zIndex: 2e3,
|
|
520
|
+
...isNative ? { elevation: 4 } : { boxShadow: "0 4px 12px rgba(0,0,0,0.1)" },
|
|
521
|
+
minWidth: iconOnly ? sizeStyles.height * 3 : void 0
|
|
522
|
+
},
|
|
523
|
+
children: [
|
|
524
|
+
searchable && !isNative && /* @__PURE__ */ jsx4(
|
|
525
|
+
Box,
|
|
526
|
+
{
|
|
527
|
+
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
528
|
+
paddingVertical: sizeStyles.paddingVertical,
|
|
529
|
+
borderBottomWidth: 1,
|
|
530
|
+
borderColor: overlayTheme.colors.border.secondary,
|
|
531
|
+
children: /* @__PURE__ */ jsxs(
|
|
532
|
+
Box,
|
|
533
|
+
{
|
|
534
|
+
flexDirection: "row",
|
|
535
|
+
alignItems: "center",
|
|
536
|
+
gap: sizeStyles.paddingHorizontal / 2,
|
|
537
|
+
paddingHorizontal: 4,
|
|
538
|
+
children: [
|
|
539
|
+
/* @__PURE__ */ jsx4(
|
|
540
|
+
Icon,
|
|
541
|
+
{
|
|
542
|
+
size: sizeStyles.iconSize - 2,
|
|
543
|
+
color: overlayInputColors.placeholder,
|
|
544
|
+
children: /* @__PURE__ */ jsx4(SearchIcon, {})
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
/* @__PURE__ */ jsx4(
|
|
548
|
+
Box,
|
|
549
|
+
{
|
|
550
|
+
as: "input",
|
|
551
|
+
ref: searchInputRef,
|
|
552
|
+
flex: 1,
|
|
553
|
+
type: "text",
|
|
554
|
+
value: searchValue,
|
|
555
|
+
onChange: (e) => setSearchValue(e.target.value),
|
|
556
|
+
placeholder: searchPlaceholder,
|
|
557
|
+
style: {
|
|
558
|
+
border: "none",
|
|
559
|
+
outline: "none",
|
|
560
|
+
background: "transparent",
|
|
561
|
+
color: overlayInputColors.text,
|
|
562
|
+
fontSize: sizeStyles.fontSize,
|
|
563
|
+
width: "100%"
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
)
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
)
|
|
570
|
+
}
|
|
571
|
+
),
|
|
572
|
+
/* @__PURE__ */ jsx4(
|
|
573
|
+
Box,
|
|
574
|
+
{
|
|
575
|
+
paddingVertical: 4,
|
|
576
|
+
overflow: "scroll",
|
|
577
|
+
style: {
|
|
578
|
+
maxHeight: searchable ? maxHeight - 60 : maxHeight,
|
|
579
|
+
...isWeb ? { overflowY: "auto" } : {}
|
|
580
|
+
},
|
|
581
|
+
children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx4(
|
|
582
|
+
Box,
|
|
583
|
+
{
|
|
584
|
+
paddingVertical: sizeStyles.paddingVertical * 2,
|
|
585
|
+
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
586
|
+
alignItems: "center",
|
|
587
|
+
children: /* @__PURE__ */ jsx4(
|
|
588
|
+
Text,
|
|
589
|
+
{
|
|
590
|
+
color: overlayTheme.colors.content.tertiary,
|
|
591
|
+
fontSize: sizeStyles.fontSize,
|
|
592
|
+
children: noOptionsMessage
|
|
593
|
+
}
|
|
594
|
+
)
|
|
595
|
+
}
|
|
596
|
+
) : filteredOptions.map((option, index2) => {
|
|
597
|
+
const optionValue = getOptionValue(option);
|
|
598
|
+
const optionLabel = getOptionLabel(option);
|
|
599
|
+
const isOptionDisabled = getOptionDisabled(option);
|
|
600
|
+
const isSelected = optionValue === selectedValue;
|
|
601
|
+
const brandColors = overlayTheme.colors.control.brand.primary;
|
|
602
|
+
const contentColors = overlayTheme.colors.content;
|
|
603
|
+
return /* @__PURE__ */ jsx4(
|
|
604
|
+
Box,
|
|
605
|
+
{
|
|
606
|
+
testID,
|
|
607
|
+
ref: isSelected ? selectedItemRef : void 0,
|
|
608
|
+
paddingVertical: sizeStyles.paddingVertical,
|
|
609
|
+
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
610
|
+
onPress: isOptionDisabled ? void 0 : () => handleSelect(option),
|
|
611
|
+
flexDirection: "row",
|
|
612
|
+
alignItems: "center",
|
|
613
|
+
justifyContent: "space-between",
|
|
614
|
+
backgroundColor: isSelected ? brandColors.bg : "transparent",
|
|
615
|
+
style: {
|
|
616
|
+
...isWeb ? {
|
|
617
|
+
cursor: isOptionDisabled ? "not-allowed" : "pointer"
|
|
618
|
+
} : {},
|
|
619
|
+
opacity: isOptionDisabled ? 0.5 : 1
|
|
620
|
+
},
|
|
621
|
+
hoverStyle: !isSelected && !isOptionDisabled ? { backgroundColor: overlayInputColors.bgHover } : void 0,
|
|
622
|
+
children: /* @__PURE__ */ jsx4(
|
|
623
|
+
Text,
|
|
624
|
+
{
|
|
625
|
+
color: isSelected ? contentColors.on.brand : overlayTheme.colors.content.secondary,
|
|
626
|
+
fontSize: sizeStyles.fontSize,
|
|
627
|
+
fontWeight: "400",
|
|
628
|
+
children: optionLabel
|
|
629
|
+
}
|
|
630
|
+
)
|
|
631
|
+
},
|
|
632
|
+
index2
|
|
633
|
+
);
|
|
634
|
+
})
|
|
635
|
+
}
|
|
636
|
+
)
|
|
637
|
+
]
|
|
638
|
+
}
|
|
639
|
+
);
|
|
461
640
|
return /* @__PURE__ */ jsxs(
|
|
462
641
|
Box,
|
|
463
642
|
{
|
|
@@ -480,6 +659,7 @@ var Select = ({
|
|
|
480
659
|
/* @__PURE__ */ jsxs(
|
|
481
660
|
Box,
|
|
482
661
|
{
|
|
662
|
+
ref: triggerRef,
|
|
483
663
|
onPress: handlePress,
|
|
484
664
|
backgroundColor,
|
|
485
665
|
borderColor,
|
|
@@ -564,139 +744,7 @@ var Select = ({
|
|
|
564
744
|
]
|
|
565
745
|
}
|
|
566
746
|
),
|
|
567
|
-
|
|
568
|
-
Box,
|
|
569
|
-
{
|
|
570
|
-
ref: dropdownRef,
|
|
571
|
-
position: "absolute",
|
|
572
|
-
top: sizeStyles.height + (label ? sizeStyles.fontSize + sizeStyles.fieldGap : 0) + sizeStyles.fieldGap,
|
|
573
|
-
width: "100%",
|
|
574
|
-
backgroundColor: overlayTheme.colors.background.secondary,
|
|
575
|
-
borderColor: overlayTheme.colors.border.secondary,
|
|
576
|
-
borderWidth: 1,
|
|
577
|
-
borderRadius: overlayTheme.shape.contextMenu[size].borderRadius,
|
|
578
|
-
style: {
|
|
579
|
-
zIndex: 1e3,
|
|
580
|
-
...isNative ? { elevation: 4 } : { boxShadow: "0 4px 12px rgba(0,0,0,0.1)" },
|
|
581
|
-
minWidth: iconOnly ? sizeStyles.height * 3 : void 0
|
|
582
|
-
},
|
|
583
|
-
children: [
|
|
584
|
-
searchable && !isNative && /* @__PURE__ */ jsx4(
|
|
585
|
-
Box,
|
|
586
|
-
{
|
|
587
|
-
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
588
|
-
paddingVertical: sizeStyles.paddingVertical,
|
|
589
|
-
borderBottomWidth: 1,
|
|
590
|
-
borderColor: overlayTheme.colors.border.secondary,
|
|
591
|
-
children: /* @__PURE__ */ jsxs(
|
|
592
|
-
Box,
|
|
593
|
-
{
|
|
594
|
-
flexDirection: "row",
|
|
595
|
-
alignItems: "center",
|
|
596
|
-
gap: sizeStyles.paddingHorizontal / 2,
|
|
597
|
-
paddingHorizontal: 4,
|
|
598
|
-
children: [
|
|
599
|
-
/* @__PURE__ */ jsx4(
|
|
600
|
-
Icon,
|
|
601
|
-
{
|
|
602
|
-
size: sizeStyles.iconSize - 2,
|
|
603
|
-
color: overlayInputColors.placeholder,
|
|
604
|
-
children: /* @__PURE__ */ jsx4(SearchIcon, {})
|
|
605
|
-
}
|
|
606
|
-
),
|
|
607
|
-
/* @__PURE__ */ jsx4(
|
|
608
|
-
Box,
|
|
609
|
-
{
|
|
610
|
-
as: "input",
|
|
611
|
-
ref: searchInputRef,
|
|
612
|
-
flex: 1,
|
|
613
|
-
type: "text",
|
|
614
|
-
value: searchValue,
|
|
615
|
-
onChange: (e) => setSearchValue(e.target.value),
|
|
616
|
-
placeholder: searchPlaceholder,
|
|
617
|
-
style: {
|
|
618
|
-
border: "none",
|
|
619
|
-
outline: "none",
|
|
620
|
-
background: "transparent",
|
|
621
|
-
color: overlayInputColors.text,
|
|
622
|
-
fontSize: sizeStyles.fontSize,
|
|
623
|
-
width: "100%"
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
)
|
|
627
|
-
]
|
|
628
|
-
}
|
|
629
|
-
)
|
|
630
|
-
}
|
|
631
|
-
),
|
|
632
|
-
/* @__PURE__ */ jsx4(
|
|
633
|
-
Box,
|
|
634
|
-
{
|
|
635
|
-
paddingVertical: 4,
|
|
636
|
-
overflow: "scroll",
|
|
637
|
-
style: {
|
|
638
|
-
maxHeight: searchable ? maxHeight - 60 : maxHeight,
|
|
639
|
-
...isWeb ? { overflowY: "auto" } : {}
|
|
640
|
-
},
|
|
641
|
-
children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx4(
|
|
642
|
-
Box,
|
|
643
|
-
{
|
|
644
|
-
paddingVertical: sizeStyles.paddingVertical * 2,
|
|
645
|
-
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
646
|
-
alignItems: "center",
|
|
647
|
-
children: /* @__PURE__ */ jsx4(
|
|
648
|
-
Text,
|
|
649
|
-
{
|
|
650
|
-
color: overlayTheme.colors.content.tertiary,
|
|
651
|
-
fontSize: sizeStyles.fontSize,
|
|
652
|
-
children: noOptionsMessage
|
|
653
|
-
}
|
|
654
|
-
)
|
|
655
|
-
}
|
|
656
|
-
) : filteredOptions.map((option, index2) => {
|
|
657
|
-
const optionValue = getOptionValue(option);
|
|
658
|
-
const optionLabel = getOptionLabel(option);
|
|
659
|
-
const isOptionDisabled = getOptionDisabled(option);
|
|
660
|
-
const isSelected = optionValue === selectedValue;
|
|
661
|
-
const brandColors = overlayTheme.colors.control.brand.primary;
|
|
662
|
-
const contentColors = overlayTheme.colors.content;
|
|
663
|
-
return /* @__PURE__ */ jsx4(
|
|
664
|
-
Box,
|
|
665
|
-
{
|
|
666
|
-
testID,
|
|
667
|
-
ref: isSelected ? selectedItemRef : void 0,
|
|
668
|
-
paddingVertical: sizeStyles.paddingVertical,
|
|
669
|
-
paddingHorizontal: sizeStyles.paddingHorizontal,
|
|
670
|
-
onPress: isOptionDisabled ? void 0 : () => handleSelect(option),
|
|
671
|
-
flexDirection: "row",
|
|
672
|
-
alignItems: "center",
|
|
673
|
-
justifyContent: "space-between",
|
|
674
|
-
backgroundColor: isSelected ? brandColors.bg : "transparent",
|
|
675
|
-
style: {
|
|
676
|
-
...isWeb ? {
|
|
677
|
-
cursor: isOptionDisabled ? "not-allowed" : "pointer"
|
|
678
|
-
} : {},
|
|
679
|
-
opacity: isOptionDisabled ? 0.5 : 1
|
|
680
|
-
},
|
|
681
|
-
hoverStyle: !isSelected && !isOptionDisabled ? { backgroundColor: overlayInputColors.bgHover } : void 0,
|
|
682
|
-
children: /* @__PURE__ */ jsx4(
|
|
683
|
-
Text,
|
|
684
|
-
{
|
|
685
|
-
color: isSelected ? contentColors.on.brand : overlayTheme.colors.content.secondary,
|
|
686
|
-
fontSize: sizeStyles.fontSize,
|
|
687
|
-
fontWeight: "400",
|
|
688
|
-
children: optionLabel
|
|
689
|
-
}
|
|
690
|
-
)
|
|
691
|
-
},
|
|
692
|
-
index2
|
|
693
|
-
);
|
|
694
|
-
})
|
|
695
|
-
}
|
|
696
|
-
)
|
|
697
|
-
]
|
|
698
|
-
}
|
|
699
|
-
),
|
|
747
|
+
isNative ? dropdown : /* @__PURE__ */ jsx4(Portal, { children: dropdown }),
|
|
700
748
|
isError && errorMessage && /* @__PURE__ */ jsx4(
|
|
701
749
|
Text,
|
|
702
750
|
{
|