@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
@@ -0,0 +1,134 @@
1
+ import { renderIcon } from './chunk-T7XZ7H7Y.mjs';
2
+ import { selectionAsync } from './chunk-RTC3CFXF.mjs';
3
+ import { EASINGS, TIMINGS } from './chunk-5IKW3VNC.mjs';
4
+ import { useTheme } from './chunk-SOYNZDVY.mjs';
5
+ import { vs, s, ms } from './chunk-2CE3TQVY.mjs';
6
+ import React, { useState } from 'react';
7
+ import { StyleSheet, View, Pressable, Text } from 'react-native';
8
+ import Animated, { useSharedValue, useDerivedValue, withTiming, useAnimatedStyle } from 'react-native-reanimated';
9
+ import { Entypo } from '@expo/vector-icons';
10
+
11
+ function AccordionItemComponent({
12
+ item,
13
+ isOpen,
14
+ onToggle
15
+ }) {
16
+ const { colors } = useTheme();
17
+ const resolvedIcon = item.iconName ? renderIcon(item.iconName, ms(16), item.iconColor ?? colors.foregroundMuted) : item.icon;
18
+ const isExpanded = useSharedValue(isOpen);
19
+ const height = useSharedValue(0);
20
+ React.useEffect(() => {
21
+ isExpanded.value = isOpen;
22
+ }, [isOpen, isExpanded]);
23
+ const derivedHeight = useDerivedValue(
24
+ () => withTiming(height.value * Number(isExpanded.value), {
25
+ duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
26
+ easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
27
+ })
28
+ );
29
+ const derivedRotation = useDerivedValue(
30
+ () => withTiming(isExpanded.value ? 1 : 0, {
31
+ duration: isExpanded.value ? TIMINGS.expand.duration : TIMINGS.collapse.duration,
32
+ easing: isExpanded.value ? EASINGS.expand : EASINGS.collapse
33
+ })
34
+ );
35
+ const bodyStyle = useAnimatedStyle(() => ({
36
+ height: derivedHeight.value,
37
+ overflow: "hidden"
38
+ }));
39
+ const rotationStyle = useAnimatedStyle(() => ({
40
+ transform: [{ rotate: `${derivedRotation.value * 180}deg` }]
41
+ }));
42
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.item, { backgroundColor: colors.card, borderColor: colors.border }] }, /* @__PURE__ */ React.createElement(
43
+ Pressable,
44
+ {
45
+ style: ({ pressed }) => [styles.trigger, { opacity: pressed ? 0.6 : 1 }],
46
+ onPress: () => {
47
+ selectionAsync();
48
+ onToggle();
49
+ },
50
+ accessibilityRole: "button",
51
+ accessibilityState: { expanded: isOpen },
52
+ accessibilityLabel: item.trigger
53
+ },
54
+ /* @__PURE__ */ React.createElement(View, { style: styles.triggerContent }, resolvedIcon ? /* @__PURE__ */ React.createElement(View, { style: styles.icon }, resolvedIcon) : null, /* @__PURE__ */ React.createElement(Text, { style: [styles.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger)),
55
+ /* @__PURE__ */ React.createElement(Animated.View, { style: [styles.chevron, rotationStyle] }, /* @__PURE__ */ React.createElement(Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
56
+ ), /* @__PURE__ */ React.createElement(Animated.View, { style: bodyStyle }, /* @__PURE__ */ React.createElement(
57
+ View,
58
+ {
59
+ style: styles.content,
60
+ onLayout: (e) => {
61
+ height.value = e.nativeEvent.layout.height;
62
+ }
63
+ },
64
+ item.content
65
+ )));
66
+ }
67
+ function Accordion({ items, type = "single", defaultValue, style }) {
68
+ const [openValues, setOpenValues] = useState(() => {
69
+ if (!defaultValue) return [];
70
+ return Array.isArray(defaultValue) ? defaultValue : [defaultValue];
71
+ });
72
+ const toggle = (value) => {
73
+ if (type === "single") {
74
+ setOpenValues((prev) => prev.includes(value) ? [] : [value]);
75
+ } else {
76
+ setOpenValues(
77
+ (prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
78
+ );
79
+ }
80
+ };
81
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.list, style] }, items.map((item) => /* @__PURE__ */ React.createElement(
82
+ AccordionItemComponent,
83
+ {
84
+ key: item.value,
85
+ item,
86
+ isOpen: openValues.includes(item.value),
87
+ onToggle: () => toggle(item.value)
88
+ }
89
+ )));
90
+ }
91
+ var styles = StyleSheet.create({
92
+ list: {
93
+ gap: s(6)
94
+ },
95
+ item: {
96
+ borderWidth: 1,
97
+ borderRadius: ms(10),
98
+ overflow: "hidden"
99
+ },
100
+ trigger: {
101
+ flexDirection: "row",
102
+ justifyContent: "space-between",
103
+ alignItems: "center",
104
+ paddingHorizontal: s(14),
105
+ paddingVertical: vs(12)
106
+ },
107
+ triggerContent: {
108
+ flexDirection: "row",
109
+ alignItems: "center",
110
+ gap: s(8),
111
+ flex: 1
112
+ },
113
+ icon: {
114
+ alignItems: "center",
115
+ justifyContent: "center"
116
+ },
117
+ triggerText: {
118
+ fontFamily: "Sohne-Medium",
119
+ fontSize: ms(14)
120
+ },
121
+ chevron: {
122
+ marginLeft: s(8)
123
+ },
124
+ // position:'absolute' is the key — the inner View escapes the animated wrapper's
125
+ // clipped height so onLayout always reports the true content height.
126
+ content: {
127
+ paddingHorizontal: s(8),
128
+ paddingBottom: vs(12),
129
+ position: "absolute",
130
+ width: "100%"
131
+ }
132
+ });
133
+
134
+ export { Accordion };
@@ -0,0 +1,191 @@
1
+ // src/tokens.ts
2
+ var SPACING = {
3
+ xxs: 2,
4
+ xs: 4,
5
+ sm: 8,
6
+ md: 12,
7
+ base: 16,
8
+ lg: 24,
9
+ xl: 32,
10
+ xxl: 48,
11
+ section: 64
12
+ };
13
+ var ICON_SIZES = {
14
+ sm: 14,
15
+ md: 18,
16
+ lg: 22,
17
+ xl: 28,
18
+ "2xl": 32
19
+ };
20
+ var RADIUS = {
21
+ none: 0,
22
+ xs: 4,
23
+ sm: 8,
24
+ md: 14,
25
+ lg: 20,
26
+ xl: 32,
27
+ full: 9999
28
+ };
29
+ var SHADOWS = {
30
+ sm: {
31
+ shadowColor: "#000",
32
+ shadowOffset: { width: 0, height: 1 },
33
+ shadowOpacity: 0.06,
34
+ shadowRadius: 4,
35
+ elevation: 2
36
+ },
37
+ md: {
38
+ shadowColor: "#000",
39
+ shadowOffset: { width: 0, height: 2 },
40
+ shadowOpacity: 0.1,
41
+ shadowRadius: 8,
42
+ elevation: 5
43
+ },
44
+ lg: {
45
+ shadowColor: "#000",
46
+ shadowOffset: { width: 0, height: 6 },
47
+ shadowOpacity: 0.16,
48
+ shadowRadius: 16,
49
+ elevation: 10
50
+ },
51
+ xl: {
52
+ shadowColor: "#000",
53
+ shadowOffset: { width: 0, height: 12 },
54
+ shadowOpacity: 0.24,
55
+ shadowRadius: 24,
56
+ elevation: 18
57
+ }
58
+ };
59
+ var BREAKPOINTS = {
60
+ wide: 700
61
+ };
62
+ var TYPOGRAPHY = {
63
+ "display-hero": {
64
+ fontFamily: "Sohne-Bold",
65
+ fontSize: 64,
66
+ fontWeight: "700",
67
+ lineHeight: 70,
68
+ letterSpacing: -1
69
+ },
70
+ "display-xl": {
71
+ fontFamily: "Sohne-Bold",
72
+ fontSize: 28,
73
+ fontWeight: "700",
74
+ lineHeight: 40,
75
+ letterSpacing: 0
76
+ },
77
+ // AUDIT FIX: was 22px/500 — raised to 24px/600; removes weight inversion vs display-md
78
+ "display-lg": {
79
+ fontFamily: "Sohne-SemiBold",
80
+ fontSize: 24,
81
+ fontWeight: "600",
82
+ lineHeight: 32,
83
+ letterSpacing: -0.3
84
+ },
85
+ // AUDIT FIX: was 21px/700 — lowered to 20px/600; weight normalised, 4px gap preserved
86
+ "display-md": {
87
+ fontFamily: "Sohne-SemiBold",
88
+ fontSize: 20,
89
+ fontWeight: "600",
90
+ lineHeight: 28,
91
+ letterSpacing: 0
92
+ },
93
+ "display-sm": {
94
+ fontFamily: "Sohne-SemiBold",
95
+ fontSize: 18,
96
+ fontWeight: "600",
97
+ lineHeight: 24,
98
+ letterSpacing: -0.18
99
+ },
100
+ // AUDIT FIX: was 16px — raised to 17px so title-md > title-sm is size-visible
101
+ "title-md": {
102
+ fontFamily: "Sohne-SemiBold",
103
+ fontSize: 17,
104
+ fontWeight: "600",
105
+ lineHeight: 22,
106
+ letterSpacing: 0
107
+ },
108
+ // AUDIT FIX: was 16px — lowered to 15px; now distinct from title-md
109
+ "title-sm": {
110
+ fontFamily: "Sohne-Medium",
111
+ fontSize: 15,
112
+ fontWeight: "500",
113
+ lineHeight: 20,
114
+ letterSpacing: 0
115
+ },
116
+ "body-md": {
117
+ fontFamily: "Sohne-Regular",
118
+ fontSize: 16,
119
+ fontWeight: "400",
120
+ lineHeight: 24,
121
+ letterSpacing: 0
122
+ },
123
+ "body-sm": {
124
+ fontFamily: "Sohne-Regular",
125
+ fontSize: 14,
126
+ fontWeight: "400",
127
+ lineHeight: 20,
128
+ letterSpacing: 0
129
+ },
130
+ "caption": {
131
+ fontFamily: "Sohne-Medium",
132
+ fontSize: 14,
133
+ fontWeight: "500",
134
+ lineHeight: 18,
135
+ letterSpacing: 0
136
+ },
137
+ "caption-sm": {
138
+ fontFamily: "Sohne-Regular",
139
+ fontSize: 13,
140
+ fontWeight: "400",
141
+ lineHeight: 16,
142
+ letterSpacing: 0
143
+ },
144
+ "badge-text": {
145
+ fontFamily: "Sohne-SemiBold",
146
+ fontSize: 11,
147
+ fontWeight: "600",
148
+ lineHeight: 14,
149
+ letterSpacing: 0
150
+ },
151
+ // AUDIT FIX: added badge-text-md so Badge md size has a canonical token
152
+ "badge-text-md": {
153
+ fontFamily: "Sohne-SemiBold",
154
+ fontSize: 13,
155
+ fontWeight: "600",
156
+ lineHeight: 16,
157
+ letterSpacing: 0
158
+ },
159
+ "micro-label": {
160
+ fontFamily: "Sohne-Bold",
161
+ fontSize: 12,
162
+ fontWeight: "700",
163
+ lineHeight: 16,
164
+ letterSpacing: 0
165
+ },
166
+ // AUDIT FIX: was 10px/0.8 letterSpacing — raised to 11px/0.6; minimum mobile readability
167
+ "uppercase-tag": {
168
+ fontFamily: "Sohne-Bold",
169
+ fontSize: 11,
170
+ fontWeight: "700",
171
+ lineHeight: 14,
172
+ letterSpacing: 0.6,
173
+ textTransform: "uppercase"
174
+ },
175
+ "button-lg": {
176
+ fontFamily: "Sohne-Medium",
177
+ fontSize: 16,
178
+ fontWeight: "500",
179
+ lineHeight: 22,
180
+ letterSpacing: 0
181
+ },
182
+ "button-sm": {
183
+ fontFamily: "Sohne-Medium",
184
+ fontSize: 14,
185
+ fontWeight: "500",
186
+ lineHeight: 18,
187
+ letterSpacing: 0
188
+ }
189
+ };
190
+
191
+ export { BREAKPOINTS, ICON_SIZES, RADIUS, SHADOWS, SPACING, TYPOGRAPHY };
@@ -0,0 +1,92 @@
1
+ import { selectionAsync } from './chunk-RTC3CFXF.mjs';
2
+ import { useTheme } from './chunk-SOYNZDVY.mjs';
3
+ import { s, mvs, ms } from './chunk-2CE3TQVY.mjs';
4
+ import React from 'react';
5
+ import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
6
+ import { Entypo } from '@expo/vector-icons';
7
+
8
+ var MONTH_NAMES = {
9
+ en: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
10
+ es: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
11
+ pt: ["janeiro", "fevereiro", "mar\xE7o", "abril", "maio", "junho", "julho", "agosto", "setembro", "outubro", "novembro", "dezembro"],
12
+ fr: ["janvier", "f\xE9vrier", "mars", "avril", "mai", "juin", "juillet", "ao\xFBt", "septembre", "octobre", "novembre", "d\xE9cembre"]
13
+ };
14
+ function MonthPicker({ value, onChange, locale = "en", formatLabel, style }) {
15
+ const { colors } = useTheme();
16
+ const getLabel = () => {
17
+ if (formatLabel) return formatLabel(value);
18
+ const names = MONTH_NAMES[locale] ?? MONTH_NAMES.en;
19
+ return `${names[value.month - 1]} ${value.year}`;
20
+ };
21
+ const handlePrev = () => {
22
+ selectionAsync();
23
+ if (value.month === 1) {
24
+ onChange({ month: 12, year: value.year - 1 });
25
+ } else {
26
+ onChange({ month: value.month - 1, year: value.year });
27
+ }
28
+ };
29
+ const handleNext = () => {
30
+ selectionAsync();
31
+ if (value.month === 12) {
32
+ onChange({ month: 1, year: value.year + 1 });
33
+ } else {
34
+ onChange({ month: value.month + 1, year: value.year });
35
+ }
36
+ };
37
+ return /* @__PURE__ */ React.createElement(View, { style: [styles.container, style], accessibilityRole: "adjustable", accessibilityLabel: getLabel() }, /* @__PURE__ */ React.createElement(
38
+ TouchableOpacity,
39
+ {
40
+ style: styles.arrow,
41
+ onPress: handlePrev,
42
+ activeOpacity: 0.6,
43
+ touchSoundDisabled: true,
44
+ accessibilityRole: "button",
45
+ accessibilityLabel: "Previous month",
46
+ hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
47
+ },
48
+ /* @__PURE__ */ React.createElement(Entypo, { name: "chevron-left", size: 22, color: colors.foreground })
49
+ ), /* @__PURE__ */ React.createElement(
50
+ Text,
51
+ {
52
+ style: [styles.label, { color: colors.foreground }],
53
+ allowFontScaling: true,
54
+ accessibilityLiveRegion: "polite"
55
+ },
56
+ getLabel()
57
+ ), /* @__PURE__ */ React.createElement(
58
+ TouchableOpacity,
59
+ {
60
+ style: styles.arrow,
61
+ onPress: handleNext,
62
+ activeOpacity: 0.6,
63
+ touchSoundDisabled: true,
64
+ accessibilityRole: "button",
65
+ accessibilityLabel: "Next month",
66
+ hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }
67
+ },
68
+ /* @__PURE__ */ React.createElement(Entypo, { name: "chevron-right", size: 22, color: colors.foreground })
69
+ ));
70
+ }
71
+ var styles = StyleSheet.create({
72
+ container: {
73
+ flexDirection: "row",
74
+ alignItems: "center",
75
+ justifyContent: "space-between"
76
+ },
77
+ arrow: {
78
+ width: s(44),
79
+ height: s(44),
80
+ alignItems: "center",
81
+ justifyContent: "center"
82
+ },
83
+ label: {
84
+ fontFamily: "Sohne-Medium",
85
+ fontSize: ms(17),
86
+ lineHeight: mvs(24),
87
+ textAlign: "center",
88
+ minWidth: s(160)
89
+ }
90
+ });
91
+
92
+ export { MonthPicker };
@@ -0,0 +1,54 @@
1
+ import { usePressScale } from './chunk-QCNARS3X.mjs';
2
+ import { impactLight } from './chunk-RTC3CFXF.mjs';
3
+ import { SPRINGS, PRESS_SCALE } from './chunk-5IKW3VNC.mjs';
4
+ import React from 'react';
5
+ import { Platform, TouchableOpacity } from 'react-native';
6
+ import Animated from 'react-native-reanimated';
7
+
8
+ function Pressable({
9
+ children,
10
+ onPress,
11
+ pressScale = PRESS_SCALE.card,
12
+ haptics = true,
13
+ style,
14
+ disabled,
15
+ hoverScale = 1.02,
16
+ ...touchableProps
17
+ }) {
18
+ const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
19
+ pressScale,
20
+ hoverScale,
21
+ pressInSpring: SPRINGS.surfacePressIn,
22
+ pressOutSpring: SPRINGS.surfacePressOut,
23
+ disabled
24
+ });
25
+ const handlePress = () => {
26
+ if (disabled || !onPress) return;
27
+ if (haptics) impactLight();
28
+ onPress();
29
+ };
30
+ return /* @__PURE__ */ React.createElement(
31
+ Animated.View,
32
+ {
33
+ style: [animatedStyle, style],
34
+ ...Platform.OS === "web" ? hoverHandlers : {}
35
+ },
36
+ /* @__PURE__ */ React.createElement(
37
+ TouchableOpacity,
38
+ {
39
+ onPress: handlePress,
40
+ onPressIn,
41
+ onPressOut,
42
+ activeOpacity: 1,
43
+ disabled,
44
+ touchSoundDisabled: true,
45
+ accessibilityRole: "button",
46
+ accessibilityState: { disabled: !!disabled },
47
+ ...touchableProps
48
+ },
49
+ children
50
+ )
51
+ );
52
+ }
53
+
54
+ export { Pressable };
@@ -0,0 +1,190 @@
1
+ import { usePressScale } from './chunk-QCNARS3X.mjs';
2
+ import { selectionAsync } from './chunk-RTC3CFXF.mjs';
3
+ import { SPRINGS, PRESS_SCALE } from './chunk-5IKW3VNC.mjs';
4
+ import { useTheme } from './chunk-SOYNZDVY.mjs';
5
+ import { ms, s, vs } from './chunk-2CE3TQVY.mjs';
6
+ import React, { useState, useRef, useCallback, useEffect } from 'react';
7
+ import { StyleSheet, View, TouchableOpacity, Text } from 'react-native';
8
+ import Animated, { useSharedValue, withSpring, useAnimatedStyle } from 'react-native-reanimated';
9
+
10
+ function TabTrigger({
11
+ tab,
12
+ isActive,
13
+ onPress,
14
+ onLayout,
15
+ variant
16
+ }) {
17
+ const { colors } = useTheme();
18
+ const { animatedStyle, onPressIn, onPressOut } = usePressScale({
19
+ pressScale: PRESS_SCALE.button
20
+ });
21
+ const isUnderline = variant === "underline";
22
+ return /* @__PURE__ */ React.createElement(
23
+ TouchableOpacity,
24
+ {
25
+ style: [
26
+ styles.trigger,
27
+ isUnderline && styles.triggerUnderline,
28
+ isUnderline && isActive && { borderBottomColor: colors.primary }
29
+ ],
30
+ onPress,
31
+ onPressIn,
32
+ onPressOut,
33
+ onLayout,
34
+ activeOpacity: 1,
35
+ touchSoundDisabled: true,
36
+ accessibilityRole: "tab",
37
+ accessibilityState: { selected: isActive },
38
+ accessibilityLabel: tab.label
39
+ },
40
+ /* @__PURE__ */ React.createElement(Animated.View, { style: animatedStyle }, /* @__PURE__ */ React.createElement(View, { style: styles.triggerInner }, tab.icon ? typeof tab.icon === "function" ? tab.icon(isActive) : tab.icon : null, /* @__PURE__ */ React.createElement(
41
+ Text,
42
+ {
43
+ style: [
44
+ styles.triggerLabel,
45
+ // AUDIT FIX: active state now only changes color, never font metrics.
46
+ // Previously: inactive=Regular, active=Medium (pill) or SemiBold+fontSize14 (underline)
47
+ // The weight/size change caused measurable layout reflow every tab switch.
48
+ // Solution: all labels render at SemiBold always; active = foreground, inactive = foregroundMuted.
49
+ { color: isActive ? colors.foreground : colors.foregroundMuted }
50
+ ],
51
+ allowFontScaling: true
52
+ },
53
+ tab.label
54
+ )))
55
+ );
56
+ }
57
+ function Tabs({ tabs, variant = "pill", value, onValueChange, children, style }) {
58
+ const [internal, setInternal] = useState(tabs[0]?.value ?? "");
59
+ const { colors } = useTheme();
60
+ const active = value ?? internal;
61
+ const tabLayouts = useRef({});
62
+ const pillX = useSharedValue(0);
63
+ const pillWidth = useSharedValue(0);
64
+ const initialised = useRef(false);
65
+ const animatePill = useCallback((tabValue, animate) => {
66
+ const layout = tabLayouts.current[tabValue];
67
+ if (!layout) return;
68
+ if (animate) {
69
+ pillX.value = withSpring(layout.x, SPRINGS.glide);
70
+ pillWidth.value = withSpring(layout.width, SPRINGS.glide);
71
+ } else {
72
+ pillX.value = layout.x;
73
+ pillWidth.value = layout.width;
74
+ }
75
+ }, [pillX, pillWidth]);
76
+ useEffect(() => {
77
+ if (initialised.current) animatePill(active, true);
78
+ }, [active, animatePill]);
79
+ const handlePress = (v) => {
80
+ selectionAsync();
81
+ if (!value) setInternal(v);
82
+ onValueChange?.(v);
83
+ };
84
+ const pillAnimatedStyle = useAnimatedStyle(() => ({
85
+ transform: [{ translateX: pillX.value }],
86
+ width: pillWidth.value
87
+ }));
88
+ return /* @__PURE__ */ React.createElement(View, { style }, /* @__PURE__ */ React.createElement(
89
+ View,
90
+ {
91
+ style: [
92
+ variant === "pill" ? [styles.list, { backgroundColor: colors.surface }] : styles.listUnderline
93
+ ],
94
+ accessibilityRole: "tablist"
95
+ },
96
+ variant === "pill" && /* @__PURE__ */ React.createElement(
97
+ Animated.View,
98
+ {
99
+ style: [
100
+ styles.pill,
101
+ {
102
+ backgroundColor: colors.background,
103
+ position: "absolute",
104
+ top: 4,
105
+ bottom: 4,
106
+ left: 0,
107
+ borderRadius: 8,
108
+ shadowColor: "#000",
109
+ shadowOffset: { width: 0, height: 1 },
110
+ shadowOpacity: 0.08,
111
+ shadowRadius: 2,
112
+ elevation: 2
113
+ },
114
+ pillAnimatedStyle
115
+ ]
116
+ }
117
+ ),
118
+ tabs.map((tab) => /* @__PURE__ */ React.createElement(
119
+ TabTrigger,
120
+ {
121
+ key: tab.value,
122
+ tab,
123
+ isActive: tab.value === active,
124
+ onPress: () => handlePress(tab.value),
125
+ variant,
126
+ onLayout: (e) => {
127
+ const { x, width } = e.nativeEvent.layout;
128
+ tabLayouts.current[tab.value] = { x, width };
129
+ if (tab.value === active) {
130
+ animatePill(tab.value, false);
131
+ initialised.current = true;
132
+ }
133
+ }
134
+ }
135
+ ))
136
+ ), children);
137
+ }
138
+ function TabsContent({ value, activeValue, children, style }) {
139
+ if (value !== activeValue) return null;
140
+ return /* @__PURE__ */ React.createElement(View, { style, accessibilityRole: "none" }, children);
141
+ }
142
+ var styles = StyleSheet.create({
143
+ list: {
144
+ flexDirection: "row",
145
+ borderRadius: 12,
146
+ padding: s(4),
147
+ gap: s(4)
148
+ },
149
+ listUnderline: {
150
+ flexDirection: "row",
151
+ // AUDIT FIX: was missing borderBottomColor — the 1px hairline would render
152
+ // as transparent on some platforms. Explicit token reference ensures visibility.
153
+ borderBottomWidth: 1
154
+ },
155
+ pill: {},
156
+ trigger: {
157
+ flex: 1,
158
+ paddingVertical: vs(7),
159
+ paddingHorizontal: s(10),
160
+ borderRadius: 8,
161
+ alignItems: "center",
162
+ justifyContent: "center",
163
+ zIndex: 1
164
+ },
165
+ triggerUnderline: {
166
+ flex: 0,
167
+ paddingVertical: vs(12),
168
+ paddingHorizontal: s(16),
169
+ borderRadius: 0,
170
+ borderBottomWidth: 2,
171
+ borderBottomColor: "transparent"
172
+ },
173
+ triggerInner: {
174
+ flexDirection: "row",
175
+ alignItems: "center",
176
+ justifyContent: "center",
177
+ gap: s(4)
178
+ },
179
+ // AUDIT FIX: was Sohne-Regular at rest, Sohne-Medium/SemiBold when active.
180
+ // Font-weight changes at runtime cause advance-width shifts → the tab bar would
181
+ // visibly jump/reflow on every selection. Now always SemiBold; active state
182
+ // is communicated by color alone (foreground vs foregroundMuted). The pill
183
+ // indicator provides additional active signal without text layout side-effects.
184
+ triggerLabel: {
185
+ fontFamily: "Sohne-SemiBold",
186
+ fontSize: ms(13)
187
+ }
188
+ });
189
+
190
+ export { Tabs, TabsContent };
@@ -0,0 +1,29 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ // src/utils/haptics.ts
4
+ var _haptics = null;
5
+ async function getHaptics() {
6
+ if (Platform.OS === "web") return null;
7
+ if (!_haptics) {
8
+ _haptics = await import('expo-haptics');
9
+ }
10
+ return _haptics;
11
+ }
12
+ function selectionAsync() {
13
+ if (Platform.OS === "web") return;
14
+ getHaptics().then((h) => h?.selectionAsync());
15
+ }
16
+ function impactLight() {
17
+ if (Platform.OS === "web") return;
18
+ getHaptics().then((h) => h?.impactAsync(h.ImpactFeedbackStyle.Light));
19
+ }
20
+ function impactMedium() {
21
+ if (Platform.OS === "web") return;
22
+ getHaptics().then((h) => h?.impactAsync(h.ImpactFeedbackStyle.Medium));
23
+ }
24
+ function notificationSuccess() {
25
+ if (Platform.OS === "web") return;
26
+ getHaptics().then((h) => h?.notificationAsync(h.NotificationFeedbackType.Success));
27
+ }
28
+
29
+ export { impactLight, impactMedium, notificationSuccess, selectionAsync };