@retray-dev/ui-kit 13.0.0 → 13.2.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.
Files changed (132) hide show
  1. package/CONSUMER.md +24 -9
  2. package/README.md +9 -10
  3. package/{COMPONENTS.md → SKILL.md} +296 -860
  4. package/dist/Accordion.d.mts +2 -0
  5. package/dist/Accordion.d.ts +2 -0
  6. package/dist/Accordion.js +1 -0
  7. package/dist/Accordion.mjs +1 -2
  8. package/dist/AlertBanner.mjs +0 -1
  9. package/dist/AppHeader.d.mts +5 -2
  10. package/dist/AppHeader.d.ts +5 -2
  11. package/dist/AppHeader.js +8 -4
  12. package/dist/AppHeader.mjs +1 -2
  13. package/dist/Avatar.mjs +0 -1
  14. package/dist/Badge.mjs +0 -1
  15. package/dist/Button.mjs +0 -1
  16. package/dist/ButtonGroup.mjs +0 -1
  17. package/dist/Card.mjs +0 -1
  18. package/dist/CategoryStrip.mjs +0 -1
  19. package/dist/Checkbox.d.mts +2 -1
  20. package/dist/Checkbox.d.ts +2 -1
  21. package/dist/Checkbox.js +3 -1
  22. package/dist/Checkbox.mjs +1 -2
  23. package/dist/Chip.mjs +0 -1
  24. package/dist/ConfirmDialog.d.mts +2 -1
  25. package/dist/ConfirmDialog.d.ts +2 -1
  26. package/dist/ConfirmDialog.js +26 -14
  27. package/dist/ConfirmDialog.mjs +1 -2
  28. package/dist/CurrencyDisplay.mjs +0 -1
  29. package/dist/CurrencyInput.mjs +0 -1
  30. package/dist/DetailRow.mjs +0 -1
  31. package/dist/EmptyState.mjs +0 -1
  32. package/dist/ErrorBoundary.mjs +0 -1
  33. package/dist/Form.mjs +0 -1
  34. package/dist/HolographicCard.mjs +0 -1
  35. package/dist/IconButton.mjs +0 -1
  36. package/dist/IconPicker.mjs +0 -1
  37. package/dist/ImageUpload.d.mts +1 -3
  38. package/dist/ImageUpload.d.ts +1 -3
  39. package/dist/ImageUpload.js +27 -26
  40. package/dist/ImageUpload.mjs +1 -2
  41. package/dist/ImageViewer.mjs +0 -1
  42. package/dist/Input.mjs +0 -1
  43. package/dist/LabelValue.mjs +0 -1
  44. package/dist/ListGroup.mjs +0 -1
  45. package/dist/ListItem.d.mts +2 -1
  46. package/dist/ListItem.d.ts +2 -1
  47. package/dist/ListItem.js +3 -1
  48. package/dist/ListItem.mjs +1 -2
  49. package/dist/MediaCard.mjs +0 -1
  50. package/dist/MenuGroup.mjs +0 -1
  51. package/dist/MenuItem.d.mts +2 -1
  52. package/dist/MenuItem.d.ts +2 -1
  53. package/dist/MenuItem.js +3 -1
  54. package/dist/MenuItem.mjs +1 -2
  55. package/dist/MonthPicker.mjs +0 -1
  56. package/dist/NumberStepper.d.mts +2 -1
  57. package/dist/NumberStepper.d.ts +2 -1
  58. package/dist/NumberStepper.js +4 -1
  59. package/dist/NumberStepper.mjs +1 -2
  60. package/dist/PagerDots.mjs +0 -1
  61. package/dist/Pressable.mjs +0 -1
  62. package/dist/PricingCard.mjs +0 -1
  63. package/dist/Progress.mjs +0 -1
  64. package/dist/RadioGroup.mjs +0 -1
  65. package/dist/RetrayProvider.mjs +0 -1
  66. package/dist/Select.d.mts +2 -1
  67. package/dist/Select.d.ts +2 -1
  68. package/dist/Select.js +3 -1
  69. package/dist/Select.mjs +1 -2
  70. package/dist/SelectableCard.mjs +0 -1
  71. package/dist/SelectableGrid.js +0 -1
  72. package/dist/SelectableGrid.mjs +1 -2
  73. package/dist/Separator.mjs +0 -1
  74. package/dist/Sheet.d.mts +1 -1
  75. package/dist/Sheet.d.ts +1 -1
  76. package/dist/Sheet.js +26 -13
  77. package/dist/Sheet.mjs +1 -2
  78. package/dist/SheetSelect.mjs +0 -1
  79. package/dist/Skeleton.mjs +0 -1
  80. package/dist/Slider.d.mts +2 -1
  81. package/dist/Slider.d.ts +2 -1
  82. package/dist/Slider.js +2 -0
  83. package/dist/Slider.mjs +1 -2
  84. package/dist/Spinner.mjs +0 -1
  85. package/dist/Stats.mjs +0 -1
  86. package/dist/Switch.d.mts +2 -1
  87. package/dist/Switch.d.ts +2 -1
  88. package/dist/Switch.js +2 -1
  89. package/dist/Switch.mjs +1 -2
  90. package/dist/TabBar.mjs +0 -1
  91. package/dist/Tabs.mjs +0 -1
  92. package/dist/Text.mjs +0 -1
  93. package/dist/Textarea.mjs +0 -1
  94. package/dist/Toast.d.mts +12 -10
  95. package/dist/Toast.d.ts +12 -10
  96. package/dist/Toast.mjs +0 -1
  97. package/dist/Toggle.mjs +0 -1
  98. package/dist/{chunk-TETMEKZE.mjs → chunk-2QXJDRVU.mjs} +4 -1
  99. package/dist/{chunk-CBIZLRYH.mjs → chunk-422IVD3H.mjs} +1 -0
  100. package/dist/{chunk-4ZO5PTKF.mjs → chunk-77UOVFIS.mjs} +3 -1
  101. package/dist/{chunk-2QOHHBJC.mjs → chunk-7BZJRB77.mjs} +25 -15
  102. package/dist/{chunk-UOKFSFNJ.mjs → chunk-C5ZRMR2E.mjs} +2 -0
  103. package/dist/{chunk-E4EQSCKR.mjs → chunk-COA2YZOX.mjs} +3 -1
  104. package/dist/{chunk-6QLBHUEG.mjs → chunk-CZN6L2QU.mjs} +3 -1
  105. package/dist/{chunk-BTUW5LSG.mjs → chunk-E2PONRJG.mjs} +2 -1
  106. package/dist/{chunk-6CR4S6W2.mjs → chunk-H6MQL7PS.mjs} +9 -4
  107. package/dist/{chunk-EROPDCB5.mjs → chunk-HHOOFDBA.mjs} +26 -21
  108. package/dist/{chunk-URIH43IJ.mjs → chunk-IDVUZIVY.mjs} +3 -1
  109. package/dist/{chunk-MP7GLMIR.mjs → chunk-NPCBNGNE.mjs} +0 -1
  110. package/dist/{chunk-V2ZB2XNS.mjs → chunk-UMZTPUB3.mjs} +27 -15
  111. package/dist/fonts.mjs +0 -2
  112. package/dist/index.d.mts +1 -1
  113. package/dist/index.d.ts +1 -1
  114. package/dist/index.js +108 -64
  115. package/dist/index.mjs +13 -14
  116. package/package.json +14 -12
  117. package/src/components/Accordion/Accordion.tsx +3 -0
  118. package/src/components/AppHeader/AppHeader.tsx +25 -10
  119. package/src/components/Checkbox/Checkbox.tsx +3 -0
  120. package/src/components/ConfirmDialog/ConfirmDialog.tsx +30 -14
  121. package/src/components/ImageUpload/ImageUpload.tsx +33 -25
  122. package/src/components/ListItem/ListItem.tsx +3 -0
  123. package/src/components/MenuItem/MenuItem.tsx +3 -0
  124. package/src/components/NumberStepper/NumberStepper.tsx +4 -0
  125. package/src/components/Select/Select.tsx +3 -0
  126. package/src/components/SelectableGrid/SelectableGrid.tsx +0 -1
  127. package/src/components/Sheet/Sheet.tsx +27 -14
  128. package/src/components/Sheet/index.ts +2 -2
  129. package/src/components/Slider/Slider.tsx +3 -0
  130. package/src/components/Switch/Switch.tsx +3 -1
  131. package/src/components/Text/Text.tsx +1 -0
  132. package/dist/chunk-Y6FXYEAI.mjs +0 -8
package/dist/index.js CHANGED
@@ -35,12 +35,7 @@ var Ionicons__default = /*#__PURE__*/_interopDefault(Ionicons);
35
35
  var Animated6__default = /*#__PURE__*/_interopDefault(Animated6);
36
36
  var RNSlider__default = /*#__PURE__*/_interopDefault(RNSlider);
37
37
 
38
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
39
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
40
- }) : x)(function(x) {
41
- if (typeof require !== "undefined") return require.apply(this, arguments);
42
- throw Error('Dynamic require of "' + x + '" is not supported');
43
- });
38
+ // src/theme/ThemeProvider.tsx
44
39
 
45
40
  // src/theme/colorUtils.ts
46
41
  function hexToRgb(hex) {
@@ -1828,7 +1823,8 @@ function Checkbox({
1828
1823
  label,
1829
1824
  disabled,
1830
1825
  style,
1831
- accessibilityLabel
1826
+ accessibilityLabel,
1827
+ accessibilityHint
1832
1828
  }) {
1833
1829
  const { colors } = useTheme();
1834
1830
  const handlePress = () => {
@@ -1849,6 +1845,7 @@ function Checkbox({
1849
1845
  touchSoundDisabled: true,
1850
1846
  accessibilityRole: "checkbox",
1851
1847
  accessibilityLabel: accessibilityLabel ?? label,
1848
+ accessibilityHint,
1852
1849
  accessibilityState: { checked, disabled: !!disabled }
1853
1850
  },
1854
1851
  /* @__PURE__ */ React54__default.default.createElement(
@@ -1912,7 +1909,7 @@ var THUMB_OFFSET = s(3);
1912
1909
  var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
1913
1910
  var ICON_SIZE = s(13);
1914
1911
  var DISABLED_OPACITY = 0.45;
1915
- function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }) {
1912
+ function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel, accessibilityHint }) {
1916
1913
  const { colors } = useTheme();
1917
1914
  const isDisabled = !!disabled;
1918
1915
  return /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: [{ alignSelf: "flex-start" }, style] }, /* @__PURE__ */ React54__default.default.createElement(
@@ -1927,6 +1924,7 @@ function Switch({ checked = false, onCheckedChange, disabled, style, accessibili
1927
1924
  touchSoundDisabled: true,
1928
1925
  accessibilityRole: "switch",
1929
1926
  accessibilityLabel,
1927
+ accessibilityHint,
1930
1928
  accessibilityState: { checked, disabled: isDisabled },
1931
1929
  style: styles16.touchable
1932
1930
  },
@@ -2456,6 +2454,7 @@ function AccordionItemComponent({
2456
2454
  accessibilityRole: "button",
2457
2455
  accessibilityState: { expanded: isOpen },
2458
2456
  accessibilityLabel: typeof item.trigger === "string" ? item.trigger : void 0,
2457
+ accessibilityHint: item.accessibilityHint,
2459
2458
  style: styles20.trigger
2460
2459
  },
2461
2460
  /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: styles20.triggerContent }, resolvedIcon ? /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: styles20.icon }, resolvedIcon) : null, typeof item.trigger === "string" ? /* @__PURE__ */ React54__default.default.createElement(reactNative.Text, { style: [styles20.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger) : item.trigger),
@@ -2567,6 +2566,7 @@ function Slider({
2567
2566
  showValue = false,
2568
2567
  formatValue: formatValue2 = (v) => v.toFixed(2),
2569
2568
  accessibilityLabel,
2569
+ accessibilityHint,
2570
2570
  disabled,
2571
2571
  style
2572
2572
  }) {
@@ -2585,6 +2585,7 @@ function Slider({
2585
2585
  style: [styles21.wrapper, style],
2586
2586
  accessibilityRole: "adjustable",
2587
2587
  accessibilityLabel: accessibilityLabel ?? label,
2588
+ accessibilityHint,
2588
2589
  accessibilityValue: {
2589
2590
  min: minimumValue,
2590
2591
  max: maximumValue,
@@ -2668,23 +2669,33 @@ function Sheet({
2668
2669
  const { colors } = useTheme();
2669
2670
  const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
2670
2671
  const ref = React54.useRef(null);
2671
- const wasOpened = React54.useRef(false);
2672
- const isPresentedRef = React54.useRef(false);
2672
+ const sheetState = React54.useRef("idle");
2673
+ const onCloseRef = React54.useRef(onClose);
2673
2674
  const name = React54.useId();
2674
- const handleDismiss = React54.useCallback(() => {
2675
- isPresentedRef.current = false;
2676
- onClose?.();
2675
+ const [tick, setTick] = React54.useState(0);
2676
+ React54.useEffect(() => {
2677
+ onCloseRef.current = onClose;
2677
2678
  }, [onClose]);
2679
+ const handleDismiss = React54.useCallback(() => {
2680
+ sheetState.current = "idle";
2681
+ onCloseRef.current?.();
2682
+ setTick((t) => t + 1);
2683
+ }, []);
2678
2684
  React54.useEffect(() => {
2679
- if (open && !isPresentedRef.current) {
2680
- impactMedium();
2681
- ref.current?.present();
2682
- wasOpened.current = true;
2683
- isPresentedRef.current = true;
2684
- } else if (!open && wasOpened.current && isPresentedRef.current) {
2685
- ref.current?.dismiss();
2685
+ if (open) {
2686
+ if (sheetState.current === "idle") {
2687
+ sheetState.current = "presenting";
2688
+ impactMedium();
2689
+ ref.current?.present();
2690
+ sheetState.current = "presented";
2691
+ }
2692
+ } else {
2693
+ if (sheetState.current === "presented" || sheetState.current === "presenting") {
2694
+ sheetState.current = "dismissing";
2695
+ ref.current?.dismiss();
2696
+ }
2686
2697
  }
2687
- }, [open]);
2698
+ }, [open, tick]);
2688
2699
  const renderBackdrop = React54.useCallback(
2689
2700
  (props) => /* @__PURE__ */ React54__default.default.createElement(
2690
2701
  bottomSheet.BottomSheetBackdrop,
@@ -2832,7 +2843,8 @@ function Select({
2832
2843
  error,
2833
2844
  disabled,
2834
2845
  style,
2835
- accessibilityLabel
2846
+ accessibilityLabel,
2847
+ accessibilityHint
2836
2848
  }) {
2837
2849
  const { colors } = useTheme();
2838
2850
  const [pickerVisible, setPickerVisible] = React54.useState(false);
@@ -2876,6 +2888,7 @@ function Select({
2876
2888
  touchSoundDisabled: true,
2877
2889
  accessibilityRole: "combobox",
2878
2890
  accessibilityLabel: accessibilityLabel ?? label,
2891
+ accessibilityHint,
2879
2892
  accessibilityValue: { text: selected?.label ?? placeholder },
2880
2893
  accessibilityState: { disabled: !!disabled, expanded: pickerVisible }
2881
2894
  },
@@ -3219,7 +3232,8 @@ function ListItemBase({
3219
3232
  subtitleStyle,
3220
3233
  subtitleNumberOfLines = 2,
3221
3234
  captionStyle,
3222
- accessibilityLabel
3235
+ accessibilityLabel,
3236
+ accessibilityHint
3223
3237
  }) {
3224
3238
  const { colors } = useTheme();
3225
3239
  const handlePress = () => {
@@ -3284,6 +3298,7 @@ function ListItemBase({
3284
3298
  activateOnHover: true,
3285
3299
  accessibilityRole: "button",
3286
3300
  accessibilityLabel: a11yLabel,
3301
+ accessibilityHint,
3287
3302
  accessibilityState: { disabled: !!disabled }
3288
3303
  },
3289
3304
  content
@@ -3444,7 +3459,8 @@ function MenuItemBase({
3444
3459
  showSeparator = false,
3445
3460
  style,
3446
3461
  labelStyle,
3447
- accessibilityLabel
3462
+ accessibilityLabel,
3463
+ accessibilityHint
3448
3464
  }) {
3449
3465
  const { colors } = useTheme();
3450
3466
  const handlePress = () => {
@@ -3475,6 +3491,7 @@ function MenuItemBase({
3475
3491
  activateOnHover: true,
3476
3492
  accessibilityRole: "button",
3477
3493
  accessibilityLabel: a11yLabel,
3494
+ accessibilityHint,
3478
3495
  accessibilityState: { disabled }
3479
3496
  },
3480
3497
  resolvedIcon ? /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: styles27.iconContainer }, resolvedIcon) : null,
@@ -3734,28 +3751,39 @@ function ConfirmDialog({
3734
3751
  loading = false,
3735
3752
  showCloseButton = false,
3736
3753
  onConfirm,
3737
- onCancel
3754
+ onCancel,
3755
+ accessibilityHint
3738
3756
  }) {
3739
3757
  const { colors } = useTheme();
3740
3758
  const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
3741
3759
  const ref = React54.useRef(null);
3742
- const wasOpened = React54.useRef(false);
3743
- const isPresentedRef = React54.useRef(false);
3760
+ const dialogState = React54.useRef("idle");
3761
+ const onCancelRef = React54.useRef(onCancel);
3744
3762
  const name = React54.useId();
3745
- const handleDismiss = React54.useCallback(() => {
3746
- isPresentedRef.current = false;
3747
- onCancel();
3763
+ const [tick, setTick] = React54.useState(0);
3764
+ React54.useEffect(() => {
3765
+ onCancelRef.current = onCancel;
3748
3766
  }, [onCancel]);
3767
+ const handleDismiss = React54.useCallback(() => {
3768
+ dialogState.current = "idle";
3769
+ onCancelRef.current?.();
3770
+ setTick((t) => t + 1);
3771
+ }, []);
3749
3772
  React54.useEffect(() => {
3750
- if (visible && !isPresentedRef.current) {
3751
- impactMedium();
3752
- ref.current?.present();
3753
- wasOpened.current = true;
3754
- isPresentedRef.current = true;
3755
- } else if (!visible && wasOpened.current && isPresentedRef.current) {
3756
- ref.current?.dismiss();
3773
+ if (visible) {
3774
+ if (dialogState.current === "idle") {
3775
+ dialogState.current = "presenting";
3776
+ impactMedium();
3777
+ ref.current?.present();
3778
+ dialogState.current = "presented";
3779
+ }
3780
+ } else {
3781
+ if (dialogState.current === "presented" || dialogState.current === "presenting") {
3782
+ dialogState.current = "dismissing";
3783
+ ref.current?.dismiss();
3784
+ }
3757
3785
  }
3758
- }, [visible]);
3786
+ }, [visible, tick]);
3759
3787
  const renderBackdrop = React54.useCallback(
3760
3788
  (props) => /* @__PURE__ */ React54__default.default.createElement(
3761
3789
  bottomSheet.BottomSheetBackdrop,
@@ -3805,6 +3833,7 @@ function ConfirmDialog({
3805
3833
  notificationSuccess();
3806
3834
  onConfirm();
3807
3835
  },
3836
+ accessibilityHint,
3808
3837
  icon: /* @__PURE__ */ React54__default.default.createElement(
3809
3838
  vectorIcons.Feather,
3810
3839
  {
@@ -4686,6 +4715,7 @@ function AppHeader({
4686
4715
  subtitle,
4687
4716
  onBack,
4688
4717
  backIconName = "chevron-left",
4718
+ iconName,
4689
4719
  left,
4690
4720
  right,
4691
4721
  titleAlign = "auto",
@@ -4699,7 +4729,7 @@ function AppHeader({
4699
4729
  const { width } = reactNative.useWindowDimensions();
4700
4730
  const isWide = width >= BREAKPOINTS.wide;
4701
4731
  const centered = titleAlign === "center" || titleAlign === "auto" && isWide;
4702
- const leftNode = left ?? (onBack ? /* @__PURE__ */ React54__default.default.createElement(
4732
+ const leftNode = left ?? /* @__PURE__ */ React54__default.default.createElement(React54__default.default.Fragment, null, onBack ? /* @__PURE__ */ React54__default.default.createElement(
4703
4733
  IconButton,
4704
4734
  {
4705
4735
  iconName: backIconName,
@@ -4708,7 +4738,7 @@ function AppHeader({
4708
4738
  onPress: onBack,
4709
4739
  accessibilityLabel: "Atr\xE1s"
4710
4740
  }
4711
- ) : null);
4741
+ ) : null, iconName && !left ? /* @__PURE__ */ React54__default.default.createElement(Icon, { name: iconName, size: 20, color: colors.foreground }) : null);
4712
4742
  const titleBlock = /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: [styles40.titleBlock, centered && styles40.titleBlockCentered], pointerEvents: "none" }, title ? /* @__PURE__ */ React54__default.default.createElement(
4713
4743
  reactNative.Text,
4714
4744
  {
@@ -4758,10 +4788,13 @@ var styles40 = reactNative.StyleSheet.create({
4758
4788
  minWidth: s(44),
4759
4789
  flexDirection: "row",
4760
4790
  alignItems: "center",
4761
- justifyContent: "flex-start"
4791
+ justifyContent: "flex-start",
4792
+ paddingLeft: s(8),
4793
+ gap: s(4)
4762
4794
  },
4763
4795
  sideRight: {
4764
- justifyContent: "flex-end"
4796
+ justifyContent: "flex-end",
4797
+ paddingRight: s(8)
4765
4798
  },
4766
4799
  titleBlock: {
4767
4800
  flex: 1,
@@ -4809,7 +4842,6 @@ function Cell({ item, selected, width, onPress }) {
4809
4842
  { width },
4810
4843
  styles41.cell,
4811
4844
  {
4812
- backgroundColor: selected ? colors.primary + "14" : colors.surface,
4813
4845
  borderColor: selected ? colors.primary : "transparent"
4814
4846
  },
4815
4847
  item.disabled && styles41.cellDisabled
@@ -5694,7 +5726,6 @@ function ImageUpload({
5694
5726
  height = 200,
5695
5727
  borderRadius = RADIUS.lg,
5696
5728
  resizeMode = "cover",
5697
- allowsEditing = true,
5698
5729
  disabled = false,
5699
5730
  style,
5700
5731
  accessibilityLabel,
@@ -5702,25 +5733,32 @@ function ImageUpload({
5702
5733
  }) {
5703
5734
  const { colors } = useTheme();
5704
5735
  const [imageLoaded, setImageLoaded] = React54.useState(false);
5736
+ const [isPicking, setIsPicking] = React54.useState(false);
5705
5737
  const handlePress = async () => {
5706
- if (disabled || loading) return;
5738
+ if (disabled || loading || isPicking) return;
5707
5739
  impactLight();
5708
5740
  onPickerStarting?.();
5709
- let picker;
5741
+ setIsPicking(true);
5710
5742
  try {
5711
- picker = __require("expo-image-picker");
5743
+ const { launchImageLibrary } = await import('react-native-image-picker');
5744
+ const result = await new Promise((resolve) => {
5745
+ launchImageLibrary(
5746
+ {
5747
+ mediaType: "photo",
5748
+ quality: 0.8,
5749
+ selectionLimit: 1,
5750
+ includeBase64: false
5751
+ },
5752
+ resolve
5753
+ );
5754
+ });
5755
+ if (!result.didCancel && !result.errorCode && result.assets?.[0]?.uri) {
5756
+ setImageLoaded(false);
5757
+ onChange?.(result.assets[0].uri);
5758
+ }
5712
5759
  } catch {
5713
- if (__DEV__) console.warn("[ImageUpload] expo-image-picker not installed.");
5714
- return;
5715
- }
5716
- const result = await picker.launchImageLibraryAsync({
5717
- mediaTypes: ["images"],
5718
- allowsEditing,
5719
- quality: 0.8
5720
- });
5721
- if (!result.canceled && result.assets?.[0]) {
5722
- setImageLoaded(false);
5723
- onChange?.(result.assets[0].uri);
5760
+ } finally {
5761
+ setIsPicking(false);
5724
5762
  }
5725
5763
  };
5726
5764
  const containerStyle = {
@@ -5763,7 +5801,7 @@ function ImageUpload({
5763
5801
  },
5764
5802
  placeholder
5765
5803
  ) : null),
5766
- loading ? /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: [styles47.loadingOverlay, { backgroundColor: colors.overlay }] }, /* @__PURE__ */ React54__default.default.createElement(Spinner, { size: "md" })) : null,
5804
+ loading || isPicking ? /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: [styles47.loadingOverlay, { backgroundColor: colors.overlay }] }, /* @__PURE__ */ React54__default.default.createElement(Spinner, { size: "md" })) : null,
5767
5805
  value && !loading ? /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: styles47.editBadge, pointerEvents: "none" }, /* @__PURE__ */ React54__default.default.createElement(reactNative.View, { style: [styles47.editBadgeInner, { backgroundColor: colors.overlay }] }, /* @__PURE__ */ React54__default.default.createElement(vectorIcons.Feather, { name: "edit-2", size: ms(12), color: "#fff" }))) : null
5768
5806
  );
5769
5807
  }
@@ -5786,12 +5824,12 @@ var styles47 = reactNative.StyleSheet.create({
5786
5824
  },
5787
5825
  editBadge: {
5788
5826
  position: "absolute",
5789
- bottom: vs(8),
5790
- right: s(8)
5827
+ bottom: vs(14),
5828
+ right: s(14)
5791
5829
  },
5792
5830
  editBadgeInner: {
5793
- width: s(28),
5794
- height: s(28),
5831
+ width: s(24),
5832
+ height: s(24),
5795
5833
  borderRadius: 999,
5796
5834
  alignItems: "center",
5797
5835
  justifyContent: "center"
@@ -6379,7 +6417,8 @@ function NumberStepperBase({
6379
6417
  size = "md",
6380
6418
  disabled = false,
6381
6419
  style,
6382
- accessibilityLabel
6420
+ accessibilityLabel,
6421
+ accessibilityHint
6383
6422
  }) {
6384
6423
  const { colors } = useTheme();
6385
6424
  const canDecrement = value > min && !disabled;
@@ -6415,6 +6454,7 @@ function NumberStepperBase({
6415
6454
  touchSoundDisabled: true,
6416
6455
  accessibilityRole: "button",
6417
6456
  accessibilityLabel: `Disminuir, valor actual ${displayValue}`,
6457
+ accessibilityHint,
6418
6458
  accessibilityState: { disabled: !canDecrement }
6419
6459
  },
6420
6460
  /* @__PURE__ */ React54__default.default.createElement(Icon, { name: "minus", size: iconSize, color: canDecrement ? colors.foreground : colors.foregroundMuted })
@@ -6454,6 +6494,7 @@ function NumberStepperBase({
6454
6494
  touchSoundDisabled: true,
6455
6495
  accessibilityRole: "button",
6456
6496
  accessibilityLabel: `Aumentar, valor actual ${displayValue}`,
6497
+ accessibilityHint,
6457
6498
  accessibilityState: { disabled: !canIncrement }
6458
6499
  },
6459
6500
  /* @__PURE__ */ React54__default.default.createElement(Icon, { name: "plus", size: iconSize, color: canIncrement ? colors.foreground : colors.foregroundMuted })
@@ -6759,6 +6800,9 @@ exports.SelectableCardGroup = SelectableCardGroup;
6759
6800
  exports.SelectableGrid = SelectableGrid;
6760
6801
  exports.Separator = Separator;
6761
6802
  exports.Sheet = Sheet;
6803
+ exports.SheetContent = SheetContent;
6804
+ exports.SheetFooter = SheetFooter;
6805
+ exports.SheetHeader = SheetHeader;
6762
6806
  exports.SheetSelect = SheetSelect;
6763
6807
  exports.Skeleton = Skeleton;
6764
6808
  exports.Slider = Slider;
package/dist/index.mjs CHANGED
@@ -1,20 +1,20 @@
1
1
  export { Toggle } from './chunk-RRKM4MKB.mjs';
2
2
  export { Stats } from './chunk-ZKDKKQCE.mjs';
3
- export { Switch } from './chunk-BTUW5LSG.mjs';
3
+ export { Switch } from './chunk-E2PONRJG.mjs';
4
4
  export { TabBar } from './chunk-U6DEBYU5.mjs';
5
5
  export { Tabs, TabsContent } from './chunk-KC5QDYGZ.mjs';
6
6
  export { Text } from './chunk-EHGBHFMH.mjs';
7
7
  export { Textarea } from './chunk-L3YKPTJQ.mjs';
8
- export { Select } from './chunk-URIH43IJ.mjs';
8
+ export { Select } from './chunk-IDVUZIVY.mjs';
9
9
  export { SelectableCard, SelectableCardGroup } from './chunk-BULKGOIZ.mjs';
10
- export { SelectableGrid } from './chunk-MP7GLMIR.mjs';
10
+ export { SelectableGrid } from './chunk-NPCBNGNE.mjs';
11
11
  export { Separator } from './chunk-EW2FIDSM.mjs';
12
- export { BottomSheetModalProvider, Sheet, BottomSheetTextInput as SheetTextInput } from './chunk-2QOHHBJC.mjs';
12
+ export { BottomSheetModalProvider, Sheet, SheetContent, SheetFooter, SheetHeader, BottomSheetTextInput as SheetTextInput } from './chunk-7BZJRB77.mjs';
13
13
  export { SheetSelect } from './chunk-WIPEDNSD.mjs';
14
14
  export { Skeleton } from './chunk-XCIG6HT2.mjs';
15
- export { Slider } from './chunk-UOKFSFNJ.mjs';
15
+ export { Slider } from './chunk-C5ZRMR2E.mjs';
16
16
  export { MonthPicker, dateToMonthPickerValue, monthPickerValueToDate } from './chunk-ITG4JQM3.mjs';
17
- export { NumberStepper } from './chunk-TETMEKZE.mjs';
17
+ export { NumberStepper } from './chunk-2QXJDRVU.mjs';
18
18
  export { Pressable } from './chunk-62BBSSUF.mjs';
19
19
  export { PricingCard } from './chunk-K3QX2M26.mjs';
20
20
  export { Progress } from './chunk-DBHSUUKU.mjs';
@@ -25,29 +25,29 @@ export { ImageViewer } from './chunk-PGQ6FMXS.mjs';
25
25
  export { PagerDots } from './chunk-S44XWTTC.mjs';
26
26
  export { LabelValue } from './chunk-DE25XTVQ.mjs';
27
27
  export { ListGroup, ListGroupFooter, ListGroupHeader } from './chunk-OBV72JD4.mjs';
28
- export { ListItem } from './chunk-6QLBHUEG.mjs';
28
+ export { ListItem } from './chunk-CZN6L2QU.mjs';
29
29
  export { MediaCard } from './chunk-CM2DG4MR.mjs';
30
30
  export { MenuGroup, MenuGroupFooter, MenuGroupHeader } from './chunk-S2VGME7X.mjs';
31
- export { MenuItem } from './chunk-E4EQSCKR.mjs';
31
+ export { MenuItem } from './chunk-COA2YZOX.mjs';
32
32
  export { DetailRow } from './chunk-KAGADD2O.mjs';
33
33
  export { EmptyState } from './chunk-FTTI6T5Q.mjs';
34
34
  export { ErrorBoundary } from './chunk-ESQDPO5E.mjs';
35
35
  export { Form, FormField, FormFooter, FormSection } from './chunk-KPTY7UYQ.mjs';
36
36
  export { IconPicker } from './chunk-NGEN2EES.mjs';
37
- export { ImageUpload } from './chunk-EROPDCB5.mjs';
37
+ export { ImageUpload } from './chunk-HHOOFDBA.mjs';
38
38
  export { Spinner } from './chunk-2VIDP72N.mjs';
39
39
  export { ButtonGroup } from './chunk-3BBOZ3OQ.mjs';
40
40
  export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-TMH263OK.mjs';
41
41
  export { CategoryStrip } from './chunk-5MYNAAFE.mjs';
42
- export { Checkbox } from './chunk-4ZO5PTKF.mjs';
42
+ export { Checkbox } from './chunk-77UOVFIS.mjs';
43
43
  export { Chip, ChipGroup } from './chunk-RA6SAAFE.mjs';
44
- export { ConfirmDialog } from './chunk-V2ZB2XNS.mjs';
44
+ export { ConfirmDialog } from './chunk-UMZTPUB3.mjs';
45
45
  export { CurrencyDisplay } from './chunk-PI6RULJX.mjs';
46
46
  export { CurrencyInput } from './chunk-HUSSF6TF.mjs';
47
47
  export { Input } from './chunk-4NQFTHN3.mjs';
48
- export { Accordion } from './chunk-CBIZLRYH.mjs';
48
+ export { Accordion } from './chunk-422IVD3H.mjs';
49
49
  export { AlertBanner } from './chunk-K7TKID3V.mjs';
50
- export { AppHeader } from './chunk-6CR4S6W2.mjs';
50
+ export { AppHeader } from './chunk-H6MQL7PS.mjs';
51
51
  export { IconButton } from './chunk-ZTPYUU5C.mjs';
52
52
  export { Avatar, AvatarGroup } from './chunk-IGU223UM.mjs';
53
53
  export { Badge } from './chunk-AZV7KNJI.mjs';
@@ -59,7 +59,6 @@ export { BREAKPOINTS, ICON_SIZES, RADIUS, SHADOWS, SPACING, TYPOGRAPHY } from '.
59
59
  export { Icon } from './chunk-MZ6WRTD2.mjs';
60
60
  export { ThemeProvider, defaultDark, defaultLight, deriveColors, hexToRgb, useTheme, withAlpha } from './chunk-KSSVIFYR.mjs';
61
61
  import './chunk-2CE3TQVY.mjs';
62
- import './chunk-Y6FXYEAI.mjs';
63
62
  import { useState, useRef, useEffect, useCallback } from 'react';
64
63
 
65
64
  // src/utils/typography.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retray-dev/ui-kit",
3
- "version": "13.0.0",
3
+ "version": "13.2.0",
4
4
  "description": "Personal UI Kit for React Native / Expo",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -26,11 +26,11 @@
26
26
  "dist",
27
27
  "src",
28
28
  "scripts",
29
- "COMPONENTS.md",
30
29
  "CONSUMER.md",
31
30
  "EXAMPLES.md",
32
31
  "FONTS.md",
33
- "DESIGN.md"
32
+ "DESIGN.md",
33
+ "SKILL.md"
34
34
  ],
35
35
  "scripts": {
36
36
  "postinstall": "node scripts/copy-fonts.js",
@@ -66,8 +66,9 @@
66
66
  "expo-font": ">=14.0.0",
67
67
  "expo-haptics": ">=14.0.0",
68
68
  "expo-image": ">=3.0.0",
69
- "expo-image-picker": ">=15.0.0",
69
+ "react-native-image-picker": ">=7.0.0",
70
70
  "expo-linear-gradient": ">=13.0.0",
71
+ "expo-modules-core": ">=3.0.0",
71
72
  "expo-sensors": ">=13.0.0",
72
73
  "pressto": ">=0.6.0",
73
74
  "react": ">=17",
@@ -89,14 +90,15 @@
89
90
  "expo-sensors": {
90
91
  "optional": true
91
92
  },
92
- "expo-image-picker": {
93
- "optional": true
94
- },
93
+
95
94
  "react-native-ease": {
96
95
  "optional": false
97
96
  },
98
97
  "pressto": {
99
98
  "optional": false
99
+ },
100
+ "react-native-image-picker": {
101
+ "optional": true
100
102
  }
101
103
  },
102
104
  "pnpm": {
@@ -133,21 +135,21 @@
133
135
  "expo-haptics": "~15.0.8",
134
136
  "expo-image": "~3.0.11",
135
137
  "expo-linear-gradient": "~15.0.8",
136
- "expo-sensors": "~15.0.7",
138
+ "expo-sensors": "~15.0.8",
137
139
  "jest-expo": "~54.0.17",
138
- "pressto": "^0.6.1",
140
+ "pressto": "^0.7.0",
139
141
  "prettier": "^3.8.3",
140
142
  "react": "19.1.0",
141
143
  "react-native": "0.81.5",
142
- "react-native-ease": "^0.7.2",
144
+ "react-native-ease": "^0.7.3",
143
145
  "react-native-gesture-handler": "~2.28.0",
144
146
  "react-native-reanimated": "~4.1.1",
145
147
  "react-native-safe-area-context": "5.6.2",
146
148
  "react-native-screens": "4.16.0",
147
149
  "react-native-size-matters": "^0.4.2",
148
- "react-native-svg": "15.12.1",
150
+ "react-native-svg": "15.15.5",
149
151
  "react-native-worklets": "~0.5.1",
150
- "sonner-native": "0.23.1",
152
+ "sonner-native": "0.26.3",
151
153
  "test-renderer": "^1.2.0",
152
154
  "tsup": "^8.0.0",
153
155
  "typescript": "^5.4.0",
@@ -30,12 +30,14 @@ export interface AccordionItem {
30
30
  icon?: React.ReactNode
31
31
  /** Override icon color. Defaults to foregroundMuted. */
32
32
  iconColor?: string
33
+ /**
33
34
  /**
34
35
  * Action buttons rendered after the trigger content but before the chevron.
35
36
  * Automatically touch-isolated — taps on actions won't toggle the accordion.
36
37
  * Use this instead of embedding interactive elements inside `trigger`.
37
38
  */
38
39
  triggerActions?: React.ReactNode
40
+ accessibilityHint?: string
39
41
  }
40
42
 
41
43
  export interface AccordionProps {
@@ -111,6 +113,7 @@ function AccordionItemComponent({
111
113
  accessibilityRole="button"
112
114
  accessibilityState={{ expanded: isOpen }}
113
115
  accessibilityLabel={typeof item.trigger === 'string' ? item.trigger : undefined}
116
+ accessibilityHint={item.accessibilityHint}
114
117
  style={styles.trigger}
115
118
  >
116
119
  <View style={styles.triggerContent}>
@@ -3,6 +3,7 @@ import { View, Text, StyleSheet, ViewStyle, useWindowDimensions } from 'react-na
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
4
  import { useTheme } from '../../theme'
5
5
  import { IconButton } from '../IconButton'
6
+ import { Icon } from '../../utils/icons'
6
7
  import { s, vs, ms, mvs } from '../../utils/scaling'
7
8
  import { BREAKPOINTS } from '../../tokens'
8
9
 
@@ -15,7 +16,9 @@ export interface AppHeaderProps {
15
16
  onBack?: () => void
16
17
  /** Icon name for the back button. Defaults to `'chevron-left'`. */
17
18
  backIconName?: string
18
- /** Custom left content overrides the back button. */
19
+ /** Icon name for a decorative icon shown left of the title, after the back button. Ignored when `left` is provided. */
20
+ iconName?: string
21
+ /** Custom left content — overrides the back button and `iconName`. */
19
22
  left?: React.ReactNode
20
23
  /** Custom right content (actions). */
21
24
  right?: React.ReactNode
@@ -40,12 +43,14 @@ export interface AppHeaderProps {
40
43
  *
41
44
  * @example
42
45
  * <AppHeader title="Settings" onBack={navigation.goBack} right={<IconButton iconName="more-horizontal" variant="text" />} />
46
+ * <AppHeader title="Perfil" iconName="user" onBack={navigation.goBack} />
43
47
  */
44
48
  export function AppHeader({
45
49
  title,
46
50
  subtitle,
47
51
  onBack,
48
52
  backIconName = 'chevron-left',
53
+ iconName,
49
54
  left,
50
55
  right,
51
56
  titleAlign = 'auto',
@@ -61,15 +66,22 @@ export function AppHeader({
61
66
  const isWide = width >= BREAKPOINTS.wide
62
67
  const centered = titleAlign === 'center' || (titleAlign === 'auto' && isWide)
63
68
 
64
- const leftNode = left ?? (onBack ? (
65
- <IconButton
66
- iconName={backIconName}
67
- variant="text"
68
- size="md"
69
- onPress={onBack}
70
- accessibilityLabel="Atrás"
71
- />
72
- ) : null)
69
+ const leftNode = left ?? (
70
+ <>
71
+ {onBack ? (
72
+ <IconButton
73
+ iconName={backIconName}
74
+ variant="text"
75
+ size="md"
76
+ onPress={onBack}
77
+ accessibilityLabel="Atrás"
78
+ />
79
+ ) : null}
80
+ {iconName && !left ? (
81
+ <Icon name={iconName} size={20} color={colors.foreground} />
82
+ ) : null}
83
+ </>
84
+ )
73
85
 
74
86
  const titleBlock = (
75
87
  <View style={[styles.titleBlock, centered && styles.titleBlockCentered]} pointerEvents="none">
@@ -143,9 +155,12 @@ const styles = StyleSheet.create({
143
155
  flexDirection: 'row',
144
156
  alignItems: 'center',
145
157
  justifyContent: 'flex-start',
158
+ paddingLeft: s(8),
159
+ gap: s(4),
146
160
  },
147
161
  sideRight: {
148
162
  justifyContent: 'flex-end',
163
+ paddingRight: s(8),
149
164
  },
150
165
  titleBlock: {
151
166
  flex: 1,
@@ -14,6 +14,7 @@ export interface CheckboxProps {
14
14
  disabled?: boolean
15
15
  style?: ViewStyle
16
16
  accessibilityLabel?: string
17
+ accessibilityHint?: string
17
18
  }
18
19
 
19
20
  export function Checkbox({
@@ -23,6 +24,7 @@ export function Checkbox({
23
24
  disabled,
24
25
  style,
25
26
  accessibilityLabel,
27
+ accessibilityHint,
26
28
  }: CheckboxProps) {
27
29
  const { colors } = useTheme()
28
30
 
@@ -43,6 +45,7 @@ export function Checkbox({
43
45
  touchSoundDisabled
44
46
  accessibilityRole="checkbox"
45
47
  accessibilityLabel={accessibilityLabel ?? label}
48
+ accessibilityHint={accessibilityHint}
46
49
  accessibilityState={{ checked, disabled: !!disabled }}
47
50
  >
48
51
  <EaseView