@xsolla/xui-button 0.79.0 → 0.80.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.d.mts +32 -6
- package/native/index.d.ts +32 -6
- package/native/index.js +172 -64
- package/native/index.js.flow +39 -6
- package/native/index.js.map +1 -1
- package/native/index.mjs +178 -70
- package/native/index.mjs.map +1 -1
- package/package.json +4 -4
- package/web/index.d.mts +32 -6
- package/web/index.d.ts +32 -6
- package/web/index.js +172 -64
- package/web/index.js.flow +39 -6
- package/web/index.js.map +1 -1
- package/web/index.mjs +178 -70
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import React, { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
interface ButtonProps {
|
|
4
4
|
/** Visual variant of the button */
|
|
5
|
-
variant?: "primary" | "secondary";
|
|
5
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
6
6
|
/** Color tone of the button */
|
|
7
7
|
tone?: "brand" | "brandExtra" | "alert" | "mono";
|
|
8
8
|
/** Size of the button */
|
|
@@ -15,10 +15,32 @@ interface ButtonProps {
|
|
|
15
15
|
children: React.ReactNode;
|
|
16
16
|
/** Click handler */
|
|
17
17
|
onPress?: () => void;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Icon to display on the left side.
|
|
20
|
+
* Size and color are automatically set based on button size/state.
|
|
21
|
+
* To override, specify size/color on the icon: `iconLeft={<ArrowLeft size={16} />}`
|
|
22
|
+
*/
|
|
19
23
|
iconLeft?: React.ReactNode;
|
|
20
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Icon to display on the right side.
|
|
26
|
+
* Size and color are automatically set based on button size/state.
|
|
27
|
+
* To override, specify size/color on the icon: `iconRight={<ArrowRight size={16} />}`
|
|
28
|
+
*/
|
|
21
29
|
iconRight?: React.ReactNode;
|
|
30
|
+
/** Show/hide vertical divider between icon and content (default: true when icon present) */
|
|
31
|
+
divider?: boolean;
|
|
32
|
+
/** Secondary text displayed inline with the main label (e.g., price), shown with 40% opacity */
|
|
33
|
+
sublabel?: string;
|
|
34
|
+
/** Alignment of the label text */
|
|
35
|
+
labelAlignment?: "left" | "center";
|
|
36
|
+
/**
|
|
37
|
+
* Small icon displayed directly next to the label text.
|
|
38
|
+
* Size and color are automatically set based on button size/state.
|
|
39
|
+
* To override, specify size/color on the icon: `labelIcon={<InfoIcon size={12} />}`
|
|
40
|
+
*/
|
|
41
|
+
labelIcon?: React.ReactNode;
|
|
42
|
+
/** Custom content slot for badges, tags, or other elements */
|
|
43
|
+
customContent?: React.ReactNode;
|
|
22
44
|
/** Accessible label for screen readers (use for icon-only buttons) */
|
|
23
45
|
"aria-label"?: string;
|
|
24
46
|
/** ID of element that describes this button */
|
|
@@ -37,7 +59,7 @@ interface ButtonProps {
|
|
|
37
59
|
id?: string;
|
|
38
60
|
/** HTML type attribute for the button */
|
|
39
61
|
type?: "button" | "submit" | "reset";
|
|
40
|
-
/** Whether the button should
|
|
62
|
+
/** Whether the button should stretch to fill the full width of its container */
|
|
41
63
|
fullWidth?: boolean;
|
|
42
64
|
}
|
|
43
65
|
/**
|
|
@@ -59,7 +81,7 @@ declare const Button: React.FC<ButtonProps>;
|
|
|
59
81
|
|
|
60
82
|
interface IconButtonProps {
|
|
61
83
|
/** Visual variant of the button */
|
|
62
|
-
variant?: "primary" | "secondary";
|
|
84
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
63
85
|
/** Color tone of the button */
|
|
64
86
|
tone?: "brand" | "brandExtra" | "alert" | "mono";
|
|
65
87
|
/** Size of the button */
|
|
@@ -68,7 +90,11 @@ interface IconButtonProps {
|
|
|
68
90
|
disabled?: boolean;
|
|
69
91
|
/** Whether the button is in a loading state */
|
|
70
92
|
loading?: boolean;
|
|
71
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Icon to display in the button (required).
|
|
95
|
+
* Size and color are automatically set based on button size/state.
|
|
96
|
+
* To override, specify size/color on the icon: `icon={<CloseIcon size={16} />}`
|
|
97
|
+
*/
|
|
72
98
|
icon: React.ReactNode;
|
|
73
99
|
/** Click handler */
|
|
74
100
|
onPress?: () => void;
|
package/native/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import React, { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
interface ButtonProps {
|
|
4
4
|
/** Visual variant of the button */
|
|
5
|
-
variant?: "primary" | "secondary";
|
|
5
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
6
6
|
/** Color tone of the button */
|
|
7
7
|
tone?: "brand" | "brandExtra" | "alert" | "mono";
|
|
8
8
|
/** Size of the button */
|
|
@@ -15,10 +15,32 @@ interface ButtonProps {
|
|
|
15
15
|
children: React.ReactNode;
|
|
16
16
|
/** Click handler */
|
|
17
17
|
onPress?: () => void;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Icon to display on the left side.
|
|
20
|
+
* Size and color are automatically set based on button size/state.
|
|
21
|
+
* To override, specify size/color on the icon: `iconLeft={<ArrowLeft size={16} />}`
|
|
22
|
+
*/
|
|
19
23
|
iconLeft?: React.ReactNode;
|
|
20
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Icon to display on the right side.
|
|
26
|
+
* Size and color are automatically set based on button size/state.
|
|
27
|
+
* To override, specify size/color on the icon: `iconRight={<ArrowRight size={16} />}`
|
|
28
|
+
*/
|
|
21
29
|
iconRight?: React.ReactNode;
|
|
30
|
+
/** Show/hide vertical divider between icon and content (default: true when icon present) */
|
|
31
|
+
divider?: boolean;
|
|
32
|
+
/** Secondary text displayed inline with the main label (e.g., price), shown with 40% opacity */
|
|
33
|
+
sublabel?: string;
|
|
34
|
+
/** Alignment of the label text */
|
|
35
|
+
labelAlignment?: "left" | "center";
|
|
36
|
+
/**
|
|
37
|
+
* Small icon displayed directly next to the label text.
|
|
38
|
+
* Size and color are automatically set based on button size/state.
|
|
39
|
+
* To override, specify size/color on the icon: `labelIcon={<InfoIcon size={12} />}`
|
|
40
|
+
*/
|
|
41
|
+
labelIcon?: React.ReactNode;
|
|
42
|
+
/** Custom content slot for badges, tags, or other elements */
|
|
43
|
+
customContent?: React.ReactNode;
|
|
22
44
|
/** Accessible label for screen readers (use for icon-only buttons) */
|
|
23
45
|
"aria-label"?: string;
|
|
24
46
|
/** ID of element that describes this button */
|
|
@@ -37,7 +59,7 @@ interface ButtonProps {
|
|
|
37
59
|
id?: string;
|
|
38
60
|
/** HTML type attribute for the button */
|
|
39
61
|
type?: "button" | "submit" | "reset";
|
|
40
|
-
/** Whether the button should
|
|
62
|
+
/** Whether the button should stretch to fill the full width of its container */
|
|
41
63
|
fullWidth?: boolean;
|
|
42
64
|
}
|
|
43
65
|
/**
|
|
@@ -59,7 +81,7 @@ declare const Button: React.FC<ButtonProps>;
|
|
|
59
81
|
|
|
60
82
|
interface IconButtonProps {
|
|
61
83
|
/** Visual variant of the button */
|
|
62
|
-
variant?: "primary" | "secondary";
|
|
84
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
63
85
|
/** Color tone of the button */
|
|
64
86
|
tone?: "brand" | "brandExtra" | "alert" | "mono";
|
|
65
87
|
/** Size of the button */
|
|
@@ -68,7 +90,11 @@ interface IconButtonProps {
|
|
|
68
90
|
disabled?: boolean;
|
|
69
91
|
/** Whether the button is in a loading state */
|
|
70
92
|
loading?: boolean;
|
|
71
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Icon to display in the button (required).
|
|
95
|
+
* Size and color are automatically set based on button size/state.
|
|
96
|
+
* To override, specify size/color on the icon: `icon={<CloseIcon size={16} />}`
|
|
97
|
+
*/
|
|
72
98
|
icon: React.ReactNode;
|
|
73
99
|
/** Click handler */
|
|
74
100
|
onPress?: () => void;
|
package/native/index.js
CHANGED
|
@@ -38,7 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
module.exports = __toCommonJS(index_exports);
|
|
39
39
|
|
|
40
40
|
// src/Button.tsx
|
|
41
|
-
var import_react4 = require("react");
|
|
41
|
+
var import_react4 = __toESM(require("react"));
|
|
42
42
|
|
|
43
43
|
// ../primitives-native/src/Box.tsx
|
|
44
44
|
var import_react_native = require("react-native");
|
|
@@ -536,6 +536,17 @@ TextAreaPrimitive.displayName = "TextAreaPrimitive";
|
|
|
536
536
|
// src/Button.tsx
|
|
537
537
|
var import_xui_core = require("@xsolla/xui-core");
|
|
538
538
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
539
|
+
var cloneIconWithDefaults = (icon, defaultSize, defaultColor) => {
|
|
540
|
+
if (!import_react4.default.isValidElement(icon)) return icon;
|
|
541
|
+
const iconElement = icon;
|
|
542
|
+
const existingProps = iconElement.props || {};
|
|
543
|
+
return import_react4.default.cloneElement(iconElement, {
|
|
544
|
+
...existingProps,
|
|
545
|
+
// Preserve existing props (including accessibility attributes)
|
|
546
|
+
size: existingProps.size ?? defaultSize,
|
|
547
|
+
color: existingProps.color ?? defaultColor
|
|
548
|
+
});
|
|
549
|
+
};
|
|
539
550
|
var Button = ({
|
|
540
551
|
variant = "primary",
|
|
541
552
|
tone = "brand",
|
|
@@ -546,6 +557,11 @@ var Button = ({
|
|
|
546
557
|
onPress,
|
|
547
558
|
iconLeft,
|
|
548
559
|
iconRight,
|
|
560
|
+
divider,
|
|
561
|
+
sublabel,
|
|
562
|
+
labelAlignment = "center",
|
|
563
|
+
labelIcon,
|
|
564
|
+
customContent,
|
|
549
565
|
"aria-label": ariaLabel,
|
|
550
566
|
"aria-describedby": ariaDescribedBy,
|
|
551
567
|
"aria-expanded": ariaExpanded,
|
|
@@ -561,9 +577,17 @@ var Button = ({
|
|
|
561
577
|
const [isKeyboardPressed, setIsKeyboardPressed] = (0, import_react4.useState)(false);
|
|
562
578
|
const isDisabled = disabled || loading;
|
|
563
579
|
const sizeStyles = theme.sizing.button(size);
|
|
564
|
-
const
|
|
580
|
+
const controlTone = theme?.colors?.control?.[tone];
|
|
581
|
+
const variantStyles = controlTone?.[variant] || theme?.colors?.control?.brand?.primary || {
|
|
565
582
|
bg: "transparent",
|
|
566
|
-
|
|
583
|
+
bgHover: "transparent",
|
|
584
|
+
bgPress: "transparent",
|
|
585
|
+
bgDisable: "transparent",
|
|
586
|
+
border: "transparent",
|
|
587
|
+
borderHover: "transparent",
|
|
588
|
+
borderPress: "transparent",
|
|
589
|
+
borderDisable: "transparent",
|
|
590
|
+
text: { primary: "#000", secondary: "#000", disable: "#666" }
|
|
567
591
|
};
|
|
568
592
|
const handlePress = () => {
|
|
569
593
|
if (!isDisabled && onPress) {
|
|
@@ -587,17 +611,19 @@ var Button = ({
|
|
|
587
611
|
}
|
|
588
612
|
}
|
|
589
613
|
};
|
|
590
|
-
|
|
591
|
-
let backgroundColor = styles.bg;
|
|
614
|
+
let backgroundColor = variantStyles.bg;
|
|
592
615
|
if (disabled) {
|
|
593
|
-
backgroundColor =
|
|
616
|
+
backgroundColor = variantStyles.bgDisable || variantStyles.bg;
|
|
594
617
|
} else if (isKeyboardPressed) {
|
|
595
|
-
backgroundColor =
|
|
618
|
+
backgroundColor = variantStyles.bgPress || variantStyles.bg;
|
|
596
619
|
}
|
|
597
|
-
const borderColor = disabled ?
|
|
598
|
-
const textColor = disabled ?
|
|
599
|
-
const
|
|
600
|
-
const
|
|
620
|
+
const borderColor = disabled ? variantStyles.borderDisable || variantStyles.border : variantStyles.border;
|
|
621
|
+
const textColor = disabled ? variantStyles.text?.disable || variantStyles.text?.primary : variantStyles.text?.primary;
|
|
622
|
+
const textColorStr = typeof textColor === "string" ? textColor : "";
|
|
623
|
+
const isDarkText = textColorStr === "#000000" || textColorStr === "black" || textColorStr.startsWith("rgba(0, 0, 0");
|
|
624
|
+
const dividerLineColor = isDarkText ? "rgba(0, 0, 0, 0.2)" : "rgba(255, 255, 255, 0.2)";
|
|
625
|
+
const hasIcon = Boolean(iconLeft || iconRight);
|
|
626
|
+
const showDivider = divider !== void 0 ? divider : hasIcon;
|
|
601
627
|
const computedAriaLabel = ariaLabel;
|
|
602
628
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
603
629
|
Box,
|
|
@@ -621,7 +647,7 @@ var Button = ({
|
|
|
621
647
|
backgroundColor,
|
|
622
648
|
borderColor,
|
|
623
649
|
borderWidth: borderColor !== "transparent" && borderColor !== "rgba(255, 255, 255, 0)" ? 1 : 0,
|
|
624
|
-
borderRadius:
|
|
650
|
+
borderRadius: sizeStyles.borderRadius,
|
|
625
651
|
height: sizeStyles.height,
|
|
626
652
|
width: fullWidth ? "100%" : void 0,
|
|
627
653
|
padding: 0,
|
|
@@ -644,72 +670,110 @@ var Button = ({
|
|
|
644
670
|
outlineStyle: "solid"
|
|
645
671
|
},
|
|
646
672
|
children: [
|
|
647
|
-
|
|
673
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
674
|
+
Box,
|
|
675
|
+
{
|
|
676
|
+
position: "absolute",
|
|
677
|
+
top: 0,
|
|
678
|
+
left: 0,
|
|
679
|
+
right: 0,
|
|
680
|
+
bottom: 0,
|
|
681
|
+
alignItems: "center",
|
|
682
|
+
justifyContent: "center",
|
|
683
|
+
zIndex: 1,
|
|
684
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
685
|
+
Spinner,
|
|
686
|
+
{
|
|
687
|
+
color: textColor,
|
|
688
|
+
size: sizeStyles.spinnerSize,
|
|
689
|
+
"aria-hidden": true
|
|
690
|
+
}
|
|
691
|
+
)
|
|
692
|
+
}
|
|
693
|
+
),
|
|
694
|
+
iconLeft && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
648
695
|
Box,
|
|
649
696
|
{
|
|
650
697
|
height: "100%",
|
|
651
698
|
flexDirection: "row",
|
|
652
699
|
alignItems: "center",
|
|
653
|
-
justifyContent: "center",
|
|
654
700
|
"aria-hidden": true,
|
|
701
|
+
style: {
|
|
702
|
+
opacity: loading ? 0 : 1,
|
|
703
|
+
pointerEvents: loading ? "none" : "auto"
|
|
704
|
+
},
|
|
655
705
|
children: [
|
|
656
706
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
657
707
|
Box,
|
|
658
708
|
{
|
|
709
|
+
width: sizeStyles.iconContainerSize,
|
|
710
|
+
height: sizeStyles.iconContainerSize,
|
|
659
711
|
alignItems: "center",
|
|
660
712
|
justifyContent: "center",
|
|
661
|
-
|
|
662
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { size: sizeStyles.iconSize, color: textColor, children: iconLeft })
|
|
713
|
+
children: cloneIconWithDefaults(iconLeft, sizeStyles.iconSize, textColor)
|
|
663
714
|
}
|
|
664
715
|
),
|
|
665
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Divider, { vertical: true, color:
|
|
716
|
+
showDivider && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Divider, { vertical: true, color: dividerLineColor, height: "100%" })
|
|
666
717
|
]
|
|
667
718
|
}
|
|
668
719
|
),
|
|
669
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
670
721
|
Box,
|
|
671
722
|
{
|
|
672
723
|
flex: fullWidth ? 1 : void 0,
|
|
673
724
|
flexDirection: "row",
|
|
674
725
|
alignItems: "center",
|
|
675
|
-
justifyContent: "center",
|
|
676
|
-
paddingHorizontal:
|
|
726
|
+
justifyContent: labelAlignment === "left" ? "flex-start" : "center",
|
|
727
|
+
paddingHorizontal: sizeStyles.padding,
|
|
677
728
|
height: "100%",
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
729
|
+
gap: sizeStyles.labelIconGap,
|
|
730
|
+
style: {
|
|
731
|
+
opacity: loading ? 0 : 1,
|
|
732
|
+
pointerEvents: loading ? "none" : "auto"
|
|
733
|
+
},
|
|
734
|
+
"aria-hidden": loading ? true : void 0,
|
|
735
|
+
children: [
|
|
736
|
+
labelIcon && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { "aria-hidden": true, children: cloneIconWithDefaults(
|
|
737
|
+
labelIcon,
|
|
738
|
+
sizeStyles.labelIconSize,
|
|
739
|
+
textColor
|
|
740
|
+
) }),
|
|
741
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: textColor, fontSize: sizeStyles.fontSize, fontWeight: "500", children }),
|
|
742
|
+
sublabel && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
743
|
+
Text,
|
|
744
|
+
{
|
|
745
|
+
color: textColor,
|
|
746
|
+
fontSize: sizeStyles.fontSize,
|
|
747
|
+
fontWeight: "500",
|
|
748
|
+
style: { opacity: 0.4 },
|
|
749
|
+
children: sublabel
|
|
750
|
+
}
|
|
751
|
+
),
|
|
752
|
+
customContent && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box, { "aria-hidden": true, children: customContent })
|
|
753
|
+
]
|
|
694
754
|
}
|
|
695
755
|
),
|
|
696
|
-
|
|
756
|
+
iconRight && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
697
757
|
Box,
|
|
698
758
|
{
|
|
699
759
|
height: "100%",
|
|
700
760
|
flexDirection: "row",
|
|
701
761
|
alignItems: "center",
|
|
702
|
-
justifyContent: "center",
|
|
703
762
|
"aria-hidden": true,
|
|
763
|
+
style: {
|
|
764
|
+
opacity: loading ? 0 : 1,
|
|
765
|
+
pointerEvents: loading ? "none" : "auto"
|
|
766
|
+
},
|
|
704
767
|
children: [
|
|
705
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Divider, { vertical: true, color:
|
|
768
|
+
showDivider && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Divider, { vertical: true, color: dividerLineColor, height: "100%" }),
|
|
706
769
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
707
770
|
Box,
|
|
708
771
|
{
|
|
772
|
+
width: sizeStyles.iconContainerSize,
|
|
773
|
+
height: sizeStyles.iconContainerSize,
|
|
709
774
|
alignItems: "center",
|
|
710
775
|
justifyContent: "center",
|
|
711
|
-
|
|
712
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { size: sizeStyles.iconSize, color: textColor, children: iconRight })
|
|
776
|
+
children: cloneIconWithDefaults(iconRight, sizeStyles.iconSize, textColor)
|
|
713
777
|
}
|
|
714
778
|
)
|
|
715
779
|
]
|
|
@@ -722,9 +786,20 @@ var Button = ({
|
|
|
722
786
|
Button.displayName = "Button";
|
|
723
787
|
|
|
724
788
|
// src/IconButton.tsx
|
|
725
|
-
var import_react5 = require("react");
|
|
789
|
+
var import_react5 = __toESM(require("react"));
|
|
726
790
|
var import_xui_core2 = require("@xsolla/xui-core");
|
|
727
791
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
792
|
+
var cloneIconWithDefaults2 = (icon, defaultSize, defaultColor) => {
|
|
793
|
+
if (!import_react5.default.isValidElement(icon)) return icon;
|
|
794
|
+
const iconElement = icon;
|
|
795
|
+
const existingProps = iconElement.props || {};
|
|
796
|
+
return import_react5.default.cloneElement(iconElement, {
|
|
797
|
+
...existingProps,
|
|
798
|
+
// Preserve existing props (including accessibility attributes)
|
|
799
|
+
size: existingProps.size ?? defaultSize,
|
|
800
|
+
color: existingProps.color ?? defaultColor
|
|
801
|
+
});
|
|
802
|
+
};
|
|
728
803
|
var IconButton = ({
|
|
729
804
|
variant = "primary",
|
|
730
805
|
tone = "brand",
|
|
@@ -747,9 +822,17 @@ var IconButton = ({
|
|
|
747
822
|
const [isKeyboardPressed, setIsKeyboardPressed] = (0, import_react5.useState)(false);
|
|
748
823
|
const isDisabled = disabled || loading;
|
|
749
824
|
const sizeStyles = theme.sizing.button(size);
|
|
750
|
-
const
|
|
825
|
+
const controlTone = theme?.colors?.control?.[tone];
|
|
826
|
+
const variantStyles = controlTone?.[variant] || theme?.colors?.control?.brand?.primary || {
|
|
751
827
|
bg: "transparent",
|
|
752
|
-
|
|
828
|
+
bgHover: "transparent",
|
|
829
|
+
bgPress: "transparent",
|
|
830
|
+
bgDisable: "transparent",
|
|
831
|
+
border: "transparent",
|
|
832
|
+
borderHover: "transparent",
|
|
833
|
+
borderPress: "transparent",
|
|
834
|
+
borderDisable: "transparent",
|
|
835
|
+
text: { primary: "#000", secondary: "#000", disable: "#666" }
|
|
753
836
|
};
|
|
754
837
|
const handlePress = () => {
|
|
755
838
|
if (!isDisabled && onPress) {
|
|
@@ -773,16 +856,15 @@ var IconButton = ({
|
|
|
773
856
|
}
|
|
774
857
|
}
|
|
775
858
|
};
|
|
776
|
-
|
|
777
|
-
let backgroundColor = styles.bg;
|
|
859
|
+
let backgroundColor = variantStyles.bg;
|
|
778
860
|
if (disabled) {
|
|
779
|
-
backgroundColor =
|
|
861
|
+
backgroundColor = variantStyles.bgDisable || variantStyles.bg;
|
|
780
862
|
} else if (isKeyboardPressed) {
|
|
781
|
-
backgroundColor =
|
|
863
|
+
backgroundColor = variantStyles.bgPress || variantStyles.bg;
|
|
782
864
|
}
|
|
783
|
-
const borderColor = disabled ?
|
|
784
|
-
const textColor = disabled ?
|
|
785
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.
|
|
865
|
+
const borderColor = disabled ? variantStyles.borderDisable || variantStyles.border : variantStyles.border;
|
|
866
|
+
const textColor = disabled ? variantStyles.text?.disable || variantStyles.text?.primary : variantStyles.text?.primary;
|
|
867
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
786
868
|
Box,
|
|
787
869
|
{
|
|
788
870
|
as: "button",
|
|
@@ -804,7 +886,7 @@ var IconButton = ({
|
|
|
804
886
|
backgroundColor,
|
|
805
887
|
borderColor,
|
|
806
888
|
borderWidth: borderColor !== "transparent" && borderColor !== "rgba(255, 255, 255, 0)" ? 1 : 0,
|
|
807
|
-
borderRadius:
|
|
889
|
+
borderRadius: sizeStyles.borderRadius,
|
|
808
890
|
height: sizeStyles.height,
|
|
809
891
|
width: sizeStyles.height,
|
|
810
892
|
padding: 0,
|
|
@@ -815,10 +897,10 @@ var IconButton = ({
|
|
|
815
897
|
cursor: disabled ? "not-allowed" : loading ? "wait" : "pointer",
|
|
816
898
|
opacity: disabled ? 0.6 : 1,
|
|
817
899
|
hoverStyle: !isDisabled ? {
|
|
818
|
-
backgroundColor:
|
|
900
|
+
backgroundColor: variantStyles.bgHover
|
|
819
901
|
} : void 0,
|
|
820
902
|
pressStyle: !isDisabled ? {
|
|
821
|
-
backgroundColor:
|
|
903
|
+
backgroundColor: variantStyles.bgPress
|
|
822
904
|
} : void 0,
|
|
823
905
|
focusStyle: {
|
|
824
906
|
outlineColor: theme.colors.border.brand,
|
|
@@ -826,14 +908,40 @@ var IconButton = ({
|
|
|
826
908
|
outlineOffset: 2,
|
|
827
909
|
outlineStyle: "solid"
|
|
828
910
|
},
|
|
829
|
-
children:
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
911
|
+
children: [
|
|
912
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
913
|
+
Box,
|
|
914
|
+
{
|
|
915
|
+
position: "absolute",
|
|
916
|
+
top: 0,
|
|
917
|
+
left: 0,
|
|
918
|
+
right: 0,
|
|
919
|
+
bottom: 0,
|
|
920
|
+
alignItems: "center",
|
|
921
|
+
justifyContent: "center",
|
|
922
|
+
zIndex: 1,
|
|
923
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
924
|
+
Spinner,
|
|
925
|
+
{
|
|
926
|
+
color: textColor,
|
|
927
|
+
size: sizeStyles.spinnerSize,
|
|
928
|
+
"aria-hidden": true
|
|
929
|
+
}
|
|
930
|
+
)
|
|
931
|
+
}
|
|
932
|
+
),
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
934
|
+
Box,
|
|
935
|
+
{
|
|
936
|
+
"aria-hidden": true,
|
|
937
|
+
style: {
|
|
938
|
+
opacity: loading ? 0 : 1,
|
|
939
|
+
pointerEvents: loading ? "none" : "auto"
|
|
940
|
+
},
|
|
941
|
+
children: cloneIconWithDefaults2(icon, sizeStyles.iconSize, textColor)
|
|
942
|
+
}
|
|
943
|
+
)
|
|
944
|
+
]
|
|
837
945
|
}
|
|
838
946
|
);
|
|
839
947
|
};
|
|
@@ -1226,7 +1334,7 @@ var ButtonGroup = ({
|
|
|
1226
1334
|
const computedAriaDescribedBy = [
|
|
1227
1335
|
ariaDescribedBy,
|
|
1228
1336
|
error && errorId ? errorId : void 0,
|
|
1229
|
-
description &&
|
|
1337
|
+
description && descriptionId ? descriptionId : void 0
|
|
1230
1338
|
].filter(Boolean).join(" ") || void 0;
|
|
1231
1339
|
const processChildren = (childrenToProcess) => {
|
|
1232
1340
|
if (orientation === "vertical") {
|
|
@@ -1289,7 +1397,7 @@ var ButtonGroup = ({
|
|
|
1289
1397
|
children: error
|
|
1290
1398
|
}
|
|
1291
1399
|
) }),
|
|
1292
|
-
description &&
|
|
1400
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box, { marginTop: 4, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1293
1401
|
Text,
|
|
1294
1402
|
{
|
|
1295
1403
|
id: descriptionId,
|
package/native/index.js.flow
CHANGED
|
@@ -10,7 +10,7 @@ declare interface ButtonProps {
|
|
|
10
10
|
/**
|
|
11
11
|
* Visual variant of the button
|
|
12
12
|
*/
|
|
13
|
-
variant?: "primary" | "secondary";
|
|
13
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Color tone of the button
|
|
@@ -43,15 +43,46 @@ declare interface ButtonProps {
|
|
|
43
43
|
onPress?: () => void;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* Icon to display on the left side
|
|
46
|
+
* Icon to display on the left side.
|
|
47
|
+
* Size and color are automatically set based on button size/state.
|
|
48
|
+
* To override, specify size/color on the icon: `iconLeft={<ArrowLeft size={16} />}`
|
|
47
49
|
*/
|
|
48
50
|
iconLeft?: React.ReactNode;
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
|
-
* Icon to display on the right side
|
|
53
|
+
* Icon to display on the right side.
|
|
54
|
+
* Size and color are automatically set based on button size/state.
|
|
55
|
+
* To override, specify size/color on the icon: `iconRight={<ArrowRight size={16} />}`
|
|
52
56
|
*/
|
|
53
57
|
iconRight?: React.ReactNode;
|
|
54
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Show/hide vertical divider between icon and content (default: true when icon present)
|
|
61
|
+
*/
|
|
62
|
+
divider?: boolean;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Secondary text displayed inline with the main label (e.g., price), shown with 40% opacity
|
|
66
|
+
*/
|
|
67
|
+
sublabel?: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Alignment of the label text
|
|
71
|
+
*/
|
|
72
|
+
labelAlignment?: "left" | "center";
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Small icon displayed directly next to the label text.
|
|
76
|
+
* Size and color are automatically set based on button size/state.
|
|
77
|
+
* To override, specify size/color on the icon: `labelIcon={<InfoIcon size={12} />}`
|
|
78
|
+
*/
|
|
79
|
+
labelIcon?: React.ReactNode;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Custom content slot for badges, tags, or other elements
|
|
83
|
+
*/
|
|
84
|
+
customContent?: React.ReactNode;
|
|
85
|
+
|
|
55
86
|
/**
|
|
56
87
|
* Accessible label for screen readers (use for icon-only buttons)
|
|
57
88
|
*/
|
|
@@ -98,7 +129,7 @@ declare interface ButtonProps {
|
|
|
98
129
|
type?: "button" | "submit" | "reset";
|
|
99
130
|
|
|
100
131
|
/**
|
|
101
|
-
* Whether the button should
|
|
132
|
+
* Whether the button should stretch to fill the full width of its container
|
|
102
133
|
*/
|
|
103
134
|
fullWidth?: boolean;
|
|
104
135
|
}
|
|
@@ -121,7 +152,7 @@ declare interface IconButtonProps {
|
|
|
121
152
|
/**
|
|
122
153
|
* Visual variant of the button
|
|
123
154
|
*/
|
|
124
|
-
variant?: "primary" | "secondary";
|
|
155
|
+
variant?: "primary" | "secondary" | "tertiary";
|
|
125
156
|
|
|
126
157
|
/**
|
|
127
158
|
* Color tone of the button
|
|
@@ -144,7 +175,9 @@ declare interface IconButtonProps {
|
|
|
144
175
|
loading?: boolean;
|
|
145
176
|
|
|
146
177
|
/**
|
|
147
|
-
* Icon to display in the button (required)
|
|
178
|
+
* Icon to display in the button (required).
|
|
179
|
+
* Size and color are automatically set based on button size/state.
|
|
180
|
+
* To override, specify size/color on the icon: `icon={<CloseIcon size={16} />}`
|
|
148
181
|
*/
|
|
149
182
|
icon: React.ReactNode;
|
|
150
183
|
|