@expokit/cli 0.2.0 → 0.3.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 (110) hide show
  1. package/README.md +14 -0
  2. package/bin/expo-kit.js +86 -24
  3. package/bin/mcp.mjs +8 -1
  4. package/package.json +8 -3
  5. package/registry/_docs/accordion.json +16 -0
  6. package/registry/_docs/action-sheet.json +28 -0
  7. package/registry/_docs/alert.json +28 -0
  8. package/registry/_docs/avatar.json +24 -0
  9. package/registry/_docs/badge.json +35 -4
  10. package/registry/_docs/bottom-nav.json +24 -0
  11. package/registry/_docs/bottom-sheet.json +28 -0
  12. package/registry/_docs/bullet.json +3 -0
  13. package/registry/_docs/button-3d.json +16 -0
  14. package/registry/_docs/button.json +16 -0
  15. package/registry/_docs/calendar.json +16 -0
  16. package/registry/_docs/card-stack.json +16 -0
  17. package/registry/_docs/card.json +20 -0
  18. package/registry/_docs/carousel.json +20 -0
  19. package/registry/_docs/chat.json +184 -0
  20. package/registry/_docs/checkbox.json +16 -0
  21. package/registry/_docs/checkout.json +3 -0
  22. package/registry/_docs/chip-group.json +16 -0
  23. package/registry/_docs/color-swatch.json +16 -0
  24. package/registry/_docs/confetti.json +20 -0
  25. package/registry/_docs/coupon.json +16 -0
  26. package/registry/_docs/cube-pager.json +16 -0
  27. package/registry/_docs/dashboard.json +3 -0
  28. package/registry/_docs/date-picker.json +20 -0
  29. package/registry/_docs/dialog.json +24 -0
  30. package/registry/_docs/drawer.json +28 -0
  31. package/registry/_docs/fab.json +24 -0
  32. package/registry/_docs/flip-card.json +16 -0
  33. package/registry/_docs/floating-input.json +20 -0
  34. package/registry/_docs/gift-card.json +16 -0
  35. package/registry/_docs/glass-button.json +24 -0
  36. package/registry/_docs/glass-nav-bar.json +24 -0
  37. package/registry/_docs/glass-search-bar.json +24 -0
  38. package/registry/_docs/glass-segmented.json +28 -0
  39. package/registry/_docs/glass-sheet.json +28 -0
  40. package/registry/_docs/glass-tab-bar.json +24 -0
  41. package/registry/_docs/glass.json +16 -0
  42. package/registry/_docs/inbox.json +3 -0
  43. package/registry/_docs/isometric-bar.json +3 -0
  44. package/registry/_docs/kit.json +3 -0
  45. package/registry/_docs/kpi-card.json +3 -0
  46. package/registry/_docs/like-button.json +20 -0
  47. package/registry/_docs/liquidglass-tab.json +3 -0
  48. package/registry/_docs/list-item.json +16 -0
  49. package/registry/_docs/loyalty-card.json +16 -0
  50. package/registry/_docs/morph-button.json +20 -0
  51. package/registry/_docs/number-ticker.json +16 -0
  52. package/registry/_docs/offers.json +3 -0
  53. package/registry/_docs/onboarding.json +3 -0
  54. package/registry/_docs/otp-input.json +24 -0
  55. package/registry/_docs/pagination-dots.json +20 -0
  56. package/registry/_docs/parallax-layers.json +20 -0
  57. package/registry/_docs/parallax-scroll.json +24 -0
  58. package/registry/_docs/password-input.json +20 -0
  59. package/registry/_docs/payment-card.json +16 -0
  60. package/registry/_docs/pixel-bar.json +3 -0
  61. package/registry/_docs/polar-area.json +3 -0
  62. package/registry/_docs/profile.json +3 -0
  63. package/registry/_docs/progress-steps.json +24 -0
  64. package/registry/_docs/progress.json +20 -0
  65. package/registry/_docs/radio-group.json +20 -0
  66. package/registry/_docs/rating.json +24 -0
  67. package/registry/_docs/ring-carousel.json +20 -0
  68. package/registry/_docs/scratch-card.json +20 -0
  69. package/registry/_docs/search-bar.json +20 -0
  70. package/registry/_docs/search-results.json +3 -0
  71. package/registry/_docs/segmented-control.json +20 -0
  72. package/registry/_docs/select.json +26 -1
  73. package/registry/_docs/settings.json +3 -0
  74. package/registry/_docs/shimmer-button.json +20 -0
  75. package/registry/_docs/sign-in.json +3 -0
  76. package/registry/_docs/skeleton.json +20 -0
  77. package/registry/_docs/slide-to-confirm.json +24 -0
  78. package/registry/_docs/slider.json +21 -1
  79. package/registry/_docs/spin-wheel.json +24 -0
  80. package/registry/_docs/spinner.json +41 -11
  81. package/registry/_docs/stateful-button.json +184 -0
  82. package/registry/_docs/stepper.json +16 -0
  83. package/registry/_docs/swipe-deck.json +16 -0
  84. package/registry/_docs/swipeable-row.json +24 -1
  85. package/registry/_docs/switch.json +20 -0
  86. package/registry/_docs/tabs.json +24 -0
  87. package/registry/_docs/tag-input.json +20 -0
  88. package/registry/_docs/text-animation.json +141 -0
  89. package/registry/_docs/textarea.json +16 -0
  90. package/registry/_docs/ticket-card.json +20 -0
  91. package/registry/_docs/ticket-shape.json +3 -0
  92. package/registry/_docs/tilt-card.json +16 -0
  93. package/registry/_docs/time-picker.json +16 -0
  94. package/registry/_docs/timeline-chart.json +3 -0
  95. package/registry/_docs/timeline.json +16 -0
  96. package/registry/_docs/toast.json +24 -0
  97. package/registry/_docs/treemap.json +3 -0
  98. package/registry/_docs/waterfall.json +3 -0
  99. package/registry/_docs/wheel-list.json +20 -0
  100. package/registry/badge/files/src/components/ui/badge.tsx +327 -17
  101. package/registry/badge.json +1 -1
  102. package/registry/chat.json +18 -0
  103. package/registry/spinner/files/src/components/ui/spinner.tsx +435 -22
  104. package/registry/spinner.json +1 -1
  105. package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +532 -0
  106. package/registry/stateful-button/files/src/lib/kit.tsx +219 -0
  107. package/registry/stateful-button.json +18 -0
  108. package/registry/text-animation/files/src/components/ui/text-animation.tsx +650 -0
  109. package/registry/text-animation/files/src/lib/kit.tsx +219 -0
  110. package/registry/text-animation.json +15 -0
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/tabs.tsx"
8
8
  ],
9
+ "summary": "Underline tabs whose indicator moves like liquid, leading edge first.",
9
10
  "props": [
10
11
  [
11
12
  "items",
@@ -80,6 +81,29 @@
80
81
  "Style for the root view wrapping the tab bar and content."
81
82
  ]
82
83
  ],
84
+ "behavior": [
85
+ [
86
+ "Touch",
87
+ "Tap a tab or drag the content panes sideways; the underline follows your finger, with rubber-band resistance at the ends."
88
+ ],
89
+ [
90
+ "Motion",
91
+ "The underline is measured to each label and springs with the leading edge first. Badges pop, and an overflowing bar scrolls to centre the active tab."
92
+ ],
93
+ [
94
+ "Reduced motion",
95
+ "Springs become short timings, the bar scrolls without animating and badges change without the pop."
96
+ ],
97
+ [
98
+ "Haptics",
99
+ "A selection tick on every change; turn it off with haptics={false}."
100
+ ],
101
+ [
102
+ "Screen readers",
103
+ "The bar is a tablist of tabs with selected and disabled state; badges are read with the label, and inactive panes are hidden."
104
+ ]
105
+ ],
106
+ "usage": "import { Tabs } from '@/components/ui/tabs';\n\n<Tabs\n items={[\n { value: 'overview', label: 'Overview', content: <Overview /> },\n { value: 'reviews', label: 'Reviews', badge: 128, content: <Reviews /> },\n ]}\n/>",
83
107
  "examples": [
84
108
  {
85
109
  "name": "Underline",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/tag-input.tsx"
8
8
  ],
9
+ "summary": "Chips that spring in on Enter or comma and shrink away as neighbours slide over.",
9
10
  "props": [
10
11
  [
11
12
  "value / defaultValue",
@@ -98,6 +99,25 @@
98
99
  "placeholder, keyboardType, …"
99
100
  ]
100
101
  ],
102
+ "behavior": [
103
+ [
104
+ "Keyboard",
105
+ "Enter or a separator commits the text as a chip. Backspace in an empty field highlights the last chip, and a second press removes it."
106
+ ],
107
+ [
108
+ "Motion",
109
+ "Chips pop in on a spring and shrink out on removal; duplicates bump and a rejected tag shakes the field."
110
+ ],
111
+ [
112
+ "Screen readers",
113
+ "Each chip has a 'Remove' button and each suggestion an 'Add' button; error messages land in a polite live region and the counter reads '3 of 5 tags'."
114
+ ],
115
+ [
116
+ "Web",
117
+ "The browser focus outline on the input is removed; the field draws its own focus state."
118
+ ]
119
+ ],
120
+ "usage": "import { useState } from 'react';\nimport { TagInput } from '@/components/ui/tag-input';\n\nconst [skills, setSkills] = useState(['TypeScript']);\n<TagInput value={skills} onChange={setSkills} placeholder=\"Add a skill…\" suggestions={['React', 'Swift', 'Kotlin']} />",
101
121
  "examples": [
102
122
  {
103
123
  "name": "Skills",
@@ -0,0 +1,141 @@
1
+ {
2
+ "name": "text-animation",
3
+ "category": "Motion",
4
+ "aliases": [
5
+ "text-effect",
6
+ "animated-text",
7
+ "typewriter",
8
+ "shimmer-text",
9
+ "scramble-text"
10
+ ],
11
+ "exportName": "AnimatedText",
12
+ "files": [
13
+ "src/components/ui/text-animation.tsx"
14
+ ],
15
+ "summary": "Reveal, shimmer, cascade, scramble and typewriter text effects.",
16
+ "props": [
17
+ [
18
+ "children",
19
+ "string",
20
+ "—",
21
+ "The text to animate."
22
+ ],
23
+ [
24
+ "variant",
25
+ "\"reveal\" | \"shimmer\" | \"cascade\" | \"scramble\" | \"typewriter\"",
26
+ "\"reveal\"",
27
+ "Which effect to play."
28
+ ],
29
+ [
30
+ "trigger",
31
+ "\"mount\" | \"change\"",
32
+ "\"change\" for cascade / typewriter, else \"mount\"",
33
+ "Animate once on mount, or also every time the text changes. A typewriter keeps typing when the new text extends the old (streaming)."
34
+ ],
35
+ [
36
+ "delay",
37
+ "number",
38
+ "0",
39
+ "ms before the first animation."
40
+ ],
41
+ [
42
+ "stagger",
43
+ "number",
44
+ "70 reveal · 80 shimmer · 28 cascade · 45 scramble · 32 typewriter",
45
+ "ms between words (reveal) or letters. Shimmer: ms of sweep per letter."
46
+ ],
47
+ [
48
+ "speed",
49
+ "number",
50
+ "1",
51
+ "Speed multiplier: 2 plays twice as fast."
52
+ ],
53
+ [
54
+ "color",
55
+ "string",
56
+ "theme foreground",
57
+ "Text colour."
58
+ ],
59
+ [
60
+ "caret",
61
+ "boolean",
62
+ "true",
63
+ "Blinking caret for the typewriter."
64
+ ],
65
+ [
66
+ "replayKey",
67
+ "string | number",
68
+ "—",
69
+ "Change it to replay the animation."
70
+ ],
71
+ [
72
+ "onComplete",
73
+ "() => void",
74
+ "—",
75
+ "Called when an animation finishes (not for the looping shimmer)."
76
+ ],
77
+ [
78
+ "textStyle",
79
+ "StyleProp<TextStyle>",
80
+ "—",
81
+ "fontSize, fontWeight, lineHeight, letterSpacing, textAlign… for every letter."
82
+ ],
83
+ [
84
+ "style",
85
+ "StyleProp<ViewStyle>",
86
+ "—",
87
+ "Style for the root view."
88
+ ]
89
+ ],
90
+ "behavior": [
91
+ [
92
+ "Motion",
93
+ "Reveal, shimmer and cascade run one native-driver clock per animation with spring curves pre-sampled into interpolations; scramble and typewriter use a light JS timer. Text wraps by word."
94
+ ],
95
+ [
96
+ "Reduced motion",
97
+ "Shows the final text immediately; shimmer stays static and the typewriter caret is hidden."
98
+ ],
99
+ [
100
+ "Screen readers",
101
+ "The whole string is one text element; the per-letter views are hidden. Cascade and typewriter announce new text when it changes (typewriter once streaming settles)."
102
+ ],
103
+ [
104
+ "Platforms",
105
+ "iOS, Android and web. Arabic, Hebrew, Indic, Thai and other connected scripts animate a word at a time so shaping is never broken; right-to-left text flows from the right."
106
+ ]
107
+ ],
108
+ "usage": "import { AnimatedText } from '@/components/ui/text-animation';\n\n<AnimatedText textStyle={{ fontSize: 28, fontWeight: '600' }}>\n Ship native apps that feel alive.\n</AnimatedText>\n\n<AnimatedText variant=\"shimmer\">Thinking…</AnimatedText>\n<AnimatedText variant=\"cascade\">{status}</AnimatedText>",
109
+ "examples": [
110
+ {
111
+ "name": "Reveal",
112
+ "title": "Reveal",
113
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nfunction Chip({ label, onPress }: { label: string; onPress: () => void }) {\n const { colors, radius } = useKit();\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n hitSlop={4}\n style={{ height: 36, paddingHorizontal: 14, borderRadius: radius.capsule(36), justifyContent: 'center', alignSelf: 'flex-start', backgroundColor: colors.muted }}\n >\n <Text style={{ color: colors.foreground, fontSize: 14 }}>{label}</Text>\n </Pressable>\n );\n}\n\nexport default function Reveal() {\n const [run, setRun] = useState(0);\n return (\n <View style={{ gap: 16 }}>\n <AnimatedText replayKey={run} textStyle={{ fontSize: 30, fontWeight: '600', letterSpacing: -0.8, lineHeight: 36 }}>\n Ship native apps that feel alive.\n </AnimatedText>\n <Chip label=\"Replay\" onPress={() => setRun((r) => r + 1)} />\n </View>\n );\n}\n"
114
+ },
115
+ {
116
+ "name": "Thinking",
117
+ "title": "Thinking",
118
+ "code": "import { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nexport default function Thinking() {\n const { colors, radius } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 10, padding: 14, borderRadius: radius.lg, backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border }}>\n <View style={{ width: 28, height: 28, borderRadius: radius.capsule(28), backgroundColor: colors.accent }} />\n <AnimatedText variant=\"shimmer\" textStyle={{ fontSize: 16 }}>\n Thinking…\n </AnimatedText>\n </View>\n );\n}\n"
119
+ },
120
+ {
121
+ "name": "DeployStatus",
122
+ "title": "Deploy Status",
123
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nfunction Chip({ label, onPress }: { label: string; onPress: () => void }) {\n const { colors, radius } = useKit();\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n hitSlop={4}\n style={{ height: 36, paddingHorizontal: 14, borderRadius: radius.capsule(36), justifyContent: 'center', alignSelf: 'flex-start', backgroundColor: colors.muted }}\n >\n <Text style={{ color: colors.foreground, fontSize: 14 }}>{label}</Text>\n </Pressable>\n );\n}\n\nconst STATUSES = ['Queued', 'Building', 'Deploying', 'Live'];\n\nexport default function DeployStatus() {\n const { colors, radius } = useKit();\n const [i, setI] = useState(0);\n const status = STATUSES[i];\n const live = status === 'Live';\n return (\n <View style={{ gap: 16 }}>\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>\n <View style={{ width: 10, height: 10, borderRadius: radius.capsule(10), backgroundColor: live ? colors.success : colors.warning }} />\n <Text style={{ fontSize: 17, color: colors.mutedForeground }}>expokit.dev</Text>\n <AnimatedText variant=\"cascade\" color={live ? colors.success : colors.foreground} textStyle={{ fontSize: 17, fontWeight: '600' }}>\n {status}\n </AnimatedText>\n </View>\n <Chip label=\"Next status\" onPress={() => setI((n) => (n + 1) % STATUSES.length)} />\n </View>\n );\n}\n"
124
+ },
125
+ {
126
+ "name": "Scramble",
127
+ "title": "Scramble",
128
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nfunction Chip({ label, onPress }: { label: string; onPress: () => void }) {\n const { colors, radius } = useKit();\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n hitSlop={4}\n style={{ height: 36, paddingHorizontal: 14, borderRadius: radius.capsule(36), justifyContent: 'center', alignSelf: 'flex-start', backgroundColor: colors.muted }}\n >\n <Text style={{ color: colors.foreground, fontSize: 14 }}>{label}</Text>\n </Pressable>\n );\n}\n\nexport default function Scramble() {\n const { colors, font } = useKit();\n const [run, setRun] = useState(0);\n return (\n <View style={{ gap: 16 }}>\n <View style={{ gap: 4 }}>\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>Your referral code</Text>\n <AnimatedText variant=\"scramble\" replayKey={run} textStyle={{ fontSize: 28, fontWeight: '600', letterSpacing: 2, fontFamily: font.mono }}>\n SPRING-7Q2X\n </AnimatedText>\n </View>\n <Chip label=\"Generate again\" onPress={() => setRun((r) => r + 1)} />\n </View>\n );\n}\n"
129
+ },
130
+ {
131
+ "name": "Streaming",
132
+ "title": "Streaming",
133
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nfunction Chip({ label, onPress }: { label: string; onPress: () => void }) {\n const { colors, radius } = useKit();\n return (\n <Pressable\n accessibilityRole=\"button\"\n onPress={onPress}\n hitSlop={4}\n style={{ height: 36, paddingHorizontal: 14, borderRadius: radius.capsule(36), justifyContent: 'center', alignSelf: 'flex-start', backgroundColor: colors.muted }}\n >\n <Text style={{ color: colors.foreground, fontSize: 14 }}>{label}</Text>\n </Pressable>\n );\n}\n\nconst ANSWER =\n 'Spring animations feel natural because they keep momentum: a flick carries its speed into the motion, and nothing stops dead.';\n\nexport default function Streaming() {\n const { colors, radius } = useKit();\n const [text, setText] = useState('');\n const [run, setRun] = useState(0);\n useEffect(() => {\n // Simulates tokens arriving from a model, a few words at a time.\n const words = ANSWER.split(' ');\n let n = 0;\n const id = setInterval(() => {\n n = Math.min(words.length, n + 1 + Math.floor(Math.random() * 3));\n setText(words.slice(0, n).join(' '));\n if (n >= words.length) clearInterval(id);\n }, 260);\n return () => clearInterval(id);\n }, [run]);\n return (\n <View style={{ gap: 16 }}>\n <View style={{ padding: 14, borderRadius: radius.lg, backgroundColor: colors.muted }}>\n <AnimatedText key={run} variant=\"typewriter\" textStyle={{ fontSize: 16, lineHeight: 23 }}>\n {text}\n </AnimatedText>\n </View>\n <Chip\n label=\"Ask again\"\n onPress={() => {\n setText('');\n setRun((r) => r + 1);\n }}\n />\n </View>\n );\n}\n"
134
+ },
135
+ {
136
+ "name": "Hero",
137
+ "title": "Hero",
138
+ "code": "import React, { useEffect, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { AnimatedText } from '@/components/ui/text-animation';\nimport { useKit } from '@/lib/kit';\n\nexport default function Hero() {\n const { colors } = useKit();\n const [run, setRun] = useState(0);\n return (\n <Pressable accessibilityRole=\"button\" accessibilityHint=\"Replays the animation\" onPress={() => setRun((r) => r + 1)} style={{ alignItems: 'center', gap: 10, paddingVertical: 12 }}>\n <AnimatedText variant=\"scramble\" replayKey={run} color={colors.accent} style={{ alignSelf: 'stretch' }} textStyle={{ fontSize: 13, fontWeight: '600', letterSpacing: 1.5, textAlign: 'center' }}>\n NEW IN EXPOKIT\n </AnimatedText>\n <AnimatedText replayKey={run} delay={250} style={{ alignSelf: 'stretch' }} textStyle={{ fontSize: 34, fontWeight: '700', letterSpacing: -1, lineHeight: 40, textAlign: 'center' }}>\n Motion your users can feel\n </AnimatedText>\n <AnimatedText variant=\"typewriter\" replayKey={run} delay={900} caret={false} style={{ alignSelf: 'stretch' }} color={colors.mutedForeground} textStyle={{ fontSize: 15, textAlign: 'center' }}>\n Tap anywhere to play it again.\n </AnimatedText>\n </Pressable>\n );\n}\n"
139
+ }
140
+ ]
141
+ }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/textarea.tsx"
8
8
  ],
9
+ "summary": "A multiline field that glides taller line by line, with a ring-style counter.",
9
10
  "props": [
10
11
  [
11
12
  "label",
@@ -140,6 +141,21 @@
140
141
  "value, defaultValue, onChangeText, placeholder, …"
141
142
  ]
142
143
  ],
144
+ "behavior": [
145
+ [
146
+ "Motion",
147
+ "The box grows smoothly between minRows and maxRows as you type; the label floats up on focus and a halo glows around the field."
148
+ ],
149
+ [
150
+ "Screen readers",
151
+ "The input is labelled by label or placeholder; the counter reads like '42 of 200 characters left' and error / success messages land in a polite live region."
152
+ ],
153
+ [
154
+ "Web",
155
+ "The browser focus outline is removed; the field draws its own focus halo."
156
+ ]
157
+ ],
158
+ "usage": "import { useState } from 'react';\nimport { Textarea } from '@/components/ui/textarea';\n\nconst [review, setReview] = useState('');\n<Textarea label=\"Your review\" value={review} onChangeText={setReview} maxLength={200} />",
143
159
  "examples": [
144
160
  {
145
161
  "name": "Composer",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/ticket-card.tsx"
8
8
  ],
9
+ "summary": "A boarding pass or event ticket with real notches and a stub you can tear off.",
9
10
  "props": [
10
11
  [
11
12
  "brand / logo",
@@ -170,5 +171,24 @@
170
171
  "Style for the root (width, margins)."
171
172
  ]
172
173
  ],
174
+ "behavior": [
175
+ [
176
+ "Touch",
177
+ "The card tilts toward your finger (tilt={false} turns it off). Tap to flip it to the big code and notes; with onTear set, swipe the stub sideways to tear it off."
178
+ ],
179
+ [
180
+ "Motion",
181
+ "A holo badge shimmers as the card leans, a stamp thumps down when set, and a torn stub falls away along the tear line."
182
+ ],
183
+ [
184
+ "Haptics",
185
+ "A success notification when the stub tears off."
186
+ ],
187
+ [
188
+ "Screen readers",
189
+ "One element whose label joins the brand, title or route, every field and the stamp; it is a button when there is a back to flip to."
190
+ ]
191
+ ],
192
+ "usage": null,
173
193
  "examples": []
174
194
  }
@@ -6,6 +6,9 @@
6
6
  "files": [
7
7
  "src/lib/ticket-shape.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [],
11
+ "behavior": [],
12
+ "usage": null,
10
13
  "examples": []
11
14
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/tilt-card.tsx"
8
8
  ],
9
+ "summary": "A card that leans toward your finger in 3D while a glare slides across it.",
9
10
  "props": [
10
11
  [
11
12
  "children",
@@ -116,6 +117,21 @@
116
117
  "The card's live tilt values (native-driver friendly) for your own effects."
117
118
  ]
118
119
  ],
120
+ "behavior": [
121
+ [
122
+ "Touch",
123
+ "Press and drag to tilt up to maxTilt degrees; the card scales by pressScale and springs flat on release. onPress fires on a tap, not after a drag."
124
+ ],
125
+ [
126
+ "Motion",
127
+ "The shadow slides away from the light and the glare (soft, sharp or holo) glides across. TiltLayer children float at their own depth, and idle makes it sway gently at rest."
128
+ ],
129
+ [
130
+ "Screen readers",
131
+ "Exposed as one element when it has onPress or accessibilityLabel; with onPress it is a button with an 'activate' action."
132
+ ]
133
+ ],
134
+ "usage": "import { TiltCard, TiltLayer } from '@/components/ui/tilt-card';\n\n<TiltCard image={{ uri: photoUrl }} idle accessibilityLabel=\"Manarola, Cinque Terre\" style={{ width: 270, height: 360 }}>\n <TiltLayer depth={1}>\n <PlaceCaption place={place} />\n </TiltLayer>\n</TiltCard>",
119
135
  "examples": [
120
136
  {
121
137
  "name": "TravelCard",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/time-picker.tsx"
8
8
  ],
9
+ "summary": "A time picker as 3D wheel drums, a draggable clock dial or bookable time chips.",
9
10
  "props": [
10
11
  [
11
12
  "value",
@@ -218,6 +219,21 @@
218
219
  "Sheet: the sheet / dialog panel — background, border, radius, padding, shadow (transform and opacity are animated)."
219
220
  ]
220
221
  ],
222
+ "behavior": [
223
+ [
224
+ "Touch",
225
+ "Wheel drums snap with momentum and a tapped row jumps into the band. On the clock, drag the hand anywhere on the dial; it snaps to hours, then moves on to minutes when you let go."
226
+ ],
227
+ [
228
+ "Motion",
229
+ "Wheel rows tilt, shrink and fade past the selection band, driven by scroll on the native driver; the clock header crossfades between hours and minutes."
230
+ ],
231
+ [
232
+ "Screen readers",
233
+ "Each wheel column and the clock dial are adjustable with increment / decrement actions; AM / PM and the time chips are radio groups, with booked or unavailable slots named. The sheet field is a button with expanded state."
234
+ ]
235
+ ],
236
+ "usage": "import { useState } from 'react';\nimport { TimePicker, type TimeValue } from '@/components/ui/time-picker';\n\nconst [time, setTime] = useState<TimeValue | null>({ hours: 7, minutes: 30 });\n<TimePicker value={time} onChange={setTime} hour12 />",
221
237
  "examples": [
222
238
  {
223
239
  "name": "Alarm",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/charts/timeline-chart.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -26,5 +27,7 @@
26
27
  "Axis labels."
27
28
  ]
28
29
  ],
30
+ "behavior": [],
31
+ "usage": null,
29
32
  "examples": []
30
33
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/timeline.tsx"
8
8
  ],
9
+ "summary": "A vertical timeline whose connector fills down to the current step as dots check off.",
9
10
  "props": [
10
11
  [
11
12
  "items",
@@ -116,6 +117,21 @@
116
117
  "Root style — for variant=\"scroll\" this is the scroll view, so set a height."
117
118
  ]
118
119
  ],
120
+ "behavior": [
121
+ [
122
+ "Motion",
123
+ "Items rise in, then the line fills to the current step: done dots draw their check as it arrives and the current dot pulses. The scroll variant ties the fill to the scroll position."
124
+ ],
125
+ [
126
+ "Reduced motion",
127
+ "Everything renders in its final state with no rise, fill or pulse, the same as animated={false}."
128
+ ],
129
+ [
130
+ "Screen readers",
131
+ "The timeline is a list; each entry is read as its title, time, description and status, and links are exposed as links."
132
+ ]
133
+ ],
134
+ "usage": "import { Timeline } from '@/components/ui/timeline';\n\n<Timeline\n items={[\n { title: 'Order placed', time: '9:41 AM', status: 'done' },\n { title: 'Out for delivery', time: '1:15 PM', status: 'current' },\n { title: 'Delivered', status: 'upcoming' },\n ]}\n/>",
119
135
  "examples": [
120
136
  {
121
137
  "name": "OrderTracking",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/toast.tsx"
8
8
  ],
9
+ "summary": "Sonner-style toasts whose tone icon draws itself while a hairline drains away.",
9
10
  "props": [
10
11
  [
11
12
  "toast(title, options?)",
@@ -116,6 +117,29 @@
116
117
  "Style for the <Toaster> host that fills the screen and positions the stack."
117
118
  ]
118
119
  ],
120
+ "behavior": [
121
+ [
122
+ "Touch",
123
+ "Tap the stack to fan it out, swipe a toast sideways or toward the edge to dismiss it; timers and the drain line pause while you touch."
124
+ ],
125
+ [
126
+ "Motion",
127
+ "Tone icons draw their outline inside a halo; toast.promise() closes the spinning arc into the success or error mark. variant=\"island\" morphs like a Dynamic Island."
128
+ ],
129
+ [
130
+ "Reduced motion",
131
+ "Tone icons appear fully drawn without the spin or pop, and the island skips its squash and staggered morph."
132
+ ],
133
+ [
134
+ "Haptics",
135
+ "A success, warning or error notification when a toast of that type appears, landing as the loading circle closes; turn it off with haptics={false}."
136
+ ],
137
+ [
138
+ "Screen readers",
139
+ "Each toast is an alert in a polite live region, labelled by its title and description, with action and Dismiss buttons."
140
+ ]
141
+ ],
142
+ "usage": "import { toast, Toaster } from '@/components/ui/toast';\n\n// once, at the root of your app\n<Toaster />\n\n// anywhere\ntoast.success('Invoice INV-0042 sent', { description: 'Maya will get it by email.' });",
119
143
  "examples": [
120
144
  {
121
145
  "name": "Default",
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/charts/treemap.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -26,5 +27,7 @@
26
27
  "Tile colours."
27
28
  ]
28
29
  ],
30
+ "behavior": [],
31
+ "usage": null,
29
32
  "examples": []
30
33
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/charts/waterfall.tsx"
8
8
  ],
9
+ "summary": null,
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -32,5 +33,7 @@
32
33
  "Change labels."
33
34
  ]
34
35
  ],
36
+ "behavior": [],
37
+ "usage": null,
35
38
  "examples": []
36
39
  }
@@ -6,6 +6,7 @@
6
6
  "files": [
7
7
  "src/components/ui/wheel-list.tsx"
8
8
  ],
9
+ "summary": "An iOS alarm-style picker whose rows curve away on a 3D cylinder.",
9
10
  "props": [
10
11
  [
11
12
  "data",
@@ -98,5 +99,24 @@
98
99
  "Style for the root (width)."
99
100
  ]
100
101
  ],
102
+ "behavior": [
103
+ [
104
+ "Touch",
105
+ "Flick to spin and it snaps to a row; tap a row to scroll it into the band."
106
+ ],
107
+ [
108
+ "Motion",
109
+ "Each row rotates, scales and fades by its distance from the band, interpolated from the scroll position on the native driver."
110
+ ],
111
+ [
112
+ "Screen readers",
113
+ "One adjustable element with increment / decrement actions; its value is the selected label, or \"3 / 12\" for custom rows."
114
+ ],
115
+ [
116
+ "Web",
117
+ "Browsers lack snap momentum, so it settles on the nearest row shortly after scrolling stops."
118
+ ]
119
+ ],
120
+ "usage": null,
101
121
  "examples": []
102
122
  }