@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
@@ -1,24 +1,18 @@
1
1
  import React from 'react'
2
- import { TouchableOpacity, View, StyleSheet, ViewStyle } from 'react-native'
3
- import Animated, {
4
- useAnimatedStyle,
5
- interpolateColor,
6
- } from 'react-native-reanimated'
2
+ import { View, Text, StyleSheet, ViewStyle } from 'react-native'
3
+ import { EaseView } from 'react-native-ease'
7
4
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
8
5
  import { useTheme } from '../../theme'
9
6
  import { s, vs, ms, mvs } from '../../utils/scaling'
10
7
  import { renderIcon } from '../../utils/icons'
11
- import { usePressScale } from '../../utils/usePressScale'
12
- import { useColorTransition } from '../../utils/useColorTransition'
13
- import { PRESS_SCALE } from '../../utils/animations'
8
+ import { COLOR_TRANSITION } from '../../utils/animations'
9
+ import { PressableChip as PressableChipComponent } from '../../utils/pressable'
14
10
 
15
11
  export interface ChipProps {
16
12
  label: string
17
13
  selected?: boolean
18
14
  onPress?: () => void
19
- /** JSX icon rendered before the label. */
20
15
  icon?: React.ReactNode
21
- /** Icon name from @expo/vector-icons resolved automatically. */
22
16
  iconName?: string
23
17
  style?: ViewStyle
24
18
  accessibilityLabel?: string
@@ -27,9 +21,7 @@ export interface ChipProps {
27
21
  export interface ChipOption {
28
22
  label: string
29
23
  value: string | number
30
- /** Icon name resolved via renderIcon (Feather, AntDesign, etc.). */
31
24
  iconName?: string
32
- /** Icon tint color override. */
33
25
  iconColor?: string
34
26
  disabled?: boolean
35
27
  }
@@ -38,26 +30,12 @@ export interface ChipGroupProps {
38
30
  options: ChipOption[]
39
31
  value?: string | number | (string | number)[]
40
32
  onValueChange?: (value: string | number | (string | number)[]) => void
41
- /** When true, allows selecting multiple chips. `value` and `onValueChange` will use arrays. */
42
33
  multiSelect?: boolean
43
34
  style?: ViewStyle
44
35
  }
45
36
 
46
- export function Chip({ label, selected = false, onPress, icon, iconName, style, accessibilityLabel }: ChipProps) {
37
+ function ChipBase({ label, selected = false, onPress, icon, iconName, style, accessibilityLabel }: ChipProps) {
47
38
  const { colors } = useTheme()
48
- const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
49
- pressScale: PRESS_SCALE.chip,
50
- })
51
- const colorProgress = useColorTransition(selected)
52
-
53
- const surfaceStyle = useAnimatedStyle(() => ({
54
- backgroundColor: interpolateColor(colorProgress.value, [0, 1], [colors.surface, colors.primary]),
55
- borderColor: interpolateColor(colorProgress.value, [0, 1], [colors.border, colors.primary]),
56
- }))
57
-
58
- const textStyle = useAnimatedStyle(() => ({
59
- color: interpolateColor(colorProgress.value, [0, 1], [colors.foreground, colors.primaryForeground]),
60
- }))
61
39
 
62
40
  const handlePress = () => {
63
41
  hapticSelection()
@@ -69,49 +47,54 @@ export function Chip({ label, selected = false, onPress, icon, iconName, style,
69
47
  : icon
70
48
 
71
49
  return (
72
- <Animated.View style={[styles.wrapper, scaleStyle, style]} {...hoverHandlers}>
73
- <TouchableOpacity
50
+ <View style={[styles.wrapper, style]}>
51
+ <PressableChipComponent
74
52
  onPress={handlePress}
75
- onPressIn={onPressIn}
76
- onPressOut={onPressOut}
77
- activeOpacity={1}
78
- touchSoundDisabled={true}
53
+ rippleColor="transparent"
54
+ touchSoundDisabled
79
55
  accessibilityRole="button"
80
56
  accessibilityLabel={accessibilityLabel ?? label}
81
57
  accessibilityState={{ selected }}
82
58
  >
83
- <Animated.View style={[styles.chip, surfaceStyle]}>
59
+ <EaseView
60
+ style={styles.chip}
61
+ animate={{
62
+ backgroundColor: selected ? colors.primary : colors.surface,
63
+ borderColor: selected ? colors.primary : colors.border,
64
+ }}
65
+ transition={COLOR_TRANSITION}
66
+ >
84
67
  {resolvedIcon ? <View style={styles.chipIcon}>{resolvedIcon}</View> : null}
85
- <Animated.Text style={[styles.label, textStyle]} allowFontScaling={true}>
68
+ <Text
69
+ style={[styles.label, { color: selected ? colors.primaryForeground : colors.foreground }]}
70
+ allowFontScaling={true}
71
+ >
86
72
  {label}
87
- </Animated.Text>
88
- </Animated.View>
89
- </TouchableOpacity>
90
- </Animated.View>
73
+ </Text>
74
+ </EaseView>
75
+ </PressableChipComponent>
76
+ </View>
91
77
  )
92
78
  }
93
79
 
80
+ export const Chip = React.memo(ChipBase)
81
+
94
82
  export function ChipGroup({ options, value, onValueChange, multiSelect = false, style }: ChipGroupProps) {
95
83
  const handlePress = (optionValue: string | number) => {
96
84
  if (!multiSelect) {
97
85
  onValueChange?.(optionValue)
98
86
  return
99
87
  }
100
-
101
88
  const currentArray = Array.isArray(value) ? value : value ? [value] : []
102
89
  const isSelected = currentArray.includes(optionValue)
103
-
104
90
  const newArray: (string | number)[] = isSelected
105
91
  ? currentArray.filter((v) => v !== optionValue)
106
92
  : [...currentArray, optionValue]
107
-
108
93
  onValueChange?.(newArray)
109
94
  }
110
95
 
111
96
  const isSelected = (optionValue: string | number): boolean => {
112
- if (Array.isArray(value)) {
113
- return value.includes(optionValue)
114
- }
97
+ if (Array.isArray(value)) return value.includes(optionValue)
115
98
  return optionValue === value
116
99
  }
117
100
 
@@ -124,7 +107,11 @@ export function ChipGroup({ options, value, onValueChange, multiSelect = false,
124
107
  selected={isSelected(opt.value)}
125
108
  onPress={opt.disabled ? undefined : () => handlePress(opt.value)}
126
109
  iconName={opt.iconName}
127
- style={opt.disabled ? { opacity: 0.4 } : undefined}
110
+ // AUDIT FIX: was style={{ opacity: 0.4 }} with no accessibilityState.
111
+ // Now passes disabled state to the Chip's TouchableOpacity via onPress=undefined
112
+ // and adds explicit accessibility state for screen readers.
113
+ style={opt.disabled ? styles.chipDisabled : undefined}
114
+ accessibilityLabel={opt.disabled ? `${opt.label}, unavailable` : opt.label}
128
115
  />
129
116
  ))}
130
117
  </View>
@@ -136,19 +123,25 @@ const styles = StyleSheet.create({
136
123
  chip: {
137
124
  borderRadius: 999,
138
125
  paddingHorizontal: s(14),
139
- paddingVertical: vs(5),
126
+ // AUDIT FIX: was vs(5) → ~28px total height — below WCAG 44px tap target.
127
+ // vs(10) → ~44px total height meets WCAG 2.5.5 (AAA) minimum.
128
+ paddingVertical: vs(10),
129
+ minHeight: 44,
140
130
  borderWidth: 1,
141
131
  alignItems: 'center',
142
132
  justifyContent: 'center',
143
133
  flexDirection: 'row',
144
134
  gap: s(5),
145
135
  },
136
+ chipDisabled: {
137
+ opacity: 0.4,
138
+ },
146
139
  chipIcon: {
147
140
  alignItems: 'center',
148
141
  justifyContent: 'center',
149
142
  },
150
143
  label: {
151
- fontFamily: 'Poppins-Medium',
144
+ fontFamily: 'Sohne-Medium',
152
145
  fontSize: ms(13),
153
146
  lineHeight: mvs(18),
154
147
  },
@@ -120,12 +120,12 @@ const styles = StyleSheet.create({
120
120
  gap: vs(12),
121
121
  },
122
122
  title: {
123
- fontFamily: 'Poppins-SemiBold',
123
+ fontFamily: 'Sohne-SemiBold',
124
124
  fontSize: ms(18),
125
125
  lineHeight: mvs(26),
126
126
  },
127
127
  description: {
128
- fontFamily: 'Poppins-Regular',
128
+ fontFamily: 'Sohne-Regular',
129
129
  fontSize: ms(15),
130
130
  lineHeight: mvs(22),
131
131
  },
@@ -49,7 +49,7 @@ function formatValue(value: number | string, prefix: string, showDecimals: boole
49
49
  return `${sign}${prefix}${intPart}`
50
50
  }
51
51
 
52
- export function CurrencyDisplay({ value, prefix = '$', showDecimals = false, textColor, variant, autoScale, maxFontSize, style }: CurrencyDisplayProps) {
52
+ function CurrencyDisplayBase({ value, prefix = '$', showDecimals = false, textColor, variant, autoScale, maxFontSize, style }: CurrencyDisplayProps) {
53
53
  const { colors } = useTheme()
54
54
  const formatted = formatValue(value, prefix, showDecimals)
55
55
  const baseFontSize = variant ? variantFontSize[variant] : ms(56)
@@ -71,12 +71,14 @@ export function CurrencyDisplay({ value, prefix = '$', showDecimals = false, tex
71
71
  )
72
72
  }
73
73
 
74
+ export const CurrencyDisplay = React.memo(CurrencyDisplayBase)
75
+
74
76
  const styles = StyleSheet.create({
75
77
  container: {
76
78
  alignSelf: 'flex-start',
77
79
  },
78
80
  amount: {
79
- fontFamily: 'Poppins-Bold',
81
+ fontFamily: 'Sohne-Bold',
80
82
  includeFontPadding: false,
81
83
  textAlignVertical: 'top',
82
84
  },
@@ -2,15 +2,13 @@ import React from 'react'
2
2
  import { ViewStyle, TextStyle } from 'react-native'
3
3
  import { Input } from '../Input'
4
4
  import { ms, vs } from '../../utils/scaling'
5
- import { renderIcon } from '../../utils/icons'
6
- import { useTheme } from '../../theme'
7
5
 
8
6
  export interface CurrencyInputProps {
9
7
  value?: string
10
8
  onChangeText?: (formatted: string) => void
11
9
  /** Called with the parsed numeric value (no separators, no prefix). */
12
10
  onChangeValue?: (raw: number) => void
13
- /** Symbol prepended to the formatted value. Defaults to `'$'`. */
11
+ /** Currency symbol shown left of the value. Any string (`'$'`, `'€'`, `'£'`, `'COP '`). Defaults to `'$'`. */
14
12
  prefix?: string
15
13
  /** Character used to separate groups of three digits. Defaults to `'.'`. */
16
14
  thousandsSeparator?: '.' | ','
@@ -47,7 +45,6 @@ export function CurrencyInput({
47
45
  containerStyle,
48
46
  style,
49
47
  }: CurrencyInputProps) {
50
- const { colors } = useTheme()
51
48
  const handleChange = (text: string) => {
52
49
  const withoutPrefix = prefix && text.startsWith(prefix) ? text.slice(prefix.length) : text
53
50
  const formatted = formatCurrency(withoutPrefix, thousandsSeparator)
@@ -58,11 +55,15 @@ export function CurrencyInput({
58
55
  onChangeValue?.(isNaN(raw) ? 0 : raw)
59
56
  }
60
57
 
61
- const inputStyle: TextStyle = size === 'large'
62
- ? { fontFamily: 'Poppins-Regular', fontSize: ms(36) }
63
- : { fontFamily: 'Poppins-Regular' }
58
+ const isLarge = size === 'large'
59
+ const inputStyle: TextStyle = isLarge
60
+ ? { fontFamily: 'Sohne-Regular', fontSize: ms(36) }
61
+ : { fontFamily: 'Sohne-Regular' }
64
62
 
65
- const dollarIcon = renderIcon('dollar-sign', size === 'large' ? 24 : 16, colors.foregroundMuted)
63
+ const prefixStyle: TextStyle = {
64
+ fontFamily: 'Sohne-Regular',
65
+ fontSize: isLarge ? ms(32) : ms(17),
66
+ }
66
67
 
67
68
  // Remove prefix from display value if present
68
69
  const displayValue = value && prefix && value.startsWith(prefix) ? value.slice(prefix.length) : value
@@ -77,9 +78,10 @@ export function CurrencyInput({
77
78
  hint={hint}
78
79
  placeholder={placeholder ?? '0'}
79
80
  editable={editable}
80
- prefix={dollarIcon}
81
+ prefix={prefix}
82
+ prefixStyle={prefixStyle}
81
83
  containerStyle={containerStyle}
82
- inputWrapperStyle={size === 'large' ? { paddingVertical: vs(16), minHeight: 72 } : undefined}
84
+ inputWrapperStyle={isLarge ? { paddingVertical: vs(16), minHeight: 72 } : undefined}
83
85
  style={[inputStyle, style]}
84
86
  />
85
87
  )
@@ -1,17 +1,17 @@
1
1
  import React from 'react'
2
2
  import { View, Text, StyleSheet, ViewStyle, TextStyle } 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 type DetailRowSeparator = 'dotted' | 'solid' | 'dashed' | 'none'
8
8
  export type DetailRowLabelWeight = 'normal' | 'medium' | 'semibold' | 'bold'
9
9
 
10
10
  const weightMap: Record<DetailRowLabelWeight, string> = {
11
- normal: 'Poppins-Regular',
12
- medium: 'Poppins-Medium',
13
- semibold: 'Poppins-SemiBold',
14
- bold: 'Poppins-Bold',
11
+ normal: 'Sohne-Regular',
12
+ medium: 'Sohne-Medium',
13
+ semibold: 'Sohne-SemiBold',
14
+ bold: 'Sohne-Bold',
15
15
  }
16
16
 
17
17
  export interface DetailRowProps {
@@ -38,7 +38,7 @@ export interface DetailRowProps {
38
38
  valueStyle?: TextStyle
39
39
  }
40
40
 
41
- export function DetailRow({
41
+ function DetailRowBase({
42
42
  label,
43
43
  value,
44
44
  separator = 'dotted',
@@ -108,6 +108,8 @@ export function DetailRow({
108
108
  )
109
109
  }
110
110
 
111
+ export const DetailRow = React.memo(DetailRowBase)
112
+
111
113
  const styles = StyleSheet.create({
112
114
  row: {
113
115
  flexDirection: 'row',
@@ -138,7 +140,7 @@ const styles = StyleSheet.create({
138
140
  flexShrink: 0,
139
141
  },
140
142
  valueText: {
141
- fontFamily: 'Poppins-SemiBold',
143
+ fontFamily: 'Sohne-SemiBold',
142
144
  fontSize: ms(13),
143
145
  lineHeight: mvs(18),
144
146
  },
@@ -84,8 +84,10 @@ const styles = StyleSheet.create({
84
84
  borderWidth: 1,
85
85
  borderStyle: 'dashed',
86
86
  borderRadius: ms(12),
87
+ paddingBottom: vs(32),
87
88
  },
88
89
  containerCompact: {
90
+ paddingBottom: vs(20),
89
91
  },
90
92
  iconWrapper: {
91
93
  width: s(80),
@@ -109,7 +111,7 @@ const styles = StyleSheet.create({
109
111
  marginTop: vs(16),
110
112
  },
111
113
  title: {
112
- fontFamily: 'Poppins-Medium',
114
+ fontFamily: 'Sohne-Medium',
113
115
  fontSize: ms(18),
114
116
  textAlign: 'center',
115
117
  },
@@ -118,14 +120,13 @@ const styles = StyleSheet.create({
118
120
  marginTop: vs(10),
119
121
  },
120
122
  description: {
121
- fontFamily: 'Poppins-Regular',
123
+ fontFamily: 'Sohne-Regular',
122
124
  fontSize: ms(14),
123
125
  lineHeight: mvs(20),
124
126
  textAlign: 'center',
125
127
  },
126
128
  action: {
127
129
  marginTop: vs(8),
128
- marginBottom: s(32),
129
130
  paddingHorizontal: s(32),
130
131
  },
131
132
  })
@@ -0,0 +1,153 @@
1
+ import React from 'react'
2
+ import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
3
+ import { useTheme } from '../../theme'
4
+ import { renderIcon } from '../../utils/icons'
5
+ import { s, vs, ms, mvs } from '../../utils/scaling'
6
+ import { RADIUS } from '../../tokens'
7
+ import { impactLight } from '../../utils/haptics'
8
+
9
+ export interface ErrorFallbackProps {
10
+ error: Error
11
+ /** Reset the boundary and attempt to re-render children. */
12
+ reset: () => void
13
+ }
14
+
15
+ export interface ErrorBoundaryProps {
16
+ children: React.ReactNode
17
+ /**
18
+ * Custom fallback. Either a React node, or a render function receiving the
19
+ * caught error and a `reset` callback. Defaults to a themed error card.
20
+ */
21
+ fallback?: React.ReactNode | ((props: ErrorFallbackProps) => React.ReactNode)
22
+ /** Title shown by the default fallback. */
23
+ title?: string
24
+ /** Body message shown by the default fallback. */
25
+ message?: string
26
+ /** Called whenever an error is caught — wire your crash reporter here. */
27
+ onError?: (error: Error, info: React.ErrorInfo) => void
28
+ }
29
+
30
+ interface ErrorBoundaryState {
31
+ error: Error | null
32
+ }
33
+
34
+ /** Default themed fallback — uses `useTheme`, so it must be a component (not inline). */
35
+ function DefaultErrorFallback({
36
+ error,
37
+ reset,
38
+ title = 'Something went wrong',
39
+ message,
40
+ }: ErrorFallbackProps & { title?: string; message?: string }) {
41
+ const { colors } = useTheme()
42
+ return (
43
+ <View style={[styles.container, { backgroundColor: colors.background }]} accessibilityRole="alert">
44
+ <View style={[styles.iconCircle, { backgroundColor: colors.destructiveTint }]}>
45
+ {renderIcon('alert-triangle', ms(28), colors.destructive)}
46
+ </View>
47
+ <Text style={[styles.title, { color: colors.foreground }]} allowFontScaling={true}>
48
+ {title}
49
+ </Text>
50
+ <Text style={[styles.message, { color: colors.foregroundMuted }]} allowFontScaling={true}>
51
+ {message ?? error.message ?? 'An unexpected error occurred.'}
52
+ </Text>
53
+ <TouchableOpacity
54
+ style={[styles.button, { backgroundColor: colors.primary }]}
55
+ onPress={() => {
56
+ impactLight()
57
+ reset()
58
+ }}
59
+ activeOpacity={0.85}
60
+ touchSoundDisabled={true}
61
+ accessibilityRole="button"
62
+ accessibilityLabel="Try again"
63
+ >
64
+ <Text style={[styles.buttonLabel, { color: colors.primaryForeground }]} allowFontScaling={true}>
65
+ Try again
66
+ </Text>
67
+ </TouchableOpacity>
68
+ </View>
69
+ )
70
+ }
71
+
72
+ /**
73
+ * Catches render-time errors in its subtree and shows a themed fallback instead
74
+ * of unmounting the whole app. Wrap screens or risky subtrees.
75
+ *
76
+ * @example
77
+ * <ErrorBoundary onError={reportCrash}>
78
+ * <DocumentViewer />
79
+ * </ErrorBoundary>
80
+ */
81
+ export class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
82
+ state: ErrorBoundaryState = { error: null }
83
+
84
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
85
+ return { error }
86
+ }
87
+
88
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
89
+ this.props.onError?.(error, info)
90
+ }
91
+
92
+ reset = () => {
93
+ this.setState({ error: null })
94
+ }
95
+
96
+ render() {
97
+ const { error } = this.state
98
+ if (error) {
99
+ const { fallback, title, message } = this.props
100
+ if (typeof fallback === 'function') {
101
+ return fallback({ error, reset: this.reset })
102
+ }
103
+ if (fallback !== undefined) {
104
+ return fallback
105
+ }
106
+ return <DefaultErrorFallback error={error} reset={this.reset} title={title} message={message} />
107
+ }
108
+ return this.props.children
109
+ }
110
+ }
111
+
112
+ const styles = StyleSheet.create({
113
+ container: {
114
+ flex: 1,
115
+ alignItems: 'center',
116
+ justifyContent: 'center',
117
+ paddingHorizontal: s(32),
118
+ gap: vs(12),
119
+ },
120
+ iconCircle: {
121
+ width: s(64),
122
+ height: s(64),
123
+ borderRadius: RADIUS.full,
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ marginBottom: vs(4),
127
+ },
128
+ title: {
129
+ fontFamily: 'Sohne-SemiBold',
130
+ fontSize: ms(18),
131
+ lineHeight: mvs(24),
132
+ textAlign: 'center',
133
+ },
134
+ message: {
135
+ fontFamily: 'Sohne-Regular',
136
+ fontSize: ms(14),
137
+ lineHeight: mvs(20),
138
+ textAlign: 'center',
139
+ },
140
+ button: {
141
+ marginTop: vs(8),
142
+ paddingHorizontal: s(20),
143
+ paddingVertical: vs(10),
144
+ borderRadius: RADIUS.md,
145
+ minHeight: vs(44),
146
+ alignItems: 'center',
147
+ justifyContent: 'center',
148
+ },
149
+ buttonLabel: {
150
+ fontFamily: 'Sohne-Medium',
151
+ fontSize: ms(15),
152
+ },
153
+ })
@@ -0,0 +1 @@
1
+ export * from './ErrorBoundary'
@@ -0,0 +1,149 @@
1
+ import React from 'react'
2
+ import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native'
3
+ import { useTheme } from '../../theme'
4
+ import { s, vs } from '../../utils/scaling'
5
+
6
+ export interface FormProps {
7
+ children: React.ReactNode
8
+ style?: ViewStyle
9
+ }
10
+
11
+ export interface FormFieldProps {
12
+ children: React.ReactNode
13
+ label?: string
14
+ error?: string
15
+ required?: boolean
16
+ style?: ViewStyle
17
+ labelStyle?: TextStyle
18
+ errorStyle?: TextStyle
19
+ }
20
+
21
+ export interface FormSectionProps {
22
+ children: React.ReactNode
23
+ title?: string
24
+ description?: string
25
+ style?: ViewStyle
26
+ }
27
+
28
+ export interface FormFooterProps {
29
+ children: React.ReactNode
30
+ style?: ViewStyle
31
+ }
32
+
33
+ /**
34
+ * Form wrapper with consistent spacing between fields.
35
+ * Use Form.Field for individual inputs with label + error,
36
+ * Form.Section for grouped fields, and Form.Footer for action buttons.
37
+ */
38
+ export function Form({ children, style }: FormProps) {
39
+ return <View style={[styles.form, style]}>{children}</View>
40
+ }
41
+
42
+ /**
43
+ * Wraps a single form input with optional label and error message.
44
+ * Automatically spaces children properly.
45
+ */
46
+ export function FormField({
47
+ children,
48
+ label,
49
+ error,
50
+ required,
51
+ style,
52
+ labelStyle,
53
+ errorStyle,
54
+ }: FormFieldProps) {
55
+ const { colors } = useTheme()
56
+
57
+ return (
58
+ <View style={[styles.field, style]}>
59
+ {label ? (
60
+ <Text style={[styles.label, { color: colors.foreground }, labelStyle]} allowFontScaling={true}>
61
+ {label}
62
+ {required ? <Text style={{ color: colors.destructive }}> *</Text> : null}
63
+ </Text>
64
+ ) : null}
65
+ {children}
66
+ {error ? (
67
+ <Text style={[styles.error, { color: colors.destructive }, errorStyle]} allowFontScaling={true}>
68
+ {error}
69
+ </Text>
70
+ ) : null}
71
+ </View>
72
+ )
73
+ }
74
+
75
+ /**
76
+ * Groups related form fields with optional title and description.
77
+ */
78
+ export function FormSection({ children, title, description, style }: FormSectionProps) {
79
+ const { colors } = useTheme()
80
+
81
+ return (
82
+ <View style={[styles.section, style]}>
83
+ {title ? (
84
+ <View style={styles.sectionHeader}>
85
+ <Text style={[styles.sectionTitle, { color: colors.foreground }]} allowFontScaling={true}>
86
+ {title}
87
+ </Text>
88
+ {description ? (
89
+ <Text style={[styles.sectionDescription, { color: colors.foregroundMuted }]} allowFontScaling={true}>
90
+ {description}
91
+ </Text>
92
+ ) : null}
93
+ </View>
94
+ ) : null}
95
+ {children}
96
+ </View>
97
+ )
98
+ }
99
+
100
+ /**
101
+ * Footer area for submit/cancel buttons or form actions.
102
+ */
103
+ export function FormFooter({ children, style }: FormFooterProps) {
104
+ return <View style={[styles.footer, style]}>{children}</View>
105
+ }
106
+
107
+ Form.Field = FormField
108
+ Form.Section = FormSection
109
+ Form.Footer = FormFooter
110
+
111
+ const styles = StyleSheet.create({
112
+ form: {
113
+ gap: vs(16),
114
+ },
115
+ field: {
116
+ gap: vs(6),
117
+ },
118
+ label: {
119
+ fontFamily: 'Sohne-Medium',
120
+ fontSize: 14,
121
+ lineHeight: 20,
122
+ },
123
+ error: {
124
+ fontFamily: 'Sohne-Regular',
125
+ fontSize: 12,
126
+ lineHeight: 16,
127
+ },
128
+ section: {
129
+ gap: vs(16),
130
+ },
131
+ sectionHeader: {
132
+ gap: vs(4),
133
+ },
134
+ sectionTitle: {
135
+ fontFamily: 'Sohne-SemiBold',
136
+ fontSize: 16,
137
+ lineHeight: 24,
138
+ },
139
+ sectionDescription: {
140
+ fontFamily: 'Sohne-Regular',
141
+ fontSize: 14,
142
+ lineHeight: 20,
143
+ },
144
+ footer: {
145
+ flexDirection: 'row',
146
+ gap: s(12),
147
+ paddingTop: vs(8),
148
+ },
149
+ })
@@ -0,0 +1 @@
1
+ export * from './Form'