@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/loyalty-card.tsx"
8
8
  ],
9
+ "summary": "A points or stamp card on a shop photo that tilts and flips to a member code.",
9
10
  "props": [
10
11
  [
11
12
  "brand",
@@ -104,5 +105,20 @@
104
105
  "Style for the root."
105
106
  ]
106
107
  ],
108
+ "behavior": [
109
+ [
110
+ "Touch",
111
+ "Tap the card to flip it to the member code for the till, and tap again to turn it back."
112
+ ],
113
+ [
114
+ "Motion",
115
+ "With tilt on (the default) the card leans toward your finger with a moving reflection, then turns over in 3D on a spring."
116
+ ],
117
+ [
118
+ "Screen readers",
119
+ "The card is a button labelled with the brand, member and their points or stamp count."
120
+ ]
121
+ ],
122
+ "usage": null,
107
123
  "examples": []
108
124
  }
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "morphing-button-group",
3
+ "category": "Buttons",
4
+ "aliases": [],
5
+ "exportName": "MorphingButtonGroup",
6
+ "files": [
7
+ "src/components/ui/morphing-button-group.tsx"
8
+ ],
9
+ "summary": "Buttons that split, join and stretch between sets — with a signature sheet built on it.",
10
+ "props": [
11
+ [
12
+ "buttons",
13
+ "{ key, label, icon?, variant?, onPress? }[]",
14
+ "—",
15
+ "MorphingButtonGroup: the buttons to show now; changing it morphs the row."
16
+ ],
17
+ [
18
+ "height",
19
+ "number",
20
+ "44",
21
+ "Button height."
22
+ ],
23
+ [
24
+ "gap",
25
+ "number",
26
+ "10",
27
+ "Space between buttons."
28
+ ],
29
+ [
30
+ "duration",
31
+ "number",
32
+ "380",
33
+ "Morph length in ms."
34
+ ],
35
+ [
36
+ "SignatureSheet label",
37
+ "string",
38
+ "'Sign'",
39
+ "The pill's text."
40
+ ],
41
+ [
42
+ "SignatureSheet title",
43
+ "string",
44
+ "'Add Signature'",
45
+ "Card title."
46
+ ],
47
+ [
48
+ "SignatureSheet onConfirm",
49
+ "({ paths, width, height }) => void",
50
+ "—",
51
+ "The finished signature."
52
+ ],
53
+ [
54
+ "SignatureSheet onCancel",
55
+ "() => void",
56
+ "—",
57
+ "Closed without signing."
58
+ ],
59
+ [
60
+ "SignatureSheet cardHeight",
61
+ "number",
62
+ "340",
63
+ "Height of the open card."
64
+ ],
65
+ [
66
+ "style",
67
+ "StyleProp<ViewStyle>",
68
+ "—",
69
+ "Root style."
70
+ ]
71
+ ],
72
+ "behavior": [
73
+ [
74
+ "Morph",
75
+ "Buttons with the same key keep their place and resize; new ones grow in from nothing and leaving ones shrink away, on one smooth ease (no bounce)."
76
+ ],
77
+ [
78
+ "Labels",
79
+ "A label change cross-fades while the button resizes."
80
+ ],
81
+ [
82
+ "Signature",
83
+ "The pad draws smoothed strokes; undo removes the last one, Reset clears, Confirm asks once more. onConfirm gets SVG path data and the pad size."
84
+ ],
85
+ [
86
+ "Haptics",
87
+ "A tick on each button, a light tap opening the sheet, success on confirm."
88
+ ],
89
+ [
90
+ "Reduced motion",
91
+ "Morphs are instant."
92
+ ]
93
+ ],
94
+ "usage": null,
95
+ "examples": []
96
+ }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/number-ticker.tsx"
8
8
  ],
9
+ "summary": "Each digit rolls like an odometer, flashing green or red as it changes.",
9
10
  "props": [
10
11
  [
11
12
  "value",
@@ -92,5 +93,20 @@
92
93
  "Style for the row of digits."
93
94
  ]
94
95
  ],
96
+ "behavior": [
97
+ [
98
+ "Motion",
99
+ "Each digit springs along its own 0–9 strip, up when the value grows and down when it shrinks, staggered right to left. The text briefly tints green or red on every change."
100
+ ],
101
+ [
102
+ "Screen readers",
103
+ "The whole number is one text element, read with its prefix and suffix instead of digit by digit."
104
+ ],
105
+ [
106
+ "Platforms",
107
+ "Plain Animated views on iOS, Android and web. The digit rolls use the native driver; only the colour flash runs in JS."
108
+ ]
109
+ ],
110
+ "usage": null,
95
111
  "examples": []
96
112
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/blocks/offers.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "offers",
@@ -74,5 +75,7 @@
74
75
  "Root style."
75
76
  ]
76
77
  ],
78
+ "behavior": [],
79
+ "usage": null,
77
80
  "examples": []
78
81
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/blocks/onboarding.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "steps",
@@ -62,5 +63,7 @@
62
63
  "Root style."
63
64
  ]
64
65
  ],
66
+ "behavior": [],
67
+ "usage": null,
65
68
  "examples": []
66
69
  }
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "orb-reveal",
3
+ "category": "Motion",
4
+ "aliases": [],
5
+ "exportName": "OrbReveal",
6
+ "files": [
7
+ "src/components/ui/orb-reveal.tsx"
8
+ ],
9
+ "summary": "Drag a liquid-glass orb up: it shows your title through the lens, then fountains glass marbles into a heart.",
10
+ "props": [
11
+ [
12
+ "headline",
13
+ "string",
14
+ "'A new era of…'",
15
+ "Copy shown before the reveal."
16
+ ],
17
+ [
18
+ "title",
19
+ "string",
20
+ "'Meet Wabi.'",
21
+ "The line the lens uncovers."
22
+ ],
23
+ [
24
+ "subtitle",
25
+ "string",
26
+ "'The first personal…'",
27
+ "Lines under the title."
28
+ ],
29
+ [
30
+ "hint",
31
+ "string",
32
+ "'Swipe up to enter'",
33
+ "Faint hint under the resting orb."
34
+ ],
35
+ [
36
+ "images",
37
+ "string[]",
38
+ "—",
39
+ "Image URIs for the marbles (app icons, avatars)."
40
+ ],
41
+ [
42
+ "emoji",
43
+ "string[]",
44
+ "24 emoji",
45
+ "Marble pictures when there are no images, each on a bright gradient."
46
+ ],
47
+ [
48
+ "count",
49
+ "number",
50
+ "52",
51
+ "Marbles in the heart (max 60), plus a trail of specks."
52
+ ],
53
+ [
54
+ "glowColors",
55
+ "[string, string]",
56
+ "blue, violet",
57
+ "The glow while you hold the orb."
58
+ ],
59
+ [
60
+ "background",
61
+ "string",
62
+ "theme background",
63
+ "Page colour."
64
+ ],
65
+ [
66
+ "footer",
67
+ "ReactNode",
68
+ "—",
69
+ "Fades in after the reveal: sign-in buttons, a CTA."
70
+ ],
71
+ [
72
+ "revealed",
73
+ "boolean",
74
+ "—",
75
+ "Controlled state."
76
+ ],
77
+ [
78
+ "defaultRevealed",
79
+ "boolean",
80
+ "false",
81
+ "Uncontrolled initial state."
82
+ ],
83
+ [
84
+ "onRevealChange",
85
+ "(revealed: boolean) => void",
86
+ "—",
87
+ "The orb settled in a new state."
88
+ ],
89
+ [
90
+ "style",
91
+ "StyleProp<ViewStyle>",
92
+ "flex: 1",
93
+ "Root style; give it a screen or a tall card."
94
+ ]
95
+ ],
96
+ "behavior": [
97
+ [
98
+ "Hold",
99
+ "The orb swells and lifts, a blue-violet smile of light glows through it and the headline fades."
100
+ ],
101
+ [
102
+ "Drag",
103
+ "Drag up past halfway (or flick) to reveal; drag the small orb down to go back. A quick tap toggles; a hold or a drag back to the start stays put."
104
+ ],
105
+ [
106
+ "Lens",
107
+ "Two Skia shaders refract the page under the orb and the title the lens uncovers: magnified middle, mirrored bevel, red/blue split at the edge."
108
+ ],
109
+ [
110
+ "Marbles",
111
+ "Fountain out of the button on arcs, pop to size and settle into a heart, then drift. Going back down, they float off the top."
112
+ ],
113
+ [
114
+ "Copy",
115
+ "The title rides with the orb. It and the footer appear as the orb settles and stay until it is most of the way back down."
116
+ ],
117
+ [
118
+ "Haptics",
119
+ "A tick when you pick the orb up and a medium impact on reveal."
120
+ ],
121
+ [
122
+ "Reduced motion",
123
+ "The orb snaps between states and the marbles appear in place."
124
+ ],
125
+ [
126
+ "Web",
127
+ "Needs CanvasKit loaded (LoadSkiaWeb); without it the revealed copy and footer are shown."
128
+ ]
129
+ ],
130
+ "usage": null,
131
+ "examples": []
132
+ }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/otp-input.tsx"
8
8
  ],
9
+ "summary": "Digits pop into cells that size themselves, with SMS autofill and paste.",
9
10
  "props": [
10
11
  [
11
12
  "length",
@@ -104,26 +105,49 @@
104
105
  "Style for the root view around the cells and message."
105
106
  ]
106
107
  ],
108
+ "behavior": [
109
+ [
110
+ "Touch",
111
+ "Tapping the row focuses one hidden number-pad input. Pasting a code like 123-456 strips the non-digits and fills every cell."
112
+ ],
113
+ [
114
+ "Motion",
115
+ "Digits pop in on a bouncy spring and the active cell glows with a halo and a blinking caret. Errors shake the row; success pulses across the cells."
116
+ ],
117
+ [
118
+ "Platforms",
119
+ "Sets textContentType 'oneTimeCode' and autoComplete 'one-time-code', so codes from SMS can autofill."
120
+ ],
121
+ [
122
+ "Screen readers",
123
+ "The cells are hidden; the input is labelled 'One-time code, 6 digits' with a hint. Helper, error and success messages are a polite live region."
124
+ ],
125
+ [
126
+ "Web",
127
+ "The browser focus outline is removed; the border and halo show focus instead."
128
+ ]
129
+ ],
130
+ "usage": "import { useState } from 'react';\nimport { OtpInput } from '@/components/ui/otp-input';\n\nconst [code, setCode] = useState('');\n<OtpInput value={code} onChangeText={setCode} helperText=\"Sent to +1 415 555 0132\" />",
107
131
  "examples": [
108
132
  {
109
133
  "name": "VerifyPhone",
110
134
  "title": "Verify Phone",
111
- "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-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 { 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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function VerifyPhone() {\n const { colors } = useKit();\n const [code, setCode] = useState('');\n const [left, setLeft] = useState(24);\n useEffect(() => {\n if (left <= 0) return;\n const id = setTimeout(() => setLeft((s) => s - 1), 1000);\n return () => clearTimeout(id);\n }, [left]);\n const done = code.length === 6;\n return (\n <Card>\n <Header title=\"Verify your number\" body=\"Enter the code sent to +91 98•••• 4210\" />\n <OtpInput\n value={code}\n onChangeText={setCode}\n success={code === '123456'}\n error={done && code !== '123456'}\n successText=\"Number verified\"\n errorText=\"That code didn't match. Try 123456.\"\n helperText=\"Tip: the demo code is 123456\"\n />\n <View style={{ flexDirection: 'row', justifyContent: 'center', gap: 16 }}>\n <Pressable disabled={left > 0} onPress={() => { setLeft(24); setCode(''); }} hitSlop={10}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: left > 0 ? colors.mutedForeground : colors.accent }}>\n {left > 0 ? `Resend in 0:${String(left).padStart(2, '0')}` : 'Resend code'}\n </Text>\n </Pressable>\n <Pressable hitSlop={10} accessibilityRole=\"button\">\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>Change number</Text>\n </Pressable>\n </View>\n </Card>\n );\n}\n"
135
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-input';\nimport { 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({ style, screen, ...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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function VerifyPhone({ screen }: DemoProps) {\n const { colors } = useKit();\n const [code, setCode] = useState('');\n const [left, setLeft] = useState(24);\n useEffect(() => {\n if (left <= 0) return;\n const id = setTimeout(() => setLeft((s) => s - 1), 1000);\n return () => clearTimeout(id);\n }, [left]);\n const done = code.length === 6;\n return (\n <Card screen={screen}>\n <Header title=\"Verify your number\" body=\"Enter the code sent to +91 98•••• 4210\" />\n <OtpInput\n value={code}\n onChangeText={setCode}\n success={code === '123456'}\n error={done && code !== '123456'}\n successText=\"Number verified\"\n errorText=\"That code didn't match. Try 123456.\"\n helperText=\"Tip: the demo code is 123456\"\n />\n <View style={{ flexDirection: 'row', justifyContent: 'center', gap: 16 }}>\n <Pressable disabled={left > 0} onPress={() => { setLeft(24); setCode(''); }} hitSlop={10}>\n <Text style={{ fontSize: 13, fontWeight: '400', color: left > 0 ? colors.mutedForeground : colors.accent }}>\n {left > 0 ? `Resend in 0:${String(left).padStart(2, '0')}` : 'Resend code'}\n </Text>\n </Pressable>\n <Pressable hitSlop={10} accessibilityRole=\"button\">\n <Text style={{ fontSize: 13, fontWeight: '400', color: colors.accent }}>Change number</Text>\n </Pressable>\n </View>\n </Card>\n );\n}\n"
112
136
  },
113
137
  {
114
138
  "name": "Pin",
115
139
  "title": "Pin",
116
- "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-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 { 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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Pin() {\n const [pin, setPin] = useState('');\n return (\n <Card>\n <Header title=\"Enter your PIN\" body=\"Confirm the transfer of ₹2,400 to Ananya\" />\n <OtpInput variant=\"pill\" length={4} secure value={pin} onChangeText={setPin} maxCellSize={56} />\n </Card>\n );\n}\n"
140
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-input';\nimport { 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({ style, screen, ...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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Pin({ screen }: DemoProps) {\n const [pin, setPin] = useState('');\n return (\n <Card screen={screen}>\n <Header title=\"Enter your PIN\" body=\"Confirm the transfer of ₹2,400 to Ananya\" />\n <OtpInput variant=\"pill\" length={4} secure value={pin} onChangeText={setPin} maxCellSize={56} />\n </Card>\n );\n}\n"
117
141
  },
118
142
  {
119
143
  "name": "Underline",
120
144
  "title": "Underline",
121
- "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-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 { 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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Underline() {\n return (\n <Card>\n <Header title=\"Check your inbox\" body=\"We emailed a 6-digit code to karan@…\" />\n <OtpInput variant=\"underline\" helperText=\"Code expires in 10 minutes\" />\n </Card>\n );\n}\n"
145
+ "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-input';\nimport { 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({ style, screen, ...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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function Underline({ screen }: DemoProps) {\n return (\n <Card screen={screen}>\n <Header title=\"Check your inbox\" body=\"We emailed a 6-digit code to karan@…\" />\n <OtpInput variant=\"underline\" helperText=\"Code expires in 10 minutes\" />\n </Card>\n );\n}\n"
122
146
  },
123
147
  {
124
148
  "name": "WithSeparator",
125
149
  "title": "With Separator",
126
- "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-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 { 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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function WithSeparator() {\n return (\n <Card>\n <Header title=\"Two-factor authentication\" body=\"Open your authenticator app\" />\n <OtpInput separatorAfter={3} maxCellSize={46} />\n </Card>\n );\n}\n"
150
+ "code": "import { Pressable, StyleSheet, Text, View, type ViewProps } from 'react-native';\nimport { OtpInput } from '@/components/ui/otp-input';\nimport { 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({ style, screen, ...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\nfunction Header({ title, body }: { title: string; body: string }) {\n const { colors } = useKit();\n return (\n <View style={{ gap: 4, alignItems: 'center' }}>\n <Text style={{ fontSize: 16, fontWeight: '400', color: colors.foreground, textAlign: 'center' }}>{title}</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>{body}</Text>\n </View>\n );\n}\n\nexport default function WithSeparator({ screen }: DemoProps) {\n return (\n <Card screen={screen}>\n <Header title=\"Two-factor authentication\" body=\"Open your authenticator app\" />\n <OtpInput separatorAfter={3} maxCellSize={46} />\n </Card>\n );\n}\n"
127
151
  },
128
152
  {
129
153
  "name": "States",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/parallax-layers.tsx"
8
8
  ],
9
+ "summary": "Drag across a layered scene: near layers slide further while it tilts in 3D.",
9
10
  "props": [
10
11
  [
11
12
  "children",
@@ -80,5 +81,24 @@
80
81
  "Style for the layer (it fills the scene)."
81
82
  ]
82
83
  ],
84
+ "behavior": [
85
+ [
86
+ "Touch",
87
+ "The finger position steers the scene and release springs it back to centre. A parent ScrollView can still take over a scroll that starts on it."
88
+ ],
89
+ [
90
+ "Motion",
91
+ "Each layer moves by its depth times travel while the whole scene tilts in perspective. Left alone, it drifts slowly on a loop."
92
+ ],
93
+ [
94
+ "Screen readers",
95
+ "With accessibilityLabel the scene is one image element with that label; without it, it is not exposed."
96
+ ],
97
+ [
98
+ "Platforms",
99
+ "Transforms run on the native driver with PanResponder, so it works on iOS, Android and web with no native modules."
100
+ ]
101
+ ],
102
+ "usage": null,
83
103
  "examples": []
84
104
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/parallax-scroll.tsx"
8
8
  ],
9
+ "summary": "A photo header glides slower than the content, then a title bar fades in.",
9
10
  "props": [
10
11
  [
11
12
  "children",
@@ -182,5 +183,28 @@
182
183
  "The live scroll offset (native-driver friendly), viewport size and content size for your own effects; null outside a ParallaxScrollView."
183
184
  ]
184
185
  ],
186
+ "behavior": [
187
+ [
188
+ "Motion",
189
+ "The header lags behind the scroll and darkens as it leaves. The bar, title and button bubbles fade in once it has scrolled under the bar."
190
+ ],
191
+ [
192
+ "Touch",
193
+ "On iOS, pulling down past the top stretches the header to fill the gap. Set stretch to false when you use a refreshControl."
194
+ ],
195
+ [
196
+ "Reduced motion",
197
+ "With Reduce Motion on, the header, ParallaxImage and ParallaxView parallax offsets switch off; the stretch and the fades stay."
198
+ ],
199
+ [
200
+ "Screen readers",
201
+ "The bar comes first in reading order and its title is a header. Header and ParallaxImage photos are labelled images only when you give them a label."
202
+ ],
203
+ [
204
+ "Platforms",
205
+ "The scroll offset drives everything through a native Animated.event, so there is no JS work while scrolling."
206
+ ]
207
+ ],
208
+ "usage": null,
185
209
  "examples": []
186
210
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/password-input.tsx"
8
8
  ],
9
+ "summary": "An eye toggle that twists between states, and a strength meter that springs full.",
9
10
  "props": [
10
11
  [
11
12
  "strength",
@@ -62,16 +63,35 @@
62
63
  "Every Floating Input prop (error, success, size, variant, …)."
63
64
  ]
64
65
  ],
66
+ "behavior": [
67
+ [
68
+ "Touch",
69
+ "The eye button has a 44pt hit area and toggles secureTextEntry. With confirmOf, a match or mismatch message appears as soon as the typing diverges."
70
+ ],
71
+ [
72
+ "Motion",
73
+ "Eye and eye-off cross-fade with a spring twist. The four meter segments fill left to right in a stagger, and checklist ticks pop in as rules are met."
74
+ ],
75
+ [
76
+ "Keyboard",
77
+ "Auto-capitalisation and autocorrect are turned off for the field."
78
+ ],
79
+ [
80
+ "Screen readers",
81
+ "The toggle is a button labelled 'Show password' or 'Hide password'. The meter reads 'Password strength: Strong' and each requirement reads as done or not yet."
82
+ ]
83
+ ],
84
+ "usage": "import { useState } from 'react';\nimport { PasswordInput } from '@/components/ui/password-input';\n\nconst [password, setPassword] = useState('');\n<PasswordInput label=\"New password\" value={password} onChangeText={setPassword} requirements />",
65
85
  "examples": [
66
86
  {
67
87
  "name": "CreatePassword",
68
88
  "title": "Create Password",
69
- "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { PasswordInput } from '@/components/ui/password-input';\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 CreatePassword() {\n const [password, setPassword] = useState('Sunset');\n const [confirm, setConfirm] = useState('');\n return (\n <Card title=\"Choose a password\" subtitle=\"You'll use it to sign in on new devices.\">\n <PasswordInput label=\"New password\" value={password} onChangeText={setPassword} requirements />\n <PasswordInput label=\"Confirm password\" value={confirm} onChangeText={setConfirm} confirmOf={password} />\n </Card>\n );\n}\n"
89
+ "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { PasswordInput } from '@/components/ui/password-input';\nimport { 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\nfunction Card({ title, subtitle, screen, children }: { title: string; subtitle?: string; screen?: boolean; children: React.ReactNode }) {\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 : {\n borderRadius: radius.xl,\n borderWidth: StyleSheet.hairlineWidth,\n borderColor: colors.border,\n backgroundColor: colors.card,\n },\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 CreatePassword({ screen }: DemoProps) {\n const [password, setPassword] = useState('Sunset');\n const [confirm, setConfirm] = useState('');\n return (\n <Card screen={screen} title=\"Choose a password\" subtitle=\"You'll use it to sign in on new devices.\">\n <PasswordInput label=\"New password\" value={password} onChangeText={setPassword} requirements />\n <PasswordInput label=\"Confirm password\" value={confirm} onChangeText={setConfirm} confirmOf={password} />\n </Card>\n );\n}\n"
70
90
  },
71
91
  {
72
92
  "name": "SignIn",
73
93
  "title": "Sign In",
74
- "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { PasswordInput } from '@/components/ui/password-input';\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 SignIn() {\n const { colors } = useKit();\n return (\n <Card title=\"Welcome back\">\n <FloatingInput label=\"Email\" defaultValue=\"maya@studio.io\" keyboardType=\"email-address\" autoCapitalize=\"none\" />\n <PasswordInput label=\"Password\" strength={false} defaultValue=\"correct horse\" />\n <Text style={{ alignSelf: 'flex-end', fontSize: 13, fontWeight: '400', color: colors.accent }}>Forgot password?</Text>\n </Card>\n );\n}\n"
94
+ "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { PasswordInput } from '@/components/ui/password-input';\nimport { 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\nfunction Card({ title, subtitle, screen, children }: { title: string; subtitle?: string; screen?: boolean; children: React.ReactNode }) {\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 : {\n borderRadius: radius.xl,\n borderWidth: StyleSheet.hairlineWidth,\n borderColor: colors.border,\n backgroundColor: colors.card,\n },\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 SignIn({ screen }: DemoProps) {\n const { colors } = useKit();\n return (\n <Card screen={screen} title=\"Welcome back\">\n <FloatingInput label=\"Email\" defaultValue=\"maya@studio.io\" keyboardType=\"email-address\" autoCapitalize=\"none\" />\n <PasswordInput label=\"Password\" strength={false} defaultValue=\"correct horse\" />\n <Text style={{ alignSelf: 'flex-end', fontSize: 13, fontWeight: '400', color: colors.accent }}>Forgot password?</Text>\n </Card>\n );\n}\n"
75
95
  },
76
96
  {
77
97
  "name": "StrengthMeter",
@@ -81,7 +101,7 @@
81
101
  {
82
102
  "name": "CustomRules",
83
103
  "title": "Custom Rules",
84
- "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { PasswordInput } from '@/components/ui/password-input';\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 CustomRules() {\n return (\n <Card title=\"Wi-Fi password\" subtitle=\"Your router needs 12+ characters and no spaces.\">\n <PasswordInput\n variant=\"filled\"\n label=\"Network password\"\n strength={false}\n defaultValue=\"cafe latte\"\n requirements={[\n { label: '12+ characters', test: (v) => v.length >= 12 },\n { label: 'No spaces', test: (v) => v.length > 0 && !/\\s/.test(v) },\n ]}\n />\n </Card>\n );\n}\n"
104
+ "code": "import React, { useState } from 'react';\nimport { StyleSheet, Text, View } from 'react-native';\nimport { PasswordInput } from '@/components/ui/password-input';\nimport { 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\nfunction Card({ title, subtitle, screen, children }: { title: string; subtitle?: string; screen?: boolean; children: React.ReactNode }) {\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 : {\n borderRadius: radius.xl,\n borderWidth: StyleSheet.hairlineWidth,\n borderColor: colors.border,\n backgroundColor: colors.card,\n },\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 CustomRules({ screen }: DemoProps) {\n return (\n <Card screen={screen} title=\"Wi-Fi password\" subtitle=\"Your router needs 12+ characters and no spaces.\">\n <PasswordInput\n variant=\"filled\"\n label=\"Network password\"\n strength={false}\n defaultValue=\"cafe latte\"\n requirements={[\n { label: '12+ characters', test: (v) => v.length >= 12 },\n { label: 'No spaces', test: (v) => v.length > 0 && !/\\s/.test(v) },\n ]}\n />\n </Card>\n );\n}\n"
85
105
  },
86
106
  {
87
107
  "name": "WrongPassword",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/payment-card.tsx"
8
8
  ],
9
+ "summary": "A bank card that tilts toward your finger and flips on tap to its back.",
9
10
  "props": [
10
11
  [
11
12
  "number",
@@ -128,6 +129,21 @@
128
129
  "Style for the root (width, margins)."
129
130
  ]
130
131
  ],
132
+ "behavior": [
133
+ [
134
+ "Touch",
135
+ "A tap flips the card to its back (stripe, signature panel, CVV, hologram); frozen cards ignore taps. flippable={false} makes a still card for use inside something tappable."
136
+ ],
137
+ [
138
+ "Motion",
139
+ "With tilt on, the card leans toward the finger with a soft glare, and its shadow narrows as it turns edge-on mid-flip."
140
+ ],
141
+ [
142
+ "Screen readers",
143
+ "Read as '{bank} card ending {last4}', plus 'Frozen' when frozen. The number is masked to the last four digits by default."
144
+ ]
145
+ ],
146
+ "usage": "import { PaymentCard } from '@/components/ui/payment-card';\n\n<PaymentCard\n bank=\"Northwind\"\n number=\"5412 7590 1234 0317\"\n name=\"Maya Patel\"\n expiry=\"09/29\"\n brand=\"mastercard\"\n/>",
131
147
  "examples": [
132
148
  {
133
149
  "name": "WalletScreen",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/charts/pixel-bar.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -62,5 +63,7 @@
62
63
  "Fade colour upwards."
63
64
  ]
64
65
  ],
66
+ "behavior": [],
67
+ "usage": null,
65
68
  "examples": []
66
69
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/charts/polar-area.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -74,5 +75,7 @@
74
75
  "Grid circles."
75
76
  ]
76
77
  ],
78
+ "behavior": [],
79
+ "usage": null,
77
80
  "examples": []
78
81
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/blocks/profile.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "user",
@@ -80,5 +81,7 @@
80
81
  "Root style."
81
82
  ]
82
83
  ],
84
+ "behavior": [],
85
+ "usage": null,
83
86
  "examples": []
84
87
  }