@retray-dev/ui-kit 6.2.0 → 7.0.1

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 (317) hide show
  1. package/COMPONENTS.md +444 -10
  2. package/EXAMPLES.md +248 -0
  3. package/README.md +11 -10
  4. package/dist/Accordion.d.mts +28 -0
  5. package/dist/Accordion.d.ts +28 -0
  6. package/dist/Accordion.js +340 -0
  7. package/dist/Accordion.mjs +6 -0
  8. package/dist/AlertBanner.d.mts +16 -0
  9. package/dist/AlertBanner.d.ts +16 -0
  10. package/dist/AlertBanner.js +247 -0
  11. package/dist/AlertBanner.mjs +5 -0
  12. package/dist/Avatar.d.mts +20 -0
  13. package/dist/Avatar.d.ts +20 -0
  14. package/dist/Avatar.js +234 -0
  15. package/dist/Avatar.mjs +3 -0
  16. package/dist/Badge.d.mts +26 -0
  17. package/dist/Badge.d.ts +26 -0
  18. package/dist/Badge.js +247 -0
  19. package/dist/Badge.mjs +4 -0
  20. package/dist/Button.d.mts +25 -0
  21. package/dist/Button.d.ts +25 -0
  22. package/dist/Button.js +414 -0
  23. package/dist/Button.mjs +8 -0
  24. package/dist/ButtonGroup.d.mts +26 -0
  25. package/dist/ButtonGroup.d.ts +26 -0
  26. package/dist/ButtonGroup.js +52 -0
  27. package/dist/ButtonGroup.mjs +2 -0
  28. package/dist/Card.d.mts +39 -0
  29. package/dist/Card.d.ts +39 -0
  30. package/dist/Card.js +329 -0
  31. package/dist/Card.mjs +7 -0
  32. package/dist/CategoryStrip.d.mts +26 -0
  33. package/dist/CategoryStrip.d.ts +26 -0
  34. package/dist/CategoryStrip.js +396 -0
  35. package/dist/CategoryStrip.mjs +9 -0
  36. package/dist/Checkbox.d.mts +14 -0
  37. package/dist/Checkbox.d.ts +14 -0
  38. package/dist/Checkbox.js +304 -0
  39. package/dist/Checkbox.mjs +7 -0
  40. package/dist/Chip.d.mts +31 -0
  41. package/dist/Chip.d.ts +31 -0
  42. package/dist/Chip.js +370 -0
  43. package/dist/Chip.mjs +8 -0
  44. package/dist/ConfirmDialog.d.mts +15 -0
  45. package/dist/ConfirmDialog.d.ts +15 -0
  46. package/dist/ConfirmDialog.js +530 -0
  47. package/dist/ConfirmDialog.mjs +9 -0
  48. package/dist/CurrencyDisplay.d.mts +24 -0
  49. package/dist/CurrencyDisplay.d.ts +24 -0
  50. package/dist/CurrencyDisplay.js +189 -0
  51. package/dist/CurrencyDisplay.mjs +3 -0
  52. package/dist/CurrencyInput.d.mts +26 -0
  53. package/dist/CurrencyInput.d.ts +26 -0
  54. package/dist/CurrencyInput.js +404 -0
  55. package/dist/CurrencyInput.mjs +7 -0
  56. package/dist/DetailRow.d.mts +32 -0
  57. package/dist/DetailRow.d.ts +32 -0
  58. package/dist/DetailRow.js +275 -0
  59. package/dist/DetailRow.mjs +4 -0
  60. package/dist/EmptyState.d.mts +27 -0
  61. package/dist/EmptyState.d.ts +27 -0
  62. package/dist/EmptyState.js +503 -0
  63. package/dist/EmptyState.mjs +9 -0
  64. package/dist/Form.d.mts +52 -0
  65. package/dist/Form.d.ts +52 -0
  66. package/dist/Form.js +204 -0
  67. package/dist/Form.mjs +3 -0
  68. package/dist/IconButton.d.mts +22 -0
  69. package/dist/IconButton.d.ts +22 -0
  70. package/dist/IconButton.js +383 -0
  71. package/dist/IconButton.mjs +7 -0
  72. package/dist/Input.d.mts +23 -0
  73. package/dist/Input.d.ts +23 -0
  74. package/dist/Input.js +351 -0
  75. package/dist/Input.mjs +6 -0
  76. package/dist/LabelValue.d.mts +16 -0
  77. package/dist/LabelValue.d.ts +16 -0
  78. package/dist/LabelValue.js +225 -0
  79. package/dist/LabelValue.mjs +4 -0
  80. package/dist/ListGroup.d.mts +34 -0
  81. package/dist/ListGroup.d.ts +34 -0
  82. package/dist/ListGroup.js +217 -0
  83. package/dist/ListGroup.mjs +4 -0
  84. package/dist/ListItem.d.mts +64 -0
  85. package/dist/ListItem.d.ts +64 -0
  86. package/dist/ListItem.js +430 -0
  87. package/dist/ListItem.mjs +8 -0
  88. package/dist/MediaCard.d.mts +39 -0
  89. package/dist/MediaCard.d.ts +39 -0
  90. package/dist/MediaCard.js +427 -0
  91. package/dist/MediaCard.mjs +8 -0
  92. package/dist/MenuGroup.d.mts +34 -0
  93. package/dist/MenuGroup.d.ts +34 -0
  94. package/dist/MenuGroup.js +217 -0
  95. package/dist/MenuGroup.mjs +4 -0
  96. package/dist/MenuItem.d.mts +48 -0
  97. package/dist/MenuItem.d.ts +48 -0
  98. package/dist/MenuItem.js +403 -0
  99. package/dist/MenuItem.mjs +8 -0
  100. package/dist/MonthPicker.d.mts +20 -0
  101. package/dist/MonthPicker.d.ts +20 -0
  102. package/dist/MonthPicker.js +234 -0
  103. package/dist/MonthPicker.mjs +4 -0
  104. package/dist/Pressable.d.mts +34 -0
  105. package/dist/Pressable.d.ts +34 -0
  106. package/dist/Pressable.js +132 -0
  107. package/dist/Pressable.mjs +4 -0
  108. package/dist/Progress.d.mts +14 -0
  109. package/dist/Progress.d.ts +14 -0
  110. package/dist/Progress.js +191 -0
  111. package/dist/Progress.mjs +4 -0
  112. package/dist/RadioGroup.d.mts +19 -0
  113. package/dist/RadioGroup.d.ts +19 -0
  114. package/dist/RadioGroup.js +341 -0
  115. package/dist/RadioGroup.mjs +7 -0
  116. package/dist/Select.d.mts +22 -0
  117. package/dist/Select.d.ts +22 -0
  118. package/dist/Select.js +441 -0
  119. package/dist/Select.mjs +6 -0
  120. package/dist/Separator.d.mts +10 -0
  121. package/dist/Separator.d.ts +10 -0
  122. package/dist/Separator.js +156 -0
  123. package/dist/Separator.mjs +2 -0
  124. package/dist/Sheet.d.mts +81 -0
  125. package/dist/Sheet.d.ts +81 -0
  126. package/dist/Sheet.js +340 -0
  127. package/dist/Sheet.mjs +4 -0
  128. package/dist/Skeleton.d.mts +17 -0
  129. package/dist/Skeleton.d.ts +17 -0
  130. package/dist/Skeleton.js +205 -0
  131. package/dist/Skeleton.mjs +4 -0
  132. package/dist/Slider.d.mts +20 -0
  133. package/dist/Slider.d.ts +20 -0
  134. package/dist/Slider.js +232 -0
  135. package/dist/Slider.mjs +4 -0
  136. package/dist/Spinner.d.mts +12 -0
  137. package/dist/Spinner.d.ts +12 -0
  138. package/dist/Spinner.js +172 -0
  139. package/dist/Spinner.mjs +3 -0
  140. package/dist/Switch.d.mts +13 -0
  141. package/dist/Switch.d.ts +13 -0
  142. package/dist/Switch.js +261 -0
  143. package/dist/Switch.mjs +5 -0
  144. package/dist/Tabs.d.mts +27 -0
  145. package/dist/Tabs.d.ts +27 -0
  146. package/dist/Tabs.js +389 -0
  147. package/dist/Tabs.mjs +6 -0
  148. package/dist/Text.d.mts +12 -0
  149. package/dist/Text.d.ts +12 -0
  150. package/dist/Text.js +311 -0
  151. package/dist/Text.mjs +4 -0
  152. package/dist/Textarea.d.mts +16 -0
  153. package/dist/Textarea.d.ts +16 -0
  154. package/dist/Textarea.js +333 -0
  155. package/dist/Textarea.mjs +6 -0
  156. package/dist/Toast.d.mts +47 -0
  157. package/dist/Toast.d.ts +47 -0
  158. package/dist/Toast.js +185 -0
  159. package/dist/Toast.mjs +3 -0
  160. package/dist/Toggle.d.mts +33 -0
  161. package/dist/Toggle.d.ts +33 -0
  162. package/dist/Toggle.js +397 -0
  163. package/dist/Toggle.mjs +8 -0
  164. package/dist/VirtualList.d.mts +19 -0
  165. package/dist/VirtualList.d.ts +19 -0
  166. package/dist/VirtualList.js +38 -0
  167. package/dist/VirtualList.mjs +1 -0
  168. package/dist/chunk-2CE3TQVY.mjs +11 -0
  169. package/dist/chunk-2UYENBLV.mjs +49 -0
  170. package/dist/chunk-3BBOZ3OQ.mjs +41 -0
  171. package/dist/chunk-5IKW3VNC.mjs +43 -0
  172. package/dist/chunk-63357L2X.mjs +51 -0
  173. package/dist/chunk-6LQYY7HC.mjs +127 -0
  174. package/dist/chunk-6Q64UFIA.mjs +71 -0
  175. package/dist/chunk-76PFOSM2.mjs +41 -0
  176. package/dist/chunk-7H2OR44A.mjs +14 -0
  177. package/dist/chunk-A4MDAP7G.mjs +42 -0
  178. package/dist/chunk-AU2VDY4P.mjs +190 -0
  179. package/dist/chunk-BRKYVJVV.mjs +60 -0
  180. package/dist/chunk-CRYBX2CM.mjs +146 -0
  181. package/dist/chunk-DITNP6PL.mjs +106 -0
  182. package/dist/chunk-FTLJOUOQ.mjs +97 -0
  183. package/dist/chunk-GCWOGZYL.mjs +104 -0
  184. package/dist/chunk-GNGLDL6Z.mjs +60 -0
  185. package/dist/chunk-GPOUINK5.mjs +148 -0
  186. package/dist/chunk-HSPSMN6U.mjs +115 -0
  187. package/dist/chunk-IRRY3CRZ.mjs +82 -0
  188. package/dist/chunk-JB67UOB5.mjs +92 -0
  189. package/dist/chunk-JBLL7U3U.mjs +64 -0
  190. package/dist/chunk-KWCPOM6W.mjs +136 -0
  191. package/dist/chunk-KZJRQOIU.mjs +64 -0
  192. package/dist/chunk-L7E7TVEZ.mjs +145 -0
  193. package/dist/chunk-LG4DO3DK.mjs +174 -0
  194. package/dist/chunk-LWG526VX.mjs +139 -0
  195. package/dist/chunk-MN7OG7IY.mjs +96 -0
  196. package/dist/chunk-MX6HRKMI.mjs +29 -0
  197. package/dist/chunk-NC5ZTR2Y.mjs +32 -0
  198. package/dist/chunk-NQGVLMWG.mjs +90 -0
  199. package/dist/chunk-QCNARS3X.mjs +46 -0
  200. package/dist/chunk-QXGYKWI7.mjs +134 -0
  201. package/dist/chunk-QY3X2UYR.mjs +191 -0
  202. package/dist/chunk-RKLHUDZS.mjs +92 -0
  203. package/dist/chunk-RMMK64W5.mjs +54 -0
  204. package/dist/chunk-RR2VQLKE.mjs +190 -0
  205. package/dist/chunk-RTC3CFXF.mjs +29 -0
  206. package/dist/chunk-SBZYEV4S.mjs +61 -0
  207. package/dist/chunk-SOA2Z4RB.mjs +82 -0
  208. package/dist/chunk-SOYNZDVY.mjs +151 -0
  209. package/dist/chunk-T7XZ7H7Y.mjs +57 -0
  210. package/dist/chunk-TAJ2PQ2O.mjs +163 -0
  211. package/dist/chunk-U4N7WF4Z.mjs +108 -0
  212. package/dist/chunk-URDE3EUU.mjs +132 -0
  213. package/dist/chunk-URLL5JBR.mjs +245 -0
  214. package/dist/chunk-XDMN67KV.mjs +59 -0
  215. package/dist/chunk-Y6MXOREN.mjs +120 -0
  216. package/dist/chunk-YZJAFS4P.mjs +131 -0
  217. package/dist/index.d.mts +94 -873
  218. package/dist/index.d.ts +94 -873
  219. package/dist/index.js +751 -357
  220. package/dist/index.mjs +50 -3895
  221. package/package.json +23 -14
  222. package/src/assets/fonts/Sohne-Bold.otf +0 -0
  223. package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
  224. package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
  225. package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
  226. package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
  227. package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
  228. package/src/assets/fonts/Sohne-Italic.otf +0 -0
  229. package/src/assets/fonts/Sohne-Light.otf +0 -0
  230. package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
  231. package/src/assets/fonts/Sohne-Medium.otf +0 -0
  232. package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
  233. package/src/assets/fonts/Sohne-Regular.otf +0 -0
  234. package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
  235. package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
  236. package/src/assets/fonts/SohneMono-Bold.otf +0 -0
  237. package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
  238. package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
  239. package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
  240. package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
  241. package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
  242. package/src/assets/fonts/SohneMono-Italic.otf +0 -0
  243. package/src/assets/fonts/SohneMono-Light.otf +0 -0
  244. package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
  245. package/src/assets/fonts/SohneMono-Medium.otf +0 -0
  246. package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
  247. package/src/assets/fonts/SohneMono-Regular.otf +0 -0
  248. package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
  249. package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
  250. package/src/components/Accordion/Accordion.tsx +3 -3
  251. package/src/components/AlertBanner/AlertBanner.tsx +33 -12
  252. package/src/components/Avatar/Avatar.tsx +4 -2
  253. package/src/components/Badge/Badge.tsx +4 -2
  254. package/src/components/Button/Button.tsx +10 -11
  255. package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
  256. package/src/components/Card/Card.tsx +17 -34
  257. package/src/components/CategoryStrip/CategoryStrip.tsx +24 -21
  258. package/src/components/Checkbox/Checkbox.tsx +11 -6
  259. package/src/components/Chip/Chip.tsx +17 -15
  260. package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
  261. package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
  262. package/src/components/CurrencyInput/CurrencyInput.tsx +2 -2
  263. package/src/components/DetailRow/DetailRow.tsx +9 -7
  264. package/src/components/EmptyState/EmptyState.tsx +2 -2
  265. package/src/components/Form/Form.tsx +149 -0
  266. package/src/components/Form/index.ts +1 -0
  267. package/src/components/IconButton/IconButton.tsx +4 -2
  268. package/src/components/Input/Input.tsx +27 -31
  269. package/src/components/LabelValue/LabelValue.tsx +6 -4
  270. package/src/components/ListGroup/ListGroup.tsx +145 -0
  271. package/src/components/ListGroup/index.ts +1 -0
  272. package/src/components/ListItem/ListItem.tsx +9 -10
  273. package/src/components/MediaCard/MediaCard.tsx +7 -5
  274. package/src/components/MenuGroup/MenuGroup.tsx +145 -0
  275. package/src/components/MenuGroup/index.ts +1 -0
  276. package/src/components/MenuItem/MenuItem.tsx +7 -9
  277. package/src/components/MonthPicker/MonthPicker.tsx +2 -2
  278. package/src/components/RadioGroup/RadioGroup.tsx +11 -14
  279. package/src/components/Select/Select.tsx +6 -6
  280. package/src/components/Separator/Separator.tsx +1 -3
  281. package/src/components/Sheet/Sheet.tsx +81 -17
  282. package/src/components/Skeleton/Skeleton.tsx +1 -1
  283. package/src/components/Slider/Slider.tsx +2 -2
  284. package/src/components/Spinner/Spinner.tsx +1 -1
  285. package/src/components/Switch/Switch.tsx +28 -5
  286. package/src/components/Tabs/Tabs.tsx +22 -18
  287. package/src/components/Text/Text.tsx +3 -1
  288. package/src/components/Textarea/Textarea.tsx +18 -14
  289. package/src/components/Toast/Toast.tsx +6 -6
  290. package/src/components/Toggle/Toggle.tsx +47 -23
  291. package/src/components/VirtualList/VirtualList.tsx +60 -0
  292. package/src/components/VirtualList/index.ts +1 -0
  293. package/src/fonts.ts +38 -20
  294. package/src/index.ts +5 -1
  295. package/src/theme/colors.ts +53 -39
  296. package/src/theme/types.ts +3 -0
  297. package/src/tokens.ts +49 -39
  298. package/src/utils/icons.ts +47 -20
  299. package/src/utils/usePressScale.ts +2 -0
  300. package/src/assets/fonts/Poppins-Black.ttf +0 -0
  301. package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
  302. package/src/assets/fonts/Poppins-Bold.ttf +0 -0
  303. package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
  304. package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
  305. package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
  306. package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
  307. package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
  308. package/src/assets/fonts/Poppins-Italic.ttf +0 -0
  309. package/src/assets/fonts/Poppins-Light.ttf +0 -0
  310. package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
  311. package/src/assets/fonts/Poppins-Medium.ttf +0 -0
  312. package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
  313. package/src/assets/fonts/Poppins-Regular.ttf +0 -0
  314. package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  315. package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
  316. package/src/assets/fonts/Poppins-Thin.ttf +0 -0
  317. package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
@@ -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'
@@ -81,7 +81,7 @@ export interface ListItemProps {
81
81
  accessibilityLabel?: string
82
82
  }
83
83
 
84
- export function ListItem({
84
+ function ListItemBase({
85
85
  leftRender,
86
86
  rightRender,
87
87
  trailing,
@@ -210,10 +210,7 @@ export function ListItem({
210
210
  <View
211
211
  style={[
212
212
  styles.separator,
213
- {
214
- backgroundColor: colors.border,
215
- marginLeft: effectiveLeft ? s(44) + s(12) : 0
216
- },
213
+ { backgroundColor: colors.separator },
217
214
  ]}
218
215
  />
219
216
  ) : null}
@@ -221,11 +218,13 @@ export function ListItem({
221
218
  )
222
219
  }
223
220
 
221
+ export const ListItem = React.memo(ListItemBase)
222
+
224
223
  const styles = StyleSheet.create({
225
224
  container: {
226
225
  flexDirection: 'row',
227
226
  alignItems: 'center',
228
- paddingHorizontal: 0,
227
+ paddingHorizontal: s(16),
229
228
  paddingVertical: vs(10),
230
229
  gap: s(12),
231
230
  },
@@ -241,17 +240,17 @@ const styles = StyleSheet.create({
241
240
  gap: vs(4),
242
241
  },
243
242
  title: {
244
- fontFamily: 'Poppins-Medium',
243
+ fontFamily: 'Sohne-Medium',
245
244
  fontSize: ms(15),
246
245
  lineHeight: mvs(22),
247
246
  },
248
247
  subtitle: {
249
- fontFamily: 'Poppins-Regular',
248
+ fontFamily: 'Sohne-Regular',
250
249
  fontSize: ms(13),
251
250
  lineHeight: mvs(18),
252
251
  },
253
252
  caption: {
254
- fontFamily: 'Poppins-Regular',
253
+ fontFamily: 'Sohne-Regular',
255
254
  fontSize: ms(12),
256
255
  lineHeight: mvs(16),
257
256
  opacity: 0.7,
@@ -263,7 +262,7 @@ const styles = StyleSheet.create({
263
262
  maxWidth: s(160),
264
263
  },
265
264
  rightText: {
266
- fontFamily: 'Poppins-Regular',
265
+ fontFamily: 'Sohne-Regular',
267
266
  fontSize: ms(14),
268
267
  },
269
268
  separator: {
@@ -61,7 +61,7 @@ export interface MediaCardProps {
61
61
  accessibilityLabel?: string
62
62
  }
63
63
 
64
- export function MediaCard({
64
+ function MediaCardBase({
65
65
  imageSource,
66
66
  aspectRatio = '4:3',
67
67
  badge,
@@ -112,7 +112,7 @@ export function MediaCard({
112
112
  {...(Platform.OS === 'web' ? hoverHandlers : {})}
113
113
  >
114
114
  <View style={[styles.imageContainer, imageStyle]}>
115
- <View style={{ paddingTop: `${ratio * 100}%` as any }}>
115
+ <View style={{ paddingTop: `${ratio * 100}%` as `${number}%` }}>
116
116
  <View style={StyleSheet.absoluteFill}>
117
117
  {imageSource ? (
118
118
  <Image
@@ -191,6 +191,8 @@ export function MediaCard({
191
191
  return cardContent
192
192
  }
193
193
 
194
+ export const MediaCard = React.memo(MediaCardBase)
195
+
194
196
  const styles = StyleSheet.create({
195
197
  card: {
196
198
  borderRadius: RADIUS.md,
@@ -233,17 +235,17 @@ const styles = StyleSheet.create({
233
235
  gap: vs(2),
234
236
  },
235
237
  title: {
236
- fontFamily: 'Poppins-SemiBold',
238
+ fontFamily: 'Sohne-SemiBold',
237
239
  fontSize: ms(14),
238
240
  lineHeight: mvs(20),
239
241
  },
240
242
  subtitle: {
241
- fontFamily: 'Poppins-Regular',
243
+ fontFamily: 'Sohne-Regular',
242
244
  fontSize: ms(13),
243
245
  lineHeight: mvs(18),
244
246
  },
245
247
  caption: {
246
- fontFamily: 'Poppins-Regular',
248
+ fontFamily: 'Sohne-Regular',
247
249
  fontSize: ms(12),
248
250
  lineHeight: mvs(16),
249
251
  },
@@ -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 MenuGroupVariant = 'plain' | 'card'
8
+
9
+ export interface MenuGroupProps {
10
+ children: React.ReactNode
11
+ /**
12
+ * - `plain` (default): no background, plain MenuItems inside.
13
+ * - `card`: card surface with background + border wrapping plain MenuItems.
14
+ */
15
+ variant?: MenuGroupVariant
16
+ style?: ViewStyle
17
+ }
18
+
19
+ export interface MenuGroupHeaderProps {
20
+ children: React.ReactNode
21
+ style?: ViewStyle
22
+ }
23
+
24
+ export interface MenuGroupFooterProps {
25
+ children: React.ReactNode
26
+ style?: ViewStyle
27
+ }
28
+
29
+ /**
30
+ * MenuGroup wraps multiple MenuItems 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 MenuGroup({ children, variant = 'plain', style }: MenuGroupProps) {
34
+ const { colors } = useTheme()
35
+
36
+ // Auto-inject showSeparator={true} to all MenuItem children except the last
37
+ const processedChildren = React.Children.map(children, (child, index) => {
38
+ if (!React.isValidElement(child)) return child
39
+
40
+ // Skip MenuGroup.Header and MenuGroup.Footer
41
+ if (child.type === MenuGroupHeader || child.type === MenuGroupFooter) {
42
+ return child
43
+ }
44
+
45
+ // Check if it's a MenuItem (has onPress prop as a heuristic)
46
+ const childProps = child.props as Record<string, unknown>
47
+ const isMenuItem = 'onPress' in childProps
48
+ if (!isMenuItem) 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 MenuGroupHeader({ children, style }: MenuGroupHeaderProps) {
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 MenuGroupFooter({ children, style }: MenuGroupFooterProps) {
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
+ MenuGroup.Header = MenuGroupHeader
118
+ MenuGroup.Footer = MenuGroupFooter
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 './MenuGroup'
@@ -60,7 +60,7 @@ export interface MenuItemProps {
60
60
  accessibilityLabel?: string
61
61
  }
62
62
 
63
- export function MenuItem({
63
+ function MenuItemBase({
64
64
  label,
65
65
  subtitle,
66
66
  iconName,
@@ -164,11 +164,7 @@ export function MenuItem({
164
164
  <View
165
165
  style={[
166
166
  styles.separator,
167
- {
168
- backgroundColor: colors.border,
169
- marginLeft: resolvedIcon ? s(22) + s(12) : 0,
170
- opacity: 0.6,
171
- },
167
+ { backgroundColor: colors.separator },
172
168
  ]}
173
169
  />
174
170
  ) : null}
@@ -176,11 +172,13 @@ export function MenuItem({
176
172
  )
177
173
  }
178
174
 
175
+ export const MenuItem = React.memo(MenuItemBase)
176
+
179
177
  const styles = StyleSheet.create({
180
178
  container: {
181
179
  flexDirection: 'row',
182
180
  alignItems: 'center',
183
- paddingHorizontal: 0,
181
+ paddingHorizontal: s(16),
184
182
  paddingVertical: vs(16),
185
183
  minHeight: vs(54),
186
184
  gap: s(12),
@@ -196,11 +194,11 @@ const styles = StyleSheet.create({
196
194
  justifyContent: 'center',
197
195
  },
198
196
  label: {
199
- fontFamily: 'Poppins-Medium',
197
+ fontFamily: 'Sohne-Medium',
200
198
  fontSize: ms(15),
201
199
  },
202
200
  subtitle: {
203
- fontFamily: 'Poppins-Regular',
201
+ fontFamily: 'Sohne-Regular',
204
202
  fontSize: ms(12),
205
203
  marginTop: vs(1),
206
204
  },
@@ -3,7 +3,7 @@ import { View, Text, TouchableOpacity, StyleSheet, ViewStyle } from 'react-nativ
3
3
  import { Entypo } from '@expo/vector-icons'
4
4
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
5
5
  import { useTheme } from '../../theme'
6
- import { s, vs, ms, mvs } from '../../utils/scaling'
6
+ import { s, ms, mvs } from '../../utils/scaling'
7
7
 
8
8
  const MONTH_NAMES: Record<string, string[]> = {
9
9
  en: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
@@ -103,7 +103,7 @@ const styles = StyleSheet.create({
103
103
  justifyContent: 'center',
104
104
  },
105
105
  label: {
106
- fontFamily: 'Poppins-Medium',
106
+ fontFamily: 'Sohne-Medium',
107
107
  fontSize: ms(17),
108
108
  lineHeight: mvs(24),
109
109
  textAlign: 'center',
@@ -45,7 +45,6 @@ function RadioItem({
45
45
  })
46
46
  const colorProgress = useColorTransition(selected)
47
47
 
48
- // Pop-in animation for the inner dot
49
48
  const dotScale = useSharedValue(selected ? 1 : 0)
50
49
  useEffect(() => {
51
50
  dotScale.value = withSpring(selected ? 1 : 0, SPRINGS.elastic)
@@ -61,8 +60,11 @@ function RadioItem({
61
60
  }))
62
61
 
63
62
  return (
63
+ // AUDIT FIX: opacity was applied only to the radio circle, leaving the label
64
+ // at full opacity when disabled. The whole row now dims uniformly so users
65
+ // get a single, consistent disabled signal across the entire item.
64
66
  <TouchableOpacity
65
- style={styles.row}
67
+ style={[styles.row, option.disabled && styles.rowDisabled]}
66
68
  onPress={() => {
67
69
  if (!option.disabled) {
68
70
  hapticSelection()
@@ -79,21 +81,12 @@ function RadioItem({
79
81
  accessibilityState={{ checked: selected, disabled: !!option.disabled }}
80
82
  >
81
83
  <Animated.View style={scaleStyle}>
82
- <Animated.View
83
- style={[
84
- styles.radio,
85
- { opacity: option.disabled ? 0.45 : 1 },
86
- radioStyle,
87
- ]}
88
- >
84
+ <Animated.View style={[styles.radio, radioStyle]}>
89
85
  <Animated.View style={[styles.dot, { backgroundColor: colors.primary }, dotStyle]} />
90
86
  </Animated.View>
91
87
  </Animated.View>
92
88
  <Text
93
- style={[
94
- styles.label,
95
- { color: option.disabled ? colors.foregroundMuted : colors.foreground },
96
- ]}
89
+ style={[styles.label, { color: colors.foreground }]}
97
90
  allowFontScaling={true}
98
91
  >
99
92
  {option.label}
@@ -141,6 +134,10 @@ const styles = StyleSheet.create({
141
134
  alignItems: 'center',
142
135
  gap: s(12),
143
136
  },
137
+ // AUDIT FIX: was opacity on the inner circle only
138
+ rowDisabled: {
139
+ opacity: 0.45,
140
+ },
144
141
  radio: {
145
142
  width: s(24),
146
143
  height: s(24),
@@ -155,7 +152,7 @@ const styles = StyleSheet.create({
155
152
  borderRadius: s(5),
156
153
  },
157
154
  label: {
158
- fontFamily: 'Poppins-Regular',
155
+ fontFamily: 'Sohne-Regular',
159
156
  fontSize: ms(14),
160
157
  lineHeight: mvs(20),
161
158
  },
@@ -60,7 +60,7 @@ export function Select({
60
60
  setPendingValue(value)
61
61
  setPickerVisible(true)
62
62
  } else if (isAndroid) {
63
- ;(pickerRef.current as any)?.focus()
63
+ ;(pickerRef.current as { focus?: () => void })?.focus?.()
64
64
  }
65
65
  }
66
66
 
@@ -234,7 +234,7 @@ const styles = StyleSheet.create({
234
234
  gap: vs(8),
235
235
  },
236
236
  label: {
237
- fontFamily: 'Poppins-Medium',
237
+ fontFamily: 'Sohne-Medium',
238
238
  fontSize: ms(13),
239
239
  },
240
240
  trigger: {
@@ -247,7 +247,7 @@ const styles = StyleSheet.create({
247
247
  paddingVertical: vs(11),
248
248
  },
249
249
  triggerText: {
250
- fontFamily: 'Poppins-Regular',
250
+ fontFamily: 'Sohne-Regular',
251
251
  fontSize: ms(15),
252
252
  flex: 1,
253
253
  },
@@ -255,7 +255,7 @@ const styles = StyleSheet.create({
255
255
  marginLeft: s(8),
256
256
  },
257
257
  helperText: {
258
- fontFamily: 'Poppins-Regular',
258
+ fontFamily: 'Sohne-Regular',
259
259
  fontSize: ms(13),
260
260
  },
261
261
  iosBackdrop: {
@@ -276,14 +276,14 @@ const styles = StyleSheet.create({
276
276
  borderBottomWidth: 1,
277
277
  },
278
278
  iosToolbarTitle: {
279
- fontFamily: 'Poppins-SemiBold',
279
+ fontFamily: 'Sohne-SemiBold',
280
280
  fontSize: ms(17),
281
281
  },
282
282
  iosDoneBtn: {
283
283
  padding: s(4),
284
284
  },
285
285
  iosDoneBtnText: {
286
- fontFamily: 'Poppins-SemiBold',
286
+ fontFamily: 'Sohne-SemiBold',
287
287
  fontSize: ms(17),
288
288
  },
289
289
  androidHiddenPicker: {
@@ -14,7 +14,7 @@ export function Separator({ orientation = 'horizontal', style }: SeparatorProps)
14
14
  <View
15
15
  style={[
16
16
  orientation === 'horizontal' ? styles.horizontal : styles.vertical,
17
- { backgroundColor: colors.border },
17
+ { backgroundColor: colors.separator },
18
18
  style,
19
19
  ]}
20
20
  />
@@ -25,11 +25,9 @@ const styles = StyleSheet.create({
25
25
  horizontal: {
26
26
  height: 1,
27
27
  width: '100%',
28
- opacity: 0.7,
29
28
  },
30
29
  vertical: {
31
30
  width: 1,
32
31
  height: '100%',
33
- opacity: 0.7,
34
32
  },
35
33
  })