@retray-dev/ui-kit 12.2.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 (296) hide show
  1. package/CONSUMER.md +26 -11
  2. package/DESIGN.md +2 -2
  3. package/README.md +15 -11
  4. package/{COMPONENTS.md → SKILL.md} +374 -996
  5. package/dist/Accordion.d.mts +2 -0
  6. package/dist/Accordion.d.ts +2 -0
  7. package/dist/Accordion.js +49 -210
  8. package/dist/Accordion.mjs +6 -6
  9. package/dist/AlertBanner.js +29 -153
  10. package/dist/AlertBanner.mjs +3 -4
  11. package/dist/AppHeader.d.mts +5 -2
  12. package/dist/AppHeader.d.ts +5 -2
  13. package/dist/AppHeader.js +45 -239
  14. package/dist/AppHeader.mjs +6 -8
  15. package/dist/Avatar.d.mts +17 -1
  16. package/dist/Avatar.d.ts +17 -1
  17. package/dist/Avatar.js +80 -115
  18. package/dist/Avatar.mjs +2 -3
  19. package/dist/Badge.js +24 -149
  20. package/dist/Badge.mjs +3 -4
  21. package/dist/Button.js +79 -267
  22. package/dist/Button.mjs +6 -7
  23. package/dist/ButtonGroup.mjs +0 -1
  24. package/dist/Card.js +15 -200
  25. package/dist/Card.mjs +4 -6
  26. package/dist/CategoryStrip.d.mts +0 -5
  27. package/dist/CategoryStrip.d.ts +0 -5
  28. package/dist/CategoryStrip.js +47 -265
  29. package/dist/CategoryStrip.mjs +6 -7
  30. package/dist/Checkbox.d.mts +2 -1
  31. package/dist/Checkbox.d.ts +2 -1
  32. package/dist/Checkbox.js +18 -201
  33. package/dist/Checkbox.mjs +5 -6
  34. package/dist/Chip.js +44 -236
  35. package/dist/Chip.mjs +7 -7
  36. package/dist/ConfirmDialog.d.mts +2 -1
  37. package/dist/ConfirmDialog.d.ts +2 -1
  38. package/dist/ConfirmDialog.js +110 -300
  39. package/dist/ConfirmDialog.mjs +7 -8
  40. package/dist/CurrencyDisplay.js +1 -114
  41. package/dist/CurrencyDisplay.mjs +2 -3
  42. package/dist/CurrencyInput.js +35 -162
  43. package/dist/CurrencyInput.mjs +5 -6
  44. package/dist/DetailRow.js +25 -150
  45. package/dist/DetailRow.mjs +3 -4
  46. package/dist/EmptyState.js +80 -268
  47. package/dist/EmptyState.mjs +7 -8
  48. package/dist/ErrorBoundary.js +32 -199
  49. package/dist/ErrorBoundary.mjs +4 -5
  50. package/dist/Form.js +1 -114
  51. package/dist/Form.mjs +2 -3
  52. package/dist/HolographicCard.d.mts +0 -28
  53. package/dist/HolographicCard.d.ts +0 -28
  54. package/dist/HolographicCard.js +20 -130
  55. package/dist/HolographicCard.mjs +9 -33
  56. package/dist/IconButton.js +36 -234
  57. package/dist/IconButton.mjs +5 -7
  58. package/dist/IconPicker.js +222 -929
  59. package/dist/IconPicker.mjs +5 -6
  60. package/dist/ImageUpload.d.mts +3 -3
  61. package/dist/ImageUpload.d.ts +3 -3
  62. package/dist/ImageUpload.js +49 -238
  63. package/dist/ImageUpload.mjs +5 -7
  64. package/dist/ImageViewer.js +75 -266
  65. package/dist/ImageViewer.mjs +8 -9
  66. package/dist/Input.d.mts +1 -1
  67. package/dist/Input.d.ts +1 -1
  68. package/dist/Input.js +35 -162
  69. package/dist/Input.mjs +4 -5
  70. package/dist/LabelValue.js +24 -149
  71. package/dist/LabelValue.mjs +3 -4
  72. package/dist/ListGroup.js +1 -114
  73. package/dist/ListGroup.mjs +2 -3
  74. package/dist/ListItem.d.mts +2 -1
  75. package/dist/ListItem.d.ts +2 -1
  76. package/dist/ListItem.js +41 -236
  77. package/dist/ListItem.mjs +5 -7
  78. package/dist/MediaCard.d.mts +0 -14
  79. package/dist/MediaCard.d.ts +0 -14
  80. package/dist/MediaCard.js +69 -315
  81. package/dist/MediaCard.mjs +5 -7
  82. package/dist/MenuGroup.js +1 -114
  83. package/dist/MenuGroup.mjs +2 -3
  84. package/dist/MenuItem.d.mts +2 -1
  85. package/dist/MenuItem.d.ts +2 -1
  86. package/dist/MenuItem.js +39 -235
  87. package/dist/MenuItem.mjs +5 -7
  88. package/dist/MonthPicker.js +8 -163
  89. package/dist/MonthPicker.mjs +3 -4
  90. package/dist/NumberStepper.d.mts +2 -1
  91. package/dist/NumberStepper.d.ts +2 -1
  92. package/dist/NumberStepper.js +44 -239
  93. package/dist/NumberStepper.mjs +5 -7
  94. package/dist/PagerDots.d.mts +1 -1
  95. package/dist/PagerDots.d.ts +1 -1
  96. package/dist/PagerDots.js +69 -224
  97. package/dist/PagerDots.mjs +6 -6
  98. package/dist/Pressable.js +14 -85
  99. package/dist/Pressable.mjs +4 -5
  100. package/dist/PricingCard.js +87 -272
  101. package/dist/PricingCard.mjs +8 -9
  102. package/dist/Progress.js +3 -123
  103. package/dist/Progress.mjs +3 -4
  104. package/dist/RadioGroup.js +52 -265
  105. package/dist/RadioGroup.mjs +5 -6
  106. package/dist/RetrayProvider.js +3 -6
  107. package/dist/RetrayProvider.mjs +3 -4
  108. package/dist/Select.d.mts +3 -1
  109. package/dist/Select.d.ts +3 -1
  110. package/dist/Select.js +27 -233
  111. package/dist/Select.mjs +4 -6
  112. package/dist/SelectableCard.js +33 -209
  113. package/dist/SelectableCard.mjs +5 -6
  114. package/dist/SelectableGrid.d.mts +0 -21
  115. package/dist/SelectableGrid.d.ts +0 -21
  116. package/dist/SelectableGrid.js +49 -272
  117. package/dist/SelectableGrid.mjs +5 -7
  118. package/dist/Separator.js +1 -114
  119. package/dist/Separator.mjs +2 -3
  120. package/dist/Sheet.d.mts +1 -1
  121. package/dist/Sheet.d.ts +1 -1
  122. package/dist/Sheet.js +33 -175
  123. package/dist/Sheet.mjs +3 -4
  124. package/dist/SheetSelect.js +39 -236
  125. package/dist/SheetSelect.mjs +6 -7
  126. package/dist/Skeleton.js +4 -124
  127. package/dist/Skeleton.mjs +3 -4
  128. package/dist/Slider.d.mts +2 -1
  129. package/dist/Slider.d.ts +2 -1
  130. package/dist/Slider.js +8 -161
  131. package/dist/Slider.mjs +3 -4
  132. package/dist/Spinner.js +3 -116
  133. package/dist/Spinner.mjs +2 -3
  134. package/dist/Stats.js +36 -234
  135. package/dist/Stats.mjs +5 -7
  136. package/dist/Switch.d.mts +2 -1
  137. package/dist/Switch.d.ts +2 -1
  138. package/dist/Switch.js +26 -176
  139. package/dist/Switch.mjs +5 -5
  140. package/dist/TabBar.js +43 -200
  141. package/dist/TabBar.mjs +5 -5
  142. package/dist/Tabs.js +15 -199
  143. package/dist/Tabs.mjs +5 -6
  144. package/dist/Text.js +9 -130
  145. package/dist/Text.mjs +2 -3
  146. package/dist/Textarea.d.mts +2 -1
  147. package/dist/Textarea.d.ts +2 -1
  148. package/dist/Textarea.js +71 -219
  149. package/dist/Textarea.mjs +4 -5
  150. package/dist/Toast.d.mts +12 -10
  151. package/dist/Toast.d.ts +12 -10
  152. package/dist/Toast.js +1 -114
  153. package/dist/Toast.mjs +2 -3
  154. package/dist/Toggle.js +39 -236
  155. package/dist/Toggle.mjs +6 -7
  156. package/dist/{chunk-ELGEOM7I.mjs → chunk-2QXJDRVU.mjs} +13 -10
  157. package/dist/{chunk-LIS6I5UP.mjs → chunk-2VIDP72N.mjs} +3 -3
  158. package/dist/{chunk-NHDI3VQB.mjs → chunk-422IVD3H.mjs} +16 -12
  159. package/dist/{chunk-DF7JA72E.mjs → chunk-4NQFTHN3.mjs} +13 -7
  160. package/dist/{chunk-3XCFYSX4.mjs → chunk-5MYNAAFE.mjs} +13 -17
  161. package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
  162. package/dist/{chunk-UBUXUMER.mjs → chunk-77UOVFIS.mjs} +7 -5
  163. package/dist/{chunk-M3C7XM2M.mjs → chunk-7BZJRB77.mjs} +28 -18
  164. package/dist/chunk-ARONDO7M.mjs +40 -0
  165. package/dist/{chunk-GH67YXG6.mjs → chunk-AZV7KNJI.mjs} +3 -3
  166. package/dist/{chunk-2P2CB235.mjs → chunk-BULKGOIZ.mjs} +7 -8
  167. package/dist/{chunk-RJNLAH76.mjs → chunk-C5ZRMR2E.mjs} +4 -2
  168. package/dist/chunk-CM2DG4MR.mjs +142 -0
  169. package/dist/{chunk-UQ4742ET.mjs → chunk-COA2YZOX.mjs} +8 -6
  170. package/dist/{chunk-EDLCGYIO.mjs → chunk-CZN6L2QU.mjs} +11 -8
  171. package/dist/{chunk-TS7DGUIR.mjs → chunk-DBHSUUKU.mjs} +2 -2
  172. package/dist/{chunk-57V2LXCK.mjs → chunk-DE25XTVQ.mjs} +3 -3
  173. package/dist/{chunk-RMRS44MQ.mjs → chunk-E2PONRJG.mjs} +13 -9
  174. package/dist/{chunk-GUTDFUNF.mjs → chunk-EHGBHFMH.mjs} +9 -17
  175. package/dist/{chunk-ZIMY2QUM.mjs → chunk-ERWJPVX7.mjs} +2 -2
  176. package/dist/{chunk-NLZY4TXU.mjs → chunk-ESQDPO5E.mjs} +7 -7
  177. package/dist/{chunk-VJBUCITV.mjs → chunk-EW2FIDSM.mjs} +1 -1
  178. package/dist/{chunk-HC4VVCWY.mjs → chunk-FTTI6T5Q.mjs} +4 -4
  179. package/dist/{chunk-MVMGPZN6.mjs → chunk-H6MQL7PS.mjs} +12 -7
  180. package/dist/{chunk-CF27NBXO.mjs → chunk-HHOOFDBA.mjs} +38 -41
  181. package/dist/{chunk-2HFD4IHU.mjs → chunk-HUSSF6TF.mjs} +1 -1
  182. package/dist/{chunk-HEDQPK4I.mjs → chunk-IDVUZIVY.mjs} +16 -22
  183. package/dist/chunk-IFYMBOEN.mjs +14 -0
  184. package/dist/{chunk-QOLWA2PW.mjs → chunk-IGU223UM.mjs} +80 -4
  185. package/dist/chunk-IJCMPVW5.mjs +121 -0
  186. package/dist/{chunk-AENAVIKT.mjs → chunk-ITG4JQM3.mjs} +4 -4
  187. package/dist/{chunk-E5UKLSJZ.mjs → chunk-K3QX2M26.mjs} +11 -8
  188. package/dist/{chunk-4OORJ2DY.mjs → chunk-K7TKID3V.mjs} +8 -7
  189. package/dist/{chunk-2LG326TT.mjs → chunk-KAGADD2O.mjs} +4 -4
  190. package/dist/{chunk-IVSRW4HS.mjs → chunk-KC5QDYGZ.mjs} +4 -4
  191. package/dist/{chunk-7AFZWSCI.mjs → chunk-KPTY7UYQ.mjs} +1 -1
  192. package/dist/{chunk-YTXRIXNZ.mjs → chunk-KSSVIFYR.mjs} +9 -12
  193. package/dist/chunk-L3YKPTJQ.mjs +119 -0
  194. package/dist/chunk-M53LC4Q7.mjs +35 -0
  195. package/dist/chunk-MZ6WRTD2.mjs +40 -0
  196. package/dist/chunk-NGEN2EES.mjs +581 -0
  197. package/dist/{chunk-ZR6HSEAB.mjs → chunk-NPCBNGNE.mjs} +17 -26
  198. package/dist/{chunk-C43HRKXH.mjs → chunk-OBV72JD4.mjs} +1 -1
  199. package/dist/{chunk-LPV4NJJK.mjs → chunk-PGQ6FMXS.mjs} +6 -5
  200. package/dist/{chunk-MEPSKGBO.mjs → chunk-PI6RULJX.mjs} +1 -1
  201. package/dist/{chunk-F3YTWO3T.mjs → chunk-RA6SAAFE.mjs} +9 -8
  202. package/dist/{chunk-UNNRUJTM.mjs → chunk-RRKM4MKB.mjs} +7 -7
  203. package/dist/{chunk-ULGNQPNE.mjs → chunk-S2VGME7X.mjs} +1 -1
  204. package/dist/{chunk-OLVJFKXS.mjs → chunk-S44XWTTC.mjs} +35 -25
  205. package/dist/{chunk-YMYIEVZP.mjs → chunk-SZEKQAOY.mjs} +1 -1
  206. package/dist/{chunk-BXF4AMHY.mjs → chunk-TMH263OK.mjs} +5 -4
  207. package/dist/{chunk-NJG7DHVF.mjs → chunk-U6DEBYU5.mjs} +10 -9
  208. package/dist/{chunk-QXDGGOLC.mjs → chunk-UMZTPUB3.mjs} +33 -21
  209. package/dist/{chunk-KSUWPU2F.mjs → chunk-WIPEDNSD.mjs} +7 -7
  210. package/dist/{chunk-QDAZGZUF.mjs → chunk-XCIG6HT2.mjs} +3 -3
  211. package/dist/{chunk-4J2PXL36.mjs → chunk-Y6YS33GM.mjs} +40 -38
  212. package/dist/{chunk-4XOB5TTD.mjs → chunk-ZKDKKQCE.mjs} +5 -5
  213. package/dist/{chunk-LOBLCFMN.mjs → chunk-ZTPYUU5C.mjs} +5 -5
  214. package/dist/fonts.mjs +0 -2
  215. package/dist/index.d.mts +13 -73
  216. package/dist/index.d.ts +13 -73
  217. package/dist/index.js +1149 -1892
  218. package/dist/index.mjs +81 -86
  219. package/package.json +20 -20
  220. package/src/components/Accordion/Accordion.tsx +15 -9
  221. package/src/components/AlertBanner/AlertBanner.tsx +7 -6
  222. package/src/components/AppHeader/AppHeader.tsx +25 -10
  223. package/src/components/Avatar/Avatar.tsx +92 -1
  224. package/src/components/Avatar/index.ts +2 -2
  225. package/src/components/Badge/Badge.tsx +2 -2
  226. package/src/components/Button/Button.tsx +50 -46
  227. package/src/components/Card/Card.tsx +1 -0
  228. package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
  229. package/src/components/Checkbox/Checkbox.tsx +3 -0
  230. package/src/components/Chip/Chip.tsx +5 -4
  231. package/src/components/ConfirmDialog/ConfirmDialog.tsx +33 -17
  232. package/src/components/DetailRow/DetailRow.tsx +3 -3
  233. package/src/components/EmptyState/EmptyState.tsx +2 -2
  234. package/src/components/ErrorBoundary/ErrorBoundary.tsx +6 -6
  235. package/src/components/HolographicCard/HolographicCard.tsx +14 -95
  236. package/src/components/IconButton/IconButton.tsx +2 -2
  237. package/src/components/IconPicker/IconPicker.tsx +13 -12
  238. package/src/components/ImageUpload/ImageUpload.tsx +43 -46
  239. package/src/components/ImageViewer/ImageViewer.tsx +3 -3
  240. package/src/components/Input/Input.tsx +11 -5
  241. package/src/components/LabelValue/LabelValue.tsx +2 -2
  242. package/src/components/ListItem/ListItem.tsx +7 -4
  243. package/src/components/MediaCard/MediaCard.tsx +21 -59
  244. package/src/components/MenuItem/MenuItem.tsx +5 -2
  245. package/src/components/MonthPicker/MonthPicker.tsx +2 -2
  246. package/src/components/NumberStepper/NumberStepper.tsx +10 -6
  247. package/src/components/PagerDots/PagerDots.tsx +38 -28
  248. package/src/components/PricingCard/PricingCard.tsx +6 -6
  249. package/src/components/RadioGroup/RadioGroup.tsx +18 -31
  250. package/src/components/Select/Select.tsx +35 -39
  251. package/src/components/SelectableCard/SelectableCard.tsx +4 -6
  252. package/src/components/SelectableGrid/SelectableGrid.tsx +37 -72
  253. package/src/components/Sheet/Sheet.tsx +28 -15
  254. package/src/components/Sheet/index.ts +2 -2
  255. package/src/components/SheetSelect/SheetSelect.tsx +3 -3
  256. package/src/components/Skeleton/Skeleton.tsx +1 -1
  257. package/src/components/Slider/Slider.tsx +3 -0
  258. package/src/components/Spinner/Spinner.tsx +2 -2
  259. package/src/components/Stats/Stats.tsx +2 -2
  260. package/src/components/Switch/Switch.tsx +12 -7
  261. package/src/components/TabBar/TabBar.tsx +9 -8
  262. package/src/components/Text/Text.tsx +13 -1
  263. package/src/components/Textarea/Textarea.tsx +18 -32
  264. package/src/components/Toggle/Toggle.tsx +3 -3
  265. package/src/hooks/useConfirmDialog.ts +31 -42
  266. package/src/index.ts +3 -4
  267. package/src/theme/ThemeProvider.tsx +1 -4
  268. package/src/theme/colorUtils.ts +1 -72
  269. package/src/theme/colors.ts +40 -1
  270. package/src/theme/types.ts +2 -2
  271. package/src/utils/animations.ts +0 -47
  272. package/src/utils/curatedIcons.ts +93 -801
  273. package/src/utils/haptics.ts +13 -208
  274. package/src/utils/icons.ts +27 -91
  275. package/src/utils/pressable.ts +10 -61
  276. package/dist/VirtualList.d.mts +0 -19
  277. package/dist/VirtualList.d.ts +0 -19
  278. package/dist/VirtualList.js +0 -38
  279. package/dist/VirtualList.mjs +0 -2
  280. package/dist/chunk-2BA3JMKK.mjs +0 -136
  281. package/dist/chunk-3DKJ2GIC.mjs +0 -30
  282. package/dist/chunk-7ELGZ66G.mjs +0 -164
  283. package/dist/chunk-DVK4G2GT.mjs +0 -59
  284. package/dist/chunk-EJ7ZPXOH.mjs +0 -163
  285. package/dist/chunk-KA7LTET3.mjs +0 -71
  286. package/dist/chunk-LNPKGWBG.mjs +0 -134
  287. package/dist/chunk-NC5ZTR2Y.mjs +0 -32
  288. package/dist/chunk-SAWUXP3A.mjs +0 -1114
  289. package/dist/chunk-Y6FXYEAI.mjs +0 -8
  290. package/dist/chunk-YNROWHQJ.mjs +0 -46
  291. package/src/components/VirtualList/VirtualList.tsx +0 -60
  292. package/src/components/VirtualList/index.ts +0 -1
  293. package/src/utils/fontGuard.ts +0 -35
  294. package/src/utils/hover.ts +0 -25
  295. package/src/utils/useColorTransition.ts +0 -40
  296. package/src/utils/usePressScale.ts +0 -75
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useMemo } from 'react'
2
- import { StyleSheet, ViewStyle, TouchableOpacity, Platform } from 'react-native'
2
+ import { ViewStyle, Platform } from 'react-native'
3
3
  import {
4
4
  Canvas,
5
5
  Group,
@@ -15,14 +15,10 @@ import Animated, {
15
15
  useAnimatedStyle,
16
16
  withTiming,
17
17
  } from 'react-native-reanimated'
18
- import { usePressScale } from '../../utils/usePressScale'
19
- import { PRESS_SCALE } from '../../utils/animations'
18
+ import { PressableCard } from '../../utils/pressable'
20
19
  import { impactLight } from '../../utils/haptics'
21
20
  import { RADIUS } from '../../tokens'
22
21
 
23
- // ─── Foil Color Presets ───────────────────────────────────────────────────────
24
-
25
- /** Available foil color preset names */
26
22
  export type FoilPreset =
27
23
  | 'rainbow'
28
24
  | 'gold'
@@ -35,9 +31,7 @@ export type FoilPreset =
35
31
  | 'aurora'
36
32
  | 'neon'
37
33
 
38
- /** Foil color presets — each is an array of RGBA colors for the gradient */
39
34
  export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
40
- // Classic holographic rainbow
41
35
  rainbow: [
42
36
  'rgba(255, 0, 128, 0.45)',
43
37
  'rgba(255, 200, 0, 0.40)',
@@ -45,7 +39,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
45
39
  'rgba(0, 170, 255, 0.45)',
46
40
  'rgba(180, 0, 255, 0.45)',
47
41
  ],
48
- // Premium gold foil
49
42
  gold: [
50
43
  'rgba(255, 215, 0, 0.50)',
51
44
  'rgba(255, 180, 0, 0.45)',
@@ -53,7 +46,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
53
46
  'rgba(255, 223, 128, 0.50)',
54
47
  'rgba(184, 134, 11, 0.45)',
55
48
  ],
56
- // Chrome silver foil
57
49
  silver: [
58
50
  'rgba(192, 192, 192, 0.50)',
59
51
  'rgba(220, 220, 220, 0.45)',
@@ -61,7 +53,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
61
53
  'rgba(240, 240, 240, 0.50)',
62
54
  'rgba(128, 128, 128, 0.45)',
63
55
  ],
64
- // Deep space cosmic
65
56
  cosmic: [
66
57
  'rgba(75, 0, 130, 0.50)',
67
58
  'rgba(138, 43, 226, 0.45)',
@@ -69,7 +60,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
69
60
  'rgba(0, 191, 255, 0.45)',
70
61
  'rgba(148, 0, 211, 0.50)',
71
62
  ],
72
- // Emerald green luxury
73
63
  emerald: [
74
64
  'rgba(0, 201, 87, 0.50)',
75
65
  'rgba(46, 139, 87, 0.45)',
@@ -77,7 +67,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
77
67
  'rgba(60, 179, 113, 0.45)',
78
68
  'rgba(0, 128, 0, 0.50)',
79
69
  ],
80
- // Rose gold / pink
81
70
  rose: [
82
71
  'rgba(255, 105, 180, 0.50)',
83
72
  'rgba(255, 182, 193, 0.45)',
@@ -85,7 +74,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
85
74
  'rgba(255, 20, 147, 0.45)',
86
75
  'rgba(199, 21, 133, 0.50)',
87
76
  ],
88
- // Deep ocean blue
89
77
  ocean: [
90
78
  'rgba(0, 119, 190, 0.50)',
91
79
  'rgba(0, 180, 216, 0.45)',
@@ -93,7 +81,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
93
81
  'rgba(144, 224, 239, 0.45)',
94
82
  'rgba(0, 150, 199, 0.50)',
95
83
  ],
96
- // Hot fire gradient
97
84
  fire: [
98
85
  'rgba(255, 69, 0, 0.50)',
99
86
  'rgba(255, 140, 0, 0.45)',
@@ -101,7 +88,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
101
88
  'rgba(255, 99, 71, 0.45)',
102
89
  'rgba(220, 20, 60, 0.50)',
103
90
  ],
104
- // Aurora borealis
105
91
  aurora: [
106
92
  'rgba(0, 255, 127, 0.45)',
107
93
  'rgba(127, 255, 212, 0.40)',
@@ -109,7 +95,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
109
95
  'rgba(138, 43, 226, 0.40)',
110
96
  'rgba(255, 20, 147, 0.45)',
111
97
  ],
112
- // Neon cyberpunk
113
98
  neon: [
114
99
  'rgba(255, 0, 255, 0.55)',
115
100
  'rgba(0, 255, 255, 0.50)',
@@ -119,64 +104,29 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
119
104
  ],
120
105
  }
121
106
 
122
- // Default preset
123
107
  const DEFAULT_FOIL_COLORS = FOIL_PRESETS.rainbow
124
-
125
- // ─── Tilt Configuration ───────────────────────────────────────────────────────
126
-
127
- /** Default max tilt in degrees */
128
108
  const DEFAULT_TILT_DEG = 10
129
- /** Default normalization factor (~30° of device rotation = full tilt) */
130
109
  const DEFAULT_NORM_FACTOR = Math.PI / 6
131
110
 
132
111
  export interface HolographicCardProps {
133
- /** Card art — `require()` asset or `{ uri }`. Omitted = gradient-only foil surface. */
134
112
  source?: Parameters<typeof useImage>[0]
135
- /** Card width (dp). Defaults to 300. */
136
113
  width?: number
137
- /** Card height (dp). Defaults to `width * 1.4` (trading-card ratio). */
138
114
  height?: number
139
- /** Corner radius (dp). Defaults to `RADIUS.md`. */
140
115
  borderRadius?: number
141
- /** React to device motion (gyroscope) for parallax tilt + sheen. Defaults to true. */
142
116
  enableTilt?: boolean
143
- /** Strength of the foil sheen, 0–1. Defaults to 1. */
144
117
  intensity?: number
145
- /** Called when the card is pressed. */
146
118
  onPress?: () => void
147
119
  style?: ViewStyle
148
-
149
- // ─── New Customization Props ────────────────────────────────────────────────
150
-
151
- /** Foil color preset. Defaults to 'rainbow'. Ignored if `foilColors` is provided. */
152
120
  foilPreset?: FoilPreset
153
- /** Custom foil gradient colors (array of RGBA strings). Overrides `foilPreset`. */
154
121
  foilColors?: string[]
155
- /** Maximum tilt angle in degrees (0–45). Defaults to 10. */
156
122
  maxTiltDegrees?: number
157
- /** Sensitivity of tilt to device motion (0.1–2). Higher = more responsive. Defaults to 1. */
158
123
  tiltSensitivity?: number
159
- /** How far the sheen moves relative to tilt (0–1). Defaults to 0.6. */
160
124
  sheenSpread?: number
161
- /** Animation duration for tilt smoothing in ms. Defaults to 80. */
162
125
  tiltAnimationDuration?: number
163
- /** Perspective depth for 3D effect (200–2000). Defaults to 800. */
164
126
  perspective?: number
165
- /** Blend mode for the foil overlay. Defaults to 'plus'. */
166
127
  blendMode?: 'plus' | 'screen' | 'overlay' | 'softLight' | 'hardLight'
167
128
  }
168
129
 
169
- /**
170
- * Holographic / foil trading-card surface (Pokémon-TCG style). Renders the art
171
- * on a Skia canvas with an animated rainbow sheen, and tilts in 3D toward device
172
- * motion. The sheen position tracks the tilt so the foil "catches the light".
173
- *
174
- * Deep-import only — keeps Skia out of the main bundle:
175
- * `import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'`
176
- *
177
- * Requires the optional peers `@shopify/react-native-skia` and (for tilt)
178
- * `expo-sensors`. Without `expo-sensors` the card renders with a static sheen.
179
- */
180
130
  export function HolographicCard({
181
131
  source,
182
132
  width = 300,
@@ -186,7 +136,6 @@ export function HolographicCard({
186
136
  intensity = 1,
187
137
  onPress,
188
138
  style,
189
- // New customization props
190
139
  foilPreset = 'rainbow',
191
140
  foilColors,
192
141
  maxTiltDegrees = DEFAULT_TILT_DEG,
@@ -197,25 +146,20 @@ export function HolographicCard({
197
146
  blendMode = 'plus',
198
147
  }: HolographicCardProps) {
199
148
  const h = height ?? width * 1.4
200
- // Called unconditionally (rules of hooks); useImage returns null for a nullish source.
201
149
  const image = useImage((source ?? null) as Parameters<typeof useImage>[0])
202
150
 
203
- // Clamp and compute values
204
151
  const clampedTilt = Math.max(0, Math.min(45, maxTiltDegrees))
205
152
  const clampedSensitivity = Math.max(0.1, Math.min(2, tiltSensitivity))
206
153
  const clampedSpread = Math.max(0, Math.min(1, sheenSpread))
207
154
  const clampedPerspective = Math.max(200, Math.min(2000, perspective))
208
-
209
- // Resolve foil colors: custom > preset > default
155
+
210
156
  const resolvedFoilColors = useMemo(() => {
211
157
  if (foilColors && foilColors.length >= 2) return foilColors
212
158
  return FOIL_PRESETS[foilPreset] ?? DEFAULT_FOIL_COLORS
213
159
  }, [foilColors, foilPreset])
214
160
 
215
- // Normalization factor adjusted by sensitivity
216
161
  const normFactor = DEFAULT_NORM_FACTOR / clampedSensitivity
217
162
 
218
- // Tilt in normalized [-1, 1] on each axis.
219
163
  const tiltX = useSharedValue(0)
220
164
  const tiltY = useSharedValue(0)
221
165
 
@@ -223,7 +167,6 @@ export function HolographicCard({
223
167
  if (!enableTilt || Platform.OS === 'web') return
224
168
  let remove: (() => void) | undefined
225
169
  let cancelled = false
226
- // Dynamic import: expo-sensors is an optional peer. Absence = static sheen.
227
170
  import('expo-sensors')
228
171
  .then(({ DeviceMotion }) => {
229
172
  if (cancelled) return
@@ -237,21 +180,13 @@ export function HolographicCard({
237
180
  })
238
181
  remove = () => sub.remove()
239
182
  })
240
- .catch(() => {
241
- // expo-sensors not installed — leave tilt at rest.
242
- })
183
+ .catch(() => {})
243
184
  return () => {
244
185
  cancelled = true
245
186
  remove?.()
246
187
  }
247
188
  }, [enableTilt, tiltX, tiltY, normFactor, tiltAnimationDuration])
248
189
 
249
- // 3D parallax — perspective tilt of the whole card toward the device motion.
250
- const { animatedStyle: pressStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
251
- pressScale: PRESS_SCALE.card,
252
- disabled: !onPress,
253
- })
254
-
255
190
  const tiltStyle = useAnimatedStyle(() => ({
256
191
  transform: [
257
192
  { perspective: clampedPerspective },
@@ -260,7 +195,6 @@ export function HolographicCard({
260
195
  ],
261
196
  }))
262
197
 
263
- // Sheen sweeps across the card as it tilts.
264
198
  const start = useDerivedValue(() => vec(width * (0.5 - tiltX.value * clampedSpread), h * (0.5 - tiltY.value * clampedSpread)))
265
199
  const end = useDerivedValue(() => vec(width * (0.5 + tiltX.value * clampedSpread), h * (0.5 + tiltY.value * clampedSpread)))
266
200
 
@@ -268,13 +202,11 @@ export function HolographicCard({
268
202
 
269
203
  const canvas = (
270
204
  <Canvas style={{ width, height: h }}>
271
- {/* Art clipped to the rounded card. */}
272
205
  {image ? (
273
206
  <Group clip={{ rect: rrct, rx: borderRadius, ry: borderRadius }}>
274
207
  <SkiaImage image={image} x={0} y={0} width={width} height={h} fit="cover" />
275
208
  </Group>
276
209
  ) : null}
277
- {/* Foil sheen — additive rainbow gradient that tracks the tilt. */}
278
210
  <RoundedRect x={0} y={0} width={width} height={h} r={borderRadius} opacity={intensity} blendMode={blendMode}>
279
211
  <LinearGradient start={start} end={end} colors={resolvedFoilColors} />
280
212
  </RoundedRect>
@@ -288,28 +220,15 @@ export function HolographicCard({
288
220
  if (!onPress) return card
289
221
 
290
222
  return (
291
- <Animated.View style={pressStyle}>
292
- <TouchableOpacity
293
- onPress={() => {
294
- impactLight()
295
- onPress()
296
- }}
297
- onPressIn={onPressIn}
298
- onPressOut={onPressOut}
299
- activeOpacity={1}
300
- touchSoundDisabled={true}
301
- accessibilityRole="imagebutton"
302
- {...hoverHandlers}
303
- style={styles.touch}
304
- >
305
- {card}
306
- </TouchableOpacity>
307
- </Animated.View>
223
+ <PressableCard
224
+ onPress={() => { impactLight(); onPress() }}
225
+ enabled
226
+ rippleColor="transparent"
227
+ touchSoundDisabled
228
+ accessibilityRole="imagebutton"
229
+ style={{ alignSelf: 'flex-start' }}
230
+ >
231
+ {card}
232
+ </PressableCard>
308
233
  )
309
234
  }
310
-
311
- const styles = StyleSheet.create({
312
- touch: {
313
- alignSelf: 'flex-start',
314
- },
315
- })
@@ -9,7 +9,7 @@ import {
9
9
  import { impactLight } from '../../utils/haptics'
10
10
  import { useTheme } from '../../theme'
11
11
  import { s, ms } from '../../utils/scaling'
12
- import { renderIcon } from '../../utils/icons'
12
+ import { Icon } from '../../utils/icons'
13
13
  import { PressableButton } from '../../utils/pressable'
14
14
 
15
15
  // primary: filled primary
@@ -92,7 +92,7 @@ function IconButtonBase({
92
92
  const { container: containerSize, icon: iconSize } = sizeMap[size]
93
93
 
94
94
  const resolvedIcon: React.ReactNode = iconName
95
- ? renderIcon(iconName, iconSize, iconColor ?? defaultIconColor)
95
+ ? <Icon name={iconName} size={iconSize} color={iconColor ?? defaultIconColor} />
96
96
  : icon
97
97
 
98
98
  // Badge rendering
@@ -8,8 +8,8 @@ import {
8
8
  } from '@gorhom/bottom-sheet'
9
9
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
10
10
  import { useTheme } from '../../theme'
11
- import { renderIcon } from '../../utils/icons'
12
- import { CURATED_ICONS, ALL_CURATED_ICONS } from '../../utils/curatedIcons'
11
+ import { Icon } from '../../utils/icons'
12
+ import { getCuratedCategories, getAllCuratedIcons } from '../../utils/curatedIcons'
13
13
  import { selectionAsync as hapticSelection, impactMedium } from '../../utils/haptics'
14
14
  import { s, vs, ms } from '../../utils/scaling'
15
15
  import { RADIUS } from '../../tokens'
@@ -54,7 +54,7 @@ function IconCell({ name, selected, size, onPress }: { name: string; selected: b
54
54
  accessibilityLabel={name}
55
55
  style={[styles.cell, { width: size, height: size, backgroundColor: bg }]}
56
56
  >
57
- {renderIcon(name, ms(20), iconColor)}
57
+ <Icon name={name} size={ms(20)} color={iconColor} />
58
58
  </TouchableOpacity>
59
59
  )
60
60
  }
@@ -83,10 +83,11 @@ export function IconPicker({
83
83
  const sheetName = useId()
84
84
 
85
85
  const activeIcons = useMemo(() => {
86
+ const allIcons = getAllCuratedIcons()
86
87
  if (activeCategory) {
87
- return CURATED_ICONS.find((c) => c.name === activeCategory)?.icons ?? ALL_CURATED_ICONS
88
+ return getCuratedCategories().find((c) => c.name === activeCategory)?.icons ?? allIcons
88
89
  }
89
- return ALL_CURATED_ICONS
90
+ return allIcons
90
91
  }, [activeCategory])
91
92
 
92
93
  const gapPx = s(gap)
@@ -129,7 +130,7 @@ export function IconPicker({
129
130
  [],
130
131
  )
131
132
 
132
- const selectedIcon = value ? renderIcon(value, ms(28), colors.foreground) : null
133
+ const selectedIcon = value ? <Icon name={value} size={ms(28)} color={colors.foreground} /> : null
133
134
 
134
135
  return (
135
136
  <View style={[styles.triggerContainer, style]}>
@@ -157,7 +158,7 @@ export function IconPicker({
157
158
  disabled && styles.triggerDisabled,
158
159
  ]}
159
160
  >
160
- {selectedIcon ?? renderIcon('plus', ms(24), colors.foregroundMuted)}
161
+ {selectedIcon ?? <Icon name="plus" size={ms(24)} color={colors.foregroundMuted} />}
161
162
  </TouchableOpacity>
162
163
  {error ? (
163
164
  <Text
@@ -223,7 +224,7 @@ export function IconPicker({
223
224
  activeOpacity={0.7}
224
225
  touchSoundDisabled={true}
225
226
  accessibilityRole="button"
226
- accessibilityLabel="Todos"
227
+ accessibilityLabel="Todas"
227
228
  accessibilityState={{ selected: activeCategory === null }}
228
229
  style={[
229
230
  styles.categoryChip,
@@ -234,7 +235,7 @@ export function IconPicker({
234
235
  ]}
235
236
  >
236
237
  <View style={styles.categoryChipInner}>
237
- {renderIcon('grid', ms(14), activeCategory === null ? colors.primaryForeground : colors.foregroundSubtle)}
238
+ <Icon name="grid" size={ms(14)} color={activeCategory === null ? colors.primaryForeground : colors.foregroundSubtle} />
238
239
  <Text
239
240
  style={[
240
241
  styles.categoryChipText,
@@ -243,11 +244,11 @@ export function IconPicker({
243
244
  allowFontScaling={true}
244
245
  numberOfLines={1}
245
246
  >
246
- Todos
247
+ Todas
247
248
  </Text>
248
249
  </View>
249
250
  </TouchableOpacity>
250
- {CURATED_ICONS.map((cat) => (
251
+ {getCuratedCategories().map((cat) => (
251
252
  <TouchableOpacity
252
253
  key={cat.name}
253
254
  onPress={() => setActiveCategory(cat.name)}
@@ -265,7 +266,7 @@ export function IconPicker({
265
266
  ]}
266
267
  >
267
268
  <View style={styles.categoryChipInner}>
268
- {renderIcon(cat.categoryIcon, ms(14), activeCategory === cat.name ? colors.primaryForeground : colors.foregroundSubtle)}
269
+ <Icon name={cat.categoryIcon} size={ms(14)} color={activeCategory === cat.name ? colors.primaryForeground : colors.foregroundSubtle} />
269
270
  <Text
270
271
  style={[
271
272
  styles.categoryChipText,
@@ -1,5 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { View, Text, Image, StyleSheet, ViewStyle, Platform } from 'react-native'
2
+ import { Image } from 'expo-image'
3
+ import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
4
  import { Feather } from '@expo/vector-icons'
4
5
  import { impactLight } from '../../utils/haptics'
5
6
  import { useTheme } from '../../theme'
@@ -27,71 +28,67 @@ export interface ImageUploadProps {
27
28
  borderRadius?: number
28
29
  /** Aspect ratio for the selected image. Defaults to 'cover'. */
29
30
  resizeMode?: 'cover' | 'contain' | 'stretch'
30
- /** Whether to allow the user to crop the image after selecting. Defaults to true. */
31
- allowsEditing?: boolean
32
31
  disabled?: boolean
33
32
  style?: ViewStyle
34
33
  accessibilityLabel?: string
34
+ /** Called synchronously when user taps the upload area, before dynamic import and permission request. */
35
+ onPickerStarting?: () => void
35
36
  }
36
37
 
37
38
  export function ImageUpload({
38
39
  value,
39
40
  onChange,
40
41
  loading = false,
41
- placeholder = 'Tap to add image',
42
+ placeholder = 'Toca para añadir imagen',
42
43
  showPlaceholderText = true,
43
44
  width,
44
45
  height = 200,
45
46
  borderRadius = RADIUS.lg,
46
47
  resizeMode = 'cover',
47
- allowsEditing = true,
48
48
  disabled = false,
49
49
  style,
50
50
  accessibilityLabel,
51
+ onPickerStarting,
51
52
  }: ImageUploadProps) {
52
53
  const { colors } = useTheme()
53
54
  const [imageLoaded, setImageLoaded] = useState(false)
55
+ const [isPicking, setIsPicking] = useState(false)
54
56
 
55
57
  const handlePress = async () => {
56
- if (disabled || loading) return
58
+ if (disabled || loading || isPicking) return
57
59
  impactLight()
58
60
 
59
- // Dynamic import so expo-image-picker is optional at module load time.
60
- // Import ExponentImagePicker (the raw native module proxy) directly to
61
- // avoid expo-image-picker's top-level createPermissionHook dependency.
62
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
- let picker: any
64
- try {
65
- const mod = await import('expo-image-picker/build/ExponentImagePicker')
66
- picker = (mod as { default: unknown }).default
67
- } catch {
68
- // Fallback: try the main module
69
- try {
70
- picker = await import('expo-image-picker')
71
- } catch {
72
- if (__DEV__) console.warn('[ImageUpload] expo-image-picker not installed.')
73
- return
74
- }
75
- }
61
+ onPickerStarting?.()
62
+ setIsPicking(true)
76
63
 
77
- if (Platform.OS !== 'web') {
78
- try {
79
- const { status } = await picker.requestMediaLibraryPermissionsAsync()
80
- if (status !== 'granted') return
81
- } catch {
82
- // Permission check failed — try picker anyway
83
- }
84
- }
64
+ try {
65
+ const { launchImageLibrary } = await import('react-native-image-picker')
85
66
 
86
- const result = await picker.launchImageLibraryAsync({
87
- mediaTypes: ['images'],
88
- allowsEditing,
89
- quality: 0.8,
90
- })
67
+ const result = await new Promise<{
68
+ didCancel?: boolean
69
+ errorCode?: string
70
+ errorMessage?: string
71
+ assets?: { uri?: string }[]
72
+ }>((resolve) => {
73
+ launchImageLibrary(
74
+ {
75
+ mediaType: 'photo',
76
+ quality: 0.8,
77
+ selectionLimit: 1,
78
+ includeBase64: false,
79
+ },
80
+ resolve,
81
+ )
82
+ })
91
83
 
92
- if (!result.canceled && result.assets?.[0]) {
93
- setImageLoaded(false)
94
- onChange?.(result.assets[0].uri)
84
+ if (!result.didCancel && !result.errorCode && result.assets?.[0]?.uri) {
85
+ setImageLoaded(false)
86
+ onChange?.(result.assets[0].uri)
87
+ }
88
+ } catch {
89
+ // Module load failed or picker errored — silently return
90
+ } finally {
91
+ setIsPicking(false)
95
92
  }
96
93
  }
97
94
 
@@ -113,7 +110,7 @@ export function ImageUpload({
113
110
  rippleColor="transparent"
114
111
  touchSoundDisabled
115
112
  accessibilityRole="button"
116
- accessibilityLabel={accessibilityLabel ?? (value ? 'Change image' : placeholder)}
113
+ accessibilityLabel={accessibilityLabel ?? (value ? 'Cambiar imagen' : placeholder)}
117
114
  accessibilityState={{ disabled: disabled || loading }}
118
115
  style={[containerStyle, style]}
119
116
  >
@@ -121,7 +118,7 @@ export function ImageUpload({
121
118
  <Image
122
119
  source={{ uri: value }}
123
120
  style={[StyleSheet.absoluteFillObject, { borderRadius }]}
124
- resizeMode={resizeMode}
121
+ contentFit={resizeMode === 'stretch' ? 'fill' : resizeMode}
125
122
  onLoad={() => setImageLoaded(true)}
126
123
  onError={() => setImageLoaded(true)}
127
124
  />
@@ -139,7 +136,7 @@ export function ImageUpload({
139
136
  ) : null}
140
137
  </View>
141
138
  )}
142
- {loading ? (
139
+ {loading || isPicking ? (
143
140
  <View style={[styles.loadingOverlay, { backgroundColor: colors.overlay }]}>
144
141
  <Spinner size="md" />
145
142
  </View>
@@ -174,12 +171,12 @@ const styles = StyleSheet.create({
174
171
  },
175
172
  editBadge: {
176
173
  position: 'absolute',
177
- bottom: vs(8),
178
- right: s(8),
174
+ bottom: vs(14),
175
+ right: s(14),
179
176
  },
180
177
  editBadgeInner: {
181
- width: s(28),
182
- height: s(28),
178
+ width: s(24),
179
+ height: s(24),
183
180
  borderRadius: 999,
184
181
  alignItems: 'center',
185
182
  justifyContent: 'center',
@@ -1,8 +1,8 @@
1
1
  import React, { useState, useCallback } from 'react'
2
+ import { Image } from 'expo-image'
2
3
  import {
3
4
  Modal,
4
5
  View,
5
- Image,
6
6
  Dimensions,
7
7
  StyleSheet,
8
8
  useWindowDimensions,
@@ -105,7 +105,7 @@ function ZoomableImage({ source, width, height, onZoomChange }: ZoomableImagePro
105
105
  <GestureDetector gesture={composed}>
106
106
  <View style={[{ width, height }, styles.imageWrap]} collapsable={false}>
107
107
  <Animated.View style={[{ width, height }, animatedStyle]}>
108
- <Image source={source} style={{ width, height }} resizeMode="contain" />
108
+ <Image source={source} style={{ width, height }} contentFit="contain" />
109
109
  </Animated.View>
110
110
  </View>
111
111
  </GestureDetector>
@@ -235,7 +235,7 @@ export function ImageViewer({ images, visible, onClose, initialIndex = 0 }: Imag
235
235
  style={{ backgroundColor: 'rgba(255,255,255,0.18)' }}
236
236
  iconColor="#fff"
237
237
  onPress={onClose}
238
- accessibilityLabel="Close"
238
+ accessibilityLabel="Cerrar"
239
239
  />
240
240
  </View>
241
241
 
@@ -5,7 +5,7 @@ import { EaseView } from 'react-native-ease'
5
5
  import { AntDesign } from '@expo/vector-icons'
6
6
  import { useTheme } from '../../theme'
7
7
  import { s, vs, ms } from '../../utils/scaling'
8
- import { renderIcon } from '../../utils/icons'
8
+ import { Icon } from '../../utils/icons'
9
9
  import { COLOR_TRANSITION } from '../../utils/animations'
10
10
 
11
11
  const webInputResetStyle: Record<string, unknown> =
@@ -33,7 +33,7 @@ export interface InputProps extends TextInputProps {
33
33
  sheetMode?: boolean
34
34
  }
35
35
 
36
- export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, inputWrapperStyle, sheetMode = false, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps) {
36
+ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, inputWrapperStyle, sheetMode = false, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, autoCapitalize, autoCorrect, ...props }: InputProps) {
37
37
  const { colors } = useTheme()
38
38
  const [focused, setFocused] = useState(false)
39
39
  const [showPassword, setShowPassword] = useState(false)
@@ -41,9 +41,11 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
41
41
  const isDisabled = disabled || editable === false
42
42
  const isPassword = type === 'password'
43
43
  const effectiveSecure = isPassword ? !showPassword : secureTextEntry
44
+ const effectiveAutoCapitalize = isPassword ? 'none' : autoCapitalize
45
+ const effectiveAutoCorrect = isPassword ? false : autoCorrect
44
46
 
45
47
  const effectivePrefix: React.ReactNode = prefixIcon
46
- ? renderIcon(prefixIcon, 20, prefixIconColor ?? colors.foregroundMuted)
48
+ ? <Icon name={prefixIcon} size={20} color={prefixIconColor ?? colors.foregroundMuted} />
47
49
  : prefix
48
50
 
49
51
  const effectiveSuffix: React.ReactNode = isPassword && !suffix && !suffixIcon ? (
@@ -54,12 +56,12 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
54
56
  style={styles.passwordToggle}
55
57
  activeOpacity={0.6}
56
58
  accessibilityRole="button"
57
- accessibilityLabel={showPassword ? 'Hide password' : 'Show password'}
59
+ accessibilityLabel={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
58
60
  >
59
61
  <AntDesign name={showPassword ? 'eye' : 'eye-invisible'} size={20} color={colors.foregroundMuted} />
60
62
  </TouchableOpacity>
61
63
  ) : suffixIcon
62
- ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted)
64
+ ? <Icon name={suffixIcon} size={20} color={suffixIconColor ?? colors.foregroundMuted} />
63
65
  : suffix
64
66
 
65
67
  // Border color animated via EaseView. Width is static (1px normal, 2px error)
@@ -109,6 +111,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
109
111
  secureTextEntry={effectiveSecure}
110
112
  editable={isDisabled ? false : editable}
111
113
  accessibilityLabel={accessibilityLabel ?? label}
114
+ autoCapitalize={effectiveAutoCapitalize}
115
+ autoCorrect={effectiveAutoCorrect}
112
116
  {...props}
113
117
  />
114
118
  ) : (
@@ -132,6 +136,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
132
136
  secureTextEntry={effectiveSecure}
133
137
  editable={isDisabled ? false : editable}
134
138
  accessibilityLabel={accessibilityLabel ?? label}
139
+ autoCapitalize={effectiveAutoCapitalize}
140
+ autoCorrect={effectiveAutoCorrect}
135
141
  {...props}
136
142
  />
137
143
  )}
@@ -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, ms, mvs } from '../../utils/scaling'
5
- import { renderIcon } from '../../utils/icons'
5
+ import { Icon } from '../../utils/icons'
6
6
 
7
7
  export interface LabelValueProps {
8
8
  label: string
@@ -18,7 +18,7 @@ function LabelValueBase({ label, value, iconName, iconColor, style }: LabelValue
18
18
  const { colors } = useTheme()
19
19
 
20
20
  const resolvedIcon = iconName
21
- ? renderIcon(iconName, ms(14), iconColor ?? colors.foregroundMuted)
21
+ ? <Icon name={iconName} size={ms(14)} color={iconColor ?? colors.foregroundMuted} />
22
22
  : null
23
23
 
24
24
  return (