@retray-dev/ui-kit 6.1.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 (321) hide show
  1. package/COMPONENTS.md +447 -13
  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 -852
  218. package/dist/index.d.ts +94 -852
  219. package/dist/index.js +1387 -942
  220. package/dist/index.mjs +50 -3844
  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 +13 -15
  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 +30 -29
  255. package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
  256. package/src/components/Card/Card.tsx +36 -65
  257. package/src/components/CategoryStrip/CategoryStrip.tsx +68 -58
  258. package/src/components/Checkbox/Checkbox.tsx +41 -55
  259. package/src/components/Chip/Chip.tsx +49 -84
  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 +24 -20
  268. package/src/components/Input/Input.tsx +63 -50
  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 +30 -43
  273. package/src/components/MediaCard/MediaCard.tsx +31 -29
  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 +29 -40
  277. package/src/components/MonthPicker/MonthPicker.tsx +14 -4
  278. package/src/components/Pressable/Pressable.tsx +27 -46
  279. package/src/components/Progress/Progress.tsx +21 -12
  280. package/src/components/RadioGroup/RadioGroup.tsx +55 -32
  281. package/src/components/Select/Select.tsx +23 -21
  282. package/src/components/Separator/Separator.tsx +1 -3
  283. package/src/components/Sheet/Sheet.tsx +85 -18
  284. package/src/components/Skeleton/Skeleton.tsx +25 -14
  285. package/src/components/Slider/Slider.tsx +13 -3
  286. package/src/components/Spinner/Spinner.tsx +1 -1
  287. package/src/components/Switch/Switch.tsx +70 -52
  288. package/src/components/Tabs/Tabs.tsx +59 -47
  289. package/src/components/Text/Text.tsx +3 -1
  290. package/src/components/Textarea/Textarea.tsx +44 -23
  291. package/src/components/Toast/Toast.tsx +6 -6
  292. package/src/components/Toggle/Toggle.tsx +86 -68
  293. package/src/components/VirtualList/VirtualList.tsx +60 -0
  294. package/src/components/VirtualList/index.ts +1 -0
  295. package/src/fonts.ts +38 -20
  296. package/src/index.ts +5 -1
  297. package/src/theme/colors.ts +53 -39
  298. package/src/theme/types.ts +3 -0
  299. package/src/tokens.ts +49 -39
  300. package/src/utils/animations.ts +58 -0
  301. package/src/utils/icons.ts +47 -20
  302. package/src/utils/useColorTransition.ts +40 -0
  303. package/src/utils/usePressScale.ts +75 -0
  304. package/src/assets/fonts/Poppins-Black.ttf +0 -0
  305. package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
  306. package/src/assets/fonts/Poppins-Bold.ttf +0 -0
  307. package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
  308. package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
  309. package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
  310. package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
  311. package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
  312. package/src/assets/fonts/Poppins-Italic.ttf +0 -0
  313. package/src/assets/fonts/Poppins-Light.ttf +0 -0
  314. package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
  315. package/src/assets/fonts/Poppins-Medium.ttf +0 -0
  316. package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
  317. package/src/assets/fonts/Poppins-Regular.ttf +0 -0
  318. package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  319. package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
  320. package/src/assets/fonts/Poppins-Thin.ttf +0 -0
  321. package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
package/src/tokens.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  // ─── Spacing ─────────────────────────────────────────────────────────────────
2
- // 8pt grid with 2pt micro-step. `section` for major band separators (Airbnb: 64px).
3
2
  export const SPACING = {
4
3
  xxs: 2,
5
4
  xs: 4,
@@ -22,8 +21,6 @@ export const ICON_SIZES = {
22
21
  } as const
23
22
 
24
23
  // ─── Border radius ────────────────────────────────────────────────────────────
25
- // Airbnb-aligned shape language — soft everywhere, no hard corners on interactive elements.
26
- // xs: micro chips/tags sm: inputs/forms md: cards lg: sheet corners xl: primary CTAs (pill)
27
24
  export const RADIUS = {
28
25
  none: 0,
29
26
  xs: 4,
@@ -35,7 +32,6 @@ export const RADIUS = {
35
32
  } as const
36
33
 
37
34
  // ─── Shadows ──────────────────────────────────────────────────────────────────
38
- // Multi-tier. Default card usage = sm. Hover float = md. Modals = lg/xl.
39
35
  export const SHADOWS = {
40
36
  sm: {
41
37
  shadowColor: '#000',
@@ -73,118 +69,132 @@ export const BREAKPOINTS = {
73
69
  } as const
74
70
 
75
71
  // ─── Typography ───────────────────────────────────────────────────────────────
76
- // Airbnb-inspired hierarchy. Modest weights500-600 on display, not 700+.
77
- // Exception: display-hero (large number display) and display-xl always bold.
78
- // Poppins carries the full scale. All fontFamily values reference loaded font names.
72
+ // AUDIT FIX: Rationalised display scale removed weight inversions and size
73
+ // collisions. display-lg/md separated by 4px with matching weights. title-md/sm
74
+ // now actually differ in size. uppercase-tag raised from 10px 11px for
75
+ // minimum mobile readability (Apple HIG: 11pt floor).
79
76
  export const TYPOGRAPHY = {
80
77
  'display-hero': {
81
- fontFamily: 'Poppins-Bold',
78
+ fontFamily: 'Sohne-Bold',
82
79
  fontSize: 64,
83
80
  fontWeight: '700' as const,
84
81
  lineHeight: 70,
85
82
  letterSpacing: -1,
86
83
  },
87
84
  'display-xl': {
88
- fontFamily: 'Poppins-Bold',
85
+ fontFamily: 'Sohne-Bold',
89
86
  fontSize: 28,
90
87
  fontWeight: '700' as const,
91
88
  lineHeight: 40,
92
89
  letterSpacing: 0,
93
90
  },
91
+ // AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
94
92
  'display-lg': {
95
- fontFamily: 'Poppins-Medium',
96
- fontSize: 22,
97
- fontWeight: '500' as const,
98
- lineHeight: 26,
99
- letterSpacing: -0.44,
93
+ fontFamily: 'Sohne-SemiBold',
94
+ fontSize: 24,
95
+ fontWeight: '600' as const,
96
+ lineHeight: 32,
97
+ letterSpacing: -0.3,
100
98
  },
99
+ // AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
101
100
  'display-md': {
102
- fontFamily: 'Poppins-Bold',
103
- fontSize: 21,
104
- fontWeight: '700' as const,
105
- lineHeight: 30,
101
+ fontFamily: 'Sohne-SemiBold',
102
+ fontSize: 20,
103
+ fontWeight: '600' as const,
104
+ lineHeight: 28,
106
105
  letterSpacing: 0,
107
106
  },
108
107
  'display-sm': {
109
- fontFamily: 'Poppins-SemiBold',
110
- fontSize: 20,
108
+ fontFamily: 'Sohne-SemiBold',
109
+ fontSize: 18,
111
110
  fontWeight: '600' as const,
112
111
  lineHeight: 24,
113
112
  letterSpacing: -0.18,
114
113
  },
114
+ // AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
115
115
  'title-md': {
116
- fontFamily: 'Poppins-SemiBold',
117
- fontSize: 16,
116
+ fontFamily: 'Sohne-SemiBold',
117
+ fontSize: 17,
118
118
  fontWeight: '600' as const,
119
- lineHeight: 20,
119
+ lineHeight: 22,
120
120
  letterSpacing: 0,
121
121
  },
122
+ // AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
122
123
  'title-sm': {
123
- fontFamily: 'Poppins-Medium',
124
- fontSize: 16,
124
+ fontFamily: 'Sohne-Medium',
125
+ fontSize: 15,
125
126
  fontWeight: '500' as const,
126
127
  lineHeight: 20,
127
128
  letterSpacing: 0,
128
129
  },
129
130
  'body-md': {
130
- fontFamily: 'Poppins-Regular',
131
+ fontFamily: 'Sohne-Regular',
131
132
  fontSize: 16,
132
133
  fontWeight: '400' as const,
133
134
  lineHeight: 24,
134
135
  letterSpacing: 0,
135
136
  },
136
137
  'body-sm': {
137
- fontFamily: 'Poppins-Regular',
138
+ fontFamily: 'Sohne-Regular',
138
139
  fontSize: 14,
139
140
  fontWeight: '400' as const,
140
141
  lineHeight: 20,
141
142
  letterSpacing: 0,
142
143
  },
143
- caption: {
144
- fontFamily: 'Poppins-Medium',
144
+ 'caption': {
145
+ fontFamily: 'Sohne-Medium',
145
146
  fontSize: 14,
146
147
  fontWeight: '500' as const,
147
148
  lineHeight: 18,
148
149
  letterSpacing: 0,
149
150
  },
150
151
  'caption-sm': {
151
- fontFamily: 'Poppins-Regular',
152
+ fontFamily: 'Sohne-Regular',
152
153
  fontSize: 13,
153
154
  fontWeight: '400' as const,
154
155
  lineHeight: 16,
155
156
  letterSpacing: 0,
156
157
  },
157
158
  'badge-text': {
158
- fontFamily: 'Poppins-SemiBold',
159
+ fontFamily: 'Sohne-SemiBold',
159
160
  fontSize: 11,
160
161
  fontWeight: '600' as const,
161
- lineHeight: 13,
162
+ lineHeight: 14,
163
+ letterSpacing: 0,
164
+ },
165
+ // AUDIT FIX: added badge-text-md so Badge md size has a canonical token
166
+ 'badge-text-md': {
167
+ fontFamily: 'Sohne-SemiBold',
168
+ fontSize: 13,
169
+ fontWeight: '600' as const,
170
+ lineHeight: 16,
162
171
  letterSpacing: 0,
163
172
  },
164
173
  'micro-label': {
165
- fontFamily: 'Poppins-Bold',
174
+ fontFamily: 'Sohne-Bold',
166
175
  fontSize: 12,
167
176
  fontWeight: '700' as const,
168
177
  lineHeight: 16,
169
178
  letterSpacing: 0,
170
179
  },
180
+ // AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
171
181
  'uppercase-tag': {
172
- fontFamily: 'Poppins-Bold',
173
- fontSize: 10,
182
+ fontFamily: 'Sohne-Bold',
183
+ fontSize: 11,
174
184
  fontWeight: '700' as const,
175
- lineHeight: 13,
176
- letterSpacing: 0.8,
185
+ lineHeight: 14,
186
+ letterSpacing: 0.6,
177
187
  textTransform: 'uppercase' as const,
178
188
  },
179
189
  'button-lg': {
180
- fontFamily: 'Poppins-Medium',
190
+ fontFamily: 'Sohne-Medium',
181
191
  fontSize: 16,
182
192
  fontWeight: '500' as const,
183
193
  lineHeight: 22,
184
194
  letterSpacing: 0,
185
195
  },
186
196
  'button-sm': {
187
- fontFamily: 'Poppins-Medium',
197
+ fontFamily: 'Sohne-Medium',
188
198
  fontSize: 14,
189
199
  fontWeight: '500' as const,
190
200
  lineHeight: 18,
@@ -0,0 +1,58 @@
1
+ import { Easing } from 'react-native-reanimated'
2
+
3
+ // ─── Spring presets ──────────────────────────────────────────────────────────
4
+ // Tuned for the "Apple HIG / Airbnb" press-feel: snap inward fast, settle out elastically.
5
+ // `stiffness`/`damping`/`mass` model — Reanimated v4 default physics units.
6
+ //
7
+ // pressIn: high stiffness, heavy damping → fast, controlled compression
8
+ // pressOut: lower stiffness, less damping → soft, elastic rebound
9
+ // settle: pillows / drawers / large surfaces → calm, never twitchy
10
+ export const SPRINGS = {
11
+ /** Tight, premium press feel — Buttons, Toggle, Tabs triggers. */
12
+ pressIn: { stiffness: 600, damping: 35, mass: 0.8 },
13
+ pressOut: { stiffness: 280, damping: 22, mass: 0.8 },
14
+
15
+ /** Slightly softer for larger surfaces — Card, ListItem, MenuItem. */
16
+ surfacePressIn: { stiffness: 380, damping: 30, mass: 0.95 },
17
+ surfacePressOut: { stiffness: 220, damping: 20, mass: 0.95 },
18
+
19
+ /** Settled transitions for moving indicators — Tabs pill, Switch thumb. */
20
+ glide: { stiffness: 380, damping: 38, mass: 1.0 },
21
+
22
+ /** Elastic indicator — Switch thumb, RadioGroup dot. */
23
+ elastic: { stiffness: 320, damping: 22, mass: 0.7 },
24
+ } as const
25
+
26
+ // ─── Timing presets ──────────────────────────────────────────────────────────
27
+ // All timings target the UI thread via Reanimated `withTiming`.
28
+ export const TIMINGS = {
29
+ /** Color/opacity transitions on toggles, checkboxes, switches. */
30
+ state: { duration: 160 },
31
+ /** Focus ring on inputs. */
32
+ focusIn: { duration: 140 },
33
+ focusOut: { duration: 100 },
34
+ /** Accordion / collapsible content. */
35
+ expand: { duration: 240 },
36
+ collapse: { duration: 200 },
37
+ /** Skeleton shimmer cycle (full pass). */
38
+ shimmer: { duration: 1400 },
39
+ } as const
40
+
41
+ // ─── Easing presets ──────────────────────────────────────────────────────────
42
+ export const EASINGS = {
43
+ /** Material-style ease-out — natural deceleration for state changes. */
44
+ standard: Easing.bezier(0.2, 0, 0, 1),
45
+ /** Strong ease-out for expanding surfaces (Accordion open). */
46
+ expand: Easing.bezier(0.23, 1, 0.32, 1),
47
+ /** Quick ease-in for collapsing. */
48
+ collapse: Easing.in(Easing.ease),
49
+ } as const
50
+
51
+ // ─── Press scale tokens ──────────────────────────────────────────────────────
52
+ // Per-component press intensities — taken from DESIGN.md.
53
+ export const PRESS_SCALE = {
54
+ button: 0.95,
55
+ card: 0.98,
56
+ row: 0.97,
57
+ chip: 0.94,
58
+ } as const
@@ -17,36 +17,63 @@ export interface IconProps {
17
17
  family?: IconFamily
18
18
  }
19
19
 
20
- type ResolvedFamily = {
20
+ type IconComponentType = React.ComponentType<{ name: string; size: number; color: string }>
21
+ type IconFamilyEntry = {
21
22
  name: IconFamily
22
- component: React.ComponentType<{ name: any; size: number; color: string }>
23
- glyphMap: Record<string, number>
23
+ component: IconComponentType
24
+ /** Deferred — glyphMap is only read when the resolution cache is first built. */
25
+ getGlyphMap: () => Record<string, number>
24
26
  }
25
27
 
26
- // Priority order: highest-priority family listed last so it overwrites lower-priority entries in the cache
27
- const ICON_FAMILIES: ResolvedFamily[] = [
28
- { name: 'Ionicons', component: Ionicons as any, glyphMap: (Ionicons as any).glyphMap },
29
- { name: 'MaterialIcons', component: MaterialIcons as any, glyphMap: (MaterialIcons as any).glyphMap },
30
- { name: 'FontAwesome5', component: FontAwesome5 as any, glyphMap: (FontAwesome5 as any).glyphMap },
31
- { name: 'Entypo', component: Entypo as any, glyphMap: (Entypo as any).glyphMap },
32
- { name: 'AntDesign', component: AntDesign as any, glyphMap: (AntDesign as any).glyphMap },
33
- { name: 'Feather', component: Feather as any, glyphMap: (Feather as any).glyphMap },
28
+ type WithGlyphMap = { glyphMap?: Record<string, number> }
29
+
30
+ const glyphMapOf = (mod: unknown): Record<string, number> =>
31
+ (mod as WithGlyphMap).glyphMap ?? {}
32
+
33
+ // Priority order: highest-priority family LAST so it overwrites lower-priority entries in the cache.
34
+ const ALL_FAMILIES: IconFamilyEntry[] = [
35
+ { name: 'Ionicons', component: Ionicons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Ionicons) },
36
+ { name: 'MaterialIcons', component: MaterialIcons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(MaterialIcons) },
37
+ { name: 'FontAwesome5', component: FontAwesome5 as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(FontAwesome5) },
38
+ { name: 'Entypo', component: Entypo as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Entypo) },
39
+ { name: 'AntDesign', component: AntDesign as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(AntDesign) },
40
+ { name: 'Feather', component: Feather as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Feather) },
34
41
  ]
35
42
 
36
- let resolvedCache: Map<string, ResolvedFamily> | null = null
43
+ // Active families participating in name resolution. Defaults to all six.
44
+ let activeFamilies: IconFamilyEntry[] = ALL_FAMILIES
45
+ let resolvedCache: Map<string, IconFamilyEntry> | null = null
46
+
47
+ /**
48
+ * Restrict which icon families participate in automatic name resolution.
49
+ * Narrowing to the families you actually use shrinks the resolution cache and
50
+ * speeds up the first `renderIcon` call (no scanning thousands of unused glyphs).
51
+ *
52
+ * Note: all six families are still statically imported by this module — Metro
53
+ * bundles them regardless. This controls *resolution scope*, not bundle size.
54
+ *
55
+ * @example configureIconFamilies(['Feather', 'MaterialIcons'])
56
+ */
57
+ export function configureIconFamilies(families: IconFamily[]): void {
58
+ const order = families
59
+ .map((n) => ALL_FAMILIES.find((f) => f.name === n))
60
+ .filter((f): f is IconFamilyEntry => f !== undefined)
61
+ activeFamilies = order.length > 0 ? order : ALL_FAMILIES
62
+ resolvedCache = null // invalidate — rebuilt lazily on next resolve
63
+ }
37
64
 
38
- function buildCache(): Map<string, ResolvedFamily> {
39
- const cache = new Map<string, ResolvedFamily>()
40
- for (const family of ICON_FAMILIES) {
41
- if (!family.glyphMap) continue
42
- for (const iconName of Object.keys(family.glyphMap)) {
65
+ function buildCache(): Map<string, IconFamilyEntry> {
66
+ const cache = new Map<string, IconFamilyEntry>()
67
+ for (const family of activeFamilies) {
68
+ const glyphMap = family.getGlyphMap()
69
+ for (const iconName of Object.keys(glyphMap)) {
43
70
  cache.set(iconName, family)
44
71
  }
45
72
  }
46
73
  return cache
47
74
  }
48
75
 
49
- function resolveFamily(name: string): ResolvedFamily | null {
76
+ function resolveFamily(name: string): IconFamilyEntry | null {
50
77
  if (!resolvedCache) {
51
78
  resolvedCache = buildCache()
52
79
  }
@@ -54,10 +81,10 @@ function resolveFamily(name: string): ResolvedFamily | null {
54
81
  }
55
82
 
56
83
  export function Icon({ name, size, color, family }: IconProps): React.ReactElement | null {
57
- let resolved: ResolvedFamily | null = null
84
+ let resolved: IconFamilyEntry | null = null
58
85
 
59
86
  if (family) {
60
- resolved = ICON_FAMILIES.find((f) => f.name === family) ?? null
87
+ resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null
61
88
  } else {
62
89
  resolved = resolveFamily(name)
63
90
  }
@@ -0,0 +1,40 @@
1
+ import { useEffect } from 'react'
2
+ import {
3
+ useSharedValue,
4
+ withTiming,
5
+ interpolateColor,
6
+ type SharedValue,
7
+ } from 'react-native-reanimated'
8
+ import { TIMINGS, EASINGS } from './animations'
9
+
10
+ export interface UseColorTransitionOptions {
11
+ /** Animation duration in ms. Defaults to `160`. */
12
+ duration?: number
13
+ }
14
+
15
+ /**
16
+ * Drives a 0→1 `SharedValue` based on a boolean state, animated via `withTiming` on the UI thread.
17
+ * Use with Reanimated's `interpolateColor` inside a `useAnimatedStyle` to drive borderColor/backgroundColor/etc.
18
+ *
19
+ * @example
20
+ * const progress = useColorTransition(focused)
21
+ * const animatedStyle = useAnimatedStyle(() => ({
22
+ * borderColor: interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
23
+ * }))
24
+ */
25
+ export function useColorTransition(
26
+ active: boolean,
27
+ options: UseColorTransitionOptions = {},
28
+ ): SharedValue<number> {
29
+ const { duration = TIMINGS.state.duration } = options
30
+ const progress = useSharedValue(active ? 1 : 0)
31
+
32
+ useEffect(() => {
33
+ progress.value = withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard })
34
+ }, [active, duration, progress])
35
+
36
+ return progress
37
+ }
38
+
39
+ // Re-export interpolateColor for ergonomic consumer access
40
+ export { interpolateColor }
@@ -0,0 +1,75 @@
1
+ import { useCallback } from 'react'
2
+ import { Platform } from 'react-native'
3
+ import {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withSpring,
7
+ } from 'react-native-reanimated'
8
+ import { SPRINGS, PRESS_SCALE } from './animations'
9
+ import { useHover } from './hover'
10
+
11
+ export interface SpringConfig {
12
+ stiffness?: number
13
+ damping?: number
14
+ mass?: number
15
+ }
16
+
17
+ export interface UsePressScaleOptions {
18
+ /** Scale value while pressed. Defaults to `0.95` (button). */
19
+ pressScale?: number
20
+ /** Scale value while hovered on web. Defaults to `1.02`. Set to `1` to disable. */
21
+ hoverScale?: number
22
+ /** Spring config for press-in. Defaults to `SPRINGS.pressIn`. */
23
+ pressInSpring?: SpringConfig
24
+ /** Spring config for press-out. Defaults to `SPRINGS.pressOut`. */
25
+ pressOutSpring?: SpringConfig
26
+ /** Disable all interaction animations (still returns stable handlers). */
27
+ disabled?: boolean
28
+ }
29
+
30
+ /**
31
+ * Unified press + hover scale primitive.
32
+ * All animation lives on the UI thread via Reanimated v4 worklets — zero JS-thread cost.
33
+ *
34
+ * Returns:
35
+ * - `animatedStyle`: spread onto an `Animated.View` (from `react-native-reanimated`)
36
+ * - `onPressIn` / `onPressOut`: bind to a `TouchableOpacity`
37
+ * - `hoverHandlers`: spread for web hover scaling (no-op on native)
38
+ */
39
+ export function usePressScale({
40
+ pressScale = PRESS_SCALE.button,
41
+ hoverScale = 1.02,
42
+ pressInSpring = SPRINGS.pressIn,
43
+ pressOutSpring = SPRINGS.pressOut,
44
+ disabled = false,
45
+ }: UsePressScaleOptions = {}) {
46
+ const scale = useSharedValue(1)
47
+ const { hovered, hoverHandlers } = useHover()
48
+
49
+ const onPressIn = useCallback(() => {
50
+ if (disabled) return
51
+ // eslint-disable-next-line react-hooks/immutability
52
+ scale.value = withSpring(pressScale, pressInSpring)
53
+ }, [disabled, pressScale, pressInSpring, scale])
54
+
55
+ const onPressOut = useCallback(() => {
56
+ if (disabled) return
57
+ // eslint-disable-next-line react-hooks/immutability
58
+ scale.value = withSpring(1, pressOutSpring)
59
+ }, [disabled, pressOutSpring, scale])
60
+
61
+ const hoverActive = Platform.OS === 'web' && hovered && hoverScale !== 1 && !disabled
62
+
63
+ const animatedStyle = useAnimatedStyle(() => ({
64
+ transform: [
65
+ { scale: scale.value * (hoverActive ? hoverScale : 1) },
66
+ ],
67
+ }))
68
+
69
+ return {
70
+ animatedStyle,
71
+ onPressIn,
72
+ onPressOut,
73
+ hoverHandlers,
74
+ }
75
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file