@retray-dev/ui-kit 12.2.0 → 13.0.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 (268) hide show
  1. package/COMPONENTS.md +85 -143
  2. package/CONSUMER.md +2 -2
  3. package/DESIGN.md +2 -2
  4. package/README.md +11 -6
  5. package/dist/Accordion.js +48 -210
  6. package/dist/Accordion.mjs +6 -5
  7. package/dist/AlertBanner.js +29 -153
  8. package/dist/AlertBanner.mjs +3 -3
  9. package/dist/AppHeader.js +37 -235
  10. package/dist/AppHeader.mjs +6 -7
  11. package/dist/Avatar.d.mts +17 -1
  12. package/dist/Avatar.d.ts +17 -1
  13. package/dist/Avatar.js +80 -115
  14. package/dist/Avatar.mjs +2 -2
  15. package/dist/Badge.js +24 -149
  16. package/dist/Badge.mjs +3 -3
  17. package/dist/Button.js +79 -267
  18. package/dist/Button.mjs +6 -6
  19. package/dist/Card.js +15 -200
  20. package/dist/Card.mjs +4 -5
  21. package/dist/CategoryStrip.d.mts +0 -5
  22. package/dist/CategoryStrip.d.ts +0 -5
  23. package/dist/CategoryStrip.js +47 -265
  24. package/dist/CategoryStrip.mjs +6 -6
  25. package/dist/Checkbox.js +15 -200
  26. package/dist/Checkbox.mjs +5 -5
  27. package/dist/Chip.js +44 -236
  28. package/dist/Chip.mjs +7 -6
  29. package/dist/ConfirmDialog.js +84 -286
  30. package/dist/ConfirmDialog.mjs +7 -7
  31. package/dist/CurrencyDisplay.js +1 -114
  32. package/dist/CurrencyDisplay.mjs +2 -2
  33. package/dist/CurrencyInput.js +35 -162
  34. package/dist/CurrencyInput.mjs +5 -5
  35. package/dist/DetailRow.js +25 -150
  36. package/dist/DetailRow.mjs +3 -3
  37. package/dist/EmptyState.js +80 -268
  38. package/dist/EmptyState.mjs +7 -7
  39. package/dist/ErrorBoundary.js +32 -199
  40. package/dist/ErrorBoundary.mjs +4 -4
  41. package/dist/Form.js +1 -114
  42. package/dist/Form.mjs +2 -2
  43. package/dist/HolographicCard.d.mts +0 -28
  44. package/dist/HolographicCard.d.ts +0 -28
  45. package/dist/HolographicCard.js +20 -130
  46. package/dist/HolographicCard.mjs +9 -32
  47. package/dist/IconButton.js +36 -234
  48. package/dist/IconButton.mjs +5 -6
  49. package/dist/IconPicker.js +222 -929
  50. package/dist/IconPicker.mjs +5 -5
  51. package/dist/ImageUpload.d.mts +3 -1
  52. package/dist/ImageUpload.d.ts +3 -1
  53. package/dist/ImageUpload.js +25 -215
  54. package/dist/ImageUpload.mjs +5 -6
  55. package/dist/ImageViewer.js +75 -266
  56. package/dist/ImageViewer.mjs +8 -8
  57. package/dist/Input.d.mts +1 -1
  58. package/dist/Input.d.ts +1 -1
  59. package/dist/Input.js +35 -162
  60. package/dist/Input.mjs +4 -4
  61. package/dist/LabelValue.js +24 -149
  62. package/dist/LabelValue.mjs +3 -3
  63. package/dist/ListGroup.js +1 -114
  64. package/dist/ListGroup.mjs +2 -2
  65. package/dist/ListItem.js +38 -235
  66. package/dist/ListItem.mjs +5 -6
  67. package/dist/MediaCard.d.mts +0 -14
  68. package/dist/MediaCard.d.ts +0 -14
  69. package/dist/MediaCard.js +69 -315
  70. package/dist/MediaCard.mjs +5 -6
  71. package/dist/MenuGroup.js +1 -114
  72. package/dist/MenuGroup.mjs +2 -2
  73. package/dist/MenuItem.js +36 -234
  74. package/dist/MenuItem.mjs +5 -6
  75. package/dist/MonthPicker.js +8 -163
  76. package/dist/MonthPicker.mjs +3 -3
  77. package/dist/NumberStepper.js +40 -238
  78. package/dist/NumberStepper.mjs +5 -6
  79. package/dist/PagerDots.d.mts +1 -1
  80. package/dist/PagerDots.d.ts +1 -1
  81. package/dist/PagerDots.js +69 -224
  82. package/dist/PagerDots.mjs +6 -5
  83. package/dist/Pressable.js +14 -85
  84. package/dist/Pressable.mjs +4 -4
  85. package/dist/PricingCard.js +87 -272
  86. package/dist/PricingCard.mjs +8 -8
  87. package/dist/Progress.js +3 -123
  88. package/dist/Progress.mjs +3 -3
  89. package/dist/RadioGroup.js +52 -265
  90. package/dist/RadioGroup.mjs +5 -5
  91. package/dist/RetrayProvider.js +3 -6
  92. package/dist/RetrayProvider.mjs +3 -3
  93. package/dist/Select.d.mts +2 -1
  94. package/dist/Select.d.ts +2 -1
  95. package/dist/Select.js +24 -232
  96. package/dist/Select.mjs +4 -5
  97. package/dist/SelectableCard.js +33 -209
  98. package/dist/SelectableCard.mjs +5 -5
  99. package/dist/SelectableGrid.d.mts +0 -21
  100. package/dist/SelectableGrid.d.ts +0 -21
  101. package/dist/SelectableGrid.js +49 -271
  102. package/dist/SelectableGrid.mjs +5 -6
  103. package/dist/Separator.js +1 -114
  104. package/dist/Separator.mjs +2 -2
  105. package/dist/Sheet.js +7 -162
  106. package/dist/Sheet.mjs +3 -3
  107. package/dist/SheetSelect.js +39 -236
  108. package/dist/SheetSelect.mjs +6 -6
  109. package/dist/Skeleton.js +4 -124
  110. package/dist/Skeleton.mjs +3 -3
  111. package/dist/Slider.js +6 -161
  112. package/dist/Slider.mjs +3 -3
  113. package/dist/Spinner.js +3 -116
  114. package/dist/Spinner.mjs +2 -2
  115. package/dist/Stats.js +36 -234
  116. package/dist/Stats.mjs +5 -6
  117. package/dist/Switch.js +24 -175
  118. package/dist/Switch.mjs +5 -4
  119. package/dist/TabBar.js +43 -200
  120. package/dist/TabBar.mjs +5 -4
  121. package/dist/Tabs.js +15 -199
  122. package/dist/Tabs.mjs +5 -5
  123. package/dist/Text.js +9 -130
  124. package/dist/Text.mjs +2 -2
  125. package/dist/Textarea.d.mts +2 -1
  126. package/dist/Textarea.d.ts +2 -1
  127. package/dist/Textarea.js +71 -219
  128. package/dist/Textarea.mjs +4 -4
  129. package/dist/Toast.js +1 -114
  130. package/dist/Toast.mjs +2 -2
  131. package/dist/Toggle.js +39 -236
  132. package/dist/Toggle.mjs +6 -6
  133. package/dist/{chunk-M3C7XM2M.mjs → chunk-2QOHHBJC.mjs} +3 -3
  134. package/dist/{chunk-LIS6I5UP.mjs → chunk-2VIDP72N.mjs} +3 -3
  135. package/dist/{chunk-DF7JA72E.mjs → chunk-4NQFTHN3.mjs} +13 -7
  136. package/dist/{chunk-UBUXUMER.mjs → chunk-4ZO5PTKF.mjs} +4 -4
  137. package/dist/{chunk-3XCFYSX4.mjs → chunk-5MYNAAFE.mjs} +13 -17
  138. package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
  139. package/dist/{chunk-MVMGPZN6.mjs → chunk-6CR4S6W2.mjs} +3 -3
  140. package/dist/{chunk-EDLCGYIO.mjs → chunk-6QLBHUEG.mjs} +8 -7
  141. package/dist/chunk-ARONDO7M.mjs +40 -0
  142. package/dist/{chunk-GH67YXG6.mjs → chunk-AZV7KNJI.mjs} +3 -3
  143. package/dist/{chunk-RMRS44MQ.mjs → chunk-BTUW5LSG.mjs} +11 -8
  144. package/dist/{chunk-2P2CB235.mjs → chunk-BULKGOIZ.mjs} +7 -8
  145. package/dist/{chunk-NHDI3VQB.mjs → chunk-CBIZLRYH.mjs} +15 -12
  146. package/dist/chunk-CM2DG4MR.mjs +142 -0
  147. package/dist/{chunk-TS7DGUIR.mjs → chunk-DBHSUUKU.mjs} +2 -2
  148. package/dist/{chunk-57V2LXCK.mjs → chunk-DE25XTVQ.mjs} +3 -3
  149. package/dist/{chunk-UQ4742ET.mjs → chunk-E4EQSCKR.mjs} +5 -5
  150. package/dist/{chunk-GUTDFUNF.mjs → chunk-EHGBHFMH.mjs} +9 -17
  151. package/dist/{chunk-CF27NBXO.mjs → chunk-EROPDCB5.mjs} +16 -24
  152. package/dist/{chunk-ZIMY2QUM.mjs → chunk-ERWJPVX7.mjs} +2 -2
  153. package/dist/{chunk-NLZY4TXU.mjs → chunk-ESQDPO5E.mjs} +7 -7
  154. package/dist/{chunk-VJBUCITV.mjs → chunk-EW2FIDSM.mjs} +1 -1
  155. package/dist/{chunk-HC4VVCWY.mjs → chunk-FTTI6T5Q.mjs} +4 -4
  156. package/dist/{chunk-2HFD4IHU.mjs → chunk-HUSSF6TF.mjs} +1 -1
  157. package/dist/chunk-IFYMBOEN.mjs +14 -0
  158. package/dist/{chunk-QOLWA2PW.mjs → chunk-IGU223UM.mjs} +80 -4
  159. package/dist/chunk-IJCMPVW5.mjs +121 -0
  160. package/dist/{chunk-AENAVIKT.mjs → chunk-ITG4JQM3.mjs} +4 -4
  161. package/dist/{chunk-E5UKLSJZ.mjs → chunk-K3QX2M26.mjs} +11 -8
  162. package/dist/{chunk-4OORJ2DY.mjs → chunk-K7TKID3V.mjs} +8 -7
  163. package/dist/{chunk-2LG326TT.mjs → chunk-KAGADD2O.mjs} +4 -4
  164. package/dist/{chunk-IVSRW4HS.mjs → chunk-KC5QDYGZ.mjs} +4 -4
  165. package/dist/{chunk-7AFZWSCI.mjs → chunk-KPTY7UYQ.mjs} +1 -1
  166. package/dist/{chunk-YTXRIXNZ.mjs → chunk-KSSVIFYR.mjs} +9 -12
  167. package/dist/chunk-L3YKPTJQ.mjs +119 -0
  168. package/dist/chunk-M53LC4Q7.mjs +35 -0
  169. package/dist/{chunk-ZR6HSEAB.mjs → chunk-MP7GLMIR.mjs} +17 -25
  170. package/dist/chunk-MZ6WRTD2.mjs +40 -0
  171. package/dist/chunk-NGEN2EES.mjs +581 -0
  172. package/dist/{chunk-C43HRKXH.mjs → chunk-OBV72JD4.mjs} +1 -1
  173. package/dist/{chunk-LPV4NJJK.mjs → chunk-PGQ6FMXS.mjs} +6 -5
  174. package/dist/{chunk-MEPSKGBO.mjs → chunk-PI6RULJX.mjs} +1 -1
  175. package/dist/{chunk-F3YTWO3T.mjs → chunk-RA6SAAFE.mjs} +9 -8
  176. package/dist/{chunk-UNNRUJTM.mjs → chunk-RRKM4MKB.mjs} +7 -7
  177. package/dist/{chunk-ULGNQPNE.mjs → chunk-S2VGME7X.mjs} +1 -1
  178. package/dist/{chunk-OLVJFKXS.mjs → chunk-S44XWTTC.mjs} +35 -25
  179. package/dist/{chunk-YMYIEVZP.mjs → chunk-SZEKQAOY.mjs} +1 -1
  180. package/dist/{chunk-ELGEOM7I.mjs → chunk-TETMEKZE.mjs} +9 -9
  181. package/dist/{chunk-BXF4AMHY.mjs → chunk-TMH263OK.mjs} +5 -4
  182. package/dist/{chunk-NJG7DHVF.mjs → chunk-U6DEBYU5.mjs} +10 -9
  183. package/dist/{chunk-RJNLAH76.mjs → chunk-UOKFSFNJ.mjs} +2 -2
  184. package/dist/{chunk-HEDQPK4I.mjs → chunk-URIH43IJ.mjs} +13 -21
  185. package/dist/{chunk-QXDGGOLC.mjs → chunk-V2ZB2XNS.mjs} +6 -6
  186. package/dist/{chunk-KSUWPU2F.mjs → chunk-WIPEDNSD.mjs} +7 -7
  187. package/dist/{chunk-QDAZGZUF.mjs → chunk-XCIG6HT2.mjs} +3 -3
  188. package/dist/{chunk-4J2PXL36.mjs → chunk-Y6YS33GM.mjs} +40 -38
  189. package/dist/{chunk-4XOB5TTD.mjs → chunk-ZKDKKQCE.mjs} +5 -5
  190. package/dist/{chunk-LOBLCFMN.mjs → chunk-ZTPYUU5C.mjs} +5 -5
  191. package/dist/index.d.mts +12 -72
  192. package/dist/index.d.ts +12 -72
  193. package/dist/index.js +1051 -1838
  194. package/dist/index.mjs +81 -85
  195. package/package.json +8 -10
  196. package/src/components/Accordion/Accordion.tsx +12 -9
  197. package/src/components/AlertBanner/AlertBanner.tsx +7 -6
  198. package/src/components/AppHeader/AppHeader.tsx +1 -1
  199. package/src/components/Avatar/Avatar.tsx +92 -1
  200. package/src/components/Avatar/index.ts +2 -2
  201. package/src/components/Badge/Badge.tsx +2 -2
  202. package/src/components/Button/Button.tsx +50 -46
  203. package/src/components/Card/Card.tsx +1 -0
  204. package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
  205. package/src/components/Chip/Chip.tsx +5 -4
  206. package/src/components/ConfirmDialog/ConfirmDialog.tsx +3 -3
  207. package/src/components/DetailRow/DetailRow.tsx +3 -3
  208. package/src/components/EmptyState/EmptyState.tsx +2 -2
  209. package/src/components/ErrorBoundary/ErrorBoundary.tsx +6 -6
  210. package/src/components/HolographicCard/HolographicCard.tsx +14 -95
  211. package/src/components/IconButton/IconButton.tsx +2 -2
  212. package/src/components/IconPicker/IconPicker.tsx +13 -12
  213. package/src/components/ImageUpload/ImageUpload.tsx +14 -25
  214. package/src/components/ImageViewer/ImageViewer.tsx +3 -3
  215. package/src/components/Input/Input.tsx +11 -5
  216. package/src/components/LabelValue/LabelValue.tsx +2 -2
  217. package/src/components/ListItem/ListItem.tsx +4 -4
  218. package/src/components/MediaCard/MediaCard.tsx +21 -59
  219. package/src/components/MenuItem/MenuItem.tsx +2 -2
  220. package/src/components/MonthPicker/MonthPicker.tsx +2 -2
  221. package/src/components/NumberStepper/NumberStepper.tsx +6 -6
  222. package/src/components/PagerDots/PagerDots.tsx +38 -28
  223. package/src/components/PricingCard/PricingCard.tsx +6 -6
  224. package/src/components/RadioGroup/RadioGroup.tsx +18 -31
  225. package/src/components/Select/Select.tsx +32 -39
  226. package/src/components/SelectableCard/SelectableCard.tsx +4 -6
  227. package/src/components/SelectableGrid/SelectableGrid.tsx +38 -72
  228. package/src/components/Sheet/Sheet.tsx +1 -1
  229. package/src/components/SheetSelect/SheetSelect.tsx +3 -3
  230. package/src/components/Skeleton/Skeleton.tsx +1 -1
  231. package/src/components/Spinner/Spinner.tsx +2 -2
  232. package/src/components/Stats/Stats.tsx +2 -2
  233. package/src/components/Switch/Switch.tsx +9 -6
  234. package/src/components/TabBar/TabBar.tsx +9 -8
  235. package/src/components/Text/Text.tsx +12 -1
  236. package/src/components/Textarea/Textarea.tsx +18 -32
  237. package/src/components/Toggle/Toggle.tsx +3 -3
  238. package/src/hooks/useConfirmDialog.ts +31 -42
  239. package/src/index.ts +3 -4
  240. package/src/theme/ThemeProvider.tsx +1 -4
  241. package/src/theme/colorUtils.ts +1 -72
  242. package/src/theme/colors.ts +40 -1
  243. package/src/theme/types.ts +2 -2
  244. package/src/utils/animations.ts +0 -47
  245. package/src/utils/curatedIcons.ts +93 -801
  246. package/src/utils/haptics.ts +13 -208
  247. package/src/utils/icons.ts +27 -91
  248. package/src/utils/pressable.ts +10 -61
  249. package/dist/VirtualList.d.mts +0 -19
  250. package/dist/VirtualList.d.ts +0 -19
  251. package/dist/VirtualList.js +0 -38
  252. package/dist/VirtualList.mjs +0 -2
  253. package/dist/chunk-2BA3JMKK.mjs +0 -136
  254. package/dist/chunk-3DKJ2GIC.mjs +0 -30
  255. package/dist/chunk-7ELGZ66G.mjs +0 -164
  256. package/dist/chunk-DVK4G2GT.mjs +0 -59
  257. package/dist/chunk-EJ7ZPXOH.mjs +0 -163
  258. package/dist/chunk-KA7LTET3.mjs +0 -71
  259. package/dist/chunk-LNPKGWBG.mjs +0 -134
  260. package/dist/chunk-NC5ZTR2Y.mjs +0 -32
  261. package/dist/chunk-SAWUXP3A.mjs +0 -1114
  262. package/dist/chunk-YNROWHQJ.mjs +0 -46
  263. package/src/components/VirtualList/VirtualList.tsx +0 -60
  264. package/src/components/VirtualList/index.ts +0 -1
  265. package/src/utils/fontGuard.ts +0 -35
  266. package/src/utils/hover.ts +0 -25
  267. package/src/utils/useColorTransition.ts +0 -40
  268. package/src/utils/usePressScale.ts +0 -75
@@ -7,12 +7,14 @@ import {
7
7
  ViewStyle,
8
8
  TextStyle,
9
9
  } from 'react-native'
10
+ import { EaseView } from 'react-native-ease'
10
11
  import { impactMedium } from '../../utils/haptics'
11
12
  import { useTheme } from '../../theme'
12
13
  import { s, vs, ms, mvs } from '../../utils/scaling'
13
- import { renderIcon } from '../../utils/icons'
14
+ import { Icon } from '../../utils/icons'
14
15
  import { RADIUS, TYPOGRAPHY } from '../../tokens'
15
16
  import { PressableButton } from '../../utils/pressable'
17
+ import { COLOR_TRANSITION } from '../../utils/animations'
16
18
 
17
19
  export type ButtonVariant = 'primary' | 'secondary' | 'text' | 'destructive'
18
20
  export type ButtonSize = 'sm' | 'md' | 'lg'
@@ -73,19 +75,16 @@ function ButtonBase({
73
75
  onPress?.()
74
76
  }
75
77
 
76
- const containerVariantStyle: ViewStyle = isDisabled
77
- ? {
78
- primary: { backgroundColor: colors.surface },
79
- secondary: { backgroundColor: 'transparent', borderWidth: 1.5, borderColor: colors.border },
80
- text: { backgroundColor: 'transparent' },
81
- destructive: { backgroundColor: colors.surface },
82
- }[variant]
83
- : {
84
- primary: { backgroundColor: colors.primary },
85
- secondary: { backgroundColor: 'transparent', borderWidth: 1.5, borderColor: colors.primary },
86
- text: { backgroundColor: 'transparent' },
87
- destructive: { backgroundColor: colors.destructive },
88
- }[variant]
78
+ const isSecondary = variant === 'secondary'
79
+ const borderWidth = isSecondary ? 1.5 : 0
80
+
81
+ const animateBgColor: string = isDisabled
82
+ ? { primary: colors.surface, secondary: 'transparent', text: 'transparent', destructive: colors.surface }[variant]
83
+ : { primary: colors.primary, secondary: 'transparent', text: 'transparent', destructive: colors.destructive }[variant]
84
+
85
+ const animateBorderColor: string = isDisabled
86
+ ? (isSecondary ? colors.border : 'transparent')
87
+ : (isSecondary ? colors.primary : 'transparent')
89
88
 
90
89
  const labelColor = isDisabled
91
90
  ? colors.foregroundMuted
@@ -99,7 +98,7 @@ function ButtonBase({
99
98
  const textColor = iconColor ?? labelColor
100
99
 
101
100
  const effectiveIcon: React.ReactNode = iconName
102
- ? renderIcon(iconName, iconSizeMap[size], textColor)
101
+ ? <Icon name={iconName} size={iconSizeMap[size]} color={textColor} />
103
102
  : typeof icon === 'function' ? icon({ label, size, variant, color: textColor }) : icon
104
103
 
105
104
  const spinnerColor = isDisabled
@@ -115,13 +114,6 @@ function ButtonBase({
115
114
  return (
116
115
  <View style={[fullWidth && styles.fullWidth, flex !== undefined && { flex }]}>
117
116
  <PressableButton
118
- style={[
119
- styles.base,
120
- containerVariantStyle,
121
- containerSizeStyles[size],
122
- fullWidth && styles.fullWidth,
123
- restStyle,
124
- ]}
125
117
  enabled={!isDisabled}
126
118
  onPress={handlePress}
127
119
  rippleColor="transparent"
@@ -132,30 +124,42 @@ function ButtonBase({
132
124
  accessibilityHint={accessibilityHint}
133
125
  accessibilityState={{ disabled: isDisabled, busy: loading }}
134
126
  >
135
- {loading ? (
136
- <>
137
- <ActivityIndicator size="small" color={spinnerColor} style={{ marginRight: s(6) }} />
138
- <Text
139
- style={[styles.label, { color: labelColor }, labelSizeStyles[size], styles.labelLoading]}
140
- allowFontScaling={true}
141
- numberOfLines={1}
142
- >
143
- {label}
144
- </Text>
145
- </>
146
- ) : (
147
- <>
148
- {effectiveIcon && iconPosition === 'left' && <>{effectiveIcon}</>}
149
- <Text
150
- style={[styles.label, { color: labelColor }, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : undefined]}
151
- allowFontScaling={true}
152
- numberOfLines={1}
153
- >
154
- {label}
155
- </Text>
156
- {effectiveIcon && iconPosition === 'right' && <>{effectiveIcon}</>}
157
- </>
158
- )}
127
+ <EaseView
128
+ style={[
129
+ styles.base,
130
+ containerSizeStyles[size],
131
+ { borderWidth },
132
+ fullWidth && styles.fullWidth,
133
+ restStyle,
134
+ ]}
135
+ animate={{ backgroundColor: animateBgColor, borderColor: animateBorderColor }}
136
+ transition={COLOR_TRANSITION}
137
+ >
138
+ {loading ? (
139
+ <>
140
+ <ActivityIndicator size="small" color={spinnerColor} style={{ marginRight: s(6) }} />
141
+ <Text
142
+ style={[styles.label, { color: labelColor }, labelSizeStyles[size], styles.labelLoading]}
143
+ allowFontScaling={true}
144
+ numberOfLines={1}
145
+ >
146
+ {label}
147
+ </Text>
148
+ </>
149
+ ) : (
150
+ <>
151
+ {effectiveIcon && iconPosition === 'left' && <>{effectiveIcon}</>}
152
+ <Text
153
+ style={[styles.label, { color: labelColor }, labelSizeStyles[size], effectiveIcon ? styles.labelWithIcon : undefined]}
154
+ allowFontScaling={true}
155
+ numberOfLines={1}
156
+ >
157
+ {label}
158
+ </Text>
159
+ {effectiveIcon && iconPosition === 'right' && <>{effectiveIcon}</>}
160
+ </>
161
+ )}
162
+ </EaseView>
159
163
  </PressableButton>
160
164
  </View>
161
165
  )
@@ -73,6 +73,7 @@ export function Card({ children, variant = 'elevated', onPress, style, accessibi
73
73
  activateOnHover
74
74
  accessibilityRole="button"
75
75
  accessibilityLabel={accessibilityLabel}
76
+ accessibilityState={{ disabled: false }}
76
77
  >
77
78
  {cardContent}
78
79
  </PressableCard>
@@ -1,40 +1,33 @@
1
1
  import React, { useCallback } from 'react'
2
2
  import {
3
3
  ScrollView,
4
- TouchableOpacity,
5
4
  Text,
6
5
  View,
7
6
  StyleSheet,
8
7
  ViewStyle,
9
8
  } from 'react-native'
10
- import Animated from 'react-native-reanimated'
11
9
  import { EaseView } from 'react-native-ease'
12
10
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
13
11
  import { useTheme } from '../../theme'
14
12
  import { s, vs, ms } from '../../utils/scaling'
15
- import { renderIcon } from '../../utils/icons'
16
- import { usePressScale } from '../../utils/usePressScale'
17
- import { COLOR_TRANSITION, PRESS_SCALE } from '../../utils/animations'
13
+ import { Icon } from '../../utils/icons'
14
+ import { PressableChip } from '../../utils/pressable'
15
+ import { COLOR_TRANSITION } from '../../utils/animations'
18
16
  import { RADIUS } from '../../tokens'
19
17
 
20
18
  export interface CategoryItem {
21
19
  label: string
22
20
  value: string
23
- /** Icon rendered to the left of the label. ReactNode or icon name string. */
24
21
  icon?: React.ReactNode | string
25
- /** Badge count over the icon/label. */
26
22
  badge?: number
27
23
  }
28
24
 
29
25
  export interface CategoryStripProps {
30
26
  categories: CategoryItem[]
31
27
  value?: string | string[]
32
- /** Called with new value(s) on selection change. */
33
28
  onValueChange?: (value: string | string[]) => void
34
- /** Allow multiple simultaneous selections. Defaults to false. */
35
29
  multiSelect?: boolean
36
30
  style?: ViewStyle
37
- /** Style applied to each pill item. */
38
31
  itemStyle?: ViewStyle
39
32
  accessibilityLabel?: string
40
33
  }
@@ -49,53 +42,47 @@ const CategoryChip = React.memo(function CategoryChip({
49
42
  onSelect: (value: string) => void
50
43
  }) {
51
44
  const { colors } = useTheme()
52
- const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
53
- pressScale: PRESS_SCALE.chip,
54
- })
55
- // Static color for icon — icon families take a static color prop, not animated.
56
45
  const iconColor = selected ? colors.primaryForeground : colors.foregroundSubtle
57
46
  const resolvedIcon =
58
47
  typeof item.icon === 'string'
59
- ? renderIcon(item.icon, 16, iconColor)
48
+ ? <Icon name={item.icon} size={16} color={iconColor} />
60
49
  : item.icon ?? null
61
50
 
62
51
  return (
63
- <Animated.View style={scaleStyle} {...hoverHandlers}>
64
- <TouchableOpacity
65
- onPress={() => onSelect(item.value)}
66
- onPressIn={onPressIn}
67
- onPressOut={onPressOut}
68
- activeOpacity={1}
69
- touchSoundDisabled={true}
70
- accessibilityRole="button"
71
- accessibilityLabel={item.label}
72
- accessibilityState={{ selected }}
52
+ <PressableChip
53
+ onPress={() => onSelect(item.value)}
54
+ enabled
55
+ rippleColor="transparent"
56
+ touchSoundDisabled
57
+ activateOnHover
58
+ accessibilityRole="button"
59
+ accessibilityLabel={item.label}
60
+ accessibilityState={{ selected }}
61
+ >
62
+ <EaseView
63
+ style={styles.chip}
64
+ animate={{
65
+ backgroundColor: selected ? colors.primary : colors.surface,
66
+ borderColor: selected ? colors.primary : colors.border,
67
+ }}
68
+ transition={COLOR_TRANSITION}
73
69
  >
74
- <EaseView
75
- style={styles.chip}
76
- animate={{
77
- backgroundColor: selected ? colors.primary : colors.surface,
78
- borderColor: selected ? colors.primary : colors.border,
79
- }}
80
- transition={COLOR_TRANSITION}
70
+ {resolvedIcon && <View style={styles.chipIcon}>{resolvedIcon}</View>}
71
+ <Text
72
+ style={[styles.chipLabel, { color: selected ? colors.primaryForeground : colors.foregroundSubtle }]}
73
+ allowFontScaling={true}
81
74
  >
82
- {resolvedIcon && <View style={styles.chipIcon}>{resolvedIcon}</View>}
83
- <Text
84
- style={[styles.chipLabel, { color: selected ? colors.primaryForeground : colors.foregroundSubtle }]}
85
- allowFontScaling={true}
86
- >
87
- {item.label}
88
- </Text>
89
- {item.badge !== undefined && item.badge > 0 && (
90
- <View style={[styles.chipBadge, { backgroundColor: colors.primary }]}>
91
- <Text style={[styles.chipBadgeText, { color: colors.primaryForeground }]}>
92
- {Math.min(item.badge, 99)}
93
- </Text>
94
- </View>
95
- )}
96
- </EaseView>
97
- </TouchableOpacity>
98
- </Animated.View>
75
+ {item.label}
76
+ </Text>
77
+ {item.badge !== undefined && item.badge > 0 && (
78
+ <View style={[styles.chipBadge, { backgroundColor: colors.primary }]}>
79
+ <Text style={[styles.chipBadgeText, { color: colors.primaryForeground }]}>
80
+ {Math.min(item.badge, 99)}
81
+ </Text>
82
+ </View>
83
+ )}
84
+ </EaseView>
85
+ </PressableChip>
99
86
  )
100
87
  })
101
88
 
@@ -4,8 +4,9 @@ import { EaseView } from 'react-native-ease'
4
4
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
5
5
  import { useTheme } from '../../theme'
6
6
  import { s, vs, ms, mvs } from '../../utils/scaling'
7
- import { renderIcon } from '../../utils/icons'
7
+ import { Icon } from '../../utils/icons'
8
8
  import { COLOR_TRANSITION } from '../../utils/animations'
9
+ import { RADIUS } from '../../tokens'
9
10
  import { PressableChip as PressableChipComponent } from '../../utils/pressable'
10
11
 
11
12
  export interface ChipProps {
@@ -43,7 +44,7 @@ function ChipBase({ label, selected = false, onPress, icon, iconName, style, acc
43
44
  }
44
45
 
45
46
  const resolvedIcon = iconName
46
- ? renderIcon(iconName, ms(13), selected ? colors.primaryForeground : colors.foreground)
47
+ ? <Icon name={iconName} size={ms(13)} color={selected ? colors.primaryForeground : colors.foreground} />
47
48
  : icon
48
49
 
49
50
  return (
@@ -111,7 +112,7 @@ export function ChipGroup({ options, value, onValueChange, multiSelect = false,
111
112
  // Now passes disabled state to the Chip's TouchableOpacity via onPress=undefined
112
113
  // and adds explicit accessibility state for screen readers.
113
114
  style={opt.disabled ? styles.chipDisabled : undefined}
114
- accessibilityLabel={opt.disabled ? `${opt.label}, unavailable` : opt.label}
115
+ accessibilityLabel={opt.disabled ? `${opt.label}, no disponible` : opt.label}
115
116
  />
116
117
  ))}
117
118
  </View>
@@ -121,7 +122,7 @@ export function ChipGroup({ options, value, onValueChange, multiSelect = false,
121
122
  const styles = StyleSheet.create({
122
123
  wrapper: {},
123
124
  chip: {
124
- borderRadius: 999,
125
+ borderRadius: RADIUS.full,
125
126
  paddingHorizontal: s(14),
126
127
  // AUDIT FIX: was vs(5) → ~28px total height — below WCAG 44px tap target.
127
128
  // vs(10) → ~44px total height meets WCAG 2.5.5 (AAA) minimum.
@@ -30,8 +30,8 @@ export function ConfirmDialog({
30
30
  visible,
31
31
  title,
32
32
  subtitle,
33
- confirmLabel = 'Confirm',
34
- cancelLabel = 'Cancel',
33
+ confirmLabel = 'Confirmar',
34
+ cancelLabel = 'Cancelar',
35
35
  confirmVariant = 'primary',
36
36
  loading = false,
37
37
  showCloseButton = false,
@@ -98,7 +98,7 @@ export function ConfirmDialog({
98
98
  activeOpacity={0.6}
99
99
  touchSoundDisabled={true}
100
100
  accessibilityRole="button"
101
- accessibilityLabel="Close"
101
+ accessibilityLabel="Cerrar"
102
102
  hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
103
103
  >
104
104
  <Feather name="x" size={ms(18)} color={colors.foregroundMuted} />
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
4
  import { s, ms, mvs } from '../../utils/scaling'
5
- import { renderIcon } from '../../utils/icons'
5
+ import { Icon } from '../../utils/icons'
6
6
 
7
7
  export type DetailRowSeparator = 'dotted' | 'solid' | 'dashed' | 'none'
8
8
  export type DetailRowLabelWeight = 'normal' | 'medium' | 'semibold' | 'bold'
@@ -56,11 +56,11 @@ function DetailRowBase({
56
56
  const { colors } = useTheme()
57
57
 
58
58
  const resolvedLeftIcon = leftIconName
59
- ? renderIcon(leftIconName, ms(14), leftIconColor ?? colors.foregroundMuted)
59
+ ? <Icon name={leftIconName} size={ms(14)} color={leftIconColor ?? colors.foregroundMuted} />
60
60
  : leftIcon
61
61
 
62
62
  const resolvedRightIcon = rightIconName
63
- ? renderIcon(rightIconName, ms(14), rightIconColor ?? colors.foregroundMuted)
63
+ ? <Icon name={rightIconName} size={ms(14)} color={rightIconColor ?? colors.foregroundMuted} />
64
64
  : null
65
65
 
66
66
  const separatorStyle: ViewStyle | null =
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
4
  import { s, vs, ms, mvs } from '../../utils/scaling'
5
- import { renderIcon } from '../../utils/icons'
5
+ import { Icon } from '../../utils/icons'
6
6
  import { Button } from '../Button'
7
7
 
8
8
  export interface EmptyStateProps {
@@ -32,7 +32,7 @@ export function EmptyState({ icon, iconName, iconColor, title, description, acti
32
32
  const isCompact = size === 'compact'
33
33
 
34
34
  const effectiveIcon: React.ReactNode = iconName
35
- ? renderIcon(iconName, isCompact ? 32 : 48, iconColor ?? colors.foregroundMuted)
35
+ ? <Icon name={iconName} size={isCompact ? 32 : 48} color={iconColor ?? colors.foregroundMuted} />
36
36
  : icon
37
37
 
38
38
  return (
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
- import { renderIcon } from '../../utils/icons'
4
+ import { Icon } from '../../utils/icons'
5
5
  import { s, vs, ms, mvs } from '../../utils/scaling'
6
6
  import { RADIUS } from '../../tokens'
7
7
  import { impactLight } from '../../utils/haptics'
@@ -35,20 +35,20 @@ interface ErrorBoundaryState {
35
35
  function DefaultErrorFallback({
36
36
  error,
37
37
  reset,
38
- title = 'Something went wrong',
38
+ title = 'Algo salió mal',
39
39
  message,
40
40
  }: ErrorFallbackProps & { title?: string; message?: string }) {
41
41
  const { colors } = useTheme()
42
42
  return (
43
43
  <View style={[styles.container, { backgroundColor: colors.background }]} accessibilityRole="alert">
44
44
  <View style={[styles.iconCircle, { backgroundColor: colors.destructiveTint }]}>
45
- {renderIcon('alert-triangle', ms(28), colors.destructive)}
45
+ <Icon name="alert-triangle" size={ms(28)} color={colors.destructive} />
46
46
  </View>
47
47
  <Text style={[styles.title, { color: colors.foreground }]} allowFontScaling={true}>
48
48
  {title}
49
49
  </Text>
50
50
  <Text style={[styles.message, { color: colors.foregroundMuted }]} allowFontScaling={true}>
51
- {message ?? error.message ?? 'An unexpected error occurred.'}
51
+ {message ?? error.message ?? 'Ocurrió un error inesperado.'}
52
52
  </Text>
53
53
  <TouchableOpacity
54
54
  style={[styles.button, { backgroundColor: colors.primary }]}
@@ -59,10 +59,10 @@ function DefaultErrorFallback({
59
59
  activeOpacity={0.85}
60
60
  touchSoundDisabled={true}
61
61
  accessibilityRole="button"
62
- accessibilityLabel="Try again"
62
+ accessibilityLabel="Intentar de nuevo"
63
63
  >
64
64
  <Text style={[styles.buttonLabel, { color: colors.primaryForeground }]} allowFontScaling={true}>
65
- Try again
65
+ Intentar de nuevo
66
66
  </Text>
67
67
  </TouchableOpacity>
68
68
  </View>