@retray-dev/ui-kit 13.0.0 → 13.4.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 (344) hide show
  1. package/CHANGELOG.md +680 -0
  2. package/CONSUMER.md +26 -9
  3. package/README.md +11 -12
  4. package/{COMPONENTS.md → SKILL.md} +515 -815
  5. package/dist/Accordion.d.mts +8 -6
  6. package/dist/Accordion.d.ts +8 -6
  7. package/dist/Accordion.js +40 -40
  8. package/dist/Accordion.mjs +4 -5
  9. package/dist/AlertBanner.d.mts +3 -3
  10. package/dist/AlertBanner.d.ts +3 -3
  11. package/dist/AlertBanner.js +7 -13
  12. package/dist/AlertBanner.mjs +4 -5
  13. package/dist/AppHeader.d.mts +8 -5
  14. package/dist/AppHeader.d.ts +8 -5
  15. package/dist/AppHeader.js +44 -31
  16. package/dist/AppHeader.mjs +6 -7
  17. package/dist/Avatar.d.mts +4 -4
  18. package/dist/Avatar.d.ts +4 -4
  19. package/dist/Avatar.mjs +2 -3
  20. package/dist/Badge.d.mts +5 -5
  21. package/dist/Badge.d.ts +5 -5
  22. package/dist/Badge.js +7 -13
  23. package/dist/Badge.mjs +3 -4
  24. package/dist/Button.d.mts +5 -5
  25. package/dist/Button.d.ts +5 -5
  26. package/dist/Button.js +31 -29
  27. package/dist/Button.mjs +5 -6
  28. package/dist/ButtonGroup.d.mts +3 -3
  29. package/dist/ButtonGroup.d.ts +3 -3
  30. package/dist/ButtonGroup.mjs +0 -1
  31. package/dist/Card.d.mts +13 -13
  32. package/dist/Card.d.ts +13 -13
  33. package/dist/Card.js +23 -14
  34. package/dist/Card.mjs +4 -5
  35. package/dist/CategoryStrip.d.mts +3 -3
  36. package/dist/CategoryStrip.d.ts +3 -3
  37. package/dist/CategoryStrip.js +30 -27
  38. package/dist/CategoryStrip.mjs +5 -6
  39. package/dist/Checkbox.d.mts +3 -2
  40. package/dist/Checkbox.d.ts +3 -2
  41. package/dist/Checkbox.js +26 -15
  42. package/dist/Checkbox.mjs +3 -4
  43. package/dist/Chip.d.mts +5 -5
  44. package/dist/Chip.d.ts +5 -5
  45. package/dist/Chip.js +30 -27
  46. package/dist/Chip.mjs +5 -6
  47. package/dist/ConfirmDialog.d.mts +3 -2
  48. package/dist/ConfirmDialog.d.ts +3 -2
  49. package/dist/ConfirmDialog.js +67 -49
  50. package/dist/ConfirmDialog.mjs +7 -7
  51. package/dist/CurrencyDisplay.d.mts +3 -3
  52. package/dist/CurrencyDisplay.d.ts +3 -3
  53. package/dist/CurrencyDisplay.mjs +2 -3
  54. package/dist/CurrencyInput.d.mts +2 -2
  55. package/dist/CurrencyInput.d.ts +2 -2
  56. package/dist/CurrencyInput.js +7 -13
  57. package/dist/CurrencyInput.mjs +4 -5
  58. package/dist/DetailRow.d.mts +6 -6
  59. package/dist/DetailRow.d.ts +6 -6
  60. package/dist/DetailRow.js +7 -13
  61. package/dist/DetailRow.mjs +3 -4
  62. package/dist/EmptyState.d.mts +4 -4
  63. package/dist/EmptyState.d.ts +4 -4
  64. package/dist/EmptyState.js +31 -29
  65. package/dist/EmptyState.mjs +6 -7
  66. package/dist/ErrorBoundary.d.mts +9 -7
  67. package/dist/ErrorBoundary.d.ts +9 -7
  68. package/dist/ErrorBoundary.js +33 -29
  69. package/dist/ErrorBoundary.mjs +5 -6
  70. package/dist/Form.d.mts +9 -9
  71. package/dist/Form.d.ts +9 -9
  72. package/dist/Form.mjs +2 -3
  73. package/dist/HolographicCard.d.mts +2 -2
  74. package/dist/HolographicCard.d.ts +2 -2
  75. package/dist/HolographicCard.js +23 -14
  76. package/dist/HolographicCard.mjs +2 -3
  77. package/dist/IconButton.d.mts +4 -4
  78. package/dist/IconButton.d.ts +4 -4
  79. package/dist/IconButton.js +30 -27
  80. package/dist/IconButton.mjs +4 -5
  81. package/dist/IconPicker.d.mts +2 -2
  82. package/dist/IconPicker.d.ts +2 -2
  83. package/dist/IconPicker.js +40 -45
  84. package/dist/IconPicker.mjs +6 -7
  85. package/dist/Image.d.mts +18 -0
  86. package/dist/Image.d.ts +18 -0
  87. package/dist/Image.js +53 -0
  88. package/dist/Image.mjs +2 -0
  89. package/dist/ImageUpload.d.mts +2 -4
  90. package/dist/ImageUpload.d.ts +2 -4
  91. package/dist/ImageUpload.js +50 -40
  92. package/dist/ImageUpload.mjs +5 -6
  93. package/dist/ImageViewer.d.mts +2 -2
  94. package/dist/ImageViewer.d.ts +2 -2
  95. package/dist/ImageViewer.js +31 -28
  96. package/dist/ImageViewer.mjs +6 -7
  97. package/dist/Input.d.mts +4 -4
  98. package/dist/Input.d.ts +4 -4
  99. package/dist/Input.js +7 -13
  100. package/dist/Input.mjs +3 -4
  101. package/dist/ItemGroup.d.mts +23 -0
  102. package/dist/ItemGroup.d.ts +23 -0
  103. package/dist/{ListGroup.js → ItemGroup.js} +11 -13
  104. package/dist/ItemGroup.mjs +4 -0
  105. package/dist/LabelValue.d.mts +4 -4
  106. package/dist/LabelValue.d.ts +4 -4
  107. package/dist/LabelValue.js +7 -13
  108. package/dist/LabelValue.mjs +3 -4
  109. package/dist/ListItem.d.mts +7 -6
  110. package/dist/ListItem.d.ts +7 -6
  111. package/dist/ListItem.js +33 -28
  112. package/dist/ListItem.mjs +5 -6
  113. package/dist/MediaCard.d.mts +6 -6
  114. package/dist/MediaCard.d.ts +6 -6
  115. package/dist/MediaCard.js +30 -27
  116. package/dist/MediaCard.mjs +5 -6
  117. package/dist/MenuItem.d.mts +6 -5
  118. package/dist/MenuItem.d.ts +6 -5
  119. package/dist/MenuItem.js +33 -28
  120. package/dist/MenuItem.mjs +5 -6
  121. package/dist/MonthPicker.d.mts +2 -2
  122. package/dist/MonthPicker.d.ts +2 -2
  123. package/dist/MonthPicker.js +23 -14
  124. package/dist/MonthPicker.mjs +3 -4
  125. package/dist/NumberStepper.d.mts +4 -3
  126. package/dist/NumberStepper.d.ts +4 -3
  127. package/dist/NumberStepper.js +34 -28
  128. package/dist/NumberStepper.mjs +5 -6
  129. package/dist/PagerDots.d.mts +2 -2
  130. package/dist/PagerDots.d.ts +2 -2
  131. package/dist/PagerDots.js +30 -27
  132. package/dist/PagerDots.mjs +4 -5
  133. package/dist/Pressable.d.mts +3 -27
  134. package/dist/Pressable.d.ts +3 -27
  135. package/dist/Pressable.js +23 -14
  136. package/dist/Pressable.mjs +2 -3
  137. package/dist/PricingCard.d.mts +2 -2
  138. package/dist/PricingCard.d.ts +2 -2
  139. package/dist/PricingCard.js +31 -29
  140. package/dist/PricingCard.mjs +7 -8
  141. package/dist/Progress.d.mts +2 -2
  142. package/dist/Progress.d.ts +2 -2
  143. package/dist/Progress.mjs +2 -3
  144. package/dist/RadioGroup.d.mts +2 -2
  145. package/dist/RadioGroup.d.ts +2 -2
  146. package/dist/RadioGroup.js +23 -14
  147. package/dist/RadioGroup.mjs +3 -4
  148. package/dist/RetrayProvider.d.mts +1 -1
  149. package/dist/RetrayProvider.d.ts +1 -1
  150. package/dist/RetrayProvider.js +14 -34
  151. package/dist/RetrayProvider.mjs +3 -4
  152. package/dist/ScreenContainer.d.mts +24 -0
  153. package/dist/ScreenContainer.d.ts +24 -0
  154. package/dist/ScreenContainer.js +85 -0
  155. package/dist/ScreenContainer.mjs +3 -0
  156. package/dist/Select.d.mts +3 -2
  157. package/dist/Select.d.ts +3 -2
  158. package/dist/Select.js +41 -46
  159. package/dist/Select.mjs +3 -4
  160. package/dist/SelectableCard.d.mts +5 -5
  161. package/dist/SelectableCard.d.ts +5 -5
  162. package/dist/SelectableCard.js +30 -27
  163. package/dist/SelectableCard.mjs +5 -6
  164. package/dist/SelectableGrid.d.mts +5 -4
  165. package/dist/SelectableGrid.d.ts +5 -4
  166. package/dist/SelectableGrid.js +80 -45
  167. package/dist/SelectableGrid.mjs +5 -6
  168. package/dist/Separator.d.mts +4 -2
  169. package/dist/Separator.d.ts +4 -2
  170. package/dist/Separator.js +29 -1
  171. package/dist/Separator.mjs +3 -3
  172. package/dist/Sheet.d.mts +11 -11
  173. package/dist/Sheet.d.ts +11 -11
  174. package/dist/Sheet.js +62 -34
  175. package/dist/Sheet.mjs +4 -4
  176. package/dist/SheetSelect.d.mts +2 -2
  177. package/dist/SheetSelect.d.ts +2 -2
  178. package/dist/SheetSelect.js +30 -27
  179. package/dist/SheetSelect.mjs +5 -6
  180. package/dist/Skeleton.d.mts +5 -5
  181. package/dist/Skeleton.d.ts +5 -5
  182. package/dist/Skeleton.mjs +3 -4
  183. package/dist/Slider.d.mts +3 -2
  184. package/dist/Slider.d.ts +3 -2
  185. package/dist/Slider.js +25 -14
  186. package/dist/Slider.mjs +3 -4
  187. package/dist/Spinner.d.mts +2 -2
  188. package/dist/Spinner.d.ts +2 -2
  189. package/dist/Spinner.mjs +2 -3
  190. package/dist/Stats.d.mts +6 -6
  191. package/dist/Stats.d.ts +6 -6
  192. package/dist/Stats.js +30 -27
  193. package/dist/Stats.mjs +5 -6
  194. package/dist/Switch.d.mts +3 -2
  195. package/dist/Switch.d.ts +3 -2
  196. package/dist/Switch.js +25 -15
  197. package/dist/Switch.mjs +3 -4
  198. package/dist/TabBar.d.mts +3 -3
  199. package/dist/TabBar.d.ts +3 -3
  200. package/dist/TabBar.js +30 -27
  201. package/dist/TabBar.mjs +4 -5
  202. package/dist/Tabs.d.mts +13 -13
  203. package/dist/Tabs.d.ts +13 -13
  204. package/dist/Tabs.js +23 -14
  205. package/dist/Tabs.mjs +3 -4
  206. package/dist/Text.d.mts +4 -4
  207. package/dist/Text.d.ts +4 -4
  208. package/dist/Text.js +20 -2
  209. package/dist/Text.mjs +3 -4
  210. package/dist/Textarea.d.mts +3 -3
  211. package/dist/Textarea.d.ts +3 -3
  212. package/dist/Textarea.js +7 -13
  213. package/dist/Textarea.mjs +3 -4
  214. package/dist/Toast.d.mts +15 -13
  215. package/dist/Toast.d.ts +15 -13
  216. package/dist/Toast.mjs +2 -3
  217. package/dist/Toggle.d.mts +4 -4
  218. package/dist/Toggle.d.ts +4 -4
  219. package/dist/Toggle.js +30 -27
  220. package/dist/Toggle.mjs +4 -5
  221. package/dist/VirtualizedList.d.mts +28 -0
  222. package/dist/VirtualizedList.d.ts +28 -0
  223. package/dist/VirtualizedList.js +130 -0
  224. package/dist/VirtualizedList.mjs +3 -0
  225. package/dist/{chunk-MZ6WRTD2.mjs → chunk-24JTXQ2M.mjs} +7 -13
  226. package/dist/{chunk-OBV72JD4.mjs → chunk-2DDJ53DK.mjs} +9 -11
  227. package/dist/{chunk-6CR4S6W2.mjs → chunk-2J5OZOMX.mjs} +19 -8
  228. package/dist/{chunk-4NQFTHN3.mjs → chunk-3GE4UFV5.mjs} +2 -2
  229. package/dist/{chunk-KAGADD2O.mjs → chunk-3RIZCKRM.mjs} +2 -2
  230. package/dist/{chunk-DE25XTVQ.mjs → chunk-3VHFOSZR.mjs} +2 -2
  231. package/dist/{chunk-UOKFSFNJ.mjs → chunk-4PF4LKNT.mjs} +4 -2
  232. package/dist/{chunk-5MYNAAFE.mjs → chunk-5J7VKFSZ.mjs} +4 -4
  233. package/dist/{chunk-BTUW5LSG.mjs → chunk-5TNQ573V.mjs} +4 -3
  234. package/dist/{chunk-6QLBHUEG.mjs → chunk-6T2DVIQT.mjs} +7 -5
  235. package/dist/{chunk-L3YKPTJQ.mjs → chunk-7CE6PDCQ.mjs} +2 -2
  236. package/dist/{chunk-Y6YS33GM.mjs → chunk-AHFEAY6M.mjs} +4 -4
  237. package/dist/{chunk-4ZO5PTKF.mjs → chunk-AZRATPNP.mjs} +5 -3
  238. package/dist/{chunk-V2ZB2XNS.mjs → chunk-BGXOEFDM.mjs} +9 -22
  239. package/dist/{chunk-KC5QDYGZ.mjs → chunk-BMAAAJWN.mjs} +2 -2
  240. package/dist/{chunk-IJCMPVW5.mjs → chunk-BQMJQMWY.mjs} +2 -2
  241. package/dist/{chunk-E4EQSCKR.mjs → chunk-BTPCY4C7.mjs} +7 -5
  242. package/dist/chunk-BVJAYPAD.mjs +55 -0
  243. package/dist/{chunk-RA6SAAFE.mjs → chunk-BWLVX2SQ.mjs} +4 -4
  244. package/dist/{chunk-EROPDCB5.mjs → chunk-CCEM3HIJ.mjs} +30 -25
  245. package/dist/chunk-CTUFFKGS.mjs +30 -0
  246. package/dist/{chunk-EHGBHFMH.mjs → chunk-CYGYC7XT.mjs} +8 -4
  247. package/dist/{chunk-ESQDPO5E.mjs → chunk-DLAOTHHS.mjs} +7 -6
  248. package/dist/{chunk-QY3X2UYR.mjs → chunk-DYYPDQA2.mjs} +21 -7
  249. package/dist/{chunk-S44XWTTC.mjs → chunk-E4BJ5WXG.mjs} +3 -3
  250. package/dist/{chunk-HUSSF6TF.mjs → chunk-EQNCMDZC.mjs} +1 -1
  251. package/dist/{chunk-PI6RULJX.mjs → chunk-EQYTDFDD.mjs} +1 -1
  252. package/dist/{chunk-BULKGOIZ.mjs → chunk-FE26TPCI.mjs} +4 -4
  253. package/dist/{chunk-DBHSUUKU.mjs → chunk-FOUSI6JD.mjs} +1 -1
  254. package/dist/{chunk-KPTY7UYQ.mjs → chunk-GR7PKEKD.mjs} +1 -1
  255. package/dist/{chunk-RRKM4MKB.mjs → chunk-HLWGFBIF.mjs} +3 -3
  256. package/dist/chunk-HMKJGVXA.mjs +35 -0
  257. package/dist/{chunk-U6DEBYU5.mjs → chunk-IFGZUJFH.mjs} +3 -3
  258. package/dist/{chunk-2VIDP72N.mjs → chunk-K3V6OTVB.mjs} +1 -1
  259. package/dist/{chunk-K7TKID3V.mjs → chunk-K4YFTUMC.mjs} +3 -3
  260. package/dist/{chunk-NGEN2EES.mjs → chunk-MQAK2W6L.mjs} +14 -22
  261. package/dist/{chunk-CM2DG4MR.mjs → chunk-MSS3CD6F.mjs} +4 -4
  262. package/dist/{chunk-TETMEKZE.mjs → chunk-NQYS6RPX.mjs} +8 -5
  263. package/dist/{chunk-62BBSSUF.mjs → chunk-P5KC3RTG.mjs} +1 -1
  264. package/dist/{chunk-K3QX2M26.mjs → chunk-PPKCGCZ3.mjs} +5 -5
  265. package/dist/{chunk-ITG4JQM3.mjs → chunk-QEE3EQ3N.mjs} +2 -2
  266. package/dist/{chunk-URIH43IJ.mjs → chunk-RLPPRIJ7.mjs} +20 -34
  267. package/dist/{chunk-XCIG6HT2.mjs → chunk-S433IOQE.mjs} +2 -2
  268. package/dist/{chunk-IGU223UM.mjs → chunk-SWUZKVYO.mjs} +1 -1
  269. package/dist/{chunk-MP7GLMIR.mjs → chunk-T4KMKHTI.mjs} +55 -23
  270. package/dist/{chunk-2QOHHBJC.mjs → chunk-UBTP4NPP.mjs} +5 -21
  271. package/dist/{chunk-TMH263OK.mjs → chunk-UEA2VYGW.mjs} +3 -3
  272. package/dist/chunk-VISIOH33.mjs +37 -0
  273. package/dist/{chunk-SZEKQAOY.mjs → chunk-VSKBODEY.mjs} +1 -1
  274. package/dist/{chunk-FTTI6T5Q.mjs → chunk-W422TEH2.mjs} +3 -3
  275. package/dist/{chunk-WIPEDNSD.mjs → chunk-WD5LBXPR.mjs} +4 -4
  276. package/dist/chunk-WFNGSYS4.mjs +111 -0
  277. package/dist/chunk-WR6DCNAE.mjs +65 -0
  278. package/dist/{chunk-ERWJPVX7.mjs → chunk-XKBB2UZU.mjs} +2 -2
  279. package/dist/{chunk-CBIZLRYH.mjs → chunk-Y5TPAKOS.mjs} +14 -17
  280. package/dist/{chunk-AZV7KNJI.mjs → chunk-YKWIMVGU.mjs} +2 -2
  281. package/dist/{chunk-ZKDKKQCE.mjs → chunk-YOXSXHDE.mjs} +4 -4
  282. package/dist/{chunk-PGQ6FMXS.mjs → chunk-ZO5BRTCW.mjs} +2 -2
  283. package/dist/{chunk-KSSVIFYR.mjs → chunk-ZQGCQ7SA.mjs} +14 -34
  284. package/dist/{chunk-ZTPYUU5C.mjs → chunk-ZRUUUVOO.mjs} +3 -3
  285. package/dist/fonts.mjs +0 -2
  286. package/dist/{index-CY34hxPN.d.ts → index-CinAt5Uo.d.mts} +3 -3
  287. package/dist/{index-CY34hxPN.d.mts → index-CinAt5Uo.d.ts} +3 -3
  288. package/dist/index.d.mts +69 -19
  289. package/dist/index.d.ts +69 -19
  290. package/dist/index.js +1023 -839
  291. package/dist/index.mjs +76 -70
  292. package/package.json +15 -12
  293. package/src/components/Accordion/Accordion.tsx +12 -18
  294. package/src/components/AppHeader/AppHeader.tsx +33 -10
  295. package/src/components/Checkbox/Checkbox.tsx +3 -0
  296. package/src/components/ConfirmDialog/ConfirmDialog.tsx +7 -21
  297. package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -2
  298. package/src/components/Image/Image.tsx +50 -0
  299. package/src/components/Image/index.ts +2 -0
  300. package/src/components/ImageUpload/ImageUpload.tsx +34 -26
  301. package/src/components/{ListGroup/ListGroup.tsx → ItemGroup/ItemGroup.tsx} +15 -29
  302. package/src/components/ItemGroup/index.ts +2 -0
  303. package/src/components/ListGroup/index.tsx +20 -0
  304. package/src/components/ListItem/ListItem.tsx +3 -0
  305. package/src/components/MenuGroup/index.tsx +20 -0
  306. package/src/components/MenuItem/MenuItem.tsx +3 -0
  307. package/src/components/NumberStepper/NumberStepper.tsx +4 -0
  308. package/src/components/Pressable/Pressable.tsx +0 -24
  309. package/src/components/ScreenContainer/ScreenContainer.tsx +94 -0
  310. package/src/components/ScreenContainer/index.ts +2 -0
  311. package/src/components/Select/Select.tsx +25 -30
  312. package/src/components/SelectableGrid/SelectableGrid.tsx +51 -20
  313. package/src/components/Separator/Separator.tsx +35 -2
  314. package/src/components/Sheet/Sheet.tsx +3 -21
  315. package/src/components/Sheet/index.ts +2 -2
  316. package/src/components/Slider/Slider.tsx +3 -0
  317. package/src/components/Switch/Switch.tsx +3 -1
  318. package/src/components/Tabs/Tabs.tsx +9 -9
  319. package/src/components/Tabs/index.ts +1 -1
  320. package/src/components/Text/Text.tsx +7 -0
  321. package/src/components/VirtualizedList/VirtualizedList.tsx +154 -0
  322. package/src/components/VirtualizedList/index.ts +2 -0
  323. package/src/hooks/useConfirmDialog.ts +2 -11
  324. package/src/hooks/useSheetModal.ts +40 -0
  325. package/src/index.ts +5 -1
  326. package/src/theme/colors.ts +19 -57
  327. package/src/tokens.ts +21 -7
  328. package/src/utils/curatedIcons.ts +9 -18
  329. package/src/utils/haptics.ts +10 -21
  330. package/src/utils/icons.ts +7 -14
  331. package/dist/ListGroup.d.mts +0 -34
  332. package/dist/ListGroup.d.ts +0 -34
  333. package/dist/ListGroup.mjs +0 -5
  334. package/dist/MenuGroup.d.mts +0 -34
  335. package/dist/MenuGroup.d.ts +0 -34
  336. package/dist/MenuGroup.js +0 -106
  337. package/dist/MenuGroup.mjs +0 -5
  338. package/dist/chunk-ARONDO7M.mjs +0 -40
  339. package/dist/chunk-EW2FIDSM.mjs +0 -29
  340. package/dist/chunk-S2VGME7X.mjs +0 -82
  341. package/dist/chunk-Y6FXYEAI.mjs +0 -8
  342. package/src/components/ListGroup/index.ts +0 -1
  343. package/src/components/MenuGroup/MenuGroup.tsx +0 -145
  344. package/src/components/MenuGroup/index.ts +0 -1
@@ -28,8 +28,6 @@ export interface ImageUploadProps {
28
28
  borderRadius?: number
29
29
  /** Aspect ratio for the selected image. Defaults to 'cover'. */
30
30
  resizeMode?: 'cover' | 'contain' | 'stretch'
31
- /** Whether to allow the user to crop the image after selecting. Defaults to true. */
32
- allowsEditing?: boolean
33
31
  disabled?: boolean
34
32
  style?: ViewStyle
35
33
  accessibilityLabel?: string
@@ -47,7 +45,6 @@ export function ImageUpload({
47
45
  height = 200,
48
46
  borderRadius = RADIUS.lg,
49
47
  resizeMode = 'cover',
50
- allowsEditing = true,
51
48
  disabled = false,
52
49
  style,
53
50
  accessibilityLabel,
@@ -55,32 +52,43 @@ export function ImageUpload({
55
52
  }: ImageUploadProps) {
56
53
  const { colors } = useTheme()
57
54
  const [imageLoaded, setImageLoaded] = useState(false)
55
+ const [isPicking, setIsPicking] = useState(false)
58
56
 
59
57
  const handlePress = async () => {
60
- if (disabled || loading) return
58
+ if (disabled || loading || isPicking) return
61
59
  impactLight()
62
60
 
63
61
  onPickerStarting?.()
62
+ setIsPicking(true)
64
63
 
65
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
- let picker: any
67
64
  try {
68
- // eslint-disable-next-line @typescript-eslint/no-require-imports
69
- picker = require('expo-image-picker')
70
- } catch {
71
- if (__DEV__) console.warn('[ImageUpload] expo-image-picker not installed.')
72
- return
73
- }
65
+ const { launchImageLibrary } = await import('react-native-image-picker')
74
66
 
75
- const result = await picker.launchImageLibraryAsync({
76
- mediaTypes: ['images'],
77
- allowsEditing,
78
- quality: 0.8,
79
- })
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
+ })
80
83
 
81
- if (!result.canceled && result.assets?.[0]) {
82
- setImageLoaded(false)
83
- 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)
84
92
  }
85
93
  }
86
94
 
@@ -128,8 +136,8 @@ export function ImageUpload({
128
136
  ) : null}
129
137
  </View>
130
138
  )}
131
- {loading ? (
132
- <View style={[styles.loadingOverlay, { backgroundColor: colors.overlay }]}>
139
+ {loading || isPicking ? (
140
+ <View style={[styles.loadingOverlay, { backgroundColor: colors.overlay, borderRadius }]}>
133
141
  <Spinner size="md" />
134
142
  </View>
135
143
  ) : null}
@@ -163,12 +171,12 @@ const styles = StyleSheet.create({
163
171
  },
164
172
  editBadge: {
165
173
  position: 'absolute',
166
- bottom: vs(8),
167
- right: s(8),
174
+ bottom: vs(14),
175
+ right: s(14),
168
176
  },
169
177
  editBadgeInner: {
170
- width: s(28),
171
- height: s(28),
178
+ width: s(24),
179
+ height: s(24),
172
180
  borderRadius: 999,
173
181
  alignItems: 'center',
174
182
  justifyContent: 'center',
@@ -4,52 +4,41 @@ import { useTheme } from '../../theme'
4
4
  import { s, vs } from '../../utils/scaling'
5
5
  import { RADIUS } from '../../tokens'
6
6
 
7
- export type ListGroupVariant = 'plain' | 'card'
7
+ export type ItemGroupVariant = 'plain' | 'card'
8
8
 
9
- export interface ListGroupProps {
9
+ export interface ItemGroupProps {
10
10
  children: React.ReactNode
11
- /**
12
- * - `plain` (default): no background, plain ListItems inside.
13
- * - `card`: card surface with background + border wrapping plain ListItems.
14
- */
15
- variant?: ListGroupVariant
11
+ variant?: ItemGroupVariant
12
+ childPropKey: 'title' | 'onPress'
16
13
  style?: ViewStyle
17
14
  }
18
15
 
19
- export interface ListGroupHeaderProps {
16
+ export interface ItemGroupHeaderProps {
20
17
  children: React.ReactNode
21
18
  style?: ViewStyle
22
19
  }
23
20
 
24
- export interface ListGroupFooterProps {
21
+ export interface ItemGroupFooterProps {
25
22
  children: React.ReactNode
26
23
  style?: ViewStyle
27
24
  }
28
25
 
29
- /**
30
- * ListGroup wraps multiple ListItems and auto-adds separators between them.
31
- * Use variant="card" for a standalone surface or "plain" for items inside another container.
32
- */
33
- export function ListGroup({ children, variant = 'plain', style }: ListGroupProps) {
26
+ export function ItemGroup({ children, variant = 'plain', childPropKey, style }: ItemGroupProps) {
34
27
  const { colors } = useTheme()
35
28
 
36
- // Auto-inject showSeparator={true} to all ListItem children except the last
37
29
  const processedChildren = React.Children.map(children, (child, index) => {
38
30
  if (!React.isValidElement(child)) return child
39
-
40
- // Skip ListGroup.Header and ListGroup.Footer
41
- if (child.type === ListGroupHeader || child.type === ListGroupFooter) {
31
+
32
+ if (child.type === ItemGroupHeader || child.type === ItemGroupFooter) {
42
33
  return child
43
34
  }
44
35
 
45
- // Check if it's a ListItem (has title prop as a heuristic)
46
36
  const childProps = child.props as Record<string, unknown>
47
- const isListItem = 'title' in childProps
48
- if (!isListItem) return child
37
+ const isTargetChild = childPropKey in childProps
38
+ if (!isTargetChild) return child
49
39
 
50
40
  const isLast = index === React.Children.count(children) - 1
51
41
 
52
- // Only add separator if not already explicitly set and not last item
53
42
  if (childProps['showSeparator'] === undefined && !isLast) {
54
43
  return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {
55
44
  showSeparator: true,
@@ -82,9 +71,9 @@ export function ListGroup({ children, variant = 'plain', style }: ListGroupProps
82
71
  )
83
72
  }
84
73
 
85
- export function ListGroupHeader({ children, style }: ListGroupHeaderProps) {
74
+ export function ItemGroupHeader({ children, style }: ItemGroupHeaderProps) {
86
75
  const { colors } = useTheme()
87
-
76
+
88
77
  if (typeof children === 'string') {
89
78
  return (
90
79
  <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>
@@ -98,9 +87,9 @@ export function ListGroupHeader({ children, style }: ListGroupHeaderProps) {
98
87
  return <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>{children}</View>
99
88
  }
100
89
 
101
- export function ListGroupFooter({ children, style }: ListGroupFooterProps) {
90
+ export function ItemGroupFooter({ children, style }: ItemGroupFooterProps) {
102
91
  const { colors } = useTheme()
103
-
92
+
104
93
  if (typeof children === 'string') {
105
94
  return (
106
95
  <View style={[styles.footer, style]}>
@@ -114,9 +103,6 @@ export function ListGroupFooter({ children, style }: ListGroupFooterProps) {
114
103
  return <View style={[styles.footer, style]}>{children}</View>
115
104
  }
116
105
 
117
- ListGroup.Header = ListGroupHeader
118
- ListGroup.Footer = ListGroupFooter
119
-
120
106
  const styles = StyleSheet.create({
121
107
  container: {
122
108
  overflow: 'hidden',
@@ -0,0 +1,2 @@
1
+ export { ItemGroup, ItemGroupHeader, ItemGroupFooter } from './ItemGroup'
2
+ export type { ItemGroupProps, ItemGroupVariant, ItemGroupHeaderProps, ItemGroupFooterProps } from './ItemGroup'
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { ItemGroup as BaseItemGroup, ItemGroupHeader, ItemGroupFooter } from '../ItemGroup'
3
+ import type { ItemGroupProps, ItemGroupVariant, ItemGroupHeaderProps, ItemGroupFooterProps } from '../ItemGroup'
4
+
5
+ export type ListGroupVariant = ItemGroupVariant
6
+
7
+ export interface ListGroupProps extends Omit<ItemGroupProps, 'childPropKey'> {}
8
+
9
+ export interface ListGroupHeaderProps extends ItemGroupHeaderProps {}
10
+
11
+ export interface ListGroupFooterProps extends ItemGroupFooterProps {}
12
+
13
+ export function ListGroup(props: ListGroupProps) {
14
+ return <BaseItemGroup childPropKey="title" {...props} />
15
+ }
16
+
17
+ ListGroup.Header = ItemGroupHeader
18
+ ListGroup.Footer = ItemGroupFooter
19
+
20
+ export { ItemGroupHeader as ListGroupHeader, ItemGroupFooter as ListGroupFooter }
@@ -85,6 +85,7 @@ export interface ListItemProps {
85
85
  captionStyle?: TextStyle
86
86
  /** Accessibility label override. Defaults to the title. */
87
87
  accessibilityLabel?: string
88
+ accessibilityHint?: string
88
89
  }
89
90
 
90
91
  function ListItemBase({
@@ -110,6 +111,7 @@ function ListItemBase({
110
111
  subtitleNumberOfLines = 2,
111
112
  captionStyle,
112
113
  accessibilityLabel,
114
+ accessibilityHint,
113
115
  }: ListItemProps) {
114
116
  const { colors } = useTheme()
115
117
 
@@ -221,6 +223,7 @@ function ListItemBase({
221
223
  activateOnHover
222
224
  accessibilityRole="button"
223
225
  accessibilityLabel={a11yLabel}
226
+ accessibilityHint={accessibilityHint}
224
227
  accessibilityState={{ disabled: !!disabled }}
225
228
  >
226
229
  {content}
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { ItemGroup as BaseItemGroup, ItemGroupHeader, ItemGroupFooter } from '../ItemGroup'
3
+ import type { ItemGroupProps, ItemGroupVariant, ItemGroupHeaderProps, ItemGroupFooterProps } from '../ItemGroup'
4
+
5
+ export type MenuGroupVariant = ItemGroupVariant
6
+
7
+ export interface MenuGroupProps extends Omit<ItemGroupProps, 'childPropKey'> {}
8
+
9
+ export interface MenuGroupHeaderProps extends ItemGroupHeaderProps {}
10
+
11
+ export interface MenuGroupFooterProps extends ItemGroupFooterProps {}
12
+
13
+ export function MenuGroup(props: MenuGroupProps) {
14
+ return <BaseItemGroup childPropKey="onPress" {...props} />
15
+ }
16
+
17
+ MenuGroup.Header = ItemGroupHeader
18
+ MenuGroup.Footer = ItemGroupFooter
19
+
20
+ export { ItemGroupHeader as MenuGroupHeader, ItemGroupFooter as MenuGroupFooter }
@@ -55,6 +55,7 @@ export interface MenuItemProps {
55
55
  labelStyle?: TextStyle
56
56
  /** Accessibility label override. Defaults to label. */
57
57
  accessibilityLabel?: string
58
+ accessibilityHint?: string
58
59
  }
59
60
 
60
61
  function MenuItemBase({
@@ -72,6 +73,7 @@ function MenuItemBase({
72
73
  style,
73
74
  labelStyle,
74
75
  accessibilityLabel,
76
+ accessibilityHint,
75
77
  }: MenuItemProps) {
76
78
  const { colors } = useTheme()
77
79
 
@@ -112,6 +114,7 @@ function MenuItemBase({
112
114
  activateOnHover
113
115
  accessibilityRole="button"
114
116
  accessibilityLabel={a11yLabel}
117
+ accessibilityHint={accessibilityHint}
115
118
  accessibilityState={{ disabled }}
116
119
  >
117
120
  {resolvedIcon ? (
@@ -19,6 +19,7 @@ export interface NumberStepperProps {
19
19
  disabled?: boolean
20
20
  style?: ViewStyle
21
21
  accessibilityLabel?: string
22
+ accessibilityHint?: string
22
23
  }
23
24
 
24
25
  const sizeConfig: Record<NumberStepperSize, { button: number; icon: number; valueFontSize: number; valueLineHeight: number; valueMinWidth: number }> = {
@@ -37,6 +38,7 @@ function NumberStepperBase({
37
38
  disabled = false,
38
39
  style,
39
40
  accessibilityLabel,
41
+ accessibilityHint,
40
42
  }: NumberStepperProps) {
41
43
  const { colors } = useTheme()
42
44
 
@@ -78,6 +80,7 @@ function NumberStepperBase({
78
80
  touchSoundDisabled
79
81
  accessibilityRole="button"
80
82
  accessibilityLabel={`Disminuir, valor actual ${displayValue}`}
83
+ accessibilityHint={accessibilityHint}
81
84
  accessibilityState={{ disabled: !canDecrement }}
82
85
  >
83
86
  <Icon name="minus" size={iconSize} color={canDecrement ? colors.foreground : colors.foregroundMuted} />
@@ -115,6 +118,7 @@ function NumberStepperBase({
115
118
  touchSoundDisabled
116
119
  accessibilityRole="button"
117
120
  accessibilityLabel={`Aumentar, valor actual ${displayValue}`}
121
+ accessibilityHint={accessibilityHint}
118
122
  accessibilityState={{ disabled: !canIncrement }}
119
123
  >
120
124
  <Icon name="plus" size={iconSize} color={canIncrement ? colors.foreground : colors.foregroundMuted} />
@@ -5,42 +5,18 @@ import { PressableCard } from '../../utils/pressable'
5
5
  import { PRESS_SCALE } from '../../utils/animations'
6
6
 
7
7
  export interface PressableProps {
8
- /** Children content to render inside the pressable. */
9
8
  children: React.ReactNode
10
- /** Called when pressed. */
11
9
  onPress?: () => void
12
- /** Scale value on press. Defaults to `0.98` (MediaCard-style). */
13
10
  pressScale?: number
14
- /** Enable haptic feedback on press. Defaults to `true`. */
15
11
  haptics?: boolean
16
- /** Additional style for the wrapper. */
17
12
  style?: ViewStyle
18
- /** Disable interaction. */
19
13
  disabled?: boolean
20
- /** Hover scale (web only). Defaults to `1.02`. Set to `1` to disable. */
21
14
  hoverScale?: number
22
- /**
23
- * Accessibility role for the pressable element.
24
- * Defaults to `"button"`.
25
- */
26
15
  accessibilityRole?: AccessibilityRole
27
- /**
28
- * Accessibility state for screen readers.
29
- * Used to communicate states like `selected`, `expanded`, `checked`, etc.
30
- * Defaults to `{ disabled: !!disabled }`.
31
- */
32
16
  accessibilityState?: Record<string, unknown>
33
- /** Accessibility label for screen readers. */
34
17
  accessibilityLabel?: string
35
18
  }
36
19
 
37
- /**
38
- * Generic pressable with a calibrated spring bounce — Apple HIG / Airbnb feel.
39
- * All animation runs on the UI thread via pressto (Reanimated v4 worklets).
40
- *
41
- * Use this for any custom pressable surface that needs consistent press feel
42
- * (cards, list rows, image tiles, etc).
43
- */
44
20
  export function Pressable({
45
21
  children,
46
22
  onPress,
@@ -0,0 +1,94 @@
1
+ import React from 'react'
2
+ import { View, ScrollView, KeyboardAvoidingView, Platform, StyleSheet, ViewStyle } from 'react-native'
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
+ import { useTheme } from '../../theme'
5
+ import { BREAKPOINTS } from '../../tokens'
6
+
7
+ export interface ScreenContainerProps {
8
+ children: React.ReactNode
9
+ /** Maximum width in points. Defaults to BREAKPOINTS.wide (700). Set to 0 to disable. */
10
+ maxWidth?: number
11
+ /** Enable scroll. Default false. */
12
+ scroll?: boolean
13
+ /** Background color. Defaults to theme `background`. */
14
+ backgroundColor?: string
15
+ /** Padding top override. Defaults to safe area top. */
16
+ paddingTop?: number
17
+ /** Padding bottom override. Defaults to safe area bottom. */
18
+ paddingBottom?: number
19
+ /** Horizontal padding. Defaults to 0. */
20
+ paddingHorizontal?: number
21
+ /** Enable keyboard avoidance. Default false. */
22
+ keyboard?: boolean
23
+ style?: ViewStyle
24
+ }
25
+
26
+ export function ScreenContainer({
27
+ children,
28
+ maxWidth = BREAKPOINTS.wide,
29
+ scroll = false,
30
+ backgroundColor,
31
+ paddingTop,
32
+ paddingBottom,
33
+ paddingHorizontal,
34
+ keyboard = false,
35
+ style: _style,
36
+ }: ScreenContainerProps) {
37
+ const insets = useSafeAreaInsets()
38
+ const { colors } = useTheme()
39
+
40
+ const wrapperStyle: ViewStyle = {
41
+ flex: 1,
42
+ backgroundColor: backgroundColor ?? colors.background,
43
+ paddingTop: paddingTop ?? insets.top,
44
+ paddingBottom: paddingBottom ?? insets.bottom,
45
+ paddingHorizontal: paddingHorizontal ?? 0,
46
+ ..._style,
47
+ }
48
+
49
+ const inner = (
50
+ <View style={[styles.inner, { maxWidth: maxWidth || undefined }]}>
51
+ {children}
52
+ </View>
53
+ )
54
+
55
+ const content = scroll ? (
56
+ <ScrollView
57
+ style={styles.scroll}
58
+ contentContainerStyle={styles.scrollContent}
59
+ keyboardShouldPersistTaps="handled"
60
+ >
61
+ {inner}
62
+ </ScrollView>
63
+ ) : (
64
+ inner
65
+ )
66
+
67
+ if (keyboard) {
68
+ return (
69
+ <KeyboardAvoidingView
70
+ style={wrapperStyle}
71
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
72
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 0}
73
+ >
74
+ {content}
75
+ </KeyboardAvoidingView>
76
+ )
77
+ }
78
+
79
+ return <View style={wrapperStyle}>{content}</View>
80
+ }
81
+
82
+ const styles = StyleSheet.create({
83
+ scroll: {
84
+ flex: 1,
85
+ },
86
+ scrollContent: {
87
+ flexGrow: 1,
88
+ },
89
+ inner: {
90
+ flex: 1,
91
+ alignSelf: 'center',
92
+ width: '100%',
93
+ },
94
+ })
@@ -0,0 +1,2 @@
1
+ export { ScreenContainer } from './ScreenContainer'
2
+ export type { ScreenContainerProps } from './ScreenContainer'
@@ -28,6 +28,7 @@ export interface SelectProps {
28
28
  disabled?: boolean
29
29
  style?: ViewStyle
30
30
  accessibilityLabel?: string
31
+ accessibilityHint?: string
31
32
  }
32
33
 
33
34
  export function Select({
@@ -41,6 +42,7 @@ export function Select({
41
42
  disabled,
42
43
  style,
43
44
  accessibilityLabel,
45
+ accessibilityHint,
44
46
  }: SelectProps) {
45
47
  const { colors } = useTheme()
46
48
  const [pickerVisible, setPickerVisible] = useState(false)
@@ -49,6 +51,25 @@ export function Select({
49
51
 
50
52
  const selected = options.find((o) => o.value === value)
51
53
 
54
+ function renderPickerItems(includePlaceholder: boolean, itemColor?: string, disabledColor?: string) {
55
+ return (
56
+ <>
57
+ {includePlaceholder ? (
58
+ <Picker.Item label={placeholder} value="" enabled={false} color={disabledColor} />
59
+ ) : null}
60
+ {options.map((o) => (
61
+ <Picker.Item
62
+ key={o.value}
63
+ label={o.label}
64
+ value={o.value}
65
+ enabled={!o.disabled}
66
+ color={o.disabled ? disabledColor : itemColor}
67
+ />
68
+ ))}
69
+ </>
70
+ )
71
+ }
72
+
52
73
  const handleOpen = () => {
53
74
  if (disabled) return
54
75
  hapticSelection()
@@ -93,6 +114,7 @@ export function Select({
93
114
  touchSoundDisabled
94
115
  accessibilityRole="combobox"
95
116
  accessibilityLabel={accessibilityLabel ?? label}
117
+ accessibilityHint={accessibilityHint}
96
118
  accessibilityValue={{ text: selected?.label ?? placeholder }}
97
119
  accessibilityState={{ disabled: !!disabled, expanded: pickerVisible }}
98
120
  >
@@ -139,18 +161,7 @@ export function Select({
139
161
  onValueChange={(val) => setPendingValue(val as string)}
140
162
  itemStyle={{ color: colors.foreground }}
141
163
  >
142
- {!value ? (
143
- <Picker.Item label={placeholder} value="" color={colors.foregroundMuted} enabled={false} />
144
- ) : null}
145
- {options.map((o) => (
146
- <Picker.Item
147
- key={o.value}
148
- label={o.label}
149
- value={o.value}
150
- enabled={!o.disabled}
151
- color={o.disabled ? colors.foregroundMuted : colors.foreground}
152
- />
153
- ))}
164
+ {renderPickerItems(!value, colors.foreground, colors.foregroundMuted)}
154
165
  </Picker>
155
166
  </View>
156
167
  </Modal>
@@ -172,15 +183,7 @@ export function Select({
172
183
  prompt={label}
173
184
  style={styles.androidHiddenPicker}
174
185
  >
175
- {!value ? <Picker.Item label={placeholder} value="" enabled={false} /> : null}
176
- {options.map((o) => (
177
- <Picker.Item
178
- key={o.value}
179
- label={o.label}
180
- value={o.value}
181
- enabled={!o.disabled}
182
- />
183
- ))}
186
+ {renderPickerItems(!value)}
184
187
  </Picker>
185
188
  ) : null}
186
189
 
@@ -204,15 +207,7 @@ export function Select({
204
207
  },
205
208
  ]}
206
209
  >
207
- <Picker.Item label={placeholder} value="" enabled={false} />
208
- {options.map((o) => (
209
- <Picker.Item
210
- key={o.value}
211
- label={o.label}
212
- value={o.value}
213
- enabled={!o.disabled}
214
- />
215
- ))}
210
+ {renderPickerItems(true)}
216
211
  </Picker>
217
212
  ) : null}
218
213
 
@@ -1,5 +1,6 @@
1
1
  import React, { useState } from 'react'
2
- import { View, Text, StyleSheet, ViewStyle, ScrollView } from 'react-native'
2
+ import { View, Text, StyleSheet, ViewStyle, ScrollView, ImageSourcePropType } from 'react-native'
3
+ import { Image } from 'expo-image'
3
4
  import { useTheme } from '../../theme'
4
5
  import { Icon } from '../../utils/icons'
5
6
  import { PressableChip } from '../../utils/pressable'
@@ -12,6 +13,7 @@ export interface SelectableGridItem<T extends string | number = string> {
12
13
  label?: string
13
14
  iconName?: string
14
15
  icon?: React.ReactNode
16
+ imageUrl?: ImageSourcePropType
15
17
  disabled?: boolean
16
18
  }
17
19
 
@@ -40,10 +42,13 @@ interface CellProps<T extends string | number> {
40
42
 
41
43
  function Cell<T extends string | number>({ item, selected, width, onPress }: CellProps<T>) {
42
44
  const { colors } = useTheme()
45
+ const hasImage = !!item.imageUrl
43
46
 
44
47
  const iconColor = selected ? colors.primary : colors.foregroundSubtle
45
48
  const iconNode = item.icon ?? (item.iconName ? <Icon name={item.iconName} size={ms(24)} color={iconColor} /> : null)
46
49
 
50
+ const imageSize = width - 4
51
+
47
52
  return (
48
53
  <PressableChip
49
54
  onPress={onPress}
@@ -54,26 +59,40 @@ function Cell<T extends string | number>({ item, selected, width, onPress }: Cel
54
59
  accessibilityRole="button"
55
60
  accessibilityState={{ selected, disabled: item.disabled }}
56
61
  accessibilityLabel={item.label ?? String(item.value)}
57
- style={[
58
- { width },
59
- styles.cell,
60
- {
61
- backgroundColor: selected ? colors.primary + '14' : colors.surface,
62
- borderColor: selected ? colors.primary : 'transparent',
63
- },
64
- item.disabled && styles.cellDisabled,
65
- ]}
66
62
  >
67
- {iconNode}
68
- {item.label ? (
69
- <Text
70
- style={[styles.label, { color: selected ? colors.primary : colors.foreground }]}
71
- numberOfLines={1}
72
- allowFontScaling={true}
73
- >
74
- {item.label}
75
- </Text>
76
- ) : null}
63
+ <View
64
+ style={[
65
+ { width },
66
+ styles.cell,
67
+ hasImage && styles.cellImage,
68
+ {
69
+ borderColor: selected ? colors.primary : 'transparent',
70
+ },
71
+ item.disabled && styles.cellDisabled,
72
+ ]}
73
+ >
74
+ {hasImage ? (
75
+ <Image
76
+ source={item.imageUrl}
77
+ style={{ width: imageSize, height: imageSize }}
78
+ contentFit="cover"
79
+ />
80
+ ) : null}
81
+ {iconNode && !hasImage ? iconNode : null}
82
+ {item.label ? (
83
+ <Text
84
+ style={[
85
+ styles.label,
86
+ hasImage && styles.labelImage,
87
+ { color: selected ? colors.primary : colors.foreground },
88
+ ]}
89
+ numberOfLines={2}
90
+ allowFontScaling={true}
91
+ >
92
+ {item.label}
93
+ </Text>
94
+ ) : null}
95
+ </View>
77
96
  </PressableChip>
78
97
  )
79
98
  }
@@ -159,6 +178,13 @@ const styles = StyleSheet.create({
159
178
  paddingHorizontal: s(8),
160
179
  paddingVertical: vs(10),
161
180
  },
181
+ cellImage: {
182
+ padding: 0,
183
+ gap: 0,
184
+ overflow: 'hidden',
185
+ alignItems: 'stretch',
186
+ justifyContent: 'flex-start',
187
+ },
162
188
  cellDisabled: {
163
189
  opacity: 0.4,
164
190
  },
@@ -168,4 +194,9 @@ const styles = StyleSheet.create({
168
194
  lineHeight: mvs(14),
169
195
  textAlign: 'center',
170
196
  },
197
+ labelImage: {
198
+ paddingHorizontal: s(6),
199
+ paddingBottom: vs(6),
200
+ paddingTop: vs(3),
201
+ },
171
202
  })