@xsolla/xui-button 0.78.0 → 0.79.0-pr122.1769779574

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/Button.tsx
2
- import { useState } from "react";
2
+ import React4, { useState } from "react";
3
3
 
4
4
  // ../primitives-native/src/Box.tsx
5
5
  import {
@@ -215,7 +215,6 @@ var Spinner = ({
215
215
  role,
216
216
  "aria-label": ariaLabel,
217
217
  "aria-live": ariaLive,
218
- "aria-describedby": ariaDescribedBy,
219
218
  testID
220
219
  }) => {
221
220
  return /* @__PURE__ */ jsx3(
@@ -334,14 +333,11 @@ var InputPrimitive = forwardRef(
334
333
  fontSize,
335
334
  placeholderTextColor,
336
335
  maxLength,
337
- name,
338
336
  type,
339
337
  inputMode,
340
338
  autoComplete,
341
339
  id,
342
- "aria-invalid": ariaInvalid,
343
340
  "aria-describedby": ariaDescribedBy,
344
- "aria-labelledby": ariaLabelledBy,
345
341
  "aria-label": ariaLabel,
346
342
  "aria-disabled": ariaDisabled,
347
343
  "data-testid": dataTestId
@@ -433,9 +429,7 @@ var TextAreaPrimitive = forwardRef2(
433
429
  maxLength,
434
430
  rows,
435
431
  id,
436
- "aria-invalid": ariaInvalid,
437
432
  "aria-describedby": ariaDescribedBy,
438
- "aria-labelledby": ariaLabelledBy,
439
433
  "aria-label": ariaLabel,
440
434
  "aria-disabled": ariaDisabled,
441
435
  "data-testid": dataTestId
@@ -507,6 +501,17 @@ TextAreaPrimitive.displayName = "TextAreaPrimitive";
507
501
  // src/Button.tsx
508
502
  import { useDesignSystem } from "@xsolla/xui-core";
509
503
  import { jsx as jsx8, jsxs } from "react/jsx-runtime";
504
+ var cloneIconWithDefaults = (icon, defaultSize, defaultColor) => {
505
+ if (!React4.isValidElement(icon)) return icon;
506
+ const iconElement = icon;
507
+ const existingProps = iconElement.props || {};
508
+ return React4.cloneElement(iconElement, {
509
+ ...existingProps,
510
+ // Preserve existing props (including accessibility attributes)
511
+ size: existingProps.size ?? defaultSize,
512
+ color: existingProps.color ?? defaultColor
513
+ });
514
+ };
510
515
  var Button = ({
511
516
  variant = "primary",
512
517
  tone = "brand",
@@ -517,6 +522,11 @@ var Button = ({
517
522
  onPress,
518
523
  iconLeft,
519
524
  iconRight,
525
+ divider,
526
+ sublabel,
527
+ labelAlignment = "center",
528
+ labelIcon,
529
+ customContent,
520
530
  "aria-label": ariaLabel,
521
531
  "aria-describedby": ariaDescribedBy,
522
532
  "aria-expanded": ariaExpanded,
@@ -532,9 +542,17 @@ var Button = ({
532
542
  const [isKeyboardPressed, setIsKeyboardPressed] = useState(false);
533
543
  const isDisabled = disabled || loading;
534
544
  const sizeStyles = theme.sizing.button(size);
535
- const variantStyles = theme?.colors?.control?.[tone]?.[variant] || theme?.colors?.control?.brand?.primary || {
545
+ const controlTone = theme?.colors?.control?.[tone];
546
+ const variantStyles = controlTone?.[variant] || theme?.colors?.control?.brand?.primary || {
536
547
  bg: "transparent",
537
- text: { primary: "#000" }
548
+ bgHover: "transparent",
549
+ bgPress: "transparent",
550
+ bgDisable: "transparent",
551
+ border: "transparent",
552
+ borderHover: "transparent",
553
+ borderPress: "transparent",
554
+ borderDisable: "transparent",
555
+ text: { primary: "#000", secondary: "#000", disable: "#666" }
538
556
  };
539
557
  const handlePress = () => {
540
558
  if (!isDisabled && onPress) {
@@ -558,17 +576,19 @@ var Button = ({
558
576
  }
559
577
  }
560
578
  };
561
- const styles = variantStyles;
562
- let backgroundColor = styles.bg;
579
+ let backgroundColor = variantStyles.bg;
563
580
  if (disabled) {
564
- backgroundColor = styles.bgDisable || styles.bg;
581
+ backgroundColor = variantStyles.bgDisable || variantStyles.bg;
565
582
  } else if (isKeyboardPressed) {
566
- backgroundColor = styles.bgPress || styles.bg;
583
+ backgroundColor = variantStyles.bgPress || variantStyles.bg;
567
584
  }
568
- const borderColor = disabled ? styles.borderDisable || styles.border : styles.border;
569
- const textColor = disabled ? styles.text?.disable || styles.text?.primary : styles.text?.primary;
570
- const isDarkText = textColor === "#000000" || textColor === "black" || textColor.startsWith("rgba(0, 0, 0");
571
- const dividerColor = isDarkText ? "rgba(0, 0, 0, 0.2)" : "rgba(255, 255, 255, 0.2)";
585
+ const borderColor = disabled ? variantStyles.borderDisable || variantStyles.border : variantStyles.border;
586
+ const textColor = disabled ? variantStyles.text?.disable || variantStyles.text?.primary : variantStyles.text?.primary;
587
+ const textColorStr = typeof textColor === "string" ? textColor : "";
588
+ const isDarkText = textColorStr === "#000000" || textColorStr === "black" || textColorStr.startsWith("rgba(0, 0, 0");
589
+ const dividerLineColor = isDarkText ? "rgba(0, 0, 0, 0.2)" : "rgba(255, 255, 255, 0.2)";
590
+ const hasIcon = Boolean(iconLeft || iconRight);
591
+ const showDivider = divider !== void 0 ? divider : hasIcon;
572
592
  const computedAriaLabel = ariaLabel;
573
593
  return /* @__PURE__ */ jsxs(
574
594
  Box,
@@ -592,7 +612,7 @@ var Button = ({
592
612
  backgroundColor,
593
613
  borderColor,
594
614
  borderWidth: borderColor !== "transparent" && borderColor !== "rgba(255, 255, 255, 0)" ? 1 : 0,
595
- borderRadius: theme.radius.button,
615
+ borderRadius: sizeStyles.borderRadius,
596
616
  height: sizeStyles.height,
597
617
  width: fullWidth ? "100%" : void 0,
598
618
  padding: 0,
@@ -615,72 +635,110 @@ var Button = ({
615
635
  outlineStyle: "solid"
616
636
  },
617
637
  children: [
618
- !loading && iconLeft && /* @__PURE__ */ jsxs(
638
+ loading && /* @__PURE__ */ jsx8(
639
+ Box,
640
+ {
641
+ position: "absolute",
642
+ top: 0,
643
+ left: 0,
644
+ right: 0,
645
+ bottom: 0,
646
+ alignItems: "center",
647
+ justifyContent: "center",
648
+ zIndex: 1,
649
+ children: /* @__PURE__ */ jsx8(
650
+ Spinner,
651
+ {
652
+ color: textColor,
653
+ size: sizeStyles.spinnerSize,
654
+ "aria-hidden": true
655
+ }
656
+ )
657
+ }
658
+ ),
659
+ iconLeft && /* @__PURE__ */ jsxs(
619
660
  Box,
620
661
  {
621
662
  height: "100%",
622
663
  flexDirection: "row",
623
664
  alignItems: "center",
624
- justifyContent: "center",
625
665
  "aria-hidden": true,
666
+ style: {
667
+ opacity: loading ? 0 : 1,
668
+ pointerEvents: loading ? "none" : "auto"
669
+ },
626
670
  children: [
627
671
  /* @__PURE__ */ jsx8(
628
672
  Box,
629
673
  {
674
+ width: sizeStyles.iconContainerSize,
675
+ height: sizeStyles.iconContainerSize,
630
676
  alignItems: "center",
631
677
  justifyContent: "center",
632
- paddingHorizontal: sizeStyles.iconPadding,
633
- children: /* @__PURE__ */ jsx8(Icon, { size: sizeStyles.iconSize, color: textColor, children: iconLeft })
678
+ children: cloneIconWithDefaults(iconLeft, sizeStyles.iconSize, textColor)
634
679
  }
635
680
  ),
636
- /* @__PURE__ */ jsx8(Divider, { vertical: true, color: dividerColor, height: "100%" })
681
+ showDivider && /* @__PURE__ */ jsx8(Divider, { vertical: true, color: dividerLineColor, height: "100%" })
637
682
  ]
638
683
  }
639
684
  ),
640
- /* @__PURE__ */ jsx8(
685
+ /* @__PURE__ */ jsxs(
641
686
  Box,
642
687
  {
643
688
  flex: fullWidth ? 1 : void 0,
644
689
  flexDirection: "row",
645
690
  alignItems: "center",
646
- justifyContent: "center",
647
- paddingHorizontal: loading ? sizeStyles.loadingPadding : sizeStyles.padding,
691
+ justifyContent: labelAlignment === "left" ? "flex-start" : "center",
692
+ paddingHorizontal: sizeStyles.padding,
648
693
  height: "100%",
649
- children: loading ? /* @__PURE__ */ jsx8(
650
- Spinner,
651
- {
652
- color: textColor,
653
- size: sizeStyles.spinnerSize,
654
- "aria-hidden": true
655
- }
656
- ) : /* @__PURE__ */ jsx8(
657
- Text,
658
- {
659
- color: textColor,
660
- fontSize: sizeStyles.fontSize,
661
- fontWeight: "500",
662
- children
663
- }
664
- )
694
+ gap: sizeStyles.labelIconGap,
695
+ style: {
696
+ opacity: loading ? 0 : 1,
697
+ pointerEvents: loading ? "none" : "auto"
698
+ },
699
+ "aria-hidden": loading ? true : void 0,
700
+ children: [
701
+ labelIcon && /* @__PURE__ */ jsx8(Box, { "aria-hidden": true, children: cloneIconWithDefaults(
702
+ labelIcon,
703
+ sizeStyles.labelIconSize,
704
+ textColor
705
+ ) }),
706
+ /* @__PURE__ */ jsx8(Text, { color: textColor, fontSize: sizeStyles.fontSize, fontWeight: "500", children }),
707
+ sublabel && /* @__PURE__ */ jsx8(
708
+ Text,
709
+ {
710
+ color: textColor,
711
+ fontSize: sizeStyles.fontSize,
712
+ fontWeight: "500",
713
+ style: { opacity: 0.4 },
714
+ children: sublabel
715
+ }
716
+ ),
717
+ customContent && /* @__PURE__ */ jsx8(Box, { "aria-hidden": true, children: customContent })
718
+ ]
665
719
  }
666
720
  ),
667
- !loading && iconRight && /* @__PURE__ */ jsxs(
721
+ iconRight && /* @__PURE__ */ jsxs(
668
722
  Box,
669
723
  {
670
724
  height: "100%",
671
725
  flexDirection: "row",
672
726
  alignItems: "center",
673
- justifyContent: "center",
674
727
  "aria-hidden": true,
728
+ style: {
729
+ opacity: loading ? 0 : 1,
730
+ pointerEvents: loading ? "none" : "auto"
731
+ },
675
732
  children: [
676
- /* @__PURE__ */ jsx8(Divider, { vertical: true, color: dividerColor, height: "100%" }),
733
+ showDivider && /* @__PURE__ */ jsx8(Divider, { vertical: true, color: dividerLineColor, height: "100%" }),
677
734
  /* @__PURE__ */ jsx8(
678
735
  Box,
679
736
  {
737
+ width: sizeStyles.iconContainerSize,
738
+ height: sizeStyles.iconContainerSize,
680
739
  alignItems: "center",
681
740
  justifyContent: "center",
682
- paddingHorizontal: sizeStyles.iconPadding,
683
- children: /* @__PURE__ */ jsx8(Icon, { size: sizeStyles.iconSize, color: textColor, children: iconRight })
741
+ children: cloneIconWithDefaults(iconRight, sizeStyles.iconSize, textColor)
684
742
  }
685
743
  )
686
744
  ]
@@ -693,9 +751,20 @@ var Button = ({
693
751
  Button.displayName = "Button";
694
752
 
695
753
  // src/IconButton.tsx
696
- import { useState as useState2 } from "react";
754
+ import React5, { useState as useState2 } from "react";
697
755
  import { useDesignSystem as useDesignSystem2 } from "@xsolla/xui-core";
698
- import { jsx as jsx9 } from "react/jsx-runtime";
756
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
757
+ var cloneIconWithDefaults2 = (icon, defaultSize, defaultColor) => {
758
+ if (!React5.isValidElement(icon)) return icon;
759
+ const iconElement = icon;
760
+ const existingProps = iconElement.props || {};
761
+ return React5.cloneElement(iconElement, {
762
+ ...existingProps,
763
+ // Preserve existing props (including accessibility attributes)
764
+ size: existingProps.size ?? defaultSize,
765
+ color: existingProps.color ?? defaultColor
766
+ });
767
+ };
699
768
  var IconButton = ({
700
769
  variant = "primary",
701
770
  tone = "brand",
@@ -718,9 +787,17 @@ var IconButton = ({
718
787
  const [isKeyboardPressed, setIsKeyboardPressed] = useState2(false);
719
788
  const isDisabled = disabled || loading;
720
789
  const sizeStyles = theme.sizing.button(size);
721
- const variantStyles = theme?.colors?.control?.[tone]?.[variant] || theme?.colors?.control?.brand?.primary || {
790
+ const controlTone = theme?.colors?.control?.[tone];
791
+ const variantStyles = controlTone?.[variant] || theme?.colors?.control?.brand?.primary || {
722
792
  bg: "transparent",
723
- text: { primary: "#000" }
793
+ bgHover: "transparent",
794
+ bgPress: "transparent",
795
+ bgDisable: "transparent",
796
+ border: "transparent",
797
+ borderHover: "transparent",
798
+ borderPress: "transparent",
799
+ borderDisable: "transparent",
800
+ text: { primary: "#000", secondary: "#000", disable: "#666" }
724
801
  };
725
802
  const handlePress = () => {
726
803
  if (!isDisabled && onPress) {
@@ -744,16 +821,15 @@ var IconButton = ({
744
821
  }
745
822
  }
746
823
  };
747
- const styles = variantStyles;
748
- let backgroundColor = styles.bg;
824
+ let backgroundColor = variantStyles.bg;
749
825
  if (disabled) {
750
- backgroundColor = styles.bgDisable || styles.bg;
826
+ backgroundColor = variantStyles.bgDisable || variantStyles.bg;
751
827
  } else if (isKeyboardPressed) {
752
- backgroundColor = styles.bgPress || styles.bg;
828
+ backgroundColor = variantStyles.bgPress || variantStyles.bg;
753
829
  }
754
- const borderColor = disabled ? styles.borderDisable || styles.border : styles.border;
755
- const textColor = disabled ? styles.text?.disable || styles.text?.primary : styles.text?.primary;
756
- return /* @__PURE__ */ jsx9(
830
+ const borderColor = disabled ? variantStyles.borderDisable || variantStyles.border : variantStyles.border;
831
+ const textColor = disabled ? variantStyles.text?.disable || variantStyles.text?.primary : variantStyles.text?.primary;
832
+ return /* @__PURE__ */ jsxs2(
757
833
  Box,
758
834
  {
759
835
  as: "button",
@@ -775,7 +851,7 @@ var IconButton = ({
775
851
  backgroundColor,
776
852
  borderColor,
777
853
  borderWidth: borderColor !== "transparent" && borderColor !== "rgba(255, 255, 255, 0)" ? 1 : 0,
778
- borderRadius: theme.radius.button,
854
+ borderRadius: sizeStyles.borderRadius,
779
855
  height: sizeStyles.height,
780
856
  width: sizeStyles.height,
781
857
  padding: 0,
@@ -786,10 +862,10 @@ var IconButton = ({
786
862
  cursor: disabled ? "not-allowed" : loading ? "wait" : "pointer",
787
863
  opacity: disabled ? 0.6 : 1,
788
864
  hoverStyle: !isDisabled ? {
789
- backgroundColor: styles.bgHover
865
+ backgroundColor: variantStyles.bgHover
790
866
  } : void 0,
791
867
  pressStyle: !isDisabled ? {
792
- backgroundColor: styles.bgPress
868
+ backgroundColor: variantStyles.bgPress
793
869
  } : void 0,
794
870
  focusStyle: {
795
871
  outlineColor: theme.colors.border.brand,
@@ -797,14 +873,40 @@ var IconButton = ({
797
873
  outlineOffset: 2,
798
874
  outlineStyle: "solid"
799
875
  },
800
- children: loading ? /* @__PURE__ */ jsx9(
801
- Spinner,
802
- {
803
- color: textColor,
804
- size: sizeStyles.spinnerSize,
805
- "aria-hidden": true
806
- }
807
- ) : /* @__PURE__ */ jsx9(Icon, { size: sizeStyles.iconSize, color: textColor, "aria-hidden": true, children: icon })
876
+ children: [
877
+ loading && /* @__PURE__ */ jsx9(
878
+ Box,
879
+ {
880
+ position: "absolute",
881
+ top: 0,
882
+ left: 0,
883
+ right: 0,
884
+ bottom: 0,
885
+ alignItems: "center",
886
+ justifyContent: "center",
887
+ zIndex: 1,
888
+ children: /* @__PURE__ */ jsx9(
889
+ Spinner,
890
+ {
891
+ color: textColor,
892
+ size: sizeStyles.spinnerSize,
893
+ "aria-hidden": true
894
+ }
895
+ )
896
+ }
897
+ ),
898
+ /* @__PURE__ */ jsx9(
899
+ Box,
900
+ {
901
+ "aria-hidden": true,
902
+ style: {
903
+ opacity: loading ? 0 : 1,
904
+ pointerEvents: loading ? "none" : "auto"
905
+ },
906
+ children: cloneIconWithDefaults2(icon, sizeStyles.iconSize, textColor)
907
+ }
908
+ )
909
+ ]
808
910
  }
809
911
  );
810
912
  };
@@ -813,7 +915,7 @@ IconButton.displayName = "IconButton";
813
915
  // src/FlexButton.tsx
814
916
  import { useRef, useState as useState3 } from "react";
815
917
  import { useDesignSystem as useDesignSystem3 } from "@xsolla/xui-core";
816
- import { Fragment, jsx as jsx10, jsxs as jsxs2 } from "react/jsx-runtime";
918
+ import { Fragment, jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
817
919
  var ICON_SIZES = {
818
920
  xs: 12,
819
921
  sm: 14,
@@ -1135,7 +1237,7 @@ var FlexButton = ({
1135
1237
  tabIndex,
1136
1238
  style: buttonStyle,
1137
1239
  "data-testid": testID || "flex-button",
1138
- children: /* @__PURE__ */ jsx10("span", { style: contentStyle, children: loading ? /* @__PURE__ */ jsx10("span", { style: spinnerStyle, children: /* @__PURE__ */ jsx10(Spinner, { size: spinnerSize, color: spinnerColor }) }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
1240
+ children: /* @__PURE__ */ jsx10("span", { style: contentStyle, children: loading ? /* @__PURE__ */ jsx10("span", { style: spinnerStyle, children: /* @__PURE__ */ jsx10(Spinner, { size: spinnerSize, color: spinnerColor }) }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
1139
1241
  iconLeft && /* @__PURE__ */ jsx10(Icon, { size: iconSize, color: colors.text, children: iconLeft }),
1140
1242
  /* @__PURE__ */ jsx10("span", { children }),
1141
1243
  iconRight && /* @__PURE__ */ jsx10(Icon, { size: iconSize, color: colors.text, children: iconRight })
@@ -1148,7 +1250,7 @@ FlexButton.displayName = "FlexButton";
1148
1250
  // src/ButtonGroup.tsx
1149
1251
  import React6 from "react";
1150
1252
  import { useDesignSystem as useDesignSystem4 } from "@xsolla/xui-core";
1151
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
1253
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
1152
1254
  var ButtonGroup = ({
1153
1255
  orientation = "horizontal",
1154
1256
  size = "md",
@@ -1197,7 +1299,7 @@ var ButtonGroup = ({
1197
1299
  const computedAriaDescribedBy = [
1198
1300
  ariaDescribedBy,
1199
1301
  error && errorId ? errorId : void 0,
1200
- description && !error && descriptionId ? descriptionId : void 0
1302
+ description && descriptionId ? descriptionId : void 0
1201
1303
  ].filter(Boolean).join(" ") || void 0;
1202
1304
  const processChildren = (childrenToProcess) => {
1203
1305
  if (orientation === "vertical") {
@@ -1219,7 +1321,7 @@ var ButtonGroup = ({
1219
1321
  if (useSpaceBetween) {
1220
1322
  const firstChild = processedChildren[0];
1221
1323
  const restChildren = processedChildren.slice(1);
1222
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1324
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1223
1325
  firstChild,
1224
1326
  /* @__PURE__ */ jsx11(Box, { flexDirection: "row", gap: computedGap, children: restChildren })
1225
1327
  ] });
@@ -1229,7 +1331,7 @@ var ButtonGroup = ({
1229
1331
  }
1230
1332
  return children;
1231
1333
  };
1232
- return /* @__PURE__ */ jsxs3(Box, { flexDirection: "column", width: "100%", gap: 8, children: [
1334
+ return /* @__PURE__ */ jsxs4(Box, { flexDirection: "column", width: "100%", gap: 8, children: [
1233
1335
  /* @__PURE__ */ jsx11(
1234
1336
  Box,
1235
1337
  {
@@ -1260,7 +1362,7 @@ var ButtonGroup = ({
1260
1362
  children: error
1261
1363
  }
1262
1364
  ) }),
1263
- description && !error && /* @__PURE__ */ jsx11(Box, { marginTop: 4, children: /* @__PURE__ */ jsx11(
1365
+ description && /* @__PURE__ */ jsx11(Box, { marginTop: 4, children: /* @__PURE__ */ jsx11(
1264
1366
  Text,
1265
1367
  {
1266
1368
  id: descriptionId,