@retray-dev/ui-kit 6.2.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/COMPONENTS.md +997 -20
  2. package/EXAMPLES.md +250 -2
  3. package/README.md +21 -14
  4. package/dist/Accordion.d.mts +28 -0
  5. package/dist/Accordion.d.ts +28 -0
  6. package/dist/Accordion.js +392 -0
  7. package/dist/Accordion.mjs +7 -0
  8. package/dist/AlertBanner.d.mts +16 -0
  9. package/dist/AlertBanner.d.ts +16 -0
  10. package/dist/AlertBanner.js +250 -0
  11. package/dist/AlertBanner.mjs +6 -0
  12. package/dist/AppHeader.d.mts +40 -0
  13. package/dist/AppHeader.d.ts +40 -0
  14. package/dist/AppHeader.js +515 -0
  15. package/dist/AppHeader.mjs +10 -0
  16. package/dist/Avatar.d.mts +20 -0
  17. package/dist/Avatar.d.ts +20 -0
  18. package/dist/Avatar.js +244 -0
  19. package/dist/Avatar.mjs +4 -0
  20. package/dist/Badge.d.mts +26 -0
  21. package/dist/Badge.d.ts +26 -0
  22. package/dist/Badge.js +257 -0
  23. package/dist/Badge.mjs +5 -0
  24. package/dist/Button.d.mts +30 -0
  25. package/dist/Button.d.ts +30 -0
  26. package/dist/Button.js +432 -0
  27. package/dist/Button.mjs +9 -0
  28. package/dist/ButtonGroup.d.mts +26 -0
  29. package/dist/ButtonGroup.d.ts +26 -0
  30. package/dist/ButtonGroup.js +52 -0
  31. package/dist/ButtonGroup.mjs +3 -0
  32. package/dist/Card.d.mts +39 -0
  33. package/dist/Card.d.ts +39 -0
  34. package/dist/Card.js +349 -0
  35. package/dist/Card.mjs +8 -0
  36. package/dist/CategoryStrip.d.mts +26 -0
  37. package/dist/CategoryStrip.d.ts +26 -0
  38. package/dist/CategoryStrip.js +453 -0
  39. package/dist/CategoryStrip.mjs +9 -0
  40. package/dist/Checkbox.d.mts +14 -0
  41. package/dist/Checkbox.d.ts +14 -0
  42. package/dist/Checkbox.js +336 -0
  43. package/dist/Checkbox.mjs +7 -0
  44. package/dist/Chip.d.mts +31 -0
  45. package/dist/Chip.d.ts +31 -0
  46. package/dist/Chip.js +403 -0
  47. package/dist/Chip.mjs +8 -0
  48. package/dist/ConfirmDialog.d.mts +15 -0
  49. package/dist/ConfirmDialog.d.ts +15 -0
  50. package/dist/ConfirmDialog.js +560 -0
  51. package/dist/ConfirmDialog.mjs +10 -0
  52. package/dist/CurrencyDisplay.d.mts +24 -0
  53. package/dist/CurrencyDisplay.d.ts +24 -0
  54. package/dist/CurrencyDisplay.js +189 -0
  55. package/dist/CurrencyDisplay.mjs +4 -0
  56. package/dist/CurrencyInput.d.mts +26 -0
  57. package/dist/CurrencyInput.d.ts +26 -0
  58. package/dist/CurrencyInput.js +408 -0
  59. package/dist/CurrencyInput.mjs +8 -0
  60. package/dist/DetailRow.d.mts +32 -0
  61. package/dist/DetailRow.d.ts +32 -0
  62. package/dist/DetailRow.js +275 -0
  63. package/dist/DetailRow.mjs +5 -0
  64. package/dist/EmptyState.d.mts +27 -0
  65. package/dist/EmptyState.d.ts +27 -0
  66. package/dist/EmptyState.js +523 -0
  67. package/dist/EmptyState.mjs +10 -0
  68. package/dist/ErrorBoundary.d.mts +42 -0
  69. package/dist/ErrorBoundary.d.ts +42 -0
  70. package/dist/ErrorBoundary.js +351 -0
  71. package/dist/ErrorBoundary.mjs +7 -0
  72. package/dist/Form.d.mts +52 -0
  73. package/dist/Form.d.ts +52 -0
  74. package/dist/Form.js +204 -0
  75. package/dist/Form.mjs +4 -0
  76. package/dist/HolographicCard.d.mts +55 -0
  77. package/dist/HolographicCard.d.ts +55 -0
  78. package/dist/HolographicCard.js +316 -0
  79. package/dist/HolographicCard.mjs +191 -0
  80. package/dist/IconButton.d.mts +27 -0
  81. package/dist/IconButton.d.ts +27 -0
  82. package/dist/IconButton.js +400 -0
  83. package/dist/IconButton.mjs +8 -0
  84. package/dist/ImageViewer.d.mts +23 -0
  85. package/dist/ImageViewer.d.ts +23 -0
  86. package/dist/ImageViewer.js +582 -0
  87. package/dist/ImageViewer.mjs +8 -0
  88. package/dist/Input.d.mts +23 -0
  89. package/dist/Input.d.ts +23 -0
  90. package/dist/Input.js +351 -0
  91. package/dist/Input.mjs +7 -0
  92. package/dist/LabelValue.d.mts +16 -0
  93. package/dist/LabelValue.d.ts +16 -0
  94. package/dist/LabelValue.js +225 -0
  95. package/dist/LabelValue.mjs +5 -0
  96. package/dist/ListGroup.d.mts +34 -0
  97. package/dist/ListGroup.d.ts +34 -0
  98. package/dist/ListGroup.js +217 -0
  99. package/dist/ListGroup.mjs +5 -0
  100. package/dist/ListItem.d.mts +64 -0
  101. package/dist/ListItem.d.ts +64 -0
  102. package/dist/ListItem.js +444 -0
  103. package/dist/ListItem.mjs +9 -0
  104. package/dist/MediaCard.d.mts +39 -0
  105. package/dist/MediaCard.d.ts +39 -0
  106. package/dist/MediaCard.js +475 -0
  107. package/dist/MediaCard.mjs +9 -0
  108. package/dist/MenuGroup.d.mts +34 -0
  109. package/dist/MenuGroup.d.ts +34 -0
  110. package/dist/MenuGroup.js +217 -0
  111. package/dist/MenuGroup.mjs +5 -0
  112. package/dist/MenuItem.d.mts +48 -0
  113. package/dist/MenuItem.d.ts +48 -0
  114. package/dist/MenuItem.js +415 -0
  115. package/dist/MenuItem.mjs +9 -0
  116. package/dist/MonthPicker.d.mts +28 -0
  117. package/dist/MonthPicker.d.ts +28 -0
  118. package/dist/MonthPicker.js +297 -0
  119. package/dist/MonthPicker.mjs +5 -0
  120. package/dist/PagerDots.d.mts +35 -0
  121. package/dist/PagerDots.d.ts +35 -0
  122. package/dist/PagerDots.js +392 -0
  123. package/dist/PagerDots.mjs +7 -0
  124. package/dist/Pressable.d.mts +34 -0
  125. package/dist/Pressable.d.ts +34 -0
  126. package/dist/Pressable.js +143 -0
  127. package/dist/Pressable.mjs +5 -0
  128. package/dist/PricingCard.d.mts +50 -0
  129. package/dist/PricingCard.d.ts +50 -0
  130. package/dist/PricingCard.js +636 -0
  131. package/dist/PricingCard.mjs +11 -0
  132. package/dist/Progress.d.mts +14 -0
  133. package/dist/Progress.d.ts +14 -0
  134. package/dist/Progress.js +191 -0
  135. package/dist/Progress.mjs +5 -0
  136. package/dist/RadioGroup.d.mts +19 -0
  137. package/dist/RadioGroup.d.ts +19 -0
  138. package/dist/RadioGroup.js +392 -0
  139. package/dist/RadioGroup.mjs +7 -0
  140. package/dist/RetrayProvider.d.mts +2 -0
  141. package/dist/RetrayProvider.d.ts +2 -0
  142. package/dist/RetrayProvider.js +214 -0
  143. package/dist/RetrayProvider.mjs +5 -0
  144. package/dist/Select.d.mts +22 -0
  145. package/dist/Select.d.ts +22 -0
  146. package/dist/Select.js +488 -0
  147. package/dist/Select.mjs +7 -0
  148. package/dist/SelectableGrid.d.mts +44 -0
  149. package/dist/SelectableGrid.d.ts +44 -0
  150. package/dist/SelectableGrid.js +448 -0
  151. package/dist/SelectableGrid.mjs +9 -0
  152. package/dist/Separator.d.mts +10 -0
  153. package/dist/Separator.d.ts +10 -0
  154. package/dist/Separator.js +156 -0
  155. package/dist/Separator.mjs +3 -0
  156. package/dist/Sheet.d.mts +93 -0
  157. package/dist/Sheet.d.ts +93 -0
  158. package/dist/Sheet.js +450 -0
  159. package/dist/Sheet.mjs +6 -0
  160. package/dist/Skeleton.d.mts +67 -0
  161. package/dist/Skeleton.d.ts +67 -0
  162. package/dist/Skeleton.js +266 -0
  163. package/dist/Skeleton.mjs +6 -0
  164. package/dist/Slider.d.mts +20 -0
  165. package/dist/Slider.d.ts +20 -0
  166. package/dist/Slider.js +279 -0
  167. package/dist/Slider.mjs +5 -0
  168. package/dist/Spinner.d.mts +12 -0
  169. package/dist/Spinner.d.ts +12 -0
  170. package/dist/Spinner.js +193 -0
  171. package/dist/Spinner.mjs +4 -0
  172. package/dist/Switch.d.mts +13 -0
  173. package/dist/Switch.d.ts +13 -0
  174. package/dist/Switch.js +311 -0
  175. package/dist/Switch.mjs +6 -0
  176. package/dist/TabBar.d.mts +42 -0
  177. package/dist/TabBar.d.ts +42 -0
  178. package/dist/TabBar.js +361 -0
  179. package/dist/TabBar.mjs +6 -0
  180. package/dist/Tabs.d.mts +27 -0
  181. package/dist/Tabs.d.ts +27 -0
  182. package/dist/Tabs.js +419 -0
  183. package/dist/Tabs.mjs +7 -0
  184. package/dist/Text.d.mts +12 -0
  185. package/dist/Text.d.ts +12 -0
  186. package/dist/Text.js +327 -0
  187. package/dist/Text.mjs +5 -0
  188. package/dist/Textarea.d.mts +16 -0
  189. package/dist/Textarea.d.ts +16 -0
  190. package/dist/Textarea.js +333 -0
  191. package/dist/Textarea.mjs +7 -0
  192. package/dist/Toast.d.mts +47 -0
  193. package/dist/Toast.d.ts +47 -0
  194. package/dist/Toast.js +185 -0
  195. package/dist/Toast.mjs +4 -0
  196. package/dist/Toggle.d.mts +36 -0
  197. package/dist/Toggle.d.ts +36 -0
  198. package/dist/Toggle.js +412 -0
  199. package/dist/Toggle.mjs +8 -0
  200. package/dist/VirtualList.d.mts +19 -0
  201. package/dist/VirtualList.d.ts +19 -0
  202. package/dist/VirtualList.js +38 -0
  203. package/dist/VirtualList.mjs +2 -0
  204. package/dist/chunk-26BCI223.mjs +14 -0
  205. package/dist/chunk-2CE3TQVY.mjs +11 -0
  206. package/dist/chunk-2TFTAWVJ.mjs +131 -0
  207. package/dist/chunk-2UYENBLV.mjs +49 -0
  208. package/dist/chunk-3BBOZ3OQ.mjs +41 -0
  209. package/dist/chunk-3DKJ2GIC.mjs +30 -0
  210. package/dist/chunk-3U4SSNWP.mjs +120 -0
  211. package/dist/chunk-4I7D47FH.mjs +139 -0
  212. package/dist/chunk-4K625MVM.mjs +142 -0
  213. package/dist/chunk-6OAZJ577.mjs +98 -0
  214. package/dist/chunk-6Q64UFIA.mjs +71 -0
  215. package/dist/chunk-756RAKE4.mjs +145 -0
  216. package/dist/chunk-7QHVVCB3.mjs +115 -0
  217. package/dist/chunk-A3A6KNQN.mjs +245 -0
  218. package/dist/chunk-A4MDAP7G.mjs +42 -0
  219. package/dist/chunk-AJ7ZDNBT.mjs +120 -0
  220. package/dist/chunk-AV4EMIRH.mjs +94 -0
  221. package/dist/chunk-AZJF2BLK.mjs +115 -0
  222. package/dist/chunk-BNP626TY.mjs +159 -0
  223. package/dist/chunk-BRKYVJVV.mjs +60 -0
  224. package/dist/chunk-DVK4G2GT.mjs +59 -0
  225. package/dist/chunk-EH745HE5.mjs +127 -0
  226. package/dist/chunk-EJ7ZPXOH.mjs +163 -0
  227. package/dist/chunk-GD6KXMG5.mjs +106 -0
  228. package/dist/chunk-GQYFLP3D.mjs +187 -0
  229. package/dist/chunk-ID72TK46.mjs +111 -0
  230. package/dist/chunk-IRRY3CRZ.mjs +82 -0
  231. package/dist/chunk-JB67UOB5.mjs +92 -0
  232. package/dist/chunk-JMOZEC77.mjs +90 -0
  233. package/dist/chunk-JT7HKXRB.mjs +114 -0
  234. package/dist/chunk-KIHCWCWL.mjs +124 -0
  235. package/dist/chunk-LXJIIOYQ.mjs +104 -0
  236. package/dist/chunk-M6ZXVBTK.mjs +64 -0
  237. package/dist/chunk-MAC465BB.mjs +61 -0
  238. package/dist/chunk-MBMXYJJV.mjs +36 -0
  239. package/dist/chunk-MLF3EZFW.mjs +119 -0
  240. package/dist/chunk-MX6HRKMI.mjs +29 -0
  241. package/dist/chunk-NA7PARID.mjs +147 -0
  242. package/dist/chunk-NC5ZTR2Y.mjs +32 -0
  243. package/dist/chunk-O3HA6TYM.mjs +139 -0
  244. package/dist/chunk-OB4JUQ3O.mjs +51 -0
  245. package/dist/chunk-PFZTM6D5.mjs +238 -0
  246. package/dist/chunk-QKH5ZOD5.mjs +97 -0
  247. package/dist/chunk-QY3X2UYR.mjs +191 -0
  248. package/dist/chunk-SOA2Z4RB.mjs +82 -0
  249. package/dist/chunk-SOYNZDVY.mjs +151 -0
  250. package/dist/chunk-T7XZ7H7Y.mjs +57 -0
  251. package/dist/chunk-TERDKCLE.mjs +74 -0
  252. package/dist/chunk-UREA2GYY.mjs +113 -0
  253. package/dist/chunk-VGTDN7SW.mjs +164 -0
  254. package/dist/chunk-VQ57HWPL.mjs +144 -0
  255. package/dist/chunk-WBOOUHSS.mjs +62 -0
  256. package/dist/chunk-WJLKJMKR.mjs +78 -0
  257. package/dist/chunk-X4G6APW6.mjs +134 -0
  258. package/dist/chunk-Y6FXYEAI.mjs +8 -0
  259. package/dist/chunk-YFZ3ELX5.mjs +16 -0
  260. package/dist/chunk-YNROWHQJ.mjs +46 -0
  261. package/dist/chunk-Z4BVUWW6.mjs +196 -0
  262. package/dist/chunk-ZJKGQMYH.mjs +131 -0
  263. package/dist/index-wt-orHUi.d.mts +85 -0
  264. package/dist/index-wt-orHUi.d.ts +85 -0
  265. package/dist/index.d.mts +149 -920
  266. package/dist/index.d.ts +149 -920
  267. package/dist/index.js +2560 -970
  268. package/dist/index.mjs +60 -3895
  269. package/package.json +55 -16
  270. package/src/assets/fonts/Sohne-Bold.otf +0 -0
  271. package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
  272. package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
  273. package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
  274. package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
  275. package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
  276. package/src/assets/fonts/Sohne-Italic.otf +0 -0
  277. package/src/assets/fonts/Sohne-Light.otf +0 -0
  278. package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
  279. package/src/assets/fonts/Sohne-Medium.otf +0 -0
  280. package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
  281. package/src/assets/fonts/Sohne-Regular.otf +0 -0
  282. package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
  283. package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
  284. package/src/assets/fonts/SohneMono-Bold.otf +0 -0
  285. package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
  286. package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
  287. package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
  288. package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
  289. package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
  290. package/src/assets/fonts/SohneMono-Italic.otf +0 -0
  291. package/src/assets/fonts/SohneMono-Light.otf +0 -0
  292. package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
  293. package/src/assets/fonts/SohneMono-Medium.otf +0 -0
  294. package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
  295. package/src/assets/fonts/SohneMono-Regular.otf +0 -0
  296. package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
  297. package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
  298. package/src/components/Accordion/Accordion.tsx +15 -4
  299. package/src/components/AlertBanner/AlertBanner.tsx +38 -12
  300. package/src/components/AppHeader/AppHeader.tsx +172 -0
  301. package/src/components/AppHeader/index.ts +1 -0
  302. package/src/components/Avatar/Avatar.tsx +14 -4
  303. package/src/components/Badge/Badge.tsx +12 -3
  304. package/src/components/Button/Button.tsx +30 -38
  305. package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
  306. package/src/components/Card/Card.tsx +29 -57
  307. package/src/components/CategoryStrip/CategoryStrip.tsx +41 -42
  308. package/src/components/Checkbox/Checkbox.tsx +36 -45
  309. package/src/components/Chip/Chip.tsx +41 -48
  310. package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
  311. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
  312. package/src/components/CurrencyInput/CurrencyInput.tsx +12 -10
  313. package/src/components/DetailRow/DetailRow.tsx +9 -7
  314. package/src/components/EmptyState/EmptyState.tsx +4 -3
  315. package/src/components/ErrorBoundary/ErrorBoundary.tsx +153 -0
  316. package/src/components/ErrorBoundary/index.ts +1 -0
  317. package/src/components/Form/Form.tsx +149 -0
  318. package/src/components/Form/index.ts +1 -0
  319. package/src/components/HolographicCard/HolographicCard.tsx +315 -0
  320. package/src/components/HolographicCard/index.ts +1 -0
  321. package/src/components/IconButton/IconButton.tsx +23 -29
  322. package/src/components/ImageViewer/ImageViewer.tsx +290 -0
  323. package/src/components/ImageViewer/index.ts +1 -0
  324. package/src/components/Input/Input.tsx +27 -31
  325. package/src/components/LabelValue/LabelValue.tsx +6 -4
  326. package/src/components/ListGroup/ListGroup.tsx +145 -0
  327. package/src/components/ListGroup/index.ts +1 -0
  328. package/src/components/ListItem/ListItem.tsx +78 -76
  329. package/src/components/MediaCard/MediaCard.tsx +15 -7
  330. package/src/components/MenuGroup/MenuGroup.tsx +145 -0
  331. package/src/components/MenuGroup/index.ts +1 -0
  332. package/src/components/MenuItem/MenuItem.tsx +16 -33
  333. package/src/components/MonthPicker/MonthPicker.tsx +41 -15
  334. package/src/components/MonthPicker/index.ts +1 -1
  335. package/src/components/PagerDots/PagerDots.tsx +200 -0
  336. package/src/components/PagerDots/index.ts +1 -0
  337. package/src/components/Pressable/Pressable.tsx +19 -35
  338. package/src/components/PricingCard/PricingCard.tsx +220 -0
  339. package/src/components/PricingCard/index.ts +1 -0
  340. package/src/components/RadioGroup/RadioGroup.tsx +23 -39
  341. package/src/components/RetrayProvider/RetrayProvider.tsx +59 -0
  342. package/src/components/RetrayProvider/index.ts +1 -0
  343. package/src/components/Select/Select.tsx +6 -6
  344. package/src/components/SelectableGrid/SelectableGrid.tsx +205 -0
  345. package/src/components/SelectableGrid/index.ts +1 -0
  346. package/src/components/Separator/Separator.tsx +1 -3
  347. package/src/components/Sheet/Sheet.tsx +146 -18
  348. package/src/components/Skeleton/Skeleton.tsx +143 -2
  349. package/src/components/Slider/Slider.tsx +2 -2
  350. package/src/components/Spinner/Spinner.tsx +18 -3
  351. package/src/components/Switch/Switch.tsx +44 -49
  352. package/src/components/TabBar/TabBar.tsx +169 -0
  353. package/src/components/TabBar/index.ts +1 -0
  354. package/src/components/Tabs/Tabs.tsx +45 -44
  355. package/src/components/Text/Text.tsx +5 -1
  356. package/src/components/Textarea/Textarea.tsx +18 -14
  357. package/src/components/Toast/Toast.tsx +6 -6
  358. package/src/components/Toggle/Toggle.tsx +80 -72
  359. package/src/components/VirtualList/VirtualList.tsx +60 -0
  360. package/src/components/VirtualList/index.ts +1 -0
  361. package/src/fonts.ts +41 -20
  362. package/src/index.ts +28 -3
  363. package/src/theme/colors.ts +53 -39
  364. package/src/theme/types.ts +3 -0
  365. package/src/tokens.ts +49 -39
  366. package/src/utils/animations.ts +29 -1
  367. package/src/utils/fontGuard.ts +34 -0
  368. package/src/utils/haptics.ts +211 -9
  369. package/src/utils/icons.ts +47 -20
  370. package/src/utils/pressable.ts +66 -0
  371. package/src/utils/usePressScale.ts +2 -0
  372. package/src/assets/fonts/Poppins-Black.ttf +0 -0
  373. package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
  374. package/src/assets/fonts/Poppins-Bold.ttf +0 -0
  375. package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
  376. package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
  377. package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
  378. package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
  379. package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
  380. package/src/assets/fonts/Poppins-Italic.ttf +0 -0
  381. package/src/assets/fonts/Poppins-Light.ttf +0 -0
  382. package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
  383. package/src/assets/fonts/Poppins-Medium.ttf +0 -0
  384. package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
  385. package/src/assets/fonts/Poppins-Regular.ttf +0 -0
  386. package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  387. package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
  388. package/src/assets/fonts/Poppins-Thin.ttf +0 -0
  389. package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
@@ -0,0 +1,290 @@
1
+ import React, { useState, useCallback } from 'react'
2
+ import {
3
+ Modal,
4
+ View,
5
+ TouchableOpacity,
6
+ StyleSheet,
7
+ useWindowDimensions,
8
+ ImageSourcePropType,
9
+ ScrollView,
10
+ NativeSyntheticEvent,
11
+ NativeScrollEvent,
12
+ } from 'react-native'
13
+ import { GestureHandlerRootView, GestureDetector, Gesture } from 'react-native-gesture-handler'
14
+ import Animated, {
15
+ useSharedValue,
16
+ useAnimatedStyle,
17
+ withTiming,
18
+ runOnJS,
19
+ } from 'react-native-reanimated'
20
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
21
+ import { renderIcon } from '../../utils/icons'
22
+ import { PagerDots } from '../PagerDots'
23
+ import { s, vs } from '../../utils/scaling'
24
+
25
+ const MAX_SCALE = 3
26
+ const DOUBLE_TAP_SCALE = 2.5
27
+
28
+ interface ZoomableImageProps {
29
+ source: ImageSourcePropType
30
+ width: number
31
+ height: number
32
+ /** Reports whether this page is currently zoomed in, so the pager can lock paging. */
33
+ onZoomChange: (zoomed: boolean) => void
34
+ }
35
+
36
+ function ZoomableImage({ source, width, height, onZoomChange }: ZoomableImageProps) {
37
+ const scale = useSharedValue(1)
38
+ const savedScale = useSharedValue(1)
39
+ const translateX = useSharedValue(0)
40
+ const translateY = useSharedValue(0)
41
+ const savedX = useSharedValue(0)
42
+ const savedY = useSharedValue(0)
43
+
44
+ const reportZoom = useCallback((zoomed: boolean) => onZoomChange(zoomed), [onZoomChange])
45
+
46
+ const reset = () => {
47
+ 'worklet'
48
+ scale.value = withTiming(1)
49
+ savedScale.value = 1
50
+ translateX.value = withTiming(0)
51
+ translateY.value = withTiming(0)
52
+ savedX.value = 0
53
+ savedY.value = 0
54
+ runOnJS(reportZoom)(false)
55
+ }
56
+
57
+ const pinch = Gesture.Pinch()
58
+ .onUpdate((e) => {
59
+ scale.value = Math.max(1, Math.min(savedScale.value * e.scale, MAX_SCALE))
60
+ })
61
+ .onEnd(() => {
62
+ savedScale.value = scale.value
63
+ if (scale.value <= 1) {
64
+ reset()
65
+ } else {
66
+ runOnJS(reportZoom)(true)
67
+ }
68
+ })
69
+
70
+ const pan = Gesture.Pan()
71
+ .onUpdate((e) => {
72
+ if (scale.value <= 1) return
73
+ translateX.value = savedX.value + e.translationX
74
+ translateY.value = savedY.value + e.translationY
75
+ })
76
+ .onEnd(() => {
77
+ savedX.value = translateX.value
78
+ savedY.value = translateY.value
79
+ })
80
+
81
+ const doubleTap = Gesture.Tap()
82
+ .numberOfTaps(2)
83
+ .onEnd(() => {
84
+ if (scale.value > 1) {
85
+ reset()
86
+ } else {
87
+ scale.value = withTiming(DOUBLE_TAP_SCALE)
88
+ savedScale.value = DOUBLE_TAP_SCALE
89
+ runOnJS(reportZoom)(true)
90
+ }
91
+ })
92
+
93
+ const composed = Gesture.Exclusive(doubleTap, Gesture.Simultaneous(pinch, pan))
94
+
95
+ const animatedStyle = useAnimatedStyle(() => ({
96
+ transform: [
97
+ { translateX: translateX.value },
98
+ { translateY: translateY.value },
99
+ { scale: scale.value },
100
+ ],
101
+ }))
102
+
103
+ return (
104
+ <GestureDetector gesture={composed}>
105
+ <Animated.View style={[{ width, height }, styles.imageWrap]}>
106
+ <Animated.Image
107
+ source={source}
108
+ style={[{ width, height }, animatedStyle]}
109
+ resizeMode="contain"
110
+ />
111
+ </Animated.View>
112
+ </GestureDetector>
113
+ )
114
+ }
115
+
116
+ export interface ImageViewerProps {
117
+ /** Images to show — URI strings via `{ uri }` or `require()` sources. */
118
+ images: ImageSourcePropType[]
119
+ visible: boolean
120
+ onClose: () => void
121
+ /** Page to open on. Defaults to 0. */
122
+ initialIndex?: number
123
+ }
124
+
125
+ /**
126
+ * Full-screen zoomable image gallery. Horizontal paging + pinch / double-tap
127
+ * zoom + pan. Page dots and a close button overlay the images.
128
+ *
129
+ * Requires `react-native-gesture-handler` (already a peer dependency).
130
+ *
131
+ * @example
132
+ * <ImageViewer images={pages} visible={open} initialIndex={page} onClose={() => setOpen(false)} />
133
+ */
134
+ export function ImageViewer({ images, visible, onClose, initialIndex = 0 }: ImageViewerProps) {
135
+ const { width, height } = useWindowDimensions()
136
+ const insets = useSafeAreaInsets()
137
+ const [index, setIndex] = useState(initialIndex)
138
+ const [pagingEnabled, setPagingEnabled] = useState(true)
139
+ const scrollRef = React.useRef<ScrollView>(null)
140
+
141
+ // Reset to the requested page each time the viewer is opened. State updates are
142
+ // deferred to the next frame (also when contentOffset must land on the page),
143
+ // so this never sets state synchronously during the effect.
144
+ React.useEffect(() => {
145
+ if (!visible) return
146
+ const handle = requestAnimationFrame(() => {
147
+ setIndex(initialIndex)
148
+ setPagingEnabled(true)
149
+ scrollRef.current?.scrollTo({ x: initialIndex * width, animated: false })
150
+ })
151
+ return () => cancelAnimationFrame(handle)
152
+ }, [visible, initialIndex, width])
153
+
154
+ // Swipe-down-to-dismiss. Only active when no image is zoomed (pagingEnabled).
155
+ // Drags the whole gallery down + fades the black backdrop; releases past
156
+ // threshold → close, otherwise springs back.
157
+ const dragY = useSharedValue(0)
158
+ const DISMISS_THRESHOLD = height * 0.18
159
+
160
+ const closeViewer = useCallback(() => onClose(), [onClose])
161
+
162
+ const swipeDown = Gesture.Pan()
163
+ .enabled(pagingEnabled)
164
+ .activeOffsetY(12)
165
+ .failOffsetX([-16, 16])
166
+ .onUpdate((e) => {
167
+ dragY.value = Math.max(0, e.translationY)
168
+ })
169
+ .onEnd((e) => {
170
+ if (e.translationY > DISMISS_THRESHOLD || e.velocityY > 800) {
171
+ runOnJS(closeViewer)()
172
+ } else {
173
+ dragY.value = withTiming(0)
174
+ }
175
+ })
176
+
177
+ // Reset drag offset whenever the viewer opens.
178
+ React.useEffect(() => {
179
+ if (visible) dragY.value = 0
180
+ }, [visible, dragY])
181
+
182
+ const dismissStyle = useAnimatedStyle(() => ({
183
+ transform: [{ translateY: dragY.value }],
184
+ }))
185
+
186
+ const backdropStyle = useAnimatedStyle(() => ({
187
+ opacity: 1 - Math.min(dragY.value / (height * 0.5), 0.85),
188
+ }))
189
+
190
+ const onMomentumEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
191
+ const page = Math.round(e.nativeEvent.contentOffset.x / width)
192
+ setIndex(page)
193
+ }
194
+
195
+ const goTo = (page: number) => {
196
+ scrollRef.current?.scrollTo({ x: page * width, animated: true })
197
+ setIndex(page)
198
+ }
199
+
200
+ return (
201
+ <Modal visible={visible} transparent={false} animationType="fade" onRequestClose={onClose} statusBarTranslucent>
202
+ <GestureHandlerRootView style={styles.root}>
203
+ <Animated.View style={[styles.backdrop, backdropStyle]} pointerEvents="none" />
204
+ <Animated.View style={[styles.container, dismissStyle]}>
205
+ <GestureDetector gesture={swipeDown}>
206
+ <Animated.View style={styles.root}>
207
+ <ScrollView
208
+ ref={scrollRef}
209
+ horizontal
210
+ pagingEnabled
211
+ scrollEnabled={pagingEnabled}
212
+ showsHorizontalScrollIndicator={false}
213
+ onMomentumScrollEnd={onMomentumEnd}
214
+ bounces={false}
215
+ >
216
+ {images.map((source, i) => (
217
+ <ZoomableImage
218
+ key={i}
219
+ source={source}
220
+ width={width}
221
+ height={height}
222
+ onZoomChange={(zoomed) => setPagingEnabled(!zoomed)}
223
+ />
224
+ ))}
225
+ </ScrollView>
226
+ </Animated.View>
227
+ </GestureDetector>
228
+
229
+ <TouchableOpacity
230
+ style={[styles.closeButton, { top: insets.top + vs(8) }]}
231
+ onPress={onClose}
232
+ activeOpacity={0.7}
233
+ touchSoundDisabled={true}
234
+ accessibilityRole="button"
235
+ accessibilityLabel="Close"
236
+ hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
237
+ >
238
+ {renderIcon('x', 26, '#fff')}
239
+ </TouchableOpacity>
240
+
241
+ {images.length > 1 ? (
242
+ <View style={[styles.dots, { bottom: insets.bottom + vs(16) }]} pointerEvents="box-none">
243
+ <PagerDots
244
+ count={images.length}
245
+ activeIndex={index}
246
+ onDotPress={goTo}
247
+ activeColor="#fff"
248
+ inactiveColor="rgba(255,255,255,0.4)"
249
+ />
250
+ </View>
251
+ ) : null}
252
+ </Animated.View>
253
+ </GestureHandlerRootView>
254
+ </Modal>
255
+ )
256
+ }
257
+
258
+ const styles = StyleSheet.create({
259
+ root: {
260
+ flex: 1,
261
+ },
262
+ container: {
263
+ flex: 1,
264
+ },
265
+ backdrop: {
266
+ ...StyleSheet.absoluteFillObject,
267
+ backgroundColor: '#000',
268
+ },
269
+ imageWrap: {
270
+ alignItems: 'center',
271
+ justifyContent: 'center',
272
+ overflow: 'hidden',
273
+ },
274
+ closeButton: {
275
+ position: 'absolute',
276
+ right: s(12),
277
+ width: s(40),
278
+ height: s(40),
279
+ borderRadius: s(20),
280
+ backgroundColor: 'rgba(0,0,0,0.4)',
281
+ alignItems: 'center',
282
+ justifyContent: 'center',
283
+ },
284
+ dots: {
285
+ position: 'absolute',
286
+ left: 0,
287
+ right: 0,
288
+ alignItems: 'center',
289
+ },
290
+ })
@@ -0,0 +1 @@
1
+ export * from './ImageViewer'
@@ -3,6 +3,7 @@ import { TextInput, View, Text, StyleSheet, TextInputProps, ViewStyle, TextStyle
3
3
  import Animated, {
4
4
  useAnimatedStyle,
5
5
  interpolateColor,
6
+ interpolate,
6
7
  } from 'react-native-reanimated'
7
8
  import { AntDesign } from '@expo/vector-icons'
8
9
  import { useTheme } from '../../theme'
@@ -11,46 +12,26 @@ import { renderIcon } from '../../utils/icons'
11
12
  import { useColorTransition } from '../../utils/useColorTransition'
12
13
  import { TIMINGS } from '../../utils/animations'
13
14
 
14
- const webInputResetStyle: any =
15
+ const webInputResetStyle: Record<string, unknown> =
15
16
  Platform.OS === 'web'
16
17
  ? { outlineStyle: 'none', outlineWidth: 0, outlineColor: 'transparent', boxShadow: 'none' }
17
18
  : {}
18
19
 
19
20
  export interface InputProps extends TextInputProps {
20
21
  label?: string
21
- /** Red helper text below the input; also changes border to `destructive` color. Takes priority over `hint`. */
22
22
  error?: string
23
- /** Helper text shown below the input when there is no error. */
24
23
  hint?: string
25
- /** Disabled visual state — dimmed appearance, not editable. Also sets `editable={false}`. */
26
24
  disabled?: boolean
27
- /** Text or component rendered before the input text. */
28
25
  prefix?: React.ReactNode
29
- /** Text or component rendered after the input text. */
30
26
  suffix?: React.ReactNode
31
- /** Style applied to prefix text if prefix is a string. */
32
27
  prefixStyle?: TextStyle
33
- /** Style applied to suffix text if suffix is a string. */
34
28
  suffixStyle?: TextStyle
35
- /**
36
- * Icon name from `@expo/vector-icons` rendered before the input text.
37
- * See https://icons.expo.fyi. Takes precedence over `prefix`.
38
- */
39
29
  prefixIcon?: string
40
- /**
41
- * Icon name from `@expo/vector-icons` rendered after the input text.
42
- * See https://icons.expo.fyi. Takes precedence over `suffix` (unless `type="password"`).
43
- */
44
30
  suffixIcon?: string
45
- /** Override the resolved prefix icon color. Defaults to `mutedForeground`. */
46
31
  prefixIconColor?: string
47
- /** Override the resolved suffix icon color. Defaults to `mutedForeground`. */
48
32
  suffixIconColor?: string
49
- /** Input type. When set to \`'password'\`, shows a toggle button to reveal/hide text. */
50
33
  type?: 'text' | 'password'
51
- /** Style for the outer container \`View\`. Use \`style\` (from \`TextInputProps\`) to style the \`TextInput\` itself. */
52
34
  containerStyle?: ViewStyle
53
- /** Style for the inner border wrapper (overrides padding, etc). */
54
35
  inputWrapperStyle?: ViewStyle
55
36
  }
56
37
 
@@ -59,7 +40,6 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
59
40
  const [focused, setFocused] = useState(false)
60
41
  const [showPassword, setShowPassword] = useState(false)
61
42
 
62
- // Asymmetric durations — focus snaps in, blurs out subtly. Runs on UI thread.
63
43
  const focusProgress = useColorTransition(focused, {
64
44
  duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration,
65
45
  })
@@ -75,6 +55,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
75
55
  const effectiveSuffix: React.ReactNode = isPassword && !suffix && !suffixIcon ? (
76
56
  <TouchableOpacity
77
57
  onPress={() => setShowPassword(!showPassword)}
58
+ // AUDIT FIX: was padding: s(4) → ~28px target (below 44px minimum).
59
+ // padding: s(12) with negative margin keeps visual size but expands hit area.
78
60
  style={styles.passwordToggle}
79
61
  activeOpacity={0.6}
80
62
  accessibilityRole="button"
@@ -86,10 +68,16 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
86
68
  ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted)
87
69
  : suffix
88
70
 
89
- const borderColorStyle = useAnimatedStyle(() => ({
71
+ // Border drawn on an absolute overlay so the 1px→2px weight change never
72
+ // resizes the layout box (which would reflow content / shift the interface).
73
+ // Wrapper keeps borderWidth: 0; overlay grows inward and is non-interactive.
74
+ const borderAnimStyle = useAnimatedStyle(() => ({
90
75
  borderColor: error
91
76
  ? colors.destructive
92
77
  : interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
78
+ borderWidth: error
79
+ ? 2
80
+ : interpolate(focusProgress.value, [0, 1], [1, 2]),
93
81
  }))
94
82
 
95
83
  return (
@@ -99,10 +87,10 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
99
87
  style={[
100
88
  styles.inputWrapper,
101
89
  { backgroundColor: isDisabled ? colors.surface : colors.background },
102
- borderColorStyle,
103
90
  inputWrapperStyle,
104
91
  ]}
105
92
  >
93
+ <Animated.View style={[styles.borderOverlay, borderAnimStyle]} pointerEvents="none" />
106
94
  {effectivePrefix ? (
107
95
  typeof effectivePrefix === 'string' ? (
108
96
  <Text style={[styles.prefixText, { color: colors.foregroundMuted }, prefixStyle]} allowFontScaling={true}>
@@ -168,20 +156,25 @@ const styles = StyleSheet.create({
168
156
  opacity: 0.6,
169
157
  },
170
158
  label: {
171
- fontFamily: 'Poppins-Medium',
159
+ fontFamily: 'Sohne-Medium',
172
160
  fontSize: ms(14),
173
161
  },
174
162
  inputWrapper: {
175
163
  flexDirection: 'row',
176
164
  alignItems: 'center',
177
- borderWidth: 2,
165
+ // Border lives on borderOverlay (absolute) so its 1px→2px focus change
166
+ // never resizes this box. Wrapper itself carries no border.
178
167
  borderRadius: 8,
179
168
  paddingHorizontal: s(14),
180
169
  paddingVertical: vs(11),
181
170
  minHeight: 48,
182
171
  },
172
+ borderOverlay: {
173
+ ...StyleSheet.absoluteFillObject,
174
+ borderRadius: 8,
175
+ },
183
176
  input: {
184
- fontFamily: 'Poppins-Regular',
177
+ fontFamily: 'Sohne-Regular',
185
178
  flex: 1,
186
179
  fontSize: ms(16),
187
180
  paddingVertical: vs(2),
@@ -191,7 +184,7 @@ const styles = StyleSheet.create({
191
184
  marginRight: s(8),
192
185
  },
193
186
  prefixText: {
194
- fontFamily: 'Poppins-Regular',
187
+ fontFamily: 'Sohne-Regular',
195
188
  fontSize: ms(15),
196
189
  marginRight: s(8),
197
190
  },
@@ -199,15 +192,18 @@ const styles = StyleSheet.create({
199
192
  marginLeft: s(8),
200
193
  },
201
194
  suffixText: {
202
- fontFamily: 'Poppins-Regular',
195
+ fontFamily: 'Sohne-Regular',
203
196
  fontSize: ms(15),
204
197
  marginLeft: s(8),
205
198
  },
199
+ // AUDIT FIX: was padding: s(4) → ~28px tap target. Now 12px padding → ~44px.
200
+ // Negative margin compensates so the visual icon position is unchanged.
206
201
  passwordToggle: {
207
- padding: s(4),
202
+ padding: s(12),
203
+ margin: -s(8),
208
204
  },
209
205
  helperText: {
210
- fontFamily: 'Poppins-Regular',
206
+ fontFamily: 'Sohne-Regular',
211
207
  fontSize: ms(13),
212
208
  },
213
209
  })
@@ -1,7 +1,7 @@
1
1
  import React from 'react'
2
2
  import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
3
  import { useTheme } from '../../theme'
4
- import { s, vs, ms, mvs } from '../../utils/scaling'
4
+ import { s, ms, mvs } from '../../utils/scaling'
5
5
  import { renderIcon } from '../../utils/icons'
6
6
 
7
7
  export interface LabelValueProps {
@@ -14,7 +14,7 @@ export interface LabelValueProps {
14
14
  style?: ViewStyle
15
15
  }
16
16
 
17
- export function LabelValue({ label, value, iconName, iconColor, style }: LabelValueProps) {
17
+ function LabelValueBase({ label, value, iconName, iconColor, style }: LabelValueProps) {
18
18
  const { colors } = useTheme()
19
19
 
20
20
  const resolvedIcon = iconName
@@ -40,6 +40,8 @@ export function LabelValue({ label, value, iconName, iconColor, style }: LabelVa
40
40
  )
41
41
  }
42
42
 
43
+ export const LabelValue = React.memo(LabelValueBase)
44
+
43
45
  const styles = StyleSheet.create({
44
46
  container: {
45
47
  flexDirection: 'row',
@@ -57,12 +59,12 @@ const styles = StyleSheet.create({
57
59
  justifyContent: 'center',
58
60
  },
59
61
  label: {
60
- fontFamily: 'Poppins-Regular',
62
+ fontFamily: 'Sohne-Regular',
61
63
  fontSize: ms(13),
62
64
  lineHeight: mvs(18),
63
65
  },
64
66
  value: {
65
- fontFamily: 'Poppins-Medium',
67
+ fontFamily: 'Sohne-Medium',
66
68
  fontSize: ms(14),
67
69
  lineHeight: mvs(20),
68
70
  textAlign: 'right',
@@ -0,0 +1,145 @@
1
+ import React from 'react'
2
+ import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
+ import { useTheme } from '../../theme'
4
+ import { s, vs } from '../../utils/scaling'
5
+ import { RADIUS } from '../../tokens'
6
+
7
+ export type ListGroupVariant = 'plain' | 'card'
8
+
9
+ export interface ListGroupProps {
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
16
+ style?: ViewStyle
17
+ }
18
+
19
+ export interface ListGroupHeaderProps {
20
+ children: React.ReactNode
21
+ style?: ViewStyle
22
+ }
23
+
24
+ export interface ListGroupFooterProps {
25
+ children: React.ReactNode
26
+ style?: ViewStyle
27
+ }
28
+
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) {
34
+ const { colors } = useTheme()
35
+
36
+ // Auto-inject showSeparator={true} to all ListItem children except the last
37
+ const processedChildren = React.Children.map(children, (child, index) => {
38
+ if (!React.isValidElement(child)) return child
39
+
40
+ // Skip ListGroup.Header and ListGroup.Footer
41
+ if (child.type === ListGroupHeader || child.type === ListGroupFooter) {
42
+ return child
43
+ }
44
+
45
+ // Check if it's a ListItem (has title prop as a heuristic)
46
+ const childProps = child.props as Record<string, unknown>
47
+ const isListItem = 'title' in childProps
48
+ if (!isListItem) return child
49
+
50
+ const isLast = index === React.Children.count(children) - 1
51
+
52
+ // Only add separator if not already explicitly set and not last item
53
+ if (childProps['showSeparator'] === undefined && !isLast) {
54
+ return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {
55
+ showSeparator: true,
56
+ })
57
+ }
58
+
59
+ return child
60
+ })
61
+
62
+ const cardStyle: ViewStyle =
63
+ variant === 'card'
64
+ ? {
65
+ backgroundColor: colors.card,
66
+ borderRadius: RADIUS.md,
67
+ borderWidth: 1,
68
+ borderColor: colors.border,
69
+ shadowColor: '#000',
70
+ shadowOffset: { width: 0, height: 2 },
71
+ shadowOpacity: 0.06,
72
+ shadowRadius: 6,
73
+ elevation: 2,
74
+ paddingVertical: vs(4),
75
+ }
76
+ : {}
77
+
78
+ return (
79
+ <View style={[styles.container, cardStyle, style]}>
80
+ {processedChildren}
81
+ </View>
82
+ )
83
+ }
84
+
85
+ export function ListGroupHeader({ children, style }: ListGroupHeaderProps) {
86
+ const { colors } = useTheme()
87
+
88
+ if (typeof children === 'string') {
89
+ return (
90
+ <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>
91
+ <Text style={[styles.headerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
92
+ {children}
93
+ </Text>
94
+ </View>
95
+ )
96
+ }
97
+
98
+ return <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>{children}</View>
99
+ }
100
+
101
+ export function ListGroupFooter({ children, style }: ListGroupFooterProps) {
102
+ const { colors } = useTheme()
103
+
104
+ if (typeof children === 'string') {
105
+ return (
106
+ <View style={[styles.footer, style]}>
107
+ <Text style={[styles.footerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
108
+ {children}
109
+ </Text>
110
+ </View>
111
+ )
112
+ }
113
+
114
+ return <View style={[styles.footer, style]}>{children}</View>
115
+ }
116
+
117
+ ListGroup.Header = ListGroupHeader
118
+ ListGroup.Footer = ListGroupFooter
119
+
120
+ const styles = StyleSheet.create({
121
+ container: {
122
+ overflow: 'hidden',
123
+ },
124
+ header: {
125
+ paddingHorizontal: s(16),
126
+ paddingTop: vs(12),
127
+ paddingBottom: vs(8),
128
+ borderBottomWidth: StyleSheet.hairlineWidth,
129
+ },
130
+ headerText: {
131
+ fontFamily: 'Sohne-SemiBold',
132
+ fontSize: 13,
133
+ letterSpacing: 0.32,
134
+ textTransform: 'uppercase',
135
+ },
136
+ footer: {
137
+ paddingHorizontal: s(16),
138
+ paddingTop: vs(8),
139
+ paddingBottom: vs(12),
140
+ },
141
+ footerText: {
142
+ fontFamily: 'Sohne-Regular',
143
+ fontSize: 12,
144
+ },
145
+ })
@@ -0,0 +1 @@
1
+ export * from './ListGroup'