@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
package/dist/index.mjs CHANGED
@@ -1,68 +1,65 @@
1
- export { Toggle } from './chunk-UNNRUJTM.mjs';
2
- export { VirtualList } from './chunk-NC5ZTR2Y.mjs';
3
- export { Stats } from './chunk-4XOB5TTD.mjs';
4
- export { Switch } from './chunk-RMRS44MQ.mjs';
5
- export { TabBar } from './chunk-NJG7DHVF.mjs';
6
- export { Tabs, TabsContent } from './chunk-IVSRW4HS.mjs';
7
- export { Text } from './chunk-GUTDFUNF.mjs';
8
- export { Textarea } from './chunk-2BA3JMKK.mjs';
9
- export { Select } from './chunk-HEDQPK4I.mjs';
10
- export { SelectableCard, SelectableCardGroup } from './chunk-2P2CB235.mjs';
11
- export { SelectableGrid } from './chunk-ZR6HSEAB.mjs';
12
- export { Separator } from './chunk-VJBUCITV.mjs';
13
- export { BottomSheetModalProvider, Sheet, BottomSheetTextInput as SheetTextInput } from './chunk-M3C7XM2M.mjs';
14
- export { SheetSelect } from './chunk-KSUWPU2F.mjs';
15
- export { Skeleton } from './chunk-QDAZGZUF.mjs';
16
- export { Slider } from './chunk-RJNLAH76.mjs';
17
- export { MonthPicker, dateToMonthPickerValue, monthPickerValueToDate } from './chunk-AENAVIKT.mjs';
18
- export { NumberStepper } from './chunk-ELGEOM7I.mjs';
19
- export { Pressable } from './chunk-E7NEHHXV.mjs';
20
- export { PricingCard } from './chunk-E5UKLSJZ.mjs';
21
- export { Progress } from './chunk-TS7DGUIR.mjs';
22
- export { RadioGroup } from './chunk-LNPKGWBG.mjs';
23
- export { RetrayProvider } from './chunk-ZIMY2QUM.mjs';
24
- export { ToastProvider, sonnerToast as toast, useToast } from './chunk-YMYIEVZP.mjs';
25
- export { ImageViewer } from './chunk-LPV4NJJK.mjs';
26
- export { PagerDots } from './chunk-OLVJFKXS.mjs';
27
- export { LabelValue } from './chunk-57V2LXCK.mjs';
28
- export { ListGroup, ListGroupFooter, ListGroupHeader } from './chunk-C43HRKXH.mjs';
29
- export { ListItem } from './chunk-EDLCGYIO.mjs';
30
- export { MediaCard } from './chunk-7ELGZ66G.mjs';
31
- export { MenuGroup, MenuGroupFooter, MenuGroupHeader } from './chunk-ULGNQPNE.mjs';
32
- export { MenuItem } from './chunk-UQ4742ET.mjs';
33
- export { DetailRow } from './chunk-2LG326TT.mjs';
34
- export { EmptyState } from './chunk-HC4VVCWY.mjs';
35
- export { ErrorBoundary } from './chunk-NLZY4TXU.mjs';
36
- export { Form, FormField, FormFooter, FormSection } from './chunk-7AFZWSCI.mjs';
37
- export { IconPicker } from './chunk-SAWUXP3A.mjs';
38
- export { ImageUpload } from './chunk-CF27NBXO.mjs';
39
- export { Spinner } from './chunk-LIS6I5UP.mjs';
1
+ export { Toggle } from './chunk-RRKM4MKB.mjs';
2
+ export { Stats } from './chunk-ZKDKKQCE.mjs';
3
+ export { Switch } from './chunk-E2PONRJG.mjs';
4
+ export { TabBar } from './chunk-U6DEBYU5.mjs';
5
+ export { Tabs, TabsContent } from './chunk-KC5QDYGZ.mjs';
6
+ export { Text } from './chunk-EHGBHFMH.mjs';
7
+ export { Textarea } from './chunk-L3YKPTJQ.mjs';
8
+ export { Select } from './chunk-IDVUZIVY.mjs';
9
+ export { SelectableCard, SelectableCardGroup } from './chunk-BULKGOIZ.mjs';
10
+ export { SelectableGrid } from './chunk-NPCBNGNE.mjs';
11
+ export { Separator } from './chunk-EW2FIDSM.mjs';
12
+ export { BottomSheetModalProvider, Sheet, SheetContent, SheetFooter, SheetHeader, BottomSheetTextInput as SheetTextInput } from './chunk-7BZJRB77.mjs';
13
+ export { SheetSelect } from './chunk-WIPEDNSD.mjs';
14
+ export { Skeleton } from './chunk-XCIG6HT2.mjs';
15
+ export { Slider } from './chunk-C5ZRMR2E.mjs';
16
+ export { MonthPicker, dateToMonthPickerValue, monthPickerValueToDate } from './chunk-ITG4JQM3.mjs';
17
+ export { NumberStepper } from './chunk-2QXJDRVU.mjs';
18
+ export { Pressable } from './chunk-62BBSSUF.mjs';
19
+ export { PricingCard } from './chunk-K3QX2M26.mjs';
20
+ export { Progress } from './chunk-DBHSUUKU.mjs';
21
+ export { RadioGroup } from './chunk-IJCMPVW5.mjs';
22
+ export { RetrayProvider } from './chunk-ERWJPVX7.mjs';
23
+ export { ToastProvider, sonnerToast as toast, useToast } from './chunk-SZEKQAOY.mjs';
24
+ export { ImageViewer } from './chunk-PGQ6FMXS.mjs';
25
+ export { PagerDots } from './chunk-S44XWTTC.mjs';
26
+ export { LabelValue } from './chunk-DE25XTVQ.mjs';
27
+ export { ListGroup, ListGroupFooter, ListGroupHeader } from './chunk-OBV72JD4.mjs';
28
+ export { ListItem } from './chunk-CZN6L2QU.mjs';
29
+ export { MediaCard } from './chunk-CM2DG4MR.mjs';
30
+ export { MenuGroup, MenuGroupFooter, MenuGroupHeader } from './chunk-S2VGME7X.mjs';
31
+ export { MenuItem } from './chunk-COA2YZOX.mjs';
32
+ export { DetailRow } from './chunk-KAGADD2O.mjs';
33
+ export { EmptyState } from './chunk-FTTI6T5Q.mjs';
34
+ export { ErrorBoundary } from './chunk-ESQDPO5E.mjs';
35
+ export { Form, FormField, FormFooter, FormSection } from './chunk-KPTY7UYQ.mjs';
36
+ export { IconPicker } from './chunk-NGEN2EES.mjs';
37
+ export { ImageUpload } from './chunk-HHOOFDBA.mjs';
38
+ export { Spinner } from './chunk-2VIDP72N.mjs';
40
39
  export { ButtonGroup } from './chunk-3BBOZ3OQ.mjs';
41
- export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-BXF4AMHY.mjs';
42
- export { CategoryStrip } from './chunk-3XCFYSX4.mjs';
43
- import './chunk-YNROWHQJ.mjs';
44
- export { Checkbox } from './chunk-UBUXUMER.mjs';
45
- export { Chip, ChipGroup } from './chunk-F3YTWO3T.mjs';
46
- export { ConfirmDialog } from './chunk-QXDGGOLC.mjs';
47
- export { CurrencyDisplay } from './chunk-MEPSKGBO.mjs';
48
- export { CurrencyInput } from './chunk-2HFD4IHU.mjs';
49
- export { Input } from './chunk-DF7JA72E.mjs';
50
- export { Accordion } from './chunk-NHDI3VQB.mjs';
51
- export { AlertBanner } from './chunk-4OORJ2DY.mjs';
52
- export { AppHeader } from './chunk-MVMGPZN6.mjs';
53
- export { IconButton } from './chunk-LOBLCFMN.mjs';
54
- export { Avatar } from './chunk-QOLWA2PW.mjs';
55
- export { Badge } from './chunk-GH67YXG6.mjs';
56
- export { Button } from './chunk-4J2PXL36.mjs';
57
- import './chunk-3DKJ2GIC.mjs';
58
- export { impactHeavy, impactLight, impactMedium, notificationError, notificationSuccess, notificationWarning, richHaptics, selectionAsync } from './chunk-EJ7ZPXOH.mjs';
59
- import './chunk-DVK4G2GT.mjs';
40
+ export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-TMH263OK.mjs';
41
+ export { CategoryStrip } from './chunk-5MYNAAFE.mjs';
42
+ export { Checkbox } from './chunk-77UOVFIS.mjs';
43
+ export { Chip, ChipGroup } from './chunk-RA6SAAFE.mjs';
44
+ export { ConfirmDialog } from './chunk-UMZTPUB3.mjs';
45
+ export { CurrencyDisplay } from './chunk-PI6RULJX.mjs';
46
+ export { CurrencyInput } from './chunk-HUSSF6TF.mjs';
47
+ export { Input } from './chunk-4NQFTHN3.mjs';
48
+ export { Accordion } from './chunk-422IVD3H.mjs';
49
+ export { AlertBanner } from './chunk-K7TKID3V.mjs';
50
+ export { AppHeader } from './chunk-H6MQL7PS.mjs';
51
+ export { IconButton } from './chunk-ZTPYUU5C.mjs';
52
+ export { Avatar, AvatarGroup } from './chunk-IGU223UM.mjs';
53
+ export { Badge } from './chunk-AZV7KNJI.mjs';
54
+ export { Button } from './chunk-Y6YS33GM.mjs';
55
+ import './chunk-M53LC4Q7.mjs';
56
+ import './chunk-IFYMBOEN.mjs';
57
+ export { impactHeavy, impactLight, impactMedium, notificationError, notificationSuccess, notificationWarning, selectionAsync } from './chunk-ARONDO7M.mjs';
60
58
  export { BREAKPOINTS, ICON_SIZES, RADIUS, SHADOWS, SPACING, TYPOGRAPHY } from './chunk-QY3X2UYR.mjs';
61
- export { Icon, configureIconFamilies, getValidIconNames, renderIcon } from './chunk-KA7LTET3.mjs';
62
- export { ThemeProvider, defaultDark, defaultLight, deriveColors, useTheme, withAlpha } from './chunk-YTXRIXNZ.mjs';
59
+ export { Icon } from './chunk-MZ6WRTD2.mjs';
60
+ export { ThemeProvider, defaultDark, defaultLight, deriveColors, hexToRgb, useTheme, withAlpha } from './chunk-KSSVIFYR.mjs';
63
61
  import './chunk-2CE3TQVY.mjs';
64
- import './chunk-Y6FXYEAI.mjs';
65
- import { useState, useCallback } from 'react';
62
+ import { useState, useRef, useEffect, useCallback } from 'react';
66
63
 
67
64
  // src/utils/typography.ts
68
65
  function getResponsiveFontSize(text, maxSize, steps = [
@@ -79,39 +76,37 @@ function getResponsiveFontSize(text, maxSize, steps = [
79
76
  }
80
77
  function useConfirmDialog(options) {
81
78
  const [visible, setVisible] = useState(false);
82
- const [target, setTarget] = useState(null);
83
79
  const [loading, setLoading] = useState(false);
84
- const open = useCallback((t) => {
85
- setTarget(t ?? null);
86
- setVisible(true);
80
+ const mountedRef = useRef(true);
81
+ const onConfirmRef = useRef(options.onConfirm);
82
+ const onCancelRef = useRef(options.onCancel);
83
+ useEffect(() => {
84
+ onConfirmRef.current = options.onConfirm;
85
+ onCancelRef.current = options.onCancel;
86
+ });
87
+ useEffect(() => {
88
+ return () => {
89
+ mountedRef.current = false;
90
+ };
87
91
  }, []);
92
+ const open = useCallback(() => setVisible(true), []);
88
93
  const handleConfirm = useCallback(async () => {
89
94
  setLoading(true);
90
95
  try {
91
- await options.onConfirm();
96
+ await onConfirmRef.current();
97
+ } catch {
92
98
  } finally {
93
- setLoading(false);
94
- setVisible(false);
95
- setTarget(null);
99
+ if (mountedRef.current) {
100
+ setLoading(false);
101
+ setVisible(false);
102
+ }
96
103
  }
97
- }, [options]);
104
+ }, []);
98
105
  const handleCancel = useCallback(() => {
99
106
  setVisible(false);
100
- setTarget(null);
101
- options.onCancel?.();
102
- }, [options]);
103
- return {
104
- visible,
105
- target,
106
- loading,
107
- open,
108
- dialogProps: {
109
- visible,
110
- loading,
111
- onConfirm: handleConfirm,
112
- onCancel: handleCancel
113
- }
114
- };
107
+ onCancelRef.current?.();
108
+ }, []);
109
+ return { visible, loading, open, onConfirm: handleConfirm, onCancel: handleCancel };
115
110
  }
116
111
 
117
112
  export { getResponsiveFontSize, useConfirmDialog };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retray-dev/ui-kit",
3
- "version": "12.2.0",
3
+ "version": "13.2.0",
4
4
  "description": "Personal UI Kit for React Native / Expo",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -26,11 +26,11 @@
26
26
  "dist",
27
27
  "src",
28
28
  "scripts",
29
- "COMPONENTS.md",
30
29
  "CONSUMER.md",
31
30
  "EXAMPLES.md",
32
31
  "FONTS.md",
33
- "DESIGN.md"
32
+ "DESIGN.md",
33
+ "SKILL.md"
34
34
  ],
35
35
  "scripts": {
36
36
  "postinstall": "node scripts/copy-fonts.js",
@@ -65,15 +65,16 @@
65
65
  "@shopify/react-native-skia": ">=1.0.0",
66
66
  "expo-font": ">=14.0.0",
67
67
  "expo-haptics": ">=14.0.0",
68
- "expo-image-picker": ">=15.0.0",
68
+ "expo-image": ">=3.0.0",
69
+ "react-native-image-picker": ">=7.0.0",
69
70
  "expo-linear-gradient": ">=13.0.0",
71
+ "expo-modules-core": ">=3.0.0",
70
72
  "expo-sensors": ">=13.0.0",
71
73
  "pressto": ">=0.6.0",
72
74
  "react": ">=17",
73
75
  "react-native": ">=0.76",
74
76
  "react-native-ease": ">=0.7.0",
75
77
  "react-native-gesture-handler": ">=2.0.0",
76
- "react-native-pulsar": ">=1.6.0",
77
78
  "react-native-reanimated": ">=4.0.0 <5.0.0",
78
79
  "react-native-safe-area-context": ">=4.0.0",
79
80
  "react-native-screens": ">=3.0.0",
@@ -89,17 +90,15 @@
89
90
  "expo-sensors": {
90
91
  "optional": true
91
92
  },
92
- "react-native-pulsar": {
93
- "optional": true
94
- },
95
- "expo-image-picker": {
96
- "optional": true
97
- },
93
+
98
94
  "react-native-ease": {
99
95
  "optional": false
100
96
  },
101
97
  "pressto": {
102
98
  "optional": false
99
+ },
100
+ "react-native-image-picker": {
101
+ "optional": true
103
102
  }
104
103
  },
105
104
  "pnpm": {
@@ -110,7 +109,8 @@
110
109
  "react-native-worklets": "0.5.1",
111
110
  "@types/react": "19.1.17",
112
111
  "react-native-safe-area-context": "5.6.2",
113
- "@gorhom/bottom-sheet": "5.2.14"
112
+ "@gorhom/bottom-sheet": "5.2.14",
113
+ "expo": "54.0.35"
114
114
  },
115
115
  "onlyBuiltDependencies": [
116
116
  "esbuild"
@@ -124,32 +124,32 @@
124
124
  "@react-native-picker/picker": "2.11.1",
125
125
  "@shopify/react-native-skia": "2.2.12",
126
126
  "@testing-library/react-native": "^14.0.0",
127
- "@types/jest": "^30.0.0",
127
+ "@types/jest": "^29.5.14",
128
128
  "@types/react": "19.1.17",
129
129
  "babel-preset-expo": "~54.0.11",
130
130
  "eslint": "^9.0.0",
131
131
  "eslint-config-prettier": "^10.0.0",
132
132
  "eslint-plugin-react": "^7.37.0",
133
133
  "eslint-plugin-react-hooks": "^7.1.1",
134
- "expo-font": "~14.0.11",
134
+ "expo-font": "~14.0.12",
135
135
  "expo-haptics": "~15.0.8",
136
+ "expo-image": "~3.0.11",
136
137
  "expo-linear-gradient": "~15.0.8",
137
- "expo-sensors": "~15.0.7",
138
+ "expo-sensors": "~15.0.8",
138
139
  "jest-expo": "~54.0.17",
139
- "pressto": "^0.6.1",
140
+ "pressto": "^0.7.0",
140
141
  "prettier": "^3.8.3",
141
142
  "react": "19.1.0",
142
143
  "react-native": "0.81.5",
143
- "react-native-ease": "^0.7.2",
144
+ "react-native-ease": "^0.7.3",
144
145
  "react-native-gesture-handler": "~2.28.0",
145
- "react-native-pulsar": "^1.6.1",
146
146
  "react-native-reanimated": "~4.1.1",
147
147
  "react-native-safe-area-context": "5.6.2",
148
148
  "react-native-screens": "4.16.0",
149
149
  "react-native-size-matters": "^0.4.2",
150
- "react-native-svg": "15.12.1",
150
+ "react-native-svg": "15.15.5",
151
151
  "react-native-worklets": "~0.5.1",
152
- "sonner-native": "0.23.1",
152
+ "sonner-native": "0.26.3",
153
153
  "test-renderer": "^1.2.0",
154
154
  "tsup": "^8.0.0",
155
155
  "typescript": "^5.4.0",
@@ -2,11 +2,11 @@ import React, { useState } from 'react'
2
2
  import {
3
3
  View,
4
4
  Text,
5
- Pressable,
6
5
  StyleSheet,
7
6
  ViewStyle,
8
7
  } from 'react-native'
9
8
  import Animated, {
9
+ Easing,
10
10
  useSharedValue,
11
11
  useDerivedValue,
12
12
  useAnimatedStyle,
@@ -16,8 +16,9 @@ import { Entypo } from '@expo/vector-icons'
16
16
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
17
17
  import { useTheme } from '../../theme'
18
18
  import { s, vs, ms } from '../../utils/scaling'
19
- import { renderIcon } from '../../utils/icons'
20
- import { TIMINGS, EASINGS } from '../../utils/animations'
19
+ import { Icon } from '../../utils/icons'
20
+ import { TIMINGS } from '../../utils/animations'
21
+ import { PressableRow } from '../../utils/pressable'
21
22
 
22
23
  export interface AccordionItem {
23
24
  value: string
@@ -29,12 +30,14 @@ export interface AccordionItem {
29
30
  icon?: React.ReactNode
30
31
  /** Override icon color. Defaults to foregroundMuted. */
31
32
  iconColor?: string
33
+ /**
32
34
  /**
33
35
  * Action buttons rendered after the trigger content but before the chevron.
34
36
  * Automatically touch-isolated — taps on actions won't toggle the accordion.
35
37
  * Use this instead of embedding interactive elements inside `trigger`.
36
38
  */
37
39
  triggerActions?: React.ReactNode
40
+ accessibilityHint?: string
38
41
  }
39
42
 
40
43
  export interface AccordionProps {
@@ -61,7 +64,7 @@ function AccordionItemComponent({
61
64
  const { colors } = useTheme()
62
65
 
63
66
  const resolvedIcon = item.iconName
64
- ? renderIcon(item.iconName, ms(16), item.iconColor ?? colors.foregroundMuted)
67
+ ? <Icon name={item.iconName} size={ms(16)} color={item.iconColor ?? colors.foregroundMuted} />
65
68
  : item.icon
66
69
 
67
70
  // Shared values — all animation lives on the UI thread
@@ -78,14 +81,14 @@ function AccordionItemComponent({
78
81
  const derivedHeight = useDerivedValue(() =>
79
82
  withTiming(height.value * Number(isExpanded.value), {
80
83
  duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
81
- easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse,
84
+ easing: isExpanded.value ? Easing.bezier(0.23, 1, 0.32, 1) : Easing.in(Easing.ease),
82
85
  })
83
86
  )
84
87
 
85
88
  const derivedRotation = useDerivedValue(() =>
86
89
  withTiming(isExpanded.value ? 1 : 0, {
87
90
  duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
88
- easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse,
91
+ easing: isExpanded.value ? Easing.bezier(0.23, 1, 0.32, 1) : Easing.in(Easing.ease),
89
92
  })
90
93
  )
91
94
 
@@ -100,15 +103,18 @@ function AccordionItemComponent({
100
103
 
101
104
  return (
102
105
  <View style={[styles.item, { backgroundColor: colors.card, borderColor: colors.border }]}>
103
- <Pressable
104
- style={({ pressed }) => [styles.trigger, { opacity: pressed ? 0.6 : 1 }]}
106
+ <PressableRow
105
107
  onPress={() => {
106
108
  hapticSelection()
107
109
  onToggle()
108
110
  }}
111
+ rippleColor="transparent"
112
+ touchSoundDisabled
109
113
  accessibilityRole="button"
110
114
  accessibilityState={{ expanded: isOpen }}
111
115
  accessibilityLabel={typeof item.trigger === 'string' ? item.trigger : undefined}
116
+ accessibilityHint={item.accessibilityHint}
117
+ style={styles.trigger}
112
118
  >
113
119
  <View style={styles.triggerContent}>
114
120
  {resolvedIcon ? <View style={styles.icon}>{resolvedIcon}</View> : null}
@@ -129,7 +135,7 @@ function AccordionItemComponent({
129
135
  <Animated.View style={[styles.chevron, rotationStyle]}>
130
136
  <Entypo name="chevron-down" size={18} color={colors.foregroundMuted} />
131
137
  </Animated.View>
132
- </Pressable>
138
+ </PressableRow>
133
139
 
134
140
  {/*
135
141
  The Animated.View height is driven by derivedHeight (0 when closed, full height when open).
@@ -3,7 +3,7 @@ import { View, Text, StyleSheet, ViewStyle, TouchableOpacity } from 'react-nativ
3
3
  import { FontAwesome5, MaterialIcons, Entypo, Feather } from '@expo/vector-icons'
4
4
  import { useTheme } from '../../theme'
5
5
  import { s, vs, ms } from '../../utils/scaling'
6
- import { renderIcon } from '../../utils/icons'
6
+ import { Icon } from '../../utils/icons'
7
7
  import { RADIUS } from '../../tokens'
8
8
 
9
9
  export type AlertBannerVariant = 'default' | 'destructive' | 'success' | 'warning'
@@ -60,7 +60,7 @@ export function AlertBanner({ title, description, variant = 'default', icon, ico
60
60
  )
61
61
 
62
62
  const effectiveIcon: React.ReactNode = iconName
63
- ? renderIcon(iconName, ms(16), iconColor ?? accentColor)
63
+ ? <Icon name={iconName} size={ms(16)} color={iconColor ?? accentColor} />
64
64
  : icon ?? defaultIcon
65
65
 
66
66
  // Accessibility: AlertBanner is a notification — "alert" role announces it.
@@ -87,9 +87,10 @@ export function AlertBanner({ title, description, variant = 'default', icon, ico
87
87
  <TouchableOpacity
88
88
  onPress={onDismiss}
89
89
  style={styles.dismissButton}
90
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
90
91
  activeOpacity={0.6}
91
92
  accessibilityRole="button"
92
- accessibilityLabel="Dismiss"
93
+ accessibilityLabel="Descartar"
93
94
  >
94
95
  <Feather name="x" size={ms(16)} color={colors.foregroundMuted} />
95
96
  </TouchableOpacity>
@@ -123,8 +124,8 @@ const styles = StyleSheet.create({
123
124
  fontSize: ms(12),
124
125
  },
125
126
  dismissButton: {
126
- padding: s(4),
127
- marginTop: vs(-2),
128
- marginRight: -s(4),
127
+ padding: s(10),
128
+ marginTop: vs(-8),
129
+ marginRight: -s(10),
129
130
  },
130
131
  })
@@ -3,6 +3,7 @@ import { View, Text, StyleSheet, ViewStyle, useWindowDimensions } from 'react-na
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
4
  import { useTheme } from '../../theme'
5
5
  import { IconButton } from '../IconButton'
6
+ import { Icon } from '../../utils/icons'
6
7
  import { s, vs, ms, mvs } from '../../utils/scaling'
7
8
  import { BREAKPOINTS } from '../../tokens'
8
9
 
@@ -15,7 +16,9 @@ export interface AppHeaderProps {
15
16
  onBack?: () => void
16
17
  /** Icon name for the back button. Defaults to `'chevron-left'`. */
17
18
  backIconName?: string
18
- /** Custom left content overrides the back button. */
19
+ /** Icon name for a decorative icon shown left of the title, after the back button. Ignored when `left` is provided. */
20
+ iconName?: string
21
+ /** Custom left content — overrides the back button and `iconName`. */
19
22
  left?: React.ReactNode
20
23
  /** Custom right content (actions). */
21
24
  right?: React.ReactNode
@@ -40,12 +43,14 @@ export interface AppHeaderProps {
40
43
  *
41
44
  * @example
42
45
  * <AppHeader title="Settings" onBack={navigation.goBack} right={<IconButton iconName="more-horizontal" variant="text" />} />
46
+ * <AppHeader title="Perfil" iconName="user" onBack={navigation.goBack} />
43
47
  */
44
48
  export function AppHeader({
45
49
  title,
46
50
  subtitle,
47
51
  onBack,
48
52
  backIconName = 'chevron-left',
53
+ iconName,
49
54
  left,
50
55
  right,
51
56
  titleAlign = 'auto',
@@ -61,15 +66,22 @@ export function AppHeader({
61
66
  const isWide = width >= BREAKPOINTS.wide
62
67
  const centered = titleAlign === 'center' || (titleAlign === 'auto' && isWide)
63
68
 
64
- const leftNode = left ?? (onBack ? (
65
- <IconButton
66
- iconName={backIconName}
67
- variant="text"
68
- size="md"
69
- onPress={onBack}
70
- accessibilityLabel="Go back"
71
- />
72
- ) : null)
69
+ const leftNode = left ?? (
70
+ <>
71
+ {onBack ? (
72
+ <IconButton
73
+ iconName={backIconName}
74
+ variant="text"
75
+ size="md"
76
+ onPress={onBack}
77
+ accessibilityLabel="Atrás"
78
+ />
79
+ ) : null}
80
+ {iconName && !left ? (
81
+ <Icon name={iconName} size={20} color={colors.foreground} />
82
+ ) : null}
83
+ </>
84
+ )
73
85
 
74
86
  const titleBlock = (
75
87
  <View style={[styles.titleBlock, centered && styles.titleBlockCentered]} pointerEvents="none">
@@ -143,9 +155,12 @@ const styles = StyleSheet.create({
143
155
  flexDirection: 'row',
144
156
  alignItems: 'center',
145
157
  justifyContent: 'flex-start',
158
+ paddingLeft: s(8),
159
+ gap: s(4),
146
160
  },
147
161
  sideRight: {
148
162
  justifyContent: 'flex-end',
163
+ paddingRight: s(8),
149
164
  },
150
165
  titleBlock: {
151
166
  flex: 1,
@@ -1,7 +1,9 @@
1
1
  import React, { useState } from 'react'
2
- import { View, Text, Image, StyleSheet, ViewStyle } from 'react-native'
2
+ import { Image } from 'expo-image'
3
+ import { View, Text, StyleSheet, ViewStyle, TouchableOpacity } from 'react-native'
3
4
  import { useTheme } from '../../theme'
4
5
  import { s, ms } from '../../utils/scaling'
6
+ import { vs } from '../../utils/scaling'
5
7
 
6
8
  export type AvatarSize = 'sm' | 'md' | 'lg' | 'xl'
7
9
  // online: green dot offline: border-only (no fill) busy: destructive away: warning
@@ -121,6 +123,80 @@ function AvatarBase({ src, fallback, fallbackText, size = 'md', status, style }:
121
123
 
122
124
  export const Avatar = React.memo(AvatarBase)
123
125
 
126
+ export interface AvatarGroupProps {
127
+ users: { name: string; src?: string }[]
128
+ /** Max avatars visible before +N overflow badge. Default 3. */
129
+ max?: number
130
+ /** Avatar size preset. Default 'sm'. */
131
+ size?: AvatarSize
132
+ /** Overlap between avatars in points. Default 8 (spacing.sm). */
133
+ overlap?: number
134
+ /** Called when +N overflow badge is tapped. */
135
+ onOverflowPress?: () => void
136
+ style?: ViewStyle
137
+ }
138
+
139
+ export function AvatarGroup({
140
+ users,
141
+ max = 3,
142
+ size = 'sm',
143
+ overlap = vs(8),
144
+ onOverflowPress,
145
+ style,
146
+ }: AvatarGroupProps) {
147
+ const { colors } = useTheme()
148
+ const visible = users.slice(0, max)
149
+ const overflowCount = users.length - max
150
+ const dimension = sizeMap[size as AvatarSize]
151
+
152
+ return (
153
+ <View style={[styles.group, style]} accessibilityLabel={`${users.length} avatares`}>
154
+ {visible.map((user, i) => (
155
+ <View
156
+ key={`${user.name}-${i}`}
157
+ style={[
158
+ styles.groupItem,
159
+ i > 0 && { marginLeft: -overlap },
160
+ { zIndex: visible.length - i },
161
+ ]}
162
+ >
163
+ <Avatar
164
+ src={user.src}
165
+ fallbackText={user.name}
166
+ size={size}
167
+ />
168
+ </View>
169
+ ))}
170
+ {overflowCount > 0 ? (
171
+ <TouchableOpacity
172
+ style={[
173
+ styles.overflowBadge,
174
+ {
175
+ width: dimension,
176
+ height: dimension,
177
+ borderRadius: dimension / 2,
178
+ backgroundColor: colors.surfaceStrong,
179
+ marginLeft: -overlap,
180
+ },
181
+ ]}
182
+ onPress={onOverflowPress}
183
+ disabled={!onOverflowPress}
184
+ activeOpacity={0.7}
185
+ accessibilityRole="button"
186
+ accessibilityLabel={`${overflowCount} avatares más`}
187
+ >
188
+ <Text
189
+ style={[styles.overflowText, { color: colors.foregroundMuted }]}
190
+ allowFontScaling={true}
191
+ >
192
+ +{overflowCount}
193
+ </Text>
194
+ </TouchableOpacity>
195
+ ) : null}
196
+ </View>
197
+ )
198
+ }
199
+
124
200
  const styles = StyleSheet.create({
125
201
  wrapper: {
126
202
  alignSelf: 'flex-start',
@@ -138,4 +214,19 @@ const styles = StyleSheet.create({
138
214
  bottom: 0,
139
215
  right: 0,
140
216
  },
217
+ group: {
218
+ flexDirection: 'row',
219
+ alignItems: 'center',
220
+ },
221
+ groupItem: {
222
+ borderRadius: 999,
223
+ },
224
+ overflowBadge: {
225
+ alignItems: 'center',
226
+ justifyContent: 'center',
227
+ },
228
+ overflowText: {
229
+ fontFamily: 'Sohne-SemiBold',
230
+ fontSize: ms(11),
231
+ },
141
232
  })
@@ -1,2 +1,2 @@
1
- export { Avatar } from './Avatar'
2
- export type { AvatarProps, AvatarSize } from './Avatar'
1
+ export { Avatar, AvatarGroup } from './Avatar'
2
+ export type { AvatarProps, AvatarSize, AvatarGroupProps } from './Avatar'
@@ -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, vs, ms } from '../../utils/scaling'
5
- import { renderIcon } from '../../utils/icons'
5
+ import { Icon } from '../../utils/icons'
6
6
 
7
7
  export type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'success' | 'warning' | 'successOutline' | 'destructiveOutline' | 'warningOutline'
8
8
  export type BadgeSize = 'sm' | 'md' | 'lg'
@@ -73,7 +73,7 @@ function BadgeBase({ label, children, variant = 'default', size = 'md', icon, ic
73
73
  }[variant]
74
74
 
75
75
  const effectiveIcon: React.ReactNode = iconName
76
- ? renderIcon(iconName, sizeIconSize[size], iconColor ?? textColor)
76
+ ? <Icon name={iconName} size={sizeIconSize[size]} color={iconColor ?? textColor} />
77
77
  : icon
78
78
 
79
79
  const content = children ?? label