@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,105 @@
1
+ {
2
+ "name": "tabs",
3
+ "category": "Navigation",
4
+ "aliases": [],
5
+ "exportName": "Tabs",
6
+ "files": [
7
+ "src/components/ui/tabs.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "items",
12
+ "{ value, label, icon?, badge?, content?, disabled?, accessibilityLabel? }[]",
13
+ "—",
14
+ "Tabs and (optionally) their content panes. `icon` is a node or `({ active, color }) => node`."
15
+ ],
16
+ [
17
+ "value / defaultValue",
18
+ "string",
19
+ "first enabled tab",
20
+ "Active tab (controlled / uncontrolled)."
21
+ ],
22
+ [
23
+ "onValueChange",
24
+ "(value: string) => void",
25
+ "—",
26
+ "Called when a tab is pressed or swiped to."
27
+ ],
28
+ [
29
+ "size",
30
+ "\"sm\" | \"md\"",
31
+ "\"md\"",
32
+ "36 / 44pt tall (sm keeps a 44pt hit area)."
33
+ ],
34
+ [
35
+ "scrollable",
36
+ "boolean",
37
+ "auto",
38
+ "`true` sizes tabs to labels and scrolls; `false` gives equal widths. Default fills the width and scrolls only when tabs overflow, keeping the active tab centred."
39
+ ],
40
+ [
41
+ "swipeable",
42
+ "boolean",
43
+ "true",
44
+ "Drag the content sideways to change tab; the underline tracks the drag."
45
+ ],
46
+ [
47
+ "transition",
48
+ "\"slide\" | \"fade\" | \"none\"",
49
+ "\"slide\"",
50
+ "How content changes on a tap."
51
+ ],
52
+ [
53
+ "haptics",
54
+ "boolean",
55
+ "true",
56
+ "Selection tick on change."
57
+ ],
58
+ [
59
+ "accent",
60
+ "string",
61
+ "theme accent",
62
+ "Underline and active badge colour."
63
+ ],
64
+ [
65
+ "variant",
66
+ "\"underline\"",
67
+ "\"underline\"",
68
+ "Deprecated: `pill` and `soft` render as `underline` — use SegmentedControl for a pill switch."
69
+ ],
70
+ [
71
+ "contentStyle",
72
+ "StyleProp<ViewStyle>",
73
+ "—",
74
+ "Style of each content pane."
75
+ ],
76
+ [
77
+ "style",
78
+ "StyleProp<ViewStyle>",
79
+ "—",
80
+ "Style for the root view wrapping the tab bar and content."
81
+ ]
82
+ ],
83
+ "examples": [
84
+ {
85
+ "name": "Underline",
86
+ "title": "Underline",
87
+ "code": "import { Pressable, Text, View } from 'react-native';\nimport { Tabs } from '@/components/ui/tabs';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Panel({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4 }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground }}>{title}</Text>\n <Text style={{ fontSize: 14, fontWeight: '400', lineHeight: 20, color: colors.mutedForeground }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Underline() {\n return (\n <Tabs\n items={[\n { value: 'overview', label: 'Overview', content: <Panel title=\"Revenue up 12%\" body=\"Annual plans drove most of the growth this week. Churn held at 1.8%.\" /> },\n { value: 'activity', label: 'Activity', badge: 3, content: <Panel title=\"3 new comments\" body=\"Priya and Leo left notes on the Q4 roadmap since yesterday.\" /> },\n { value: 'settings', label: 'Settings', content: <Panel title=\"Project settings\" body=\"Notifications, members and integrations for Mobile app 2.0.\" /> },\n ]}\n />\n );\n}\n"
88
+ },
89
+ {
90
+ "name": "Profile",
91
+ "title": "Profile",
92
+ "code": "import { Pressable, Text, View } from 'react-native';\nimport { Tabs } from '@/components/ui/tabs';\nimport { alpha, useKit } from '@/lib/kit';\n\ntype Post = [who: string, text: string, meta: string];\n\nfunction Feed({ posts }: { posts: Post[] }) {\n const { colors, radius, dark } = useKit();\n return (\n <View style={{ gap: 14 }}>\n {posts.map(([who, text, meta]) => (\n <View key={text} style={{ flexDirection: 'row', gap: 10 }}>\n <View\n style={{\n width: 34,\n height: 34,\n borderRadius: radius.capsule(34),\n backgroundColor: alpha(colors.accent, dark ? 0.22 : 0.12),\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>{who.slice(0, 1)}</Text>\n </View>\n <View style={{ flex: 1, gap: 2 }}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.mutedForeground }}>\n <Text style={{ color: colors.foreground }}>{who}</Text> · {meta}\n </Text>\n <Text style={{ fontSize: 14.5, fontWeight: '400', lineHeight: 20, color: colors.foreground }}>{text}</Text>\n </View>\n </View>\n ))}\n </View>\n );\n}\n\nfunction Grid() {\n const { colors, radius, dark } = useKit();\n const tones = [0.1, 0.18, 0.26, 0.14, 0.22, 0.3];\n return (\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 6 }}>\n {tones.map((a, i) => (\n <View\n key={i}\n style={{ width: '32%', aspectRatio: 1, borderRadius: radius.scale(10), backgroundColor: alpha(colors.accent, dark ? a + 0.08 : a) }}\n />\n ))}\n </View>\n );\n}\n\nexport default function Profile() {\n return (\n <Tabs\n items={[\n {\n value: 'posts',\n label: 'Posts',\n badge: 128,\n content: (\n <Feed\n posts={[\n ['Maya Chen', 'Shipped the new onboarding today. Three screens instead of seven, and it finally feels calm.', '2h'],\n ['Maya Chen', 'Hot take: every tab bar needs a haptic tick.', '1d'],\n ]}\n />\n ),\n },\n {\n value: 'replies',\n label: 'Replies',\n content: <Feed posts={[['Maya Chen', 'Agreed, the spring on that indicator is perfect. Ship it.', '5h']]} />,\n },\n { value: 'media', label: 'Media', badge: 24, content: <Grid /> },\n {\n value: 'likes',\n label: 'Likes',\n content: (\n <Feed\n posts={[\n ['Leo Park', 'Offsite is booked: June 12–14 in Lisbon. Bring sunscreen.', '3h'],\n ['Ana Ruiz', 'Pricing page v3 is live. Conversion up 0.6 points so far.', '1d'],\n ]}\n />\n ),\n },\n ]}\n />\n );\n}\n"
93
+ },
94
+ {
95
+ "name": "Scrollable",
96
+ "title": "Scrollable",
97
+ "code": "import { Pressable, Text, View } from 'react-native';\nimport { Tabs } from '@/components/ui/tabs';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Panel({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4 }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground }}>{title}</Text>\n <Text style={{ fontSize: 14, fontWeight: '400', lineHeight: 20, color: colors.mutedForeground }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Scrollable() {\n const categories = ['For you', 'Trending', 'Design', 'Engineering', 'Product', 'Marketing', 'Finance', 'Remote'];\n return (\n <Tabs\n items={categories.map((c, i) => ({\n value: c,\n label: c,\n badge: i === 1 ? 'New' : undefined,\n content: <Panel title={c} body={`Hand-picked ${c.toLowerCase()} stories from people you follow, updated every hour.`} />,\n }))}\n />\n );\n}\n"
98
+ },
99
+ {
100
+ "name": "WithIcons",
101
+ "title": "With Icons",
102
+ "code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { BottomNavIcon } from '@/components/ui/bottom-nav';\nimport { Tabs } from '@/components/ui/tabs';\nimport { alpha, useKit } from '@/lib/kit';\n\nfunction Panel({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4 }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground }}>{title}</Text>\n <Text style={{ fontSize: 14, fontWeight: '400', lineHeight: 20, color: colors.mutedForeground }}>{body}</Text>\n </View>\n );\n}\n\ntype Post = [who: string, text: string, meta: string];\n\nfunction Feed({ posts }: { posts: Post[] }) {\n const { colors, radius, dark } = useKit();\n return (\n <View style={{ gap: 14 }}>\n {posts.map(([who, text, meta]) => (\n <View key={text} style={{ flexDirection: 'row', gap: 10 }}>\n <View\n style={{\n width: 34,\n height: 34,\n borderRadius: radius.capsule(34),\n backgroundColor: alpha(colors.accent, dark ? 0.22 : 0.12),\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>{who.slice(0, 1)}</Text>\n </View>\n <View style={{ flex: 1, gap: 2 }}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.mutedForeground }}>\n <Text style={{ color: colors.foreground }}>{who}</Text> · {meta}\n </Text>\n <Text style={{ fontSize: 14.5, fontWeight: '400', lineHeight: 20, color: colors.foreground }}>{text}</Text>\n </View>\n </View>\n ))}\n </View>\n );\n}\n\nexport default function WithIcons() {\n const { colors } = useKit();\n const [unread, setUnread] = useState(4);\n const [mentions, setMentions] = useState(2);\n const clear = (\n <Pressable\n accessibilityRole=\"button\"\n onPress={() => {\n setUnread(0);\n setMentions(0);\n }}\n hitSlop={10}\n style={{ alignSelf: 'flex-start', marginTop: 12 }}\n >\n <Text style={{ fontSize: 14, fontWeight: '400', color: colors.accent }}>Mark all as read</Text>\n </Pressable>\n );\n return (\n <Tabs\n size=\"sm\"\n items={[\n {\n value: 'inbox',\n label: 'Inbox',\n icon: ({ active, color }) => <BottomNavIcon name=\"inbox\" color={color} size={17} active={active} />,\n badge: unread || undefined,\n content: (\n <View>\n <Feed posts={[['Priya Nair', 'Can you review the pricing page before 3pm?', '9:41']]} />\n {clear}\n </View>\n ),\n },\n {\n value: 'mentions',\n label: 'Mentions',\n icon: ({ active, color }) => <BottomNavIcon name=\"message\" color={color} size={17} active={active} />,\n badge: mentions || undefined,\n content: <Feed posts={[['Leo Park', '@karan the offsite deck is ready for a look.', '9:12']]} />,\n },\n { value: 'activity', label: 'Activity', icon: ({ active, color }) => <BottomNavIcon name=\"activity\" color={color} size={17} active={active} />, content: <Panel title=\"All quiet\" body=\"Nothing new since you last checked.\" /> },\n ]}\n />\n );\n}\n"
103
+ }
104
+ ]
105
+ }
@@ -0,0 +1,128 @@
1
+ {
2
+ "name": "tag-input",
3
+ "category": "Inputs",
4
+ "aliases": [],
5
+ "exportName": "TagInput",
6
+ "files": [
7
+ "src/components/ui/tag-input.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "value / defaultValue",
12
+ "string[]",
13
+ "[]",
14
+ "Controlled or uncontrolled tags."
15
+ ],
16
+ [
17
+ "onChange",
18
+ "(tags) => void",
19
+ "—",
20
+ "Called when a tag is added or removed (the removed chip then shrinks out)."
21
+ ],
22
+ [
23
+ "variant",
24
+ "\"outlined\" | \"filled\"",
25
+ "\"outlined\"",
26
+ "Field style."
27
+ ],
28
+ [
29
+ "chipVariant",
30
+ "\"soft\" | \"solid\" | \"outline\"",
31
+ "\"soft\"",
32
+ "Tinted accent chips, filled accent chips, or bordered chips with an accent dot."
33
+ ],
34
+ [
35
+ "colorize",
36
+ "boolean",
37
+ "false",
38
+ "Tint each chip from a hash of its label."
39
+ ],
40
+ [
41
+ "prefix",
42
+ "string",
43
+ "—",
44
+ "Shown before every chip label (e.g. \"#\"); typed copies are stripped."
45
+ ],
46
+ [
47
+ "transform",
48
+ "(tag) => string",
49
+ "—",
50
+ "Normalise a tag before validation (lowercase, strip spaces…)."
51
+ ],
52
+ [
53
+ "maxTags",
54
+ "number",
55
+ "—",
56
+ "Limit; shows a filling ring and \"3/5\" counter, and locks the input when reached."
57
+ ],
58
+ [
59
+ "suggestions",
60
+ "string[]",
61
+ "—",
62
+ "Pills under the empty field; while typing, a list with the match highlighted and an \"Add …\" row."
63
+ ],
64
+ [
65
+ "separators",
66
+ "string[]",
67
+ "[\",\"]",
68
+ "Characters that commit a tag (Enter always does)."
69
+ ],
70
+ [
71
+ "validate",
72
+ "(tag, tags) => boolean | string",
73
+ "—",
74
+ "Reject a tag (the field shakes); return a string to show it as the error."
75
+ ],
76
+ [
77
+ "error / helper",
78
+ "string",
79
+ "—",
80
+ "Message under the field; errors shake once."
81
+ ],
82
+ [
83
+ "accent",
84
+ "string",
85
+ "theme accent",
86
+ "Focus and chip colour."
87
+ ],
88
+ [
89
+ "style",
90
+ "StyleProp<ViewStyle>",
91
+ "—",
92
+ "Style for the outer wrapper around the field, suggestions and message (the one that shakes)."
93
+ ],
94
+ [
95
+ "…TextInputProps",
96
+ "",
97
+ "",
98
+ "placeholder, keyboardType, …"
99
+ ]
100
+ ],
101
+ "examples": [
102
+ {
103
+ "name": "Skills",
104
+ "title": "Skills",
105
+ "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { TagInput } from '@/components/ui/tag-input';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n});\n\nexport default function Skills() {\n return (\n <Card>\n <Ink style={s.title}>Your skills</Ink>\n <TagInput\n placeholder=\"Add a skill…\"\n defaultValue={['TypeScript', 'React Native']}\n suggestions={['React', 'Swift', 'SwiftUI', 'Kotlin', 'GraphQL', 'Figma', 'Node.js', 'Rust', 'PostgreSQL']}\n helper=\"Type to search, or tap a suggestion.\"\n />\n </Card>\n );\n}\n"
106
+ },
107
+ {
108
+ "name": "InviteByEmail",
109
+ "title": "Invite By Email",
110
+ "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { TagInput } from '@/components/ui/tag-input';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n});\n\nexport default function InviteByEmail() {\n const [emails, setEmails] = useState(['maya@studio.co', 'leo@studio.co']);\n return (\n <Card>\n <Ink style={s.title}>Invite teammates</Ink>\n <TagInput\n value={emails}\n onChange={setEmails}\n validate={(tag) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/.test(tag) || `“${tag}” isn't a valid email address`}\n transform={(tag) => tag.toLowerCase()}\n chipVariant=\"outline\"\n keyboardType=\"email-address\"\n placeholder=\"name@company.com\"\n helper=\"Separate addresses with a comma or space.\"\n separators={[',', ' ']}\n />\n </Card>\n );\n}\n"
111
+ },
112
+ {
113
+ "name": "Topics",
114
+ "title": "Topics",
115
+ "code": "import { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { TagInput } from '@/components/ui/tag-input';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n});\n\nexport default function Topics() {\n return (\n <Card>\n <Ink style={s.title}>Follow topics</Ink>\n <TagInput\n colorize\n maxTags={5}\n defaultValue={['Design', 'Climate', 'Startups']}\n suggestions={['Space', 'AI', 'Music', 'Cooking', 'Photography', 'Travel']}\n placeholder=\"Add a topic…\"\n helper=\"Pick up to five for your feed.\"\n />\n </Card>\n );\n}\n"
116
+ },
117
+ {
118
+ "name": "Hashtags",
119
+ "title": "Hashtags",
120
+ "code": "import { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { TagInput } from '@/components/ui/tag-input';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n});\n\nexport default function Hashtags() {\n return (\n <Card>\n <Ink style={s.title}>New post</Ink>\n <TagInput\n variant=\"filled\"\n chipVariant=\"solid\"\n prefix=\"#\"\n transform={(tag) => tag.replace(/\\s+/g, '').toLowerCase()}\n separators={[',', ' ']}\n defaultValue={['sunset', 'lisbon']}\n suggestions={['travel', 'goldenhour', 'streetphotography', 'portugal']}\n placeholder=\"#hashtag\"\n helper=\"Backspace once to highlight the last tag, twice to remove it.\"\n />\n </Card>\n );\n}\n"
121
+ },
122
+ {
123
+ "name": "ChipStyles",
124
+ "title": "Chip Styles",
125
+ "code": "import { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { TagInput } from '@/components/ui/tag-input';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n});\n\nexport default function ChipStyles() {\n return (\n <Card>\n <Ink tone=\"muted\" style={s.label}>Soft</Ink>\n <TagInput defaultValue={['Vegan', 'Gluten-free']} placeholder=\"Dietary needs\" />\n <Ink tone=\"muted\" style={s.label}>Solid</Ink>\n <TagInput chipVariant=\"solid\" defaultValue={['Urgent', 'Bug']} placeholder=\"Labels\" />\n <Ink tone=\"muted\" style={s.label}>Outline</Ink>\n <TagInput chipVariant=\"outline\" defaultValue={['Remote', 'Full-time']} placeholder=\"Job filters\" />\n <Ink tone=\"muted\" style={s.label}>Disabled</Ink>\n <TagInput editable={false} defaultValue={['Read-only']} />\n </Card>\n );\n}\n"
126
+ }
127
+ ]
128
+ }
@@ -0,0 +1,175 @@
1
+ {
2
+ "name": "textarea",
3
+ "category": "Inputs",
4
+ "aliases": [],
5
+ "exportName": "Textarea",
6
+ "files": [
7
+ "src/components/ui/textarea.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "label",
12
+ "string",
13
+ "—",
14
+ "Rests on the first line, floats onto the border on focus."
15
+ ],
16
+ [
17
+ "floatingLabel",
18
+ "boolean",
19
+ "true",
20
+ "Set to false to put the label above the field as static text (no notch); placeholder shows inside."
21
+ ],
22
+ [
23
+ "variant",
24
+ "\"outlined\" | \"filled\"",
25
+ "\"outlined\"",
26
+ "Field style."
27
+ ],
28
+ [
29
+ "size",
30
+ "\"sm\" | \"md\" | \"lg\"",
31
+ "\"md\"",
32
+ "14 / 16 / 18px text; line height and padding scale too."
33
+ ],
34
+ [
35
+ "minRows / maxRows",
36
+ "number",
37
+ "3 / 8",
38
+ "Grows smoothly between these, then scrolls."
39
+ ],
40
+ [
41
+ "maxLength",
42
+ "number",
43
+ "—",
44
+ "Character limit; enables the counter."
45
+ ],
46
+ [
47
+ "enforceMaxLength",
48
+ "boolean",
49
+ "true",
50
+ "false makes the limit soft: typing past it turns the counter red and negative."
51
+ ],
52
+ [
53
+ "showCount",
54
+ "boolean",
55
+ "true when maxLength",
56
+ "Counter that becomes a ring in the last 20%."
57
+ ],
58
+ [
59
+ "toolbar",
60
+ "ReactNode",
61
+ "—",
62
+ "Row inside the bottom edge — attach, emoji, send."
63
+ ],
64
+ [
65
+ "error",
66
+ "string",
67
+ "—",
68
+ "Red state, icon + message that slides in, one shake."
69
+ ],
70
+ [
71
+ "success",
72
+ "boolean | string",
73
+ "—",
74
+ "Green border + animated check; a string is shown as the message."
75
+ ],
76
+ [
77
+ "helper",
78
+ "string",
79
+ "—",
80
+ "Hint under the field."
81
+ ],
82
+ [
83
+ "accent",
84
+ "string",
85
+ "theme accent",
86
+ "Focus border and halo colour."
87
+ ],
88
+ [
89
+ "surface",
90
+ "string",
91
+ "theme background",
92
+ "Colour behind the field (paints the label notch)."
93
+ ],
94
+ [
95
+ "style",
96
+ "StyleProp<ViewStyle>",
97
+ "—",
98
+ "Style for the outer wrapper around the field and footer (the one that shakes)."
99
+ ],
100
+ [
101
+ "fieldStyle",
102
+ "StyleProp<ViewStyle>",
103
+ "—",
104
+ "The bordered box: background, border width / colour, radius, height, padding. Wins over the computed style; a borderColor replaces the resting border only (focus, error and success colours still show). height is ignored: the box grows with minRows / maxRows."
105
+ ],
106
+ [
107
+ "inputStyle",
108
+ "StyleProp<TextStyle>",
109
+ "—",
110
+ "The typed text — fontSize, lineHeight, fontWeight, color, fontFamily. Row height follows lineHeight (or scales with fontSize)."
111
+ ],
112
+ [
113
+ "labelStyle",
114
+ "StyleProp<TextStyle>",
115
+ "—",
116
+ "Label in both modes (floating and above). color is the resting colour — focus (accent), error and success still take over; fontSize sets the resting size, it floats at the same ratio and the notch follows its width."
117
+ ],
118
+ [
119
+ "messageStyle",
120
+ "StyleProp<TextStyle>",
121
+ "—",
122
+ "Helper / error / success text. color applies to the helper; error and success keep their tone colour."
123
+ ],
124
+ [
125
+ "counterStyle",
126
+ "StyleProp<TextStyle>",
127
+ "—",
128
+ "Counter text (42/280 and the characters-left number); warning / danger still win near the limit."
129
+ ],
130
+ [
131
+ "placeholderTextColor",
132
+ "string",
133
+ "theme mutedForeground",
134
+ "Placeholder colour."
135
+ ],
136
+ [
137
+ "…TextInputProps",
138
+ "",
139
+ "",
140
+ "value, defaultValue, onChangeText, placeholder, …"
141
+ ]
142
+ ],
143
+ "examples": [
144
+ {
145
+ "name": "Composer",
146
+ "title": "Composer",
147
+ "code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { Textarea } from '@/components/ui/textarea';\nimport { useKit } from '@/lib/kit';\n\nfunction ToolButton({ glyph, label }: { glyph: string; label: string }) {\n const { colors } = useKit();\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityLabel={label}\n hitSlop={6}\n style={{ width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.muted }}\n >\n <Text style={{ fontSize: 17, fontWeight: '400', color: colors.mutedForeground }}>{glyph}</Text>\n </Pressable>\n );\n}\n\nexport default function Composer() {\n const { colors, radius } = useKit();\n const [draft, setDraft] = useState('');\n const [sent, setSent] = useState<string[]>(['Are we still on for the design review at 3?']);\n const canSend = draft.trim().length > 0;\n const send = () => {\n if (!canSend) return;\n setSent((s) => [...s.slice(-1), draft.trim()]);\n setDraft('');\n };\n return (\n <View style={{ gap: 10 }}>\n {sent.map((m, i) => (\n <View\n key={i}\n style={{ alignSelf: 'flex-end', maxWidth: '80%', backgroundColor: colors.accent, borderRadius: radius.scale(18), paddingHorizontal: 14, paddingVertical: 9 }}\n >\n <Text style={{ color: colors.accentForeground, fontSize: 15 }}>{m}</Text>\n </View>\n ))}\n <Textarea\n placeholder=\"Message Alex…\"\n value={draft}\n onChangeText={setDraft}\n minRows={1}\n maxRows={5}\n toolbar={\n <>\n <ToolButton glyph=\"+\" label=\"Attach a file\" />\n <ToolButton glyph=\"@\" label=\"Mention someone\" />\n <View style={{ flex: 1 }} />\n <Pressable\n onPress={send}\n disabled={!canSend}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Send message\"\n hitSlop={6}\n style={{\n height: 32,\n paddingHorizontal: 14,\n borderRadius: radius.capsule(32),\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: colors.accent,\n opacity: canSend ? 1 : 0.4,\n }}\n >\n <Text style={{ color: colors.accentForeground, fontSize: 14, fontWeight: '400' }}>Send ↑</Text>\n </Pressable>\n </>\n }\n />\n </View>\n );\n}\n"
148
+ },
149
+ {
150
+ "name": "Review",
151
+ "title": "Review",
152
+ "code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { Textarea } from '@/components/ui/textarea';\nimport { useKit } from '@/lib/kit';\n\nfunction Card({ title, subtitle, children }: { title: string; subtitle?: string; children: React.ReactNode }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={{\n padding: 16,\n gap: 12,\n borderRadius: radius.xl,\n borderWidth: StyleSheet.hairlineWidth,\n borderColor: colors.border,\n backgroundColor: colors.card,\n }}\n >\n <View style={{ gap: 2, marginBottom: 2 }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground }}>{title}</Text>\n {subtitle ? <Text style={{ fontSize: 13, color: colors.mutedForeground }}>{subtitle}</Text> : null}\n </View>\n {children}\n </View>\n );\n}\n\nexport default function Review() {\n const [review, setReview] = useState('Great coffee, but');\n const length = review.trim().length;\n return (\n <Card title=\"Rate Blue Bottle, Hayes Valley\" subtitle=\"Reviews are public and show your first name.\">\n <Textarea\n label=\"Your review\"\n value={review}\n onChangeText={setReview}\n maxLength={200}\n enforceMaxLength={false}\n minRows={3}\n error={length > 0 && length < 20 ? 'Tell us a little more — at least 20 characters' : length > 200 ? 'Keep it under 200 characters' : undefined}\n success={length >= 20 && length <= 200 ? 'Thanks — that will really help others' : undefined}\n />\n </Card>\n );\n}\n"
153
+ },
154
+ {
155
+ "name": "Feedback",
156
+ "title": "Feedback",
157
+ "code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { Textarea } from '@/components/ui/textarea';\nimport { useKit } from '@/lib/kit';\n\nfunction Card({ title, subtitle, children }: { title: string; subtitle?: string; children: React.ReactNode }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={{\n padding: 16,\n gap: 12,\n borderRadius: radius.xl,\n borderWidth: StyleSheet.hairlineWidth,\n borderColor: colors.border,\n backgroundColor: colors.card,\n }}\n >\n <View style={{ gap: 2, marginBottom: 2 }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground }}>{title}</Text>\n {subtitle ? <Text style={{ fontSize: 13, color: colors.mutedForeground }}>{subtitle}</Text> : null}\n </View>\n {children}\n </View>\n );\n}\n\nexport default function Feedback() {\n return (\n <Card title=\"Send feedback\" subtitle=\"Goes straight to the product team.\">\n <Textarea\n variant=\"filled\"\n label=\"What could be better?\"\n defaultValue=\"Dark mode on the invoices page is a little too low-contrast for me.\"\n helper=\"Screenshots help — attach them in the next step.\"\n minRows={3}\n maxRows={6}\n />\n </Card>\n );\n}\n"
158
+ },
159
+ {
160
+ "name": "CharacterLimit",
161
+ "title": "Character Limit",
162
+ "code": "import { Textarea } from '@/components/ui/textarea';\n\nexport default function CharacterLimit() {\n return (\n <Textarea\n label=\"What's happening?\"\n maxLength={140}\n defaultValue=\"Shipping the new ExpoKit inputs today — focus halos, animated checks and fields that glide taller as you type.\"\n minRows={3}\n />\n );\n}\n"
163
+ },
164
+ {
165
+ "name": "States",
166
+ "title": "States",
167
+ "code": "import { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { Textarea } from '@/components/ui/textarea';\n\nexport default function States() {\n return (\n <View style={{ gap: 16 }}>\n <Textarea label=\"Delivery instructions\" minRows={2} defaultValue=\"Leave it with the concierge, code 4417.\" success=\"Saved for next time\" />\n <Textarea label=\"Notes for the courier\" minRows={2} editable={false} defaultValue=\"Locked while the order is out for delivery.\" />\n </View>\n );\n}\n"
168
+ },
169
+ {
170
+ "name": "Sizes",
171
+ "title": "Sizes",
172
+ "code": "import { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { Textarea } from '@/components/ui/textarea';\n\nexport default function Sizes() {\n return (\n <View style={{ gap: 14 }}>\n <Textarea size=\"sm\" label=\"Small · 14px\" minRows={1} defaultValue=\"Compact comment box\" />\n <Textarea size=\"md\" label=\"Medium · 16px\" minRows={1} defaultValue=\"The default for forms\" />\n <Textarea size=\"lg\" label=\"Large · 18px\" minRows={1} defaultValue=\"Journaling and long-form\" />\n </View>\n );\n}\n"
173
+ }
174
+ ]
175
+ }
@@ -0,0 +1,174 @@
1
+ {
2
+ "name": "ticket-card",
3
+ "category": "3D",
4
+ "aliases": [],
5
+ "exportName": "TicketCard",
6
+ "files": [
7
+ "src/components/ui/ticket-card.tsx"
8
+ ],
9
+ "props": [
10
+ [
11
+ "brand / logo",
12
+ "string / ReactNode",
13
+ "—",
14
+ "Operator, venue or brand (and its logo), top-left."
15
+ ],
16
+ [
17
+ "badge",
18
+ "string",
19
+ "—",
20
+ "Chip top-right (\"VIP\", \"Business\") — on holographic foil when holo."
21
+ ],
22
+ [
23
+ "eyebrow",
24
+ "string",
25
+ "—",
26
+ "Small line above the title or route (\"Boarding pass · TP 1043\")."
27
+ ],
28
+ [
29
+ "title / subtitle",
30
+ "string",
31
+ "—",
32
+ "Event name and details (omit for a route pass)."
33
+ ],
34
+ [
35
+ "from / to",
36
+ "{ code: string; detail?: string }",
37
+ "—",
38
+ "Route endpoints; a dashed flight path runs between them."
39
+ ],
40
+ [
41
+ "duration",
42
+ "string",
43
+ "—",
44
+ "Under the flight path (\"7h 25m\")."
45
+ ],
46
+ [
47
+ "transport",
48
+ "\"flight\" | \"train\" | \"bus\" | \"boat\"",
49
+ "\"flight\"",
50
+ "Icon riding the flight path."
51
+ ],
52
+ [
53
+ "fields",
54
+ "{ label: string; value: string; span?: number }[]",
55
+ "[]",
56
+ "Details grid that wraps onto more rows; span widens a field."
57
+ ],
58
+ [
59
+ "columns",
60
+ "number",
61
+ "up to 4",
62
+ "Columns in the details grid."
63
+ ],
64
+ [
65
+ "code",
66
+ "string",
67
+ "—",
68
+ "Printed in the stub and shown big on the back. Omit for a ticket without a stub."
69
+ ],
70
+ [
71
+ "codeType",
72
+ "\"qr\" | \"barcode\"",
73
+ "\"qr\"",
74
+ "Look-alike code style — use renderCode for a scannable one."
75
+ ],
76
+ [
77
+ "renderCode",
78
+ "(code: string, size: number) => ReactNode",
79
+ "—",
80
+ "Draw a real code (e.g. react-native-qrcode-svg)."
81
+ ],
82
+ [
83
+ "notes",
84
+ "string | string[]",
85
+ "—",
86
+ "Lines on the back: terms, baggage, gate notes."
87
+ ],
88
+ [
89
+ "image",
90
+ "ImageSourcePropType",
91
+ "—",
92
+ "Header photo (vertical) or full-bleed art (horizontal)."
93
+ ],
94
+ [
95
+ "layout",
96
+ "\"vertical\" | \"horizontal\"",
97
+ "\"vertical\"",
98
+ "Pass with the stub below, or admit-one ticket with the stub on the right."
99
+ ],
100
+ [
101
+ "theme",
102
+ "\"midnight\" | \"paper\" | \"aurora\" | \"sunset\" | \"neon\" | \"royal\" | \"mint\" | TicketTheme",
103
+ "\"midnight\"",
104
+ "Preset, or { fill, stub?, ink, soft?, accent, pattern? } — fill can be a gradient."
105
+ ],
106
+ [
107
+ "tone",
108
+ "\"dark\" | \"light\"",
109
+ "—",
110
+ "Shorthand for theme: midnight / paper."
111
+ ],
112
+ [
113
+ "accent",
114
+ "string",
115
+ "theme accent",
116
+ "Route line, badge and stamp colour."
117
+ ],
118
+ [
119
+ "holo",
120
+ "boolean",
121
+ "false",
122
+ "Rainbow foil glare and a holographic badge."
123
+ ],
124
+ [
125
+ "stamp / stampColor",
126
+ "string / string",
127
+ "— / accent",
128
+ "Rubber stamp across the ticket (\"CHECKED IN\"); thumps in when set."
129
+ ],
130
+ [
131
+ "onTear",
132
+ "() => void",
133
+ "—",
134
+ "Enables swiping the stub off along the tear line; called once it's gone."
135
+ ],
136
+ [
137
+ "torn",
138
+ "boolean",
139
+ "—",
140
+ "Controlled torn state (the stub is gone, the torn edge stays)."
141
+ ],
142
+ [
143
+ "flipped / defaultFlipped / onFlip",
144
+ "boolean / boolean / (flipped) => void",
145
+ "— / false / —",
146
+ "Controlled or uncontrolled side (tap to flip)."
147
+ ],
148
+ [
149
+ "tilt",
150
+ "boolean",
151
+ "true",
152
+ "Tilt toward the finger; false for long lists."
153
+ ],
154
+ [
155
+ "radius",
156
+ "number",
157
+ "22",
158
+ "Corner radius."
159
+ ],
160
+ [
161
+ "labels",
162
+ "{ scan?, admit?, tear?, back? }",
163
+ "English",
164
+ "Every built-in string, for translation."
165
+ ],
166
+ [
167
+ "style",
168
+ "StyleProp<ViewStyle>",
169
+ "—",
170
+ "Style for the root (width, margins)."
171
+ ]
172
+ ],
173
+ "examples": []
174
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "ticket-shape",
3
+ "category": null,
4
+ "aliases": [],
5
+ "exportName": "TicketStamp",
6
+ "files": [
7
+ "src/lib/ticket-shape.tsx"
8
+ ],
9
+ "props": [],
10
+ "examples": []
11
+ }