@expokit/cli 0.2.0 → 0.4.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 (232) hide show
  1. package/README.md +20 -2
  2. package/bin/expo-kit.js +219 -44
  3. package/bin/lib.mjs +110 -1
  4. package/bin/mcp.mjs +48 -19
  5. package/package.json +9 -4
  6. package/registry/_docs/accordion.json +16 -0
  7. package/registry/_docs/action-sheet.json +28 -0
  8. package/registry/_docs/alert.json +28 -0
  9. package/registry/_docs/assistant-app.json +47 -0
  10. package/registry/_docs/avatar.json +25 -1
  11. package/registry/_docs/badge.json +36 -5
  12. package/registry/_docs/bottom-nav.json +30 -6
  13. package/registry/_docs/bottom-sheet.json +28 -0
  14. package/registry/_docs/bullet.json +3 -0
  15. package/registry/_docs/button-3d.json +18 -2
  16. package/registry/_docs/button.json +16 -0
  17. package/registry/_docs/calendar.json +21 -5
  18. package/registry/_docs/card-stack.json +16 -0
  19. package/registry/_docs/card.json +20 -0
  20. package/registry/_docs/carousel.json +20 -0
  21. package/registry/_docs/chat.json +184 -0
  22. package/registry/_docs/checkbox.json +16 -0
  23. package/registry/_docs/checkout.json +10 -1
  24. package/registry/_docs/chip-group.json +16 -0
  25. package/registry/_docs/confetti.json +23 -3
  26. package/registry/_docs/coupon.json +16 -0
  27. package/registry/_docs/cube-pager.json +16 -0
  28. package/registry/_docs/dashboard.json +3 -0
  29. package/registry/_docs/date-picker.json +24 -4
  30. package/registry/_docs/dialog.json +24 -0
  31. package/registry/_docs/donut-shop.json +88 -0
  32. package/registry/_docs/drawer.json +32 -4
  33. package/registry/_docs/fab.json +24 -0
  34. package/registry/_docs/fintech-app.json +49 -0
  35. package/registry/_docs/flip-card.json +16 -0
  36. package/registry/_docs/floating-input.json +25 -5
  37. package/registry/_docs/food-app.json +47 -0
  38. package/registry/_docs/gift-card.json +16 -0
  39. package/registry/_docs/glass-button.json +24 -0
  40. package/registry/_docs/glass-nav-bar.json +24 -0
  41. package/registry/_docs/glass-search-bar.json +24 -0
  42. package/registry/_docs/glass-segmented.json +28 -0
  43. package/registry/_docs/glass-sheet.json +28 -0
  44. package/registry/_docs/glass-tab-bar.json +24 -0
  45. package/registry/_docs/glass.json +17 -1
  46. package/registry/_docs/grain.json +80 -0
  47. package/registry/_docs/inbox.json +3 -0
  48. package/registry/_docs/isometric-bar.json +3 -0
  49. package/registry/_docs/kit.json +3 -0
  50. package/registry/_docs/liquidglass-tab.json +3 -0
  51. package/registry/_docs/list-item.json +16 -0
  52. package/registry/_docs/loyalty-card.json +16 -0
  53. package/registry/_docs/morphing-button-group.json +96 -0
  54. package/registry/_docs/number-ticker.json +16 -0
  55. package/registry/_docs/offers.json +3 -0
  56. package/registry/_docs/onboarding.json +3 -0
  57. package/registry/_docs/orb-reveal.json +132 -0
  58. package/registry/_docs/otp-input.json +28 -4
  59. package/registry/_docs/parallax-layers.json +20 -0
  60. package/registry/_docs/parallax-scroll.json +24 -0
  61. package/registry/_docs/password-input.json +23 -3
  62. package/registry/_docs/payment-card.json +16 -0
  63. package/registry/_docs/pixel-bar.json +3 -0
  64. package/registry/_docs/polar-area.json +3 -0
  65. package/registry/_docs/profile.json +3 -0
  66. package/registry/_docs/progress-steps.json +24 -0
  67. package/registry/_docs/progress.json +20 -0
  68. package/registry/_docs/qr-code-button.json +122 -0
  69. package/registry/_docs/radio-group.json +20 -0
  70. package/registry/_docs/rating.json +24 -0
  71. package/registry/_docs/ring-carousel.json +20 -0
  72. package/registry/_docs/scratch-card.json +20 -0
  73. package/registry/_docs/search-bar.json +23 -3
  74. package/registry/_docs/search-results.json +3 -0
  75. package/registry/_docs/segmented-control.json +20 -0
  76. package/registry/_docs/select.json +33 -8
  77. package/registry/_docs/settings.json +9 -0
  78. package/registry/_docs/sign-in.json +3 -0
  79. package/registry/_docs/skeleton.json +22 -2
  80. package/registry/_docs/slide-to-confirm.json +24 -0
  81. package/registry/_docs/slider.json +27 -7
  82. package/registry/_docs/spin-wheel.json +24 -0
  83. package/registry/_docs/spinner.json +41 -11
  84. package/registry/_docs/stateful-button.json +184 -0
  85. package/registry/_docs/stepper.json +23 -7
  86. package/registry/_docs/swipe-deck.json +16 -0
  87. package/registry/_docs/swipeable-row.json +24 -1
  88. package/registry/_docs/switch.json +20 -0
  89. package/registry/_docs/tabs.json +24 -0
  90. package/registry/_docs/text-animation.json +141 -0
  91. package/registry/_docs/textarea.json +18 -2
  92. package/registry/_docs/ticket-card.json +20 -0
  93. package/registry/_docs/ticket-shape.json +4 -1
  94. package/registry/_docs/tilt-card.json +20 -4
  95. package/registry/_docs/time-picker.json +22 -6
  96. package/registry/_docs/timeline-chart.json +3 -0
  97. package/registry/_docs/timeline.json +18 -2
  98. package/registry/_docs/toast.json +32 -8
  99. package/registry/_docs/treemap.json +3 -0
  100. package/registry/_docs/waterfall.json +3 -0
  101. package/registry/_docs/wheel-list.json +20 -0
  102. package/registry/accordion/files/src/components/ui/accordion.tsx +5 -4
  103. package/registry/accordion/files/src/lib/kit.tsx +8 -5
  104. package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +9 -8
  105. package/registry/action-sheet/files/src/lib/kit.tsx +8 -5
  106. package/registry/alert/files/src/components/ui/alert.tsx +7 -4
  107. package/registry/alert/files/src/components/ui/button.tsx +4 -3
  108. package/registry/alert/files/src/lib/kit.tsx +8 -5
  109. package/registry/assistant-app.json +49 -0
  110. package/registry/avatar/files/src/components/ui/avatar.tsx +7 -4
  111. package/registry/avatar/files/src/lib/kit.tsx +8 -5
  112. package/registry/badge/files/src/components/ui/badge.tsx +345 -21
  113. package/registry/badge/files/src/lib/kit.tsx +8 -5
  114. package/registry/badge.json +1 -1
  115. package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +14 -7
  116. package/registry/bottom-nav/files/src/lib/kit.tsx +8 -5
  117. package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +7 -6
  118. package/registry/bottom-sheet/files/src/lib/kit.tsx +8 -5
  119. package/registry/button/files/src/components/ui/button.tsx +4 -3
  120. package/registry/button/files/src/lib/kit.tsx +8 -5
  121. package/registry/button-3d/files/src/components/ui/button-3d.tsx +3 -2
  122. package/registry/button-3d/files/src/lib/kit.tsx +8 -5
  123. package/registry/calendar/files/src/components/ui/calendar.tsx +9 -5
  124. package/registry/calendar/files/src/lib/kit.tsx +8 -5
  125. package/registry/card/files/src/components/ui/card.tsx +8 -6
  126. package/registry/card/files/src/lib/kit.tsx +8 -5
  127. package/registry/chat.json +18 -0
  128. package/registry/checkbox/files/src/components/ui/checkbox.tsx +6 -5
  129. package/registry/checkbox/files/src/lib/kit.tsx +8 -5
  130. package/registry/chip-group/files/src/components/ui/chip-group.tsx +4 -2
  131. package/registry/chip-group/files/src/lib/kit.tsx +8 -5
  132. package/registry/confetti/files/src/lib/kit.tsx +8 -5
  133. package/registry/coupon/files/src/components/ui/coupon.tsx +23 -20
  134. package/registry/coupon/files/src/components/ui/flip-card.tsx +1 -1
  135. package/registry/coupon/files/src/components/ui/tilt-card.tsx +2 -2
  136. package/registry/coupon/files/src/lib/kit.tsx +8 -5
  137. package/registry/date-picker/files/src/components/ui/calendar.tsx +9 -5
  138. package/registry/date-picker/files/src/components/ui/date-picker.tsx +2 -2
  139. package/registry/date-picker/files/src/lib/kit.tsx +8 -5
  140. package/registry/dialog/files/src/components/ui/dialog.tsx +12 -6
  141. package/registry/dialog/files/src/lib/kit.tsx +8 -5
  142. package/registry/donut-shop.json +18 -0
  143. package/registry/drawer/files/src/components/ui/drawer.tsx +25 -19
  144. package/registry/drawer/files/src/lib/kit.tsx +8 -5
  145. package/registry/fintech-app.json +57 -0
  146. package/registry/flip-card/files/src/components/ui/flip-card.tsx +1 -1
  147. package/registry/flip-card/files/src/lib/kit.tsx +8 -5
  148. package/registry/floating-input/files/src/components/ui/floating-input.tsx +16 -6
  149. package/registry/floating-input/files/src/lib/kit.tsx +8 -5
  150. package/registry/food-app.json +55 -0
  151. package/registry/grain/files/src/components/ui/grain.tsx +113 -0
  152. package/registry/{tag-input → grain}/files/src/lib/kit.tsx +8 -5
  153. package/registry/grain.json +17 -0
  154. package/registry/kit/files/src/lib/kit.tsx +8 -5
  155. package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +1 -1
  156. package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +1 -1
  157. package/registry/list-item/files/src/components/ui/list-item.tsx +20 -16
  158. package/registry/list-item/files/src/lib/kit.tsx +8 -5
  159. package/registry/morphing-button-group.json +18 -0
  160. package/registry/orb-reveal.json +20 -0
  161. package/registry/otp-input/files/src/components/ui/otp-input.tsx +8 -6
  162. package/registry/otp-input/files/src/lib/kit.tsx +8 -5
  163. package/registry/password-input/files/src/components/ui/floating-input.tsx +16 -6
  164. package/registry/password-input/files/src/components/ui/password-input.tsx +2 -2
  165. package/registry/password-input/files/src/lib/kit.tsx +8 -5
  166. package/registry/payment-card/files/src/components/ui/flip-card.tsx +1 -1
  167. package/registry/payment-card/files/src/components/ui/payment-card.tsx +27 -14
  168. package/registry/payment-card/files/src/components/ui/tilt-card.tsx +2 -2
  169. package/registry/payment-card/files/src/lib/kit.tsx +8 -5
  170. package/registry/progress/files/src/components/ui/progress.tsx +8 -5
  171. package/registry/progress/files/src/lib/kit.tsx +8 -5
  172. package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +15 -11
  173. package/registry/progress-steps/files/src/lib/kit.tsx +8 -5
  174. package/registry/qr-code-button.json +18 -0
  175. package/registry/radio-group/files/src/components/ui/radio-group.tsx +10 -9
  176. package/registry/radio-group/files/src/lib/kit.tsx +8 -5
  177. package/registry/search-bar/files/src/components/ui/search-bar.tsx +13 -11
  178. package/registry/search-bar/files/src/lib/kit.tsx +8 -5
  179. package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +4 -2
  180. package/registry/segmented-control/files/src/lib/kit.tsx +8 -5
  181. package/registry/select/files/src/components/ui/select.tsx +3 -3
  182. package/registry/select/files/src/lib/kit.tsx +8 -5
  183. package/registry/skeleton/files/src/components/ui/skeleton.tsx +4 -4
  184. package/registry/skeleton/files/src/lib/kit.tsx +8 -5
  185. package/registry/slider/files/src/components/ui/slider.tsx +5 -4
  186. package/registry/slider/files/src/lib/kit.tsx +8 -5
  187. package/registry/spinner/files/src/components/ui/spinner.tsx +452 -34
  188. package/registry/spinner/files/src/lib/kit.tsx +8 -5
  189. package/registry/spinner.json +1 -1
  190. package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +532 -0
  191. package/registry/{pagination-dots → stateful-button}/files/src/lib/kit.tsx +8 -5
  192. package/registry/stateful-button.json +18 -0
  193. package/registry/stepper/files/src/components/ui/stepper.tsx +8 -4
  194. package/registry/stepper/files/src/lib/kit.tsx +8 -5
  195. package/registry/switch/files/src/components/ui/switch.tsx +4 -3
  196. package/registry/switch/files/src/lib/kit.tsx +8 -5
  197. package/registry/tabs/files/src/components/ui/tabs.tsx +10 -8
  198. package/registry/tabs/files/src/lib/kit.tsx +8 -5
  199. package/registry/text-animation/files/src/components/ui/text-animation.tsx +650 -0
  200. package/registry/text-animation/files/src/lib/kit.tsx +222 -0
  201. package/registry/text-animation.json +15 -0
  202. package/registry/textarea/files/src/components/ui/textarea.tsx +11 -9
  203. package/registry/textarea/files/src/lib/kit.tsx +8 -5
  204. package/registry/ticket-shape/files/src/lib/kit.tsx +8 -5
  205. package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +2 -2
  206. package/registry/tilt-card/files/src/lib/kit.tsx +8 -5
  207. package/registry/time-picker/files/src/components/ui/time-picker.tsx +2 -2
  208. package/registry/time-picker/files/src/lib/kit.tsx +8 -5
  209. package/registry/timeline/files/src/components/ui/avatar.tsx +7 -4
  210. package/registry/timeline/files/src/components/ui/timeline.tsx +12 -10
  211. package/registry/timeline/files/src/lib/kit.tsx +8 -5
  212. package/registry/toast/files/src/components/ui/button.tsx +4 -3
  213. package/registry/toast/files/src/components/ui/toast.tsx +13 -11
  214. package/registry/toast/files/src/lib/kit.tsx +8 -5
  215. package/schema/components.schema.json +1 -1
  216. package/registry/_docs/color-swatch.json +0 -66
  217. package/registry/_docs/kpi-card.json +0 -11
  218. package/registry/_docs/like-button.json +0 -72
  219. package/registry/_docs/morph-button.json +0 -108
  220. package/registry/_docs/pagination-dots.json +0 -88
  221. package/registry/_docs/shimmer-button.json +0 -78
  222. package/registry/_docs/tag-input.json +0 -128
  223. package/registry/color-swatch.json +0 -17
  224. package/registry/kpi-card/files/src/components/charts/kpi-card.tsx +0 -45
  225. package/registry/kpi-card.json +0 -14
  226. package/registry/like-button.json +0 -18
  227. package/registry/morph-button.json +0 -18
  228. package/registry/pagination-dots/files/src/components/ui/pagination-dots.tsx +0 -262
  229. package/registry/pagination-dots.json +0 -15
  230. package/registry/shimmer-button.json +0 -17
  231. package/registry/tag-input/files/src/components/ui/tag-input.tsx +0 -720
  232. package/registry/tag-input.json +0 -17
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/progress-steps.tsx"
8
8
  ],
9
+ "summary": "Finished steps pop and draw a check while the line pours into the next one.",
9
10
  "props": [
10
11
  [
11
12
  "steps",
@@ -62,6 +63,29 @@
62
63
  "Style for the step row / column (the bar container in the bar variant)."
63
64
  ]
64
65
  ],
66
+ "behavior": [
67
+ [
68
+ "Motion",
69
+ "When current changes, the finished node pops and draws its check, the connector fills toward the next step and the new step lights up. The current step's ring pulses."
70
+ ],
71
+ [
72
+ "Touch",
73
+ "With onStepPress, steps become buttons that squish on press; pressableSteps='completed' limits taps to finished steps."
74
+ ],
75
+ [
76
+ "Haptics",
77
+ "A selection tick plays whenever current changes (haptics, on by default)."
78
+ ],
79
+ [
80
+ "Reduced motion",
81
+ "Steps move with a short timing instead of springs, the ring stops pulsing and the done node appears without the overshoot pop."
82
+ ],
83
+ [
84
+ "Screen readers",
85
+ "Each step reads like 'Step 2 of 4, Shipping, current'. The bar variant is a progressbar labelled 'Step N of M' with the step name."
86
+ ]
87
+ ],
88
+ "usage": "import { useState } from 'react';\nimport { ProgressSteps } from '@/components/ui/progress-steps';\n\nconst [step, setStep] = useState(1);\n<ProgressSteps steps={['Cart', 'Shipping', 'Payment', 'Review']} current={step} onStepPress={setStep} pressableSteps=\"completed\" />",
65
89
  "examples": [
66
90
  {
67
91
  "name": "Checkout",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/progress.tsx"
8
8
  ],
9
+ "summary": "A bar, ring or segments with a glowing head; finishing flashes and draws a check.",
9
10
  "props": [
10
11
  [
11
12
  "variant",
@@ -92,6 +93,25 @@
92
93
  "Style for the root view of the bar, ring or step row."
93
94
  ]
94
95
  ],
96
+ "behavior": [
97
+ [
98
+ "Motion",
99
+ "The fill springs to each value with a glow riding its head, and the ring's percentage counts up. Reaching max flashes the fill and morphs the value into a drawn check."
100
+ ],
101
+ [
102
+ "Reduced motion",
103
+ "The completion flash, moving stripes and segment pop and pulse are skipped. The fill still springs and indeterminate loops still run."
104
+ ],
105
+ [
106
+ "Screen readers",
107
+ "A progressbar with your label and its min, max and current value. Indeterminate progress is marked busy."
108
+ ],
109
+ [
110
+ "Platforms",
111
+ "Transforms and opacity use the native driver; only the ring's SVG stroke and the check drawing use the JS driver."
112
+ ]
113
+ ],
114
+ "usage": "import { Progress } from '@/components/ui/progress';\n\n<Progress value={64} label=\"Uploading trip-to-lisbon.mov\" showValue />\n<Progress variant=\"circular\" value={64} />",
95
115
  "examples": [
96
116
  {
97
117
  "name": "Linear",
@@ -0,0 +1,122 @@
1
+ {
2
+ "name": "qr-code-button",
3
+ "category": "Buttons",
4
+ "aliases": [],
5
+ "exportName": "QrCodeButton",
6
+ "files": [
7
+ "src/components/ui/qr-code-button.tsx"
8
+ ],
9
+ "summary": "A pill that morphs into a card with a real, scannable QR code.",
10
+ "props": [
11
+ [
12
+ "value",
13
+ "string",
14
+ "—",
15
+ "What the code encodes: a URL, a payment link, a ticket id."
16
+ ],
17
+ [
18
+ "label",
19
+ "string",
20
+ "'Show QR Code'",
21
+ "Text on the pill."
22
+ ],
23
+ [
24
+ "copyLabel",
25
+ "string",
26
+ "'Copy'",
27
+ "Copy button text."
28
+ ],
29
+ [
30
+ "copiedLabel",
31
+ "string",
32
+ "'Copied'",
33
+ "Shown after Copy is pressed."
34
+ ],
35
+ [
36
+ "onCopy",
37
+ "(value: string) => void",
38
+ "—",
39
+ "Wire your clipboard here (expo-clipboard)."
40
+ ],
41
+ [
42
+ "open",
43
+ "boolean",
44
+ "—",
45
+ "Controlled state."
46
+ ],
47
+ [
48
+ "defaultOpen",
49
+ "boolean",
50
+ "false",
51
+ "Uncontrolled initial state."
52
+ ],
53
+ [
54
+ "onOpenChange",
55
+ "(open: boolean) => void",
56
+ "—",
57
+ "Opened or closed."
58
+ ],
59
+ [
60
+ "size",
61
+ "\"sm\" | \"md\" | \"lg\"",
62
+ "\"md\"",
63
+ "Pill height 36 / 44 / 52."
64
+ ],
65
+ [
66
+ "codeSize",
67
+ "number",
68
+ "168",
69
+ "Side of the code in points; the card wraps it."
70
+ ],
71
+ [
72
+ "color",
73
+ "string",
74
+ "white (dark) / primary (light)",
75
+ "Pill colour. The card stays white so the code scans."
76
+ ],
77
+ [
78
+ "accessibilityLabel",
79
+ "string",
80
+ "label",
81
+ "Screen reader label for the pill."
82
+ ],
83
+ [
84
+ "style",
85
+ "StyleProp<ViewStyle>",
86
+ "—",
87
+ "Root style."
88
+ ]
89
+ ],
90
+ "behavior": [
91
+ [
92
+ "Motion",
93
+ "Press swells the pill; it glides into the card while its label fades out and the code fades and scales in. Close glides it back."
94
+ ],
95
+ [
96
+ "Layout",
97
+ "Reserves the open card's size up front, so nothing around it moves and every control stays inside its own bounds (taps work on Android)."
98
+ ],
99
+ [
100
+ "Code",
101
+ "Encoded in the component: UTF-8 bytes, error correction M, smallest version that fits, mask chosen by the spec's penalty rules. Always dark on white so it scans in dark mode too."
102
+ ],
103
+ [
104
+ "Copy",
105
+ "Calls onCopy with the value and flips to a tick and \"Copied\" for 1.5 s."
106
+ ],
107
+ [
108
+ "Haptics",
109
+ "A light impact on open, a success tap on Copy, a tick on close."
110
+ ],
111
+ [
112
+ "Reduced motion",
113
+ "Opens and closes with a short fade."
114
+ ],
115
+ [
116
+ "Screen readers",
117
+ "A button with an expanded state; the code reads as \"QR code for …\"."
118
+ ]
119
+ ],
120
+ "usage": null,
121
+ "examples": []
122
+ }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/radio-group.tsx"
8
8
  ],
9
+ "summary": "The dot springs in with a ripple; cards light up and draw a check badge.",
9
10
  "props": [
10
11
  [
11
12
  "options",
@@ -62,6 +63,25 @@
62
63
  "Style for the group container (the bordered card in the segmented-list variant)."
63
64
  ]
64
65
  ],
66
+ "behavior": [
67
+ [
68
+ "Touch",
69
+ "Rows squish on press in the default and card variants, and the default dot has extra hitSlop. Disabled options are dimmed and ignore taps."
70
+ ],
71
+ [
72
+ "Motion",
73
+ "The selected dot pops on a bouncy spring with a ripple ring. Cards tint their border and pop a self-drawing check; the list variant draws a tick."
74
+ ],
75
+ [
76
+ "Haptics",
77
+ "A selection tick plays on each change (haptics, on by default)."
78
+ ],
79
+ [
80
+ "Screen readers",
81
+ "The group is a radiogroup and each option a radio with checked and disabled state. Descriptions are read as hints."
82
+ ]
83
+ ],
84
+ "usage": "import { RadioGroup } from '@/components/ui/radio-group';\n\n<RadioGroup\n defaultValue=\"standard\"\n options={[\n { value: 'standard', label: 'Standard shipping', description: '4–6 business days · Free' },\n { value: 'express', label: 'Express', description: '1–2 business days · $9' },\n ]}\n/>",
65
85
  "examples": [
66
86
  {
67
87
  "name": "Default",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/rating.tsx"
8
8
  ],
9
+ "summary": "Drag across the stars to rate; the top one throws a little spark burst.",
9
10
  "props": [
10
11
  [
11
12
  "value / onValueChange",
@@ -86,5 +87,28 @@
86
87
  "Style for the row of icons."
87
88
  ]
88
89
  ],
90
+ "behavior": [
91
+ [
92
+ "Touch",
93
+ "Tap or drag across the row to set the value, to half-icon precision with allowHalf. With clearable, tapping the current value clears it."
94
+ ],
95
+ [
96
+ "Motion",
97
+ "Icons fill smoothly and pop in a quick stagger with a wobble. When you raise the rating, the top icon throws a spark burst."
98
+ ],
99
+ [
100
+ "Haptics",
101
+ "A selection tick plays for every step while tapping or dragging."
102
+ ],
103
+ [
104
+ "Screen readers",
105
+ "One adjustable element read as 'N of 5'. Swipe up or down to change it by one step."
106
+ ],
107
+ [
108
+ "Web",
109
+ "Works with the mouse too, and shows a pointer cursor while interactive."
110
+ ]
111
+ ],
112
+ "usage": null,
89
113
  "examples": []
90
114
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/ring-carousel.tsx"
8
8
  ],
9
+ "summary": "Cards on a 3D ring you spin with a swipe; it snaps and loops forever.",
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -98,5 +99,24 @@
98
99
  "Style for the root view."
99
100
  ]
100
101
  ],
102
+ "behavior": [
103
+ [
104
+ "Touch",
105
+ "Horizontal drags spin the ring and a flick carries it a little further before snapping. Tapping a side card turns to it; tapping the front card calls onPress."
106
+ ],
107
+ [
108
+ "Motion",
109
+ "Neighbours turn, shrink and fall into shadow as they go round the back. With autoplay it advances every 3s by default and pauses while touched."
110
+ ],
111
+ [
112
+ "Screen readers",
113
+ "The ring is one adjustable element ('2 / 7'): swipe up or down to turn it, double-tap to press the front card. Side cards are hidden."
114
+ ],
115
+ [
116
+ "Platforms",
117
+ "The loop runs on the native driver via Animated.modulo. Each card turns in its own flat layer so iOS never slices a side card into the front one."
118
+ ]
119
+ ],
120
+ "usage": null,
101
121
  "examples": []
102
122
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/scratch-card.tsx"
8
8
  ],
9
+ "summary": "Rub a shimmering foil away; past a threshold the rest clears with a haptic tap.",
9
10
  "props": [
10
11
  [
11
12
  "children",
@@ -86,5 +87,24 @@
86
87
  "Width, margins."
87
88
  ]
88
89
  ],
90
+ "behavior": [
91
+ [
92
+ "Touch",
93
+ "Your finger scratches the foil away with a round brush, and once threshold of it is gone the rest clears by itself. The card keeps the touch, so a parent ScrollView cannot steal it mid-rub."
94
+ ],
95
+ [
96
+ "Motion",
97
+ "A light band sweeps across the foil until the first touch. On reveal the foil fades out while scaling up slightly."
98
+ ],
99
+ [
100
+ "Haptics",
101
+ "A success notification plays when the foil clears."
102
+ ],
103
+ [
104
+ "Screen readers",
105
+ "The foil is a button labelled with label and sublabel, with the hint 'Double-tap to reveal'."
106
+ ]
107
+ ],
108
+ "usage": null,
89
109
  "examples": []
90
110
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/search-bar.tsx"
8
8
  ],
9
+ "summary": "Focus pops the magnifier and springs in Cancel; suggestions drop down below.",
9
10
  "props": [
10
11
  [
11
12
  "variant",
@@ -110,21 +111,40 @@
110
111
  "placeholder, onSubmitEditing, autoFocus, …"
111
112
  ]
112
113
  ],
114
+ "behavior": [
115
+ [
116
+ "Motion",
117
+ "On focus a halo glows and the magnifier pops; Cancel slides in as the field springs narrower and the clear button scales in. loading swaps the magnifier for a spinning arc."
118
+ ],
119
+ [
120
+ "Touch",
121
+ "The 'minimal' variant rests as a round icon and expands into a full field when tapped. Picking a suggestion fills the query and dismisses the keyboard."
122
+ ],
123
+ [
124
+ "Screen readers",
125
+ "The input has the search role, labelled by its placeholder. 'Clear search', Cancel and each suggestion are labelled buttons."
126
+ ],
127
+ [
128
+ "Web",
129
+ "The browser outline is replaced by the border and halo, and the suggestion panel stays open a beat after blur so clicks land."
130
+ ]
131
+ ],
132
+ "usage": "import { useState } from 'react';\nimport { SearchBar } from '@/components/ui/search-bar';\n\nconst [query, setQuery] = useState('');\n<SearchBar value={query} onChangeText={setQuery} placeholder=\"Search products\" />",
113
133
  "examples": [
114
134
  {
115
135
  "name": "WithSuggestions",
116
136
  "title": "With Suggestions",
117
- "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst SUGGESTIONS: SearchSuggestion[] = [\n { key: 'r1', label: 'Noise cancelling headphones', icon: 'recent' },\n { key: 'r2', label: 'Running shoes', icon: 'recent' },\n { key: 't1', label: 'Mechanical keyboard', icon: 'trending', hint: 'Trending' },\n { key: 't2', label: 'Standing desk', icon: 'trending', hint: '2.1k searches' },\n { key: 's1', label: 'Wireless charger', hint: 'Electronics' },\n { key: 's2', label: 'Coffee grinder', hint: 'Kitchen' },\n];\n\nexport default function WithSuggestions() {\n const { colors } = useKit();\n const [query, setQuery] = useState('');\n const [picked, setPicked] = useState<string | null>(null);\n return (\n // Reserve room for the open list, so the bar stays put when suggestions drop down below it.\n <View style={{ gap: 10, minHeight: 400 }}>\n <SearchBar\n value={query}\n onChangeText={setQuery}\n placeholder=\"Search products\"\n suggestions={SUGGESTIONS}\n maxSuggestions={5}\n onSelectSuggestion={(item) => setPicked(item.label)}\n />\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>{picked ? `Showing results for “${picked}”` : 'Tap the field to see recent and trending searches'}</Text>\n </View>\n );\n}\n"
137
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst SUGGESTIONS: SearchSuggestion[] = [\n { key: 'r1', label: 'Noise cancelling headphones', icon: 'recent' },\n { key: 'r2', label: 'Running shoes', icon: 'recent' },\n { key: 't1', label: 'Mechanical keyboard', icon: 'trending', hint: 'Trending' },\n { key: 't2', label: 'Standing desk', icon: 'trending', hint: '2.1k searches' },\n { key: 's1', label: 'Wireless charger', hint: 'Electronics' },\n { key: 's2', label: 'Coffee grinder', hint: 'Kitchen' },\n];\n\nexport default function WithSuggestions({ screen }: DemoProps) {\n const { colors } = useKit();\n const [query, setQuery] = useState('');\n const [picked, setPicked] = useState<string | null>(null);\n return (\n // Reserve room for the open list, so the bar stays put when suggestions drop down below it.\n <View style={[{ gap: 10 }, screen ? { flex: 1 } : { minHeight: 400 }]}>\n <SearchBar\n value={query}\n onChangeText={setQuery}\n placeholder=\"Search products\"\n suggestions={SUGGESTIONS}\n maxSuggestions={5}\n onSelectSuggestion={(item) => setPicked(item.label)}\n />\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>{picked ? `Showing results for “${picked}”` : 'Tap the field to see recent and trending searches'}</Text>\n </View>\n );\n}\n"
118
138
  },
119
139
  {
120
140
  "name": "LiveResults",
121
141
  "title": "Live Results",
122
- "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, 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 { padding: 16, gap: 12, borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst CONTACTS = [\n { name: 'Aarav Mehta', role: 'Design lead' },\n { name: 'Priya Nair', role: 'Product manager' },\n { name: 'Rohan Kapoor', role: 'iOS engineer' },\n { name: 'Sara Ali', role: 'Marketing' },\n { name: 'Vikram Rao', role: 'Backend engineer' },\n];\n\nexport default function LiveResults() {\n const { colors } = useKit();\n const [query, setQuery] = useState('');\n const [loading, setLoading] = useState(false);\n useEffect(() => {\n if (!query) return setLoading(false);\n setLoading(true);\n const id = setTimeout(() => setLoading(false), 600);\n return () => clearTimeout(id);\n }, [query]);\n const q = query.trim().toLowerCase();\n const results = CONTACTS.filter((c) => c.name.toLowerCase().includes(q) || c.role.toLowerCase().includes(q));\n return (\n <Card>\n <SearchBar variant=\"filled\" value={query} onChangeText={setQuery} loading={loading} placeholder=\"Search people\" />\n {loading ? (\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>Searching your team…</Text>\n ) : results.length ? (\n results.slice(0, 4).map((c) => (\n <View key={c.name} style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <View style={{ width: 34, height: 34, borderRadius: 17, backgroundColor: alpha(colors.accent, 0.16), alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>{c.name.split(' ').map((p) => p[0]).join('')}</Text>\n </View>\n <View>\n <Text style={{ fontSize: 15, fontWeight: '400', color: colors.foreground }}>{c.name}</Text>\n <Text style={{ fontSize: 12.5, color: colors.mutedForeground }}>{c.role}</Text>\n </View>\n </View>\n ))\n ) : (\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>No one matches “{query}”</Text>\n )}\n </Card>\n );\n}\n"
142
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n { padding: 16, gap: 12 },\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst CONTACTS = [\n { name: 'Aarav Mehta', role: 'Design lead' },\n { name: 'Priya Nair', role: 'Product manager' },\n { name: 'Rohan Kapoor', role: 'iOS engineer' },\n { name: 'Sara Ali', role: 'Marketing' },\n { name: 'Vikram Rao', role: 'Backend engineer' },\n];\n\nexport default function LiveResults({ screen }: DemoProps) {\n const { colors } = useKit();\n const [query, setQuery] = useState('');\n const [loading, setLoading] = useState(false);\n useEffect(() => {\n if (!query) return setLoading(false);\n setLoading(true);\n const id = setTimeout(() => setLoading(false), 600);\n return () => clearTimeout(id);\n }, [query]);\n const q = query.trim().toLowerCase();\n const results = CONTACTS.filter((c) => c.name.toLowerCase().includes(q) || c.role.toLowerCase().includes(q));\n return (\n <Card screen={screen}>\n <SearchBar variant=\"filled\" value={query} onChangeText={setQuery} loading={loading} placeholder=\"Search people\" />\n {loading ? (\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>Searching your team…</Text>\n ) : results.length ? (\n results.slice(0, 4).map((c) => (\n <View key={c.name} style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <View style={{ width: 34, height: 34, borderRadius: 17, backgroundColor: alpha(colors.accent, 0.16), alignItems: 'center', justifyContent: 'center' }}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>{c.name.split(' ').map((p) => p[0]).join('')}</Text>\n </View>\n <View>\n <Text style={{ fontSize: 15, fontWeight: '400', color: colors.foreground }}>{c.name}</Text>\n <Text style={{ fontSize: 12.5, color: colors.mutedForeground }}>{c.role}</Text>\n </View>\n </View>\n ))\n ) : (\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>No one matches “{query}”</Text>\n )}\n </Card>\n );\n}\n"
123
143
  },
124
144
  {
125
145
  "name": "Minimal",
126
146
  "title": "Minimal",
127
- "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, 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 { padding: 16, gap: 12, borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nexport default function Minimal() {\n const { colors } = useKit();\n return (\n <Card style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <Text style={{ fontSize: 22, fontWeight: '400', letterSpacing: -0.4, color: colors.foreground }}>Inbox</Text>\n <SearchBar variant=\"minimal\" align=\"right\" placeholder=\"Search mail\" style={{ flex: 1 }} />\n </Card>\n );\n}\n"
147
+ "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { SearchBar, type SearchSuggestion } from '@/components/ui/search-bar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n { padding: 16, gap: 12 },\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nexport default function Minimal({ screen }: DemoProps) {\n const { colors } = useKit();\n return (\n <Card screen={screen} style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <Text style={{ fontSize: 22, fontWeight: '400', letterSpacing: -0.4, color: colors.foreground }}>Inbox</Text>\n <SearchBar variant=\"minimal\" align=\"right\" placeholder=\"Search mail\" style={{ flex: 1 }} />\n </Card>\n );\n}\n"
128
148
  },
129
149
  {
130
150
  "name": "WithFilter",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/blocks/search-results.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "results",
@@ -116,5 +117,7 @@
116
117
  "Root style."
117
118
  ]
118
119
  ],
120
+ "behavior": [],
121
+ "usage": null,
119
122
  "examples": []
120
123
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/segmented-control.tsx"
8
8
  ],
9
+ "summary": "A liquid indicator that stretches as it slides; drag it to scrub.",
9
10
  "props": [
10
11
  [
11
12
  "options",
@@ -68,6 +69,25 @@
68
69
  "Style for the track holding the segments."
69
70
  ]
70
71
  ],
72
+ "behavior": [
73
+ [
74
+ "Motion",
75
+ "The leading edge of the indicator springs ahead and the trailing edge catches up, so it stretches as it travels. Labels squish on press and bounce when selected."
76
+ ],
77
+ [
78
+ "Touch",
79
+ "A sideways drag that starts on the selected segment scrubs across the others; drags that start elsewhere are left to a parent ScrollView. Short segments get hitSlop up to 44pt."
80
+ ],
81
+ [
82
+ "Haptics",
83
+ "A selection tick plays on each change (haptics, on by default)."
84
+ ],
85
+ [
86
+ "Screen readers",
87
+ "A tablist of tabs with selected and disabled state, labelled by each option's label or accessibilityLabel."
88
+ ]
89
+ ],
90
+ "usage": "import { useState } from 'react';\nimport { SegmentedControl } from '@/components/ui/segmented-control';\n\nconst [range, setRange] = useState('Week');\n<SegmentedControl options={['Day', 'Week', 'Month', 'Year']} value={range} onValueChange={setRange} />",
71
91
  "examples": [
72
92
  {
73
93
  "name": "Pill",