@expokit/cli 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -2
  3. package/bin/expo-kit.js +1204 -0
  4. package/bin/lib.mjs +343 -0
  5. package/bin/mcp.mjs +338 -0
  6. package/package.json +44 -4
  7. package/registry/_docs/accordion.json +99 -0
  8. package/registry/_docs/action-sheet.json +110 -0
  9. package/registry/_docs/alert.json +127 -0
  10. package/registry/_docs/avatar.json +203 -0
  11. package/registry/_docs/badge.json +117 -0
  12. package/registry/_docs/bottom-nav.json +119 -0
  13. package/registry/_docs/bottom-sheet.json +158 -0
  14. package/registry/_docs/bullet.json +24 -0
  15. package/registry/_docs/button-3d.json +122 -0
  16. package/registry/_docs/button.json +115 -0
  17. package/registry/_docs/calendar.json +182 -0
  18. package/registry/_docs/card-stack.json +108 -0
  19. package/registry/_docs/card.json +111 -0
  20. package/registry/_docs/carousel.json +102 -0
  21. package/registry/_docs/checkbox.json +93 -0
  22. package/registry/_docs/checkout.json +102 -0
  23. package/registry/_docs/chip-group.json +116 -0
  24. package/registry/_docs/color-swatch.json +66 -0
  25. package/registry/_docs/confetti.json +82 -0
  26. package/registry/_docs/coupon.json +176 -0
  27. package/registry/_docs/cube-pager.json +84 -0
  28. package/registry/_docs/dashboard.json +120 -0
  29. package/registry/_docs/date-picker.json +249 -0
  30. package/registry/_docs/dialog.json +162 -0
  31. package/registry/_docs/drawer.json +171 -0
  32. package/registry/_docs/fab.json +120 -0
  33. package/registry/_docs/flip-card.json +111 -0
  34. package/registry/_docs/floating-input.json +191 -0
  35. package/registry/_docs/gift-card.json +108 -0
  36. package/registry/_docs/glass-button.json +118 -0
  37. package/registry/_docs/glass-nav-bar.json +78 -0
  38. package/registry/_docs/glass-search-bar.json +90 -0
  39. package/registry/_docs/glass-segmented.json +66 -0
  40. package/registry/_docs/glass-sheet.json +108 -0
  41. package/registry/_docs/glass-tab-bar.json +76 -0
  42. package/registry/_docs/glass.json +78 -0
  43. package/registry/_docs/inbox.json +72 -0
  44. package/registry/_docs/isometric-bar.json +72 -0
  45. package/registry/_docs/kit.json +11 -0
  46. package/registry/_docs/kpi-card.json +11 -0
  47. package/registry/_docs/like-button.json +72 -0
  48. package/registry/_docs/liquidglass-tab.json +27 -0
  49. package/registry/_docs/list-item.json +200 -0
  50. package/registry/_docs/loyalty-card.json +108 -0
  51. package/registry/_docs/morph-button.json +108 -0
  52. package/registry/_docs/number-ticker.json +96 -0
  53. package/registry/_docs/offers.json +78 -0
  54. package/registry/_docs/onboarding.json +66 -0
  55. package/registry/_docs/otp-input.json +134 -0
  56. package/registry/_docs/pagination-dots.json +88 -0
  57. package/registry/_docs/parallax-layers.json +84 -0
  58. package/registry/_docs/parallax-scroll.json +186 -0
  59. package/registry/_docs/password-input.json +92 -0
  60. package/registry/_docs/payment-card.json +153 -0
  61. package/registry/_docs/pixel-bar.json +66 -0
  62. package/registry/_docs/polar-area.json +78 -0
  63. package/registry/_docs/profile.json +84 -0
  64. package/registry/_docs/progress-steps.json +92 -0
  65. package/registry/_docs/progress.json +132 -0
  66. package/registry/_docs/radio-group.json +92 -0
  67. package/registry/_docs/rating.json +90 -0
  68. package/registry/_docs/ring-carousel.json +102 -0
  69. package/registry/_docs/scratch-card.json +90 -0
  70. package/registry/_docs/search-bar.json +140 -0
  71. package/registry/_docs/search-results.json +120 -0
  72. package/registry/_docs/segmented-control.json +103 -0
  73. package/registry/_docs/select.json +252 -0
  74. package/registry/_docs/settings.json +72 -0
  75. package/registry/_docs/shimmer-button.json +78 -0
  76. package/registry/_docs/sign-in.json +198 -0
  77. package/registry/_docs/skeleton.json +142 -0
  78. package/registry/_docs/slide-to-confirm.json +84 -0
  79. package/registry/_docs/slider.json +157 -0
  80. package/registry/_docs/spin-wheel.json +114 -0
  81. package/registry/_docs/spinner.json +91 -0
  82. package/registry/_docs/stepper.json +168 -0
  83. package/registry/_docs/swipe-deck.json +102 -0
  84. package/registry/_docs/swipeable-row.json +72 -0
  85. package/registry/_docs/switch.json +104 -0
  86. package/registry/_docs/tabs.json +105 -0
  87. package/registry/_docs/tag-input.json +128 -0
  88. package/registry/_docs/textarea.json +175 -0
  89. package/registry/_docs/ticket-card.json +174 -0
  90. package/registry/_docs/ticket-shape.json +11 -0
  91. package/registry/_docs/tilt-card.json +141 -0
  92. package/registry/_docs/time-picker.json +253 -0
  93. package/registry/_docs/timeline-chart.json +30 -0
  94. package/registry/_docs/timeline.json +156 -0
  95. package/registry/_docs/toast.json +161 -0
  96. package/registry/_docs/treemap.json +30 -0
  97. package/registry/_docs/waterfall.json +36 -0
  98. package/registry/_docs/wheel-list.json +102 -0
  99. package/registry/accordion/files/src/components/ui/accordion.tsx +233 -0
  100. package/registry/accordion/files/src/lib/kit.tsx +219 -0
  101. package/registry/accordion.json +17 -0
  102. package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +580 -0
  103. package/registry/action-sheet/files/src/lib/kit.tsx +219 -0
  104. package/registry/action-sheet.json +18 -0
  105. package/registry/alert/files/src/components/ui/alert.tsx +654 -0
  106. package/registry/alert/files/src/components/ui/button.tsx +274 -0
  107. package/registry/alert/files/src/lib/kit.tsx +219 -0
  108. package/registry/alert.json +20 -0
  109. package/registry/avatar/files/src/components/ui/avatar.tsx +790 -0
  110. package/registry/avatar/files/src/lib/kit.tsx +219 -0
  111. package/registry/avatar.json +18 -0
  112. package/registry/badge/files/src/components/ui/badge.tsx +316 -0
  113. package/registry/badge/files/src/lib/kit.tsx +219 -0
  114. package/registry/badge.json +17 -0
  115. package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +1050 -0
  116. package/registry/bottom-nav/files/src/lib/kit.tsx +219 -0
  117. package/registry/bottom-nav.json +18 -0
  118. package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +585 -0
  119. package/registry/bottom-sheet/files/src/lib/kit.tsx +219 -0
  120. package/registry/bottom-sheet.json +17 -0
  121. package/registry/bullet.json +14 -0
  122. package/registry/button/files/src/components/ui/button.tsx +274 -0
  123. package/registry/button/files/src/lib/kit.tsx +219 -0
  124. package/registry/button-3d/files/src/components/ui/button-3d.tsx +212 -0
  125. package/registry/button-3d/files/src/lib/kit.tsx +219 -0
  126. package/registry/button-3d.json +18 -0
  127. package/registry/button.json +18 -0
  128. package/registry/calendar/files/src/components/ui/calendar.tsx +822 -0
  129. package/registry/calendar/files/src/lib/kit.tsx +219 -0
  130. package/registry/calendar.json +17 -0
  131. package/registry/card/files/src/components/ui/card.tsx +300 -0
  132. package/registry/card/files/src/lib/kit.tsx +219 -0
  133. package/registry/card-stack.json +15 -0
  134. package/registry/card.json +17 -0
  135. package/registry/carousel.json +15 -0
  136. package/registry/checkbox/files/src/components/ui/checkbox.tsx +150 -0
  137. package/registry/checkbox/files/src/lib/kit.tsx +219 -0
  138. package/registry/checkbox.json +17 -0
  139. package/registry/checkout.json +26 -0
  140. package/registry/chip-group/files/src/components/ui/chip-group.tsx +269 -0
  141. package/registry/chip-group/files/src/lib/kit.tsx +219 -0
  142. package/registry/chip-group.json +17 -0
  143. package/registry/color-swatch.json +17 -0
  144. package/registry/confetti/files/src/components/ui/confetti.tsx +222 -0
  145. package/registry/confetti/files/src/lib/kit.tsx +219 -0
  146. package/registry/confetti.json +15 -0
  147. package/registry/coupon/files/src/components/ui/coupon.tsx +698 -0
  148. package/registry/coupon/files/src/components/ui/flip-card.tsx +205 -0
  149. package/registry/coupon/files/src/components/ui/tilt-card.tsx +635 -0
  150. package/registry/coupon/files/src/lib/kit.tsx +219 -0
  151. package/registry/coupon/files/src/lib/ticket-shape.tsx +543 -0
  152. package/registry/coupon.json +23 -0
  153. package/registry/cube-pager.json +15 -0
  154. package/registry/dashboard.json +32 -0
  155. package/registry/date-picker/files/src/components/ui/calendar.tsx +822 -0
  156. package/registry/date-picker/files/src/components/ui/date-picker.tsx +796 -0
  157. package/registry/date-picker/files/src/lib/kit.tsx +219 -0
  158. package/registry/date-picker.json +19 -0
  159. package/registry/dialog/files/src/components/ui/dialog.tsx +759 -0
  160. package/registry/dialog/files/src/lib/kit.tsx +219 -0
  161. package/registry/dialog.json +18 -0
  162. package/registry/drawer/files/src/components/ui/drawer.tsx +1135 -0
  163. package/registry/drawer/files/src/lib/kit.tsx +219 -0
  164. package/registry/drawer.json +18 -0
  165. package/registry/fab.json +18 -0
  166. package/registry/flip-card/files/src/components/ui/flip-card.tsx +205 -0
  167. package/registry/flip-card/files/src/lib/kit.tsx +219 -0
  168. package/registry/flip-card.json +15 -0
  169. package/registry/floating-input/files/src/components/ui/floating-input.tsx +528 -0
  170. package/registry/floating-input/files/src/lib/kit.tsx +219 -0
  171. package/registry/floating-input.json +17 -0
  172. package/registry/gift-card.json +21 -0
  173. package/registry/glass-button.json +22 -0
  174. package/registry/glass-nav-bar.json +21 -0
  175. package/registry/glass-search-bar.json +21 -0
  176. package/registry/glass-segmented.json +22 -0
  177. package/registry/glass-sheet.json +22 -0
  178. package/registry/glass-tab-bar.json +22 -0
  179. package/registry/glass.json +19 -0
  180. package/registry/inbox.json +30 -0
  181. package/registry/isometric-bar.json +14 -0
  182. package/registry/kit/files/src/lib/kit.tsx +219 -0
  183. package/registry/kit.json +11 -0
  184. package/registry/kpi-card/files/src/components/charts/kpi-card.tsx +45 -0
  185. package/registry/kpi-card.json +14 -0
  186. package/registry/like-button.json +18 -0
  187. package/registry/liquidglass-tab/files/src/app/(tabs)/_layout.tsx +97 -0
  188. package/registry/liquidglass-tab/files/src/app/(tabs)/alerts.tsx +5 -0
  189. package/registry/liquidglass-tab/files/src/app/(tabs)/explore.tsx +5 -0
  190. package/registry/liquidglass-tab/files/src/app/(tabs)/index.tsx +5 -0
  191. package/registry/liquidglass-tab/files/src/app/(tabs)/profile.tsx +5 -0
  192. package/registry/liquidglass-tab/files/src/app/_layout.tsx +33 -0
  193. package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +259 -0
  194. package/registry/liquidglass-tab/files/src/components/TabScreen.tsx +122 -0
  195. package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +61 -0
  196. package/registry/liquidglass-tab/files/src/lib/tab-icons.ts +130 -0
  197. package/registry/liquidglass-tab/files/src/lib/tabs.ts +108 -0
  198. package/registry/liquidglass-tab.json +23 -0
  199. package/registry/list-item/files/src/components/ui/list-item.tsx +508 -0
  200. package/registry/list-item/files/src/lib/kit.tsx +219 -0
  201. package/registry/list-item.json +17 -0
  202. package/registry/loyalty-card.json +23 -0
  203. package/registry/morph-button.json +18 -0
  204. package/registry/number-ticker.json +15 -0
  205. package/registry/offers.json +24 -0
  206. package/registry/onboarding.json +17 -0
  207. package/registry/otp-input/files/src/components/ui/otp-input.tsx +380 -0
  208. package/registry/otp-input/files/src/lib/kit.tsx +219 -0
  209. package/registry/otp-input.json +17 -0
  210. package/registry/pagination-dots/files/src/components/ui/pagination-dots.tsx +262 -0
  211. package/registry/pagination-dots/files/src/lib/kit.tsx +219 -0
  212. package/registry/pagination-dots.json +15 -0
  213. package/registry/parallax-layers.json +15 -0
  214. package/registry/parallax-scroll.json +17 -0
  215. package/registry/password-input/files/src/components/ui/floating-input.tsx +528 -0
  216. package/registry/password-input/files/src/components/ui/password-input.tsx +271 -0
  217. package/registry/password-input/files/src/lib/kit.tsx +219 -0
  218. package/registry/password-input.json +19 -0
  219. package/registry/payment-card/files/src/components/ui/flip-card.tsx +205 -0
  220. package/registry/payment-card/files/src/components/ui/payment-card.tsx +385 -0
  221. package/registry/payment-card/files/src/components/ui/tilt-card.tsx +635 -0
  222. package/registry/payment-card/files/src/lib/kit.tsx +219 -0
  223. package/registry/payment-card.json +21 -0
  224. package/registry/pixel-bar.json +14 -0
  225. package/registry/polar-area.json +14 -0
  226. package/registry/profile.json +17 -0
  227. package/registry/progress/files/src/components/ui/progress.tsx +883 -0
  228. package/registry/progress/files/src/lib/kit.tsx +219 -0
  229. package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +559 -0
  230. package/registry/progress-steps/files/src/lib/kit.tsx +219 -0
  231. package/registry/progress-steps.json +18 -0
  232. package/registry/progress.json +17 -0
  233. package/registry/radio-group/files/src/components/ui/radio-group.tsx +327 -0
  234. package/registry/radio-group/files/src/lib/kit.tsx +219 -0
  235. package/registry/radio-group.json +18 -0
  236. package/registry/rating.json +18 -0
  237. package/registry/ring-carousel.json +15 -0
  238. package/registry/scratch-card.json +18 -0
  239. package/registry/search-bar/files/src/components/ui/search-bar.tsx +530 -0
  240. package/registry/search-bar/files/src/lib/kit.tsx +219 -0
  241. package/registry/search-bar.json +17 -0
  242. package/registry/search-results.json +30 -0
  243. package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +341 -0
  244. package/registry/segmented-control/files/src/lib/kit.tsx +219 -0
  245. package/registry/segmented-control.json +18 -0
  246. package/registry/select/files/src/components/ui/select.tsx +1398 -0
  247. package/registry/select/files/src/lib/kit.tsx +219 -0
  248. package/registry/select.json +17 -0
  249. package/registry/settings.json +26 -0
  250. package/registry/shimmer-button.json +17 -0
  251. package/registry/sign-in.json +26 -0
  252. package/registry/skeleton/files/src/components/ui/skeleton.tsx +799 -0
  253. package/registry/skeleton/files/src/lib/kit.tsx +219 -0
  254. package/registry/skeleton.json +17 -0
  255. package/registry/slide-to-confirm.json +18 -0
  256. package/registry/slider/files/src/components/ui/slider.tsx +716 -0
  257. package/registry/slider/files/src/lib/kit.tsx +219 -0
  258. package/registry/slider.json +17 -0
  259. package/registry/spin-wheel.json +18 -0
  260. package/registry/spinner/files/src/components/ui/spinner.tsx +335 -0
  261. package/registry/spinner/files/src/lib/kit.tsx +219 -0
  262. package/registry/spinner.json +17 -0
  263. package/registry/stepper/files/src/components/ui/stepper.tsx +646 -0
  264. package/registry/stepper/files/src/lib/kit.tsx +219 -0
  265. package/registry/stepper.json +17 -0
  266. package/registry/swipe-deck.json +15 -0
  267. package/registry/swipeable-row.json +15 -0
  268. package/registry/switch/files/src/components/ui/switch.tsx +344 -0
  269. package/registry/switch/files/src/lib/kit.tsx +219 -0
  270. package/registry/switch.json +18 -0
  271. package/registry/tabs/files/src/components/ui/tabs.tsx +539 -0
  272. package/registry/tabs/files/src/lib/kit.tsx +219 -0
  273. package/registry/tabs.json +17 -0
  274. package/registry/tag-input/files/src/components/ui/tag-input.tsx +720 -0
  275. package/registry/tag-input/files/src/lib/kit.tsx +219 -0
  276. package/registry/tag-input.json +17 -0
  277. package/registry/textarea/files/src/components/ui/textarea.tsx +553 -0
  278. package/registry/textarea/files/src/lib/kit.tsx +219 -0
  279. package/registry/textarea.json +17 -0
  280. package/registry/ticket-card.json +24 -0
  281. package/registry/ticket-shape/files/src/lib/kit.tsx +219 -0
  282. package/registry/ticket-shape/files/src/lib/ticket-shape.tsx +543 -0
  283. package/registry/ticket-shape.json +17 -0
  284. package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +635 -0
  285. package/registry/tilt-card/files/src/lib/kit.tsx +219 -0
  286. package/registry/tilt-card.json +17 -0
  287. package/registry/time-picker/files/src/components/ui/time-picker.tsx +1159 -0
  288. package/registry/time-picker/files/src/lib/kit.tsx +219 -0
  289. package/registry/time-picker.json +17 -0
  290. package/registry/timeline/files/src/components/ui/avatar.tsx +790 -0
  291. package/registry/timeline/files/src/components/ui/timeline.tsx +1059 -0
  292. package/registry/timeline/files/src/lib/kit.tsx +219 -0
  293. package/registry/timeline-chart.json +14 -0
  294. package/registry/timeline.json +20 -0
  295. package/registry/toast/files/src/components/ui/button.tsx +274 -0
  296. package/registry/toast/files/src/components/ui/toast.tsx +1284 -0
  297. package/registry/toast/files/src/lib/kit.tsx +219 -0
  298. package/registry/toast.json +20 -0
  299. package/registry/treemap.json +14 -0
  300. package/registry/waterfall.json +14 -0
  301. package/registry/wheel-list.json +17 -0
  302. package/schema/components.schema.json +13 -0
@@ -0,0 +1,153 @@
1
+ {
2
+ "name": "payment-card",
3
+ "category": "3D",
4
+ "aliases": [],
5
+ "exportName": "PaymentCard",
6
+ "files": [
7
+ "src/components/ui/payment-card.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "number",
12
+ "string",
13
+ "—",
14
+ "Card number (spaces ok). Masked to the last 4 unless masked={false}."
15
+ ],
16
+ [
17
+ "name",
18
+ "string",
19
+ "—",
20
+ "Cardholder name."
21
+ ],
22
+ [
23
+ "expiry",
24
+ "string",
25
+ "—",
26
+ "Expiry, e.g. \"09/29\"."
27
+ ],
28
+ [
29
+ "cvv",
30
+ "string",
31
+ "—",
32
+ "Shown on the back."
33
+ ],
34
+ [
35
+ "brand",
36
+ "\"visa\" | \"mastercard\" | \"amex\" | \"rupay\" | \"none\"",
37
+ "\"visa\"",
38
+ "Brand mark; Amex numbers group 4-6-5."
39
+ ],
40
+ [
41
+ "bank",
42
+ "string",
43
+ "—",
44
+ "Issuer name, top-left."
45
+ ],
46
+ [
47
+ "label",
48
+ "string",
49
+ "—",
50
+ "Small label top-right (\"Debit\", \"Platinum\")."
51
+ ],
52
+ [
53
+ "image",
54
+ "ImageSourcePropType",
55
+ "brushed graphite",
56
+ "Card art — a photo or texture (require() or { uri }). Soft, blurred photos look premium."
57
+ ],
58
+ [
59
+ "tone",
60
+ "\"light\" | \"dark\"",
61
+ "\"light\"",
62
+ "Light text for dark art, dark text for pale art."
63
+ ],
64
+ [
65
+ "chip",
66
+ "\"gold\" | \"silver\"",
67
+ "\"gold\"",
68
+ "EMV chip finish."
69
+ ],
70
+ [
71
+ "masked",
72
+ "boolean",
73
+ "true",
74
+ "Hide every digit but the last four (any card length)."
75
+ ],
76
+ [
77
+ "flipped",
78
+ "boolean",
79
+ "—",
80
+ "Controlled side (true = back)."
81
+ ],
82
+ [
83
+ "defaultFlipped",
84
+ "boolean",
85
+ "false",
86
+ "Uncontrolled initial side."
87
+ ],
88
+ [
89
+ "onFlip",
90
+ "(flipped: boolean) => void",
91
+ "—",
92
+ "Fires when tapped."
93
+ ],
94
+ [
95
+ "tilt",
96
+ "boolean",
97
+ "true",
98
+ "Tilt toward the finger."
99
+ ],
100
+ [
101
+ "flippable",
102
+ "boolean",
103
+ "true",
104
+ "Tap flips the card. false makes a still card (no tilt, no taps) for use inside something tappable, e.g. a CardStack; a controlled flipped still turns it."
105
+ ],
106
+ [
107
+ "frozen",
108
+ "boolean",
109
+ "false",
110
+ "Dim the card with a Frozen label and ignore taps."
111
+ ],
112
+ [
113
+ "radius",
114
+ "number",
115
+ "16",
116
+ "Corner radius — a real card's corner at phone size."
117
+ ],
118
+ [
119
+ "labels",
120
+ "{ cardholder?, validThru?, frozen?, legal?, back?, accessibility? }",
121
+ "English",
122
+ "Every built-in string, for translation ({bank} and {last4} are filled in)."
123
+ ],
124
+ [
125
+ "style",
126
+ "StyleProp<ViewStyle>",
127
+ "—",
128
+ "Style for the root (width, margins)."
129
+ ]
130
+ ],
131
+ "examples": [
132
+ {
133
+ "name": "WalletScreen",
134
+ "title": "Wallet Screen",
135
+ "code": "import { Image, Pressable, Text, View } from 'react-native';\nimport { PaymentCard } from '@/components/ui/payment-card';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** Soft, blurred photos make premium card art — any image works (`require()` or a URL). */\nconst art = (id: number) => ({ uri: `https://picsum.photos/id/${id}/240/151?blur=10` });\n\nexport default function WalletScreen() {\n const { colors } = useKit();\n const actions = [\n ['↑', 'Send'],\n ['↓', 'Request'],\n ['+', 'Top up'],\n ['⋯', 'More'],\n ];\n const activity = [\n ['B', 'Blue Tokai Coffee', 'Today · 09:12', '−₹240'],\n ['U', 'Uber', 'Yesterday · 21:40', '−₹386'],\n ['S', 'Salary · Northwind Labs', 'Mon · 10:00', '+₹82,000'],\n ];\n return (\n <View style={{ gap: 20 }}>\n <View style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>\n <View>\n <Text style={{ color: colors.mutedForeground, fontSize: 13 }}>Total balance</Text>\n <Text style={{ color: colors.foreground, fontSize: 30, fontWeight: '700', letterSpacing: -0.8, fontVariant: ['tabular-nums'] }}>₹1,24,580.20</Text>\n <Text style={{ color: colors.success, fontSize: 12, fontWeight: '500' }}>+₹2,140 this week</Text>\n </View>\n <View style={{ width: 40, height: 40, borderRadius: 20, backgroundColor: colors.muted, alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: colors.foreground, fontSize: 14, fontWeight: '700' }}>MP</Text>\n </View>\n </View>\n\n <PaymentCard\n image={art(189)}\n bank=\"Northwind\"\n label=\"World Elite\"\n number=\"5412 7590 1234 0317\"\n name=\"Maya Patel\"\n expiry=\"09/29\"\n cvv=\"482\"\n brand=\"mastercard\"\n />\n\n <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>\n {actions.map(([glyph, label]) => (\n <View key={label} style={{ alignItems: 'center', gap: 6, width: 64 }}>\n <View style={{ width: 52, height: 52, borderRadius: 26, backgroundColor: colors.muted, alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: colors.foreground, fontSize: 20, fontWeight: '500' }}>{glyph}</Text>\n </View>\n <Text style={{ color: colors.mutedForeground, fontSize: 12 }}>{label}</Text>\n </View>\n ))}\n </View>\n\n <View>\n <Text style={{ color: colors.foreground, fontSize: 16, fontWeight: '600', marginBottom: 4 }}>Recent activity</Text>\n {activity.map(([initial, what, when, amount]) => (\n <View key={what} style={{ flexDirection: 'row', alignItems: 'center', gap: 12, paddingVertical: 10 }}>\n <View style={{ width: 38, height: 38, borderRadius: 12, backgroundColor: colors.muted, alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ color: colors.foreground, fontSize: 14, fontWeight: '700' }}>{initial}</Text>\n </View>\n <View style={{ flex: 1 }}>\n <Text style={{ color: colors.foreground, fontSize: 14, fontWeight: '500' }}>{what}</Text>\n <Text style={{ color: colors.mutedForeground, fontSize: 12 }}>{when}</Text>\n </View>\n <Text style={{ color: amount.startsWith('+') ? colors.success : colors.foreground, fontSize: 14, fontWeight: '600', fontVariant: ['tabular-nums'] }}>{amount}</Text>\n </View>\n ))}\n </View>\n </View>\n );\n}\n"
136
+ },
137
+ {
138
+ "name": "CardControls",
139
+ "title": "Card Controls",
140
+ "code": "import React, { useState } from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport { PaymentCard } from '@/components/ui/payment-card';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** Soft, blurred photos make premium card art — any image works (`require()` or a URL). */\nconst art = (id: number) => ({ uri: `https://picsum.photos/id/${id}/240/151?blur=10` });\n\n/** A screen title, as it sits above the card in your app. */\nfunction Header({ title, sub, right }: { title: string; sub?: string; right?: React.ReactNode }) {\n const { colors } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <View style={{ flex: 1 }}>\n <Text style={{ color: colors.foreground, fontSize: 22, fontWeight: '700', letterSpacing: -0.4 }}>{title}</Text>\n {sub ? <Text style={{ color: colors.mutedForeground, fontSize: 13, marginTop: 2 }}>{sub}</Text> : null}\n </View>\n {right}\n </View>\n );\n}\n\nexport default function CardControls() {\n const { colors } = useKit();\n const [shown, setShown] = useState(false);\n const [frozen, setFrozen] = useState(false);\n const [flipped, setFlipped] = useState(false);\n const row = (label: string, detail: string, value: boolean, onPress: () => void) => (\n <Pressable\n onPress={onPress}\n accessibilityRole=\"switch\"\n accessibilityState={{ checked: value }}\n style={{ flexDirection: 'row', alignItems: 'center', gap: 12, paddingVertical: 12 }}\n >\n <View style={{ flex: 1 }}>\n <Text style={{ color: colors.foreground, fontSize: 15, fontWeight: '500' }}>{label}</Text>\n <Text style={{ color: colors.mutedForeground, fontSize: 12 }}>{detail}</Text>\n </View>\n <View style={{ width: 46, height: 28, borderRadius: 14, padding: 3, backgroundColor: value ? colors.success : alpha(colors.mutedForeground, 0.3) }}>\n <View style={{ width: 22, height: 22, borderRadius: 11, backgroundColor: '#ffffff', alignSelf: value ? 'flex-end' : 'flex-start' }} />\n </View>\n </Pressable>\n );\n return (\n <View style={{ gap: 14 }}>\n <Header title=\"Manage card\" sub=\"Changes apply instantly\" />\n <PaymentCard\n image={art(888)}\n bank=\"Northwind\"\n label=\"Platinum\"\n number=\"4821 7590 3321 7752\"\n name=\"Maya Patel\"\n expiry=\"11/28\"\n cvv=\"219\"\n brand=\"visa\"\n chip=\"silver\"\n masked={!shown}\n frozen={frozen}\n flipped={flipped}\n onFlip={setFlipped}\n />\n <View>\n {row('Show card number', 'Hidden again when you leave', shown, () => setShown((v) => !v))}\n {row('Show CVV', 'Turns the card over', flipped, () => setFlipped((v) => !v))}\n {row('Freeze card', 'Blocks new payments instantly', frozen, () => setFrozen((v) => !v))}\n </View>\n </View>\n );\n}\n"
141
+ },
142
+ {
143
+ "name": "ChooseDesign",
144
+ "title": "Choose Design",
145
+ "code": "import React, { useState } from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport { PaymentCard } from '@/components/ui/payment-card';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** Soft, blurred photos make premium card art — any image works (`require()` or a URL). */\nconst art = (id: number) => ({ uri: `https://picsum.photos/id/${id}/240/151?blur=10` });\n\n/** A screen title, as it sits above the card in your app. */\nfunction Header({ title, sub, right }: { title: string; sub?: string; right?: React.ReactNode }) {\n const { colors } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <View style={{ flex: 1 }}>\n <Text style={{ color: colors.foreground, fontSize: 22, fontWeight: '700', letterSpacing: -0.4 }}>{title}</Text>\n {sub ? <Text style={{ color: colors.mutedForeground, fontSize: 13, marginTop: 2 }}>{sub}</Text> : null}\n </View>\n {right}\n </View>\n );\n}\n\nconst DESIGNS = [\n { key: 'meadow', image: art(189) },\n { key: 'lagoon', image: art(846) },\n { key: 'violet', image: art(888) },\n { key: 'dusk', image: art(721) },\n { key: 'night', image: art(765) },\n];\n\nexport default function ChooseDesign() {\n const { colors } = useKit();\n const [pick, setPick] = useState(0);\n return (\n <View style={{ gap: 16 }}>\n <Header title=\"Pick your card\" sub=\"Your design ships in 3–5 days\" />\n <PaymentCard\n image={DESIGNS[pick].image}\n bank=\"Northwind\"\n label=\"Debit\"\n number=\"6521 4400 9911 4410\"\n name=\"Maya Patel\"\n expiry=\"01/30\"\n brand=\"rupay\"\n />\n <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>\n {DESIGNS.map((d, i) => {\n const on = i === pick;\n return (\n <Pressable\n key={d.key}\n onPress={() => setPick(i)}\n accessibilityRole=\"radio\"\n accessibilityLabel={d.key}\n accessibilityState={{ selected: on }}\n style={{ padding: 2, borderRadius: 10, borderWidth: 2, borderColor: on ? colors.foreground : 'transparent' }}\n >\n <Image alt=\"\" source={d.image} style={{ width: 52, height: 33, borderRadius: 6, backgroundColor: colors.muted }} />\n </Pressable>\n );\n })}\n </View>\n <Pressable accessibilityRole=\"button\" style={{ alignItems: 'center', paddingVertical: 14, borderRadius: 14, backgroundColor: colors.primary, marginTop: 8 }}>\n <Text style={{ color: colors.primaryForeground, fontSize: 15, fontWeight: '600' }}>Order this card</Text>\n </Pressable>\n </View>\n );\n}\n"
146
+ },
147
+ {
148
+ "name": "AddCard",
149
+ "title": "Add Card",
150
+ "code": "import React, { useState } from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport { PaymentCard } from '@/components/ui/payment-card';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** A screen title, as it sits above the card in your app. */\nfunction Header({ title, sub, right }: { title: string; sub?: string; right?: React.ReactNode }) {\n const { colors } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <View style={{ flex: 1 }}>\n <Text style={{ color: colors.foreground, fontSize: 22, fontWeight: '700', letterSpacing: -0.4 }}>{title}</Text>\n {sub ? <Text style={{ color: colors.mutedForeground, fontSize: 13, marginTop: 2 }}>{sub}</Text> : null}\n </View>\n {right}\n </View>\n );\n}\n\nexport default function AddCard() {\n const { colors } = useKit();\n const [digits, setDigits] = useState('4821');\n const keys = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];\n return (\n <View style={{ gap: 16 }}>\n <Header title=\"Add a card\" sub=\"Type the number on the front\" />\n <PaymentCard bank=\"New card\" number={digits.padEnd(16, '•')} name=\"Your name\" expiry=\"MM/YY\" brand=\"visa\" chip=\"silver\" masked={false} />\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8, justifyContent: 'center' }}>\n {keys.map((k) => (\n <Pressable\n key={k}\n onPress={() => setDigits((d) => (d.length >= 16 ? '4821' : d + k))}\n accessibilityRole=\"button\"\n style={{ width: 58, height: 46, borderRadius: 12, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.muted }}\n >\n <Text style={{ color: colors.foreground, fontSize: 19, fontWeight: '500' }}>{k}</Text>\n </Pressable>\n ))}\n </View>\n </View>\n );\n}\n"
151
+ }
152
+ ]
153
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "pixel-bar",
3
+ "category": "Charts",
4
+ "aliases": [],
5
+ "exportName": "PixelBarChart",
6
+ "files": [
7
+ "src/components/charts/pixel-bar.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "data",
12
+ "{ label, value, color? }[]",
13
+ "—",
14
+ "One block per category."
15
+ ],
16
+ [
17
+ "height",
18
+ "number",
19
+ "240",
20
+ "Chart height."
21
+ ],
22
+ [
23
+ "animate",
24
+ "boolean",
25
+ "true",
26
+ "Entrance animation."
27
+ ],
28
+ [
29
+ "isLoading",
30
+ "boolean",
31
+ "false",
32
+ "Skeleton state."
33
+ ],
34
+ [
35
+ "formatValue",
36
+ "(v) => string",
37
+ "compact",
38
+ "Value formatting."
39
+ ],
40
+ [
41
+ "onSelect",
42
+ "(item, index) => void",
43
+ "—",
44
+ "Tap callback."
45
+ ],
46
+ [
47
+ "levels",
48
+ "number",
49
+ "10",
50
+ "Squares per column."
51
+ ],
52
+ [
53
+ "gap",
54
+ "number",
55
+ "2",
56
+ "Gap between squares."
57
+ ],
58
+ [
59
+ "gradient",
60
+ "boolean",
61
+ "true",
62
+ "Fade colour upwards."
63
+ ]
64
+ ],
65
+ "examples": []
66
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "polar-area",
3
+ "category": "Charts",
4
+ "aliases": [],
5
+ "exportName": "PolarAreaChart",
6
+ "files": [
7
+ "src/components/charts/polar-area.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "data",
12
+ "Datum[]",
13
+ "—",
14
+ "Rows like [{ browser: \"chrome\", visitors: 275 }]."
15
+ ],
16
+ [
17
+ "nameKey / valueKey",
18
+ "string",
19
+ "\"name\" / \"value\"",
20
+ "Which keys hold the label and the number."
21
+ ],
22
+ [
23
+ "config",
24
+ "ChartConfig",
25
+ "—",
26
+ "Labels / colours keyed by name."
27
+ ],
28
+ [
29
+ "size",
30
+ "number",
31
+ "260",
32
+ "Diameter."
33
+ ],
34
+ [
35
+ "showLegend",
36
+ "boolean",
37
+ "false",
38
+ "Legend under the chart."
39
+ ],
40
+ [
41
+ "legendVariant",
42
+ "LegendVariant",
43
+ "\"rounded-square\"",
44
+ "Legend marker style."
45
+ ],
46
+ [
47
+ "glow",
48
+ "boolean | string[]",
49
+ "false",
50
+ "Glow every segment or only named ones."
51
+ ],
52
+ [
53
+ "isLoading",
54
+ "boolean",
55
+ "false",
56
+ "Skeleton state."
57
+ ],
58
+ [
59
+ "onSelect",
60
+ "(index, datum) => void",
61
+ "—",
62
+ "Selection callback."
63
+ ],
64
+ [
65
+ "padAngle",
66
+ "number (deg)",
67
+ "2",
68
+ "Gap between petals."
69
+ ],
70
+ [
71
+ "levels",
72
+ "number",
73
+ "4",
74
+ "Grid circles."
75
+ ]
76
+ ],
77
+ "examples": []
78
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "profile",
3
+ "category": "Blocks",
4
+ "aliases": [],
5
+ "exportName": "Profile",
6
+ "files": [
7
+ "src/components/blocks/profile.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "user",
12
+ "{ name, email?, phone?, avatar?, subtitle?, badge? }",
13
+ "Aarav Mehta",
14
+ "Who the account belongs to. subtitle is a muted line (e.g. 'Member since 2023'); badge shows a chip next to the name (e.g. 'Pro')."
15
+ ],
16
+ [
17
+ "stats",
18
+ "{ label, value, onPress? }[]",
19
+ "Orders / Wishlist / Reviews",
20
+ "Highlights strip under the header. Pass [] to hide."
21
+ ],
22
+ [
23
+ "details",
24
+ "{ key, label, value?, icon? }[]",
25
+ "Date of birth, Address",
26
+ "“Personal details” rows (name, email and phone already show in the header). Empty value shows a muted “Add”. Pass [] to hide."
27
+ ],
28
+ [
29
+ "sections",
30
+ "{ title?, items: { key, label, value?, icon?, badge?, destructive?, onPress? }[] }[]",
31
+ "Account, Preferences, Support",
32
+ "Grouped rows below the details. destructive rows are red with no chevron."
33
+ ],
34
+ [
35
+ "title",
36
+ "string",
37
+ "'Profile'",
38
+ "Header title."
39
+ ],
40
+ [
41
+ "onEditProfile",
42
+ "() => void",
43
+ "—",
44
+ "Shows a small 'Edit profile' pill under the contact details."
45
+ ],
46
+ [
47
+ "onAvatarPress",
48
+ "() => void",
49
+ "—",
50
+ "Makes the avatar pressable and adds a camera badge."
51
+ ],
52
+ [
53
+ "onRowPress",
54
+ "(key: string) => void",
55
+ "—",
56
+ "Any detail or section row was pressed (after the item's own onPress)."
57
+ ],
58
+ [
59
+ "onSignOut",
60
+ "() => void",
61
+ "—",
62
+ "The destructive 'Sign out' row at the end was pressed."
63
+ ],
64
+ [
65
+ "onBack",
66
+ "() => void",
67
+ "—",
68
+ "Shows a back button in the header."
69
+ ],
70
+ [
71
+ "accent",
72
+ "string",
73
+ "theme accent",
74
+ "Badge chip and pressed-state tint. Everything else stays monochrome."
75
+ ],
76
+ [
77
+ "style",
78
+ "StyleProp<ViewStyle>",
79
+ "—",
80
+ "Root style."
81
+ ]
82
+ ],
83
+ "examples": []
84
+ }
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "progress-steps",
3
+ "category": "Navigation",
4
+ "aliases": [],
5
+ "exportName": "ProgressSteps",
6
+ "files": [
7
+ "src/components/ui/progress-steps.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "steps",
12
+ "(string | { label, description? })[]",
13
+ "—",
14
+ "Step labels with optional descriptions (vertical, and two short lines in horizontal)."
15
+ ],
16
+ [
17
+ "current",
18
+ "number",
19
+ "—",
20
+ "Active step index. Earlier steps are complete; steps.length marks all done."
21
+ ],
22
+ [
23
+ "errorStep",
24
+ "number",
25
+ "—",
26
+ "A failed step, drawn red with \"!\"."
27
+ ],
28
+ [
29
+ "variant",
30
+ "\"horizontal\" | \"vertical\" | \"bar\"",
31
+ "\"horizontal\"",
32
+ "Nodes with labels · vertical list with descriptions · compact header and segmented bar."
33
+ ],
34
+ [
35
+ "onStepPress",
36
+ "(index: number) => void",
37
+ "—",
38
+ "Makes steps tappable, e.g. to jump back."
39
+ ],
40
+ [
41
+ "pressableSteps",
42
+ "\"all\" | \"completed\"",
43
+ "\"all\"",
44
+ "Which steps onStepPress applies to; \"completed\" only lets people go back."
45
+ ],
46
+ [
47
+ "haptics",
48
+ "boolean",
49
+ "true",
50
+ "Selection tick whenever current changes."
51
+ ],
52
+ [
53
+ "accent",
54
+ "string",
55
+ "theme accent",
56
+ "Solid colour of completed steps, connectors and the current ring; halos and tracks are tints of it."
57
+ ],
58
+ [
59
+ "style",
60
+ "StyleProp<ViewStyle>",
61
+ "—",
62
+ "Style for the step row / column (the bar container in the bar variant)."
63
+ ]
64
+ ],
65
+ "examples": [
66
+ {
67
+ "name": "Checkout",
68
+ "title": "Checkout",
69
+ "code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Buttons({ step, max, set, last = 'Place order' }: { step: number; max: number; set: (n: number) => void; last?: string }) {\n const { colors, radius } = useKit();\n const done = step >= max;\n return (\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Pressable\n onPress={() => set(Math.max(0, step - 1))}\n disabled={step === 0}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: alpha(colors.foreground, pressed ? 0.1 : 0.05),\n alignItems: 'center',\n justifyContent: 'center',\n opacity: step === 0 ? 0.4 : 1,\n })}\n >\n <Text style={{ fontSize: 15, color: colors.foreground }}>Back</Text>\n </Pressable>\n <Pressable\n onPress={() => set(done ? 0 : step + 1)}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1.5,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: pressed ? 0.98 : 1 }],\n })}\n >\n <Text style={{ fontSize: 15, color: colors.accentForeground }}>\n {done ? 'Start over' : step === max - 1 ? last : 'Continue'}\n </Text>\n </Pressable>\n </View>\n );\n}\n\nexport default function Checkout() {\n const { colors } = useKit();\n const [step, setStep] = useState(1);\n const copy = [\n '2 items · ₹2,798',\n 'Delivering to 14 Rua das Flores, Lisbon',\n 'Visa ending 4242',\n 'Arrives Thursday, 16 October',\n ];\n return (\n <View style={{ gap: 22 }}>\n <ProgressSteps\n steps={['Cart', 'Shipping', 'Payment', 'Review']}\n current={step}\n pressableSteps=\"completed\"\n onStepPress={setStep}\n />\n <Text style={{ fontSize: 14, textAlign: 'center', color: colors.mutedForeground }}>\n {step >= 4 ? 'Order #4821 placed — receipt sent to amelia@hart.studio' : copy[step]}\n </Text>\n <Buttons step={step} max={4} set={setStep} />\n </View>\n );\n}\n"
70
+ },
71
+ {
72
+ "name": "Onboarding",
73
+ "title": "Onboarding",
74
+ "code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Buttons({ step, max, set, last = 'Place order' }: { step: number; max: number; set: (n: number) => void; last?: string }) {\n const { colors, radius } = useKit();\n const done = step >= max;\n return (\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Pressable\n onPress={() => set(Math.max(0, step - 1))}\n disabled={step === 0}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: alpha(colors.foreground, pressed ? 0.1 : 0.05),\n alignItems: 'center',\n justifyContent: 'center',\n opacity: step === 0 ? 0.4 : 1,\n })}\n >\n <Text style={{ fontSize: 15, color: colors.foreground }}>Back</Text>\n </Pressable>\n <Pressable\n onPress={() => set(done ? 0 : step + 1)}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1.5,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: pressed ? 0.98 : 1 }],\n })}\n >\n <Text style={{ fontSize: 15, color: colors.accentForeground }}>\n {done ? 'Start over' : step === max - 1 ? last : 'Continue'}\n </Text>\n </Pressable>\n </View>\n );\n}\n\nexport default function Onboarding() {\n const [step, setStep] = useState(2);\n return (\n <View style={{ gap: 20 }}>\n <ProgressSteps\n variant=\"vertical\"\n current={step}\n pressableSteps=\"completed\"\n onStepPress={setStep}\n steps={[\n { label: 'Create your account', description: 'Signed up with amelia@hart.studio' },\n { label: 'Verify your email', description: 'Confirmed with a 6-digit code.' },\n { label: 'Connect your bank', description: 'Read-only access. You can disconnect any time.' },\n { label: 'Set your first budget', description: 'Pick categories and a monthly limit.' },\n ]}\n />\n <Buttons step={step} max={4} set={setStep} last=\"Finish setup\" />\n </View>\n );\n}\n"
75
+ },
76
+ {
77
+ "name": "Compact",
78
+ "title": "Compact",
79
+ "code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Buttons({ step, max, set, last = 'Place order' }: { step: number; max: number; set: (n: number) => void; last?: string }) {\n const { colors, radius } = useKit();\n const done = step >= max;\n return (\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Pressable\n onPress={() => set(Math.max(0, step - 1))}\n disabled={step === 0}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: alpha(colors.foreground, pressed ? 0.1 : 0.05),\n alignItems: 'center',\n justifyContent: 'center',\n opacity: step === 0 ? 0.4 : 1,\n })}\n >\n <Text style={{ fontSize: 15, color: colors.foreground }}>Back</Text>\n </Pressable>\n <Pressable\n onPress={() => set(done ? 0 : step + 1)}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1.5,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: pressed ? 0.98 : 1 }],\n })}\n >\n <Text style={{ fontSize: 15, color: colors.accentForeground }}>\n {done ? 'Start over' : step === max - 1 ? last : 'Continue'}\n </Text>\n </Pressable>\n </View>\n );\n}\n\nexport default function Compact() {\n const [step, setStep] = useState(1);\n return (\n <View style={{ gap: 20 }}>\n <ProgressSteps variant=\"bar\" steps={['Shipping address', 'Delivery options', 'Payment', 'Review order']} current={step} />\n <Buttons step={step} max={4} set={setStep} />\n </View>\n );\n}\n"
80
+ },
81
+ {
82
+ "name": "WithDescriptions",
83
+ "title": "With Descriptions",
84
+ "code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Buttons({ step, max, set, last = 'Place order' }: { step: number; max: number; set: (n: number) => void; last?: string }) {\n const { colors, radius } = useKit();\n const done = step >= max;\n return (\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Pressable\n onPress={() => set(Math.max(0, step - 1))}\n disabled={step === 0}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: alpha(colors.foreground, pressed ? 0.1 : 0.05),\n alignItems: 'center',\n justifyContent: 'center',\n opacity: step === 0 ? 0.4 : 1,\n })}\n >\n <Text style={{ fontSize: 15, color: colors.foreground }}>Back</Text>\n </Pressable>\n <Pressable\n onPress={() => set(done ? 0 : step + 1)}\n accessibilityRole=\"button\"\n style={({ pressed }) => ({\n flex: 1.5,\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n transform: [{ scale: pressed ? 0.98 : 1 }],\n })}\n >\n <Text style={{ fontSize: 15, color: colors.accentForeground }}>\n {done ? 'Start over' : step === max - 1 ? last : 'Continue'}\n </Text>\n </Pressable>\n </View>\n );\n}\n\nexport default function WithDescriptions() {\n const [step, setStep] = useState(1);\n return (\n <View style={{ gap: 22 }}>\n <ProgressSteps\n current={step}\n steps={[\n { label: 'Profile', description: 'Name, photo' },\n { label: 'Workspace', description: 'Invite team' },\n { label: 'Plan', description: 'Free or Pro' },\n ]}\n />\n <Buttons step={step} max={3} set={setStep} last=\"Create workspace\" />\n </View>\n );\n}\n"
85
+ },
86
+ {
87
+ "name": "WithError",
88
+ "title": "With Error",
89
+ "code": "import { Pressable, Text, View } from 'react-native';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\nimport { alpha, useKit } from '@/lib/kit';\n\nexport default function WithError() {\n const { colors } = useKit();\n return (\n <View style={{ gap: 14 }}>\n <ProgressSteps steps={['Upload', 'Verify', 'Approve', 'Publish']} current={1} errorStep={1} />\n <Text style={{ fontSize: 13, lineHeight: 18, color: colors.mutedForeground, textAlign: 'center' }}>\n ID photo was blurry — retake it to continue.\n </Text>\n </View>\n );\n}\n"
90
+ }
91
+ ]
92
+ }
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "progress",
3
+ "category": "Feedback",
4
+ "aliases": [],
5
+ "exportName": "Progress",
6
+ "files": [
7
+ "src/components/ui/progress.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "variant",
12
+ "\"linear\" | \"circular\" | \"steps\"",
13
+ "\"linear\"",
14
+ "Horizontal bar, circular ring, or a row of segments."
15
+ ],
16
+ [
17
+ "value",
18
+ "number",
19
+ "—",
20
+ "0 → max (completed steps for steps). Omit for indeterminate."
21
+ ],
22
+ [
23
+ "max",
24
+ "number",
25
+ "100 (steps: steps)",
26
+ "Upper bound."
27
+ ],
28
+ [
29
+ "indeterminate",
30
+ "boolean",
31
+ "false",
32
+ "Comet sweep on the bar, spinning arc on the ring."
33
+ ],
34
+ [
35
+ "steps",
36
+ "number",
37
+ "4",
38
+ "Segment count for the steps variant."
39
+ ],
40
+ [
41
+ "size",
42
+ "\"sm\" | \"md\" | \"lg\"",
43
+ "\"md\"",
44
+ "Bar 4 / 8 / 12pt, ring 44 / 72 / 112pt."
45
+ ],
46
+ [
47
+ "color",
48
+ "string",
49
+ "theme accent",
50
+ "Fill colour (solid); the track, glow and pulse are tints of it."
51
+ ],
52
+ [
53
+ "trackColor",
54
+ "string",
55
+ "subtle foreground",
56
+ "Track colour."
57
+ ],
58
+ [
59
+ "label",
60
+ "string",
61
+ "—",
62
+ "Caption above the bar or under the ring."
63
+ ],
64
+ [
65
+ "showValue",
66
+ "boolean",
67
+ "ring: true",
68
+ "Show the percentage (a drawn check once complete)."
69
+ ],
70
+ [
71
+ "formatValue",
72
+ "(value, max) => string",
73
+ "—",
74
+ "Custom value text (e.g. \"3 of 5\")."
75
+ ],
76
+ [
77
+ "celebrate",
78
+ "boolean",
79
+ "true",
80
+ "At max, flash the fill and turn the value into a drawn check."
81
+ ],
82
+ [
83
+ "striped",
84
+ "boolean",
85
+ "false",
86
+ "Animated diagonal stripes on the linear fill for processing states."
87
+ ],
88
+ [
89
+ "style",
90
+ "StyleProp<ViewStyle>",
91
+ "—",
92
+ "Style for the root view of the bar, ring or step row."
93
+ ]
94
+ ],
95
+ "examples": [
96
+ {
97
+ "name": "Linear",
98
+ "title": "Linear",
99
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Linear() {\n const [value, setValue] = useState(32);\n return (\n <View style={{ gap: 18 }}>\n <Progress value={value} label=\"Uploading trip-to-lisbon.mov\" showValue />\n <Progress value={value} size=\"sm\" />\n <Progress value={value} size=\"lg\" />\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Button size=\"sm\" variant=\"outline\" onPress={() => setValue((v) => Math.max(0, v - 20))}>\n − 20\n </Button>\n <Button size=\"sm\" variant=\"outline\" onPress={() => setValue((v) => Math.min(100, v + 20))}>\n + 20\n </Button>\n </View>\n </View>\n );\n}\n"
100
+ },
101
+ {
102
+ "name": "Download",
103
+ "title": "Download",
104
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { Progress } from '@/components/ui/progress';\nimport { useKit } from '@/lib/kit';\n\nexport default function Download() {\n const { colors } = useKit();\n const [mb, setMb] = useState(6);\n useEffect(() => {\n const id = setInterval(() => setMb((v) => (v >= 48 ? 0 : Math.min(48, v + 3.4))), 700);\n return () => clearInterval(id);\n }, []);\n return (\n <View style={{ gap: 6 }}>\n <Progress\n value={mb}\n max={48}\n label=\"Offline maps · Portugal\"\n showValue\n formatValue={(v, max) => `${v.toFixed(1)} of ${max} MB`}\n />\n <Text style={{ fontSize: 12, color: colors.mutedForeground }}>\n {mb >= 48 ? 'Ready to use offline' : `4.8 MB/s · about ${Math.ceil((48 - mb) / 4.8)} s left`}\n </Text>\n </View>\n );\n}\n"
105
+ },
106
+ {
107
+ "name": "Completion",
108
+ "title": "Completion",
109
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Completion() {\n const [value, setValue] = useState(0);\n useEffect(() => {\n if (value >= 100) return;\n const id = setTimeout(() => setValue((v) => Math.min(100, v + 12 + Math.round(Math.random() * 10))), 450);\n return () => clearTimeout(id);\n }, [value]);\n return (\n <View style={{ gap: 18 }}>\n <Progress value={value} label={value >= 100 ? 'Backup complete' : 'Backing up photos'} showValue />\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 16 }}>\n <Progress variant=\"circular\" size=\"md\" value={value} />\n <Button size=\"sm\" variant=\"outline\" onPress={() => setValue(0)}>\n Run again\n </Button>\n </View>\n </View>\n );\n}\n"
110
+ },
111
+ {
112
+ "name": "Indeterminate",
113
+ "title": "Indeterminate",
114
+ "code": "import { Text, View } from 'react-native';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Indeterminate() {\n return (\n <View style={{ gap: 18 }}>\n <Progress indeterminate label=\"Connecting to Wi‑Fi printer\" />\n <Progress value={64} striped label=\"Compressing video\" showValue />\n <Progress indeterminate size=\"sm\" />\n </View>\n );\n}\n"
115
+ },
116
+ {
117
+ "name": "Spinning",
118
+ "title": "Spinning",
119
+ "code": "import { Text, View } from 'react-native';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Spinning() {\n return (\n <View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>\n <Progress variant=\"circular\" size=\"sm\" indeterminate />\n <Progress variant=\"circular\" size=\"md\" indeterminate label=\"Restoring backup\" />\n </View>\n );\n}\n"
120
+ },
121
+ {
122
+ "name": "Circular",
123
+ "title": "Circular",
124
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Circular() {\n const [value, setValue] = useState(0);\n useEffect(() => {\n const id = setInterval(() => setValue((v) => (v >= 100 ? 0 : v + 25)), 1600);\n return () => clearInterval(id);\n }, []);\n return (\n <View style={{ flexDirection: 'row', alignItems: 'flex-end', justifyContent: 'space-around' }}>\n <Progress variant=\"circular\" size=\"sm\" value={value} />\n <Progress variant=\"circular\" size=\"md\" value={72} label=\"iCloud storage\" />\n <Progress variant=\"circular\" size=\"lg\" value={value} label=\"Move goal\" />\n </View>\n );\n}\n"
125
+ },
126
+ {
127
+ "name": "Steps",
128
+ "title": "Steps",
129
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function Steps() {\n const [step, setStep] = useState(2);\n return (\n <View style={{ gap: 16 }}>\n <Progress\n variant=\"steps\"\n steps={5}\n value={step}\n label={step >= 5 ? 'Profile ready' : 'Set up your profile'}\n showValue\n formatValue={(v, max) => `Step ${Math.min(max, v + 1)} of ${max}`}\n />\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Button size=\"sm\" variant=\"outline\" onPress={() => setStep((s) => Math.max(0, s - 1))}>\n Back\n </Button>\n <Button size=\"sm\" variant=\"accent\" onPress={() => setStep((s) => Math.min(5, s + 1))}>\n Continue\n </Button>\n </View>\n </View>\n );\n}\n"
130
+ }
131
+ ]
132
+ }