@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.
- package/README.md +20 -2
- package/bin/expo-kit.js +219 -44
- package/bin/lib.mjs +110 -1
- package/bin/mcp.mjs +48 -19
- package/package.json +9 -4
- package/registry/_docs/accordion.json +16 -0
- package/registry/_docs/action-sheet.json +28 -0
- package/registry/_docs/alert.json +28 -0
- package/registry/_docs/assistant-app.json +47 -0
- package/registry/_docs/avatar.json +25 -1
- package/registry/_docs/badge.json +36 -5
- package/registry/_docs/bottom-nav.json +30 -6
- package/registry/_docs/bottom-sheet.json +28 -0
- package/registry/_docs/bullet.json +3 -0
- package/registry/_docs/button-3d.json +18 -2
- package/registry/_docs/button.json +16 -0
- package/registry/_docs/calendar.json +21 -5
- package/registry/_docs/card-stack.json +16 -0
- package/registry/_docs/card.json +20 -0
- package/registry/_docs/carousel.json +20 -0
- package/registry/_docs/chat.json +184 -0
- package/registry/_docs/checkbox.json +16 -0
- package/registry/_docs/checkout.json +10 -1
- package/registry/_docs/chip-group.json +16 -0
- package/registry/_docs/confetti.json +23 -3
- package/registry/_docs/coupon.json +16 -0
- package/registry/_docs/cube-pager.json +16 -0
- package/registry/_docs/dashboard.json +3 -0
- package/registry/_docs/date-picker.json +24 -4
- package/registry/_docs/dialog.json +24 -0
- package/registry/_docs/donut-shop.json +88 -0
- package/registry/_docs/drawer.json +32 -4
- package/registry/_docs/fab.json +24 -0
- package/registry/_docs/fintech-app.json +49 -0
- package/registry/_docs/flip-card.json +16 -0
- package/registry/_docs/floating-input.json +25 -5
- package/registry/_docs/food-app.json +47 -0
- package/registry/_docs/gift-card.json +16 -0
- package/registry/_docs/glass-button.json +24 -0
- package/registry/_docs/glass-nav-bar.json +24 -0
- package/registry/_docs/glass-search-bar.json +24 -0
- package/registry/_docs/glass-segmented.json +28 -0
- package/registry/_docs/glass-sheet.json +28 -0
- package/registry/_docs/glass-tab-bar.json +24 -0
- package/registry/_docs/glass.json +17 -1
- package/registry/_docs/grain.json +80 -0
- package/registry/_docs/inbox.json +3 -0
- package/registry/_docs/isometric-bar.json +3 -0
- package/registry/_docs/kit.json +3 -0
- package/registry/_docs/liquidglass-tab.json +3 -0
- package/registry/_docs/list-item.json +16 -0
- package/registry/_docs/loyalty-card.json +16 -0
- package/registry/_docs/morphing-button-group.json +96 -0
- package/registry/_docs/number-ticker.json +16 -0
- package/registry/_docs/offers.json +3 -0
- package/registry/_docs/onboarding.json +3 -0
- package/registry/_docs/orb-reveal.json +132 -0
- package/registry/_docs/otp-input.json +28 -4
- package/registry/_docs/parallax-layers.json +20 -0
- package/registry/_docs/parallax-scroll.json +24 -0
- package/registry/_docs/password-input.json +23 -3
- package/registry/_docs/payment-card.json +16 -0
- package/registry/_docs/pixel-bar.json +3 -0
- package/registry/_docs/polar-area.json +3 -0
- package/registry/_docs/profile.json +3 -0
- package/registry/_docs/progress-steps.json +24 -0
- package/registry/_docs/progress.json +20 -0
- package/registry/_docs/qr-code-button.json +122 -0
- package/registry/_docs/radio-group.json +20 -0
- package/registry/_docs/rating.json +24 -0
- package/registry/_docs/ring-carousel.json +20 -0
- package/registry/_docs/scratch-card.json +20 -0
- package/registry/_docs/search-bar.json +23 -3
- package/registry/_docs/search-results.json +3 -0
- package/registry/_docs/segmented-control.json +20 -0
- package/registry/_docs/select.json +33 -8
- package/registry/_docs/settings.json +9 -0
- package/registry/_docs/sign-in.json +3 -0
- package/registry/_docs/skeleton.json +22 -2
- package/registry/_docs/slide-to-confirm.json +24 -0
- package/registry/_docs/slider.json +27 -7
- package/registry/_docs/spin-wheel.json +24 -0
- package/registry/_docs/spinner.json +41 -11
- package/registry/_docs/stateful-button.json +184 -0
- package/registry/_docs/stepper.json +23 -7
- package/registry/_docs/swipe-deck.json +16 -0
- package/registry/_docs/swipeable-row.json +24 -1
- package/registry/_docs/switch.json +20 -0
- package/registry/_docs/tabs.json +24 -0
- package/registry/_docs/text-animation.json +141 -0
- package/registry/_docs/textarea.json +18 -2
- package/registry/_docs/ticket-card.json +20 -0
- package/registry/_docs/ticket-shape.json +4 -1
- package/registry/_docs/tilt-card.json +20 -4
- package/registry/_docs/time-picker.json +22 -6
- package/registry/_docs/timeline-chart.json +3 -0
- package/registry/_docs/timeline.json +18 -2
- package/registry/_docs/toast.json +32 -8
- package/registry/_docs/treemap.json +3 -0
- package/registry/_docs/waterfall.json +3 -0
- package/registry/_docs/wheel-list.json +20 -0
- package/registry/accordion/files/src/components/ui/accordion.tsx +5 -4
- package/registry/accordion/files/src/lib/kit.tsx +8 -5
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +9 -8
- package/registry/action-sheet/files/src/lib/kit.tsx +8 -5
- package/registry/alert/files/src/components/ui/alert.tsx +7 -4
- package/registry/alert/files/src/components/ui/button.tsx +4 -3
- package/registry/alert/files/src/lib/kit.tsx +8 -5
- package/registry/assistant-app.json +49 -0
- package/registry/avatar/files/src/components/ui/avatar.tsx +7 -4
- package/registry/avatar/files/src/lib/kit.tsx +8 -5
- package/registry/badge/files/src/components/ui/badge.tsx +345 -21
- package/registry/badge/files/src/lib/kit.tsx +8 -5
- package/registry/badge.json +1 -1
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +14 -7
- package/registry/bottom-nav/files/src/lib/kit.tsx +8 -5
- package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +7 -6
- package/registry/bottom-sheet/files/src/lib/kit.tsx +8 -5
- package/registry/button/files/src/components/ui/button.tsx +4 -3
- package/registry/button/files/src/lib/kit.tsx +8 -5
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +3 -2
- package/registry/button-3d/files/src/lib/kit.tsx +8 -5
- package/registry/calendar/files/src/components/ui/calendar.tsx +9 -5
- package/registry/calendar/files/src/lib/kit.tsx +8 -5
- package/registry/card/files/src/components/ui/card.tsx +8 -6
- package/registry/card/files/src/lib/kit.tsx +8 -5
- package/registry/chat.json +18 -0
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +6 -5
- package/registry/checkbox/files/src/lib/kit.tsx +8 -5
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +4 -2
- package/registry/chip-group/files/src/lib/kit.tsx +8 -5
- package/registry/confetti/files/src/lib/kit.tsx +8 -5
- package/registry/coupon/files/src/components/ui/coupon.tsx +23 -20
- package/registry/coupon/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/coupon/files/src/lib/kit.tsx +8 -5
- package/registry/date-picker/files/src/components/ui/calendar.tsx +9 -5
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +2 -2
- package/registry/date-picker/files/src/lib/kit.tsx +8 -5
- package/registry/dialog/files/src/components/ui/dialog.tsx +12 -6
- package/registry/dialog/files/src/lib/kit.tsx +8 -5
- package/registry/donut-shop.json +18 -0
- package/registry/drawer/files/src/components/ui/drawer.tsx +25 -19
- package/registry/drawer/files/src/lib/kit.tsx +8 -5
- package/registry/fintech-app.json +57 -0
- package/registry/flip-card/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/flip-card/files/src/lib/kit.tsx +8 -5
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +16 -6
- package/registry/floating-input/files/src/lib/kit.tsx +8 -5
- package/registry/food-app.json +55 -0
- package/registry/grain/files/src/components/ui/grain.tsx +113 -0
- package/registry/{tag-input → grain}/files/src/lib/kit.tsx +8 -5
- package/registry/grain.json +17 -0
- package/registry/kit/files/src/lib/kit.tsx +8 -5
- package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +1 -1
- package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +1 -1
- package/registry/list-item/files/src/components/ui/list-item.tsx +20 -16
- package/registry/list-item/files/src/lib/kit.tsx +8 -5
- package/registry/morphing-button-group.json +18 -0
- package/registry/orb-reveal.json +20 -0
- package/registry/otp-input/files/src/components/ui/otp-input.tsx +8 -6
- package/registry/otp-input/files/src/lib/kit.tsx +8 -5
- package/registry/password-input/files/src/components/ui/floating-input.tsx +16 -6
- package/registry/password-input/files/src/components/ui/password-input.tsx +2 -2
- package/registry/password-input/files/src/lib/kit.tsx +8 -5
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +1 -1
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +27 -14
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/payment-card/files/src/lib/kit.tsx +8 -5
- package/registry/progress/files/src/components/ui/progress.tsx +8 -5
- package/registry/progress/files/src/lib/kit.tsx +8 -5
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +15 -11
- package/registry/progress-steps/files/src/lib/kit.tsx +8 -5
- package/registry/qr-code-button.json +18 -0
- package/registry/radio-group/files/src/components/ui/radio-group.tsx +10 -9
- package/registry/radio-group/files/src/lib/kit.tsx +8 -5
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +13 -11
- package/registry/search-bar/files/src/lib/kit.tsx +8 -5
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +4 -2
- package/registry/segmented-control/files/src/lib/kit.tsx +8 -5
- package/registry/select/files/src/components/ui/select.tsx +3 -3
- package/registry/select/files/src/lib/kit.tsx +8 -5
- package/registry/skeleton/files/src/components/ui/skeleton.tsx +4 -4
- package/registry/skeleton/files/src/lib/kit.tsx +8 -5
- package/registry/slider/files/src/components/ui/slider.tsx +5 -4
- package/registry/slider/files/src/lib/kit.tsx +8 -5
- package/registry/spinner/files/src/components/ui/spinner.tsx +452 -34
- package/registry/spinner/files/src/lib/kit.tsx +8 -5
- package/registry/spinner.json +1 -1
- package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +532 -0
- package/registry/{pagination-dots → stateful-button}/files/src/lib/kit.tsx +8 -5
- package/registry/stateful-button.json +18 -0
- package/registry/stepper/files/src/components/ui/stepper.tsx +8 -4
- package/registry/stepper/files/src/lib/kit.tsx +8 -5
- package/registry/switch/files/src/components/ui/switch.tsx +4 -3
- package/registry/switch/files/src/lib/kit.tsx +8 -5
- package/registry/tabs/files/src/components/ui/tabs.tsx +10 -8
- package/registry/tabs/files/src/lib/kit.tsx +8 -5
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +650 -0
- package/registry/text-animation/files/src/lib/kit.tsx +222 -0
- package/registry/text-animation.json +15 -0
- package/registry/textarea/files/src/components/ui/textarea.tsx +11 -9
- package/registry/textarea/files/src/lib/kit.tsx +8 -5
- package/registry/ticket-shape/files/src/lib/kit.tsx +8 -5
- package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +2 -2
- package/registry/tilt-card/files/src/lib/kit.tsx +8 -5
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +2 -2
- package/registry/time-picker/files/src/lib/kit.tsx +8 -5
- package/registry/timeline/files/src/components/ui/avatar.tsx +7 -4
- package/registry/timeline/files/src/components/ui/timeline.tsx +12 -10
- package/registry/timeline/files/src/lib/kit.tsx +8 -5
- package/registry/toast/files/src/components/ui/button.tsx +4 -3
- package/registry/toast/files/src/components/ui/toast.tsx +13 -11
- package/registry/toast/files/src/lib/kit.tsx +8 -5
- package/schema/components.schema.json +1 -1
- package/registry/_docs/color-swatch.json +0 -66
- package/registry/_docs/kpi-card.json +0 -11
- package/registry/_docs/like-button.json +0 -72
- package/registry/_docs/morph-button.json +0 -108
- package/registry/_docs/pagination-dots.json +0 -88
- package/registry/_docs/shimmer-button.json +0 -78
- package/registry/_docs/tag-input.json +0 -128
- package/registry/color-swatch.json +0 -17
- package/registry/kpi-card/files/src/components/charts/kpi-card.tsx +0 -45
- package/registry/kpi-card.json +0 -14
- package/registry/like-button.json +0 -18
- package/registry/morph-button.json +0 -18
- package/registry/pagination-dots/files/src/components/ui/pagination-dots.tsx +0 -262
- package/registry/pagination-dots.json +0 -15
- package/registry/shimmer-button.json +0 -17
- package/registry/tag-input/files/src/components/ui/tag-input.tsx +0 -720
- package/registry/tag-input.json +0 -17
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/floating-input.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A text field whose label glides onto the border as an accent halo blooms.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"label",
|
|
@@ -146,16 +147,35 @@
|
|
|
146
147
|
"Everything TextInput accepts."
|
|
147
148
|
]
|
|
148
149
|
],
|
|
150
|
+
"behavior": [
|
|
151
|
+
[
|
|
152
|
+
"Touch",
|
|
153
|
+
"Tapping anywhere on the field focuses the input. With clearable, a × springs in once there is text and empties the field."
|
|
154
|
+
],
|
|
155
|
+
[
|
|
156
|
+
"Motion",
|
|
157
|
+
"The label springs onto the border on focus or when filled, and a soft halo blooms around the field. An error shakes it once; a success check springs in."
|
|
158
|
+
],
|
|
159
|
+
[
|
|
160
|
+
"Screen readers",
|
|
161
|
+
"The input is labelled with your label and the clear button reads \"Clear\" plus the label. Helper, error and success messages are polite live regions."
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"Web",
|
|
165
|
+
"Browser autofill floats the label too, and the field keeps its own background instead of the autofill blue."
|
|
166
|
+
]
|
|
167
|
+
],
|
|
168
|
+
"usage": "import { useState } from 'react';\nimport { FloatingInput } from '@/components/ui/floating-input';\n\nconst [email, setEmail] = useState('');\n<FloatingInput label=\"Email\" value={email} onChangeText={setEmail} keyboardType=\"email-address\" clearable />",
|
|
149
169
|
"examples": [
|
|
150
170
|
{
|
|
151
171
|
"name": "SignUp",
|
|
152
172
|
"title": "Sign Up",
|
|
153
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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={
|
|
173
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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 : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, 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\nconst isEmail = (v: string) => /^\\S+@\\S+\\.\\S{2,}$/.test(v);\n\nexport default function SignUp({ screen }: DemoProps) {\n const { colors } = useKit();\n const [name, setName] = useState('Priya Sharma');\n const [email, setEmail] = useState('priya@');\n const [phone, setPhone] = useState('');\n const emailError = email.length > 0 && !isEmail(email) ? 'Enter a valid email address' : undefined;\n return (\n <Card title=\"Create your account\" subtitle=\"It takes less than a minute.\" screen={screen}>\n <FloatingInput label=\"Full name\" value={name} onChangeText={setName} autoComplete=\"name\" clearable />\n <FloatingInput\n label=\"Email\"\n value={email}\n onChangeText={setEmail}\n keyboardType=\"email-address\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n error={emailError}\n success={isEmail(email) ? 'Looks good' : undefined}\n />\n <FloatingInput\n label=\"Mobile number\"\n prefix=\"+91\"\n value={phone}\n onChangeText={(v) => setPhone(v.replace(/\\D/g, ''))}\n keyboardType=\"phone-pad\"\n maxLength={10}\n success={phone.length === 10}\n helper=\"We'll text you a 6-digit code\"\n />\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>\n Already have an account? <Text style={{ fontWeight: '400', color: colors.accent }}>Sign in</Text>\n </Text>\n </Card>\n );\n}\n"
|
|
154
174
|
},
|
|
155
175
|
{
|
|
156
176
|
"name": "Payment",
|
|
157
177
|
"title": "Payment",
|
|
158
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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={
|
|
178
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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 : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, 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\nconst formatCard = (v: string) =>\n v\n .replace(/\\D/g, '')\n .slice(0, 16)\n .replace(/(\\d{4})(?=\\d)/g, '$1 ');\n\nconst formatExpiry = (v: string) => {\n const d = v.replace(/\\D/g, '').slice(0, 4);\n return d.length > 2 ? `${d.slice(0, 2)}/${d.slice(2)}` : d;\n};\n\nconst cardBrand = (v: string) => {\n const d = v.replace(/\\D/g, '');\n if (/^4/.test(d)) return 'VISA';\n if (/^(5[1-5]|2[2-7])/.test(d)) return 'MC';\n if (/^3[47]/.test(d)) return 'AMEX';\n return undefined;\n};\n\n/** '' = not finished yet, otherwise an error message or null when valid. */\nconst expiryError = (v: string): string | null | '' => {\n if (v.length < 5) return '';\n const month = Number(v.slice(0, 2));\n const year = 2000 + Number(v.slice(3));\n if (month < 1 || month > 12) return 'Month must be 01–12';\n const now = new Date();\n if (year < now.getFullYear() || (year === now.getFullYear() && month < now.getMonth() + 1)) return 'This card has expired';\n return null;\n};\n\nconst rupees = (n: number) => {\n const [int, frac] = n.toFixed(2).split('.');\n return `₹${int.replace(/(\\d)(?=(\\d\\d)+\\d$)/g, '$1,')}${frac === '00' ? '' : `.${frac}`}`;\n};\n\nexport default function Payment({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const [amount, setAmount] = useState('1299');\n const [card, setCard] = useState('4242 4242 4242 4242');\n const [expiry, setExpiry] = useState('');\n const [cvc, setCvc] = useState('');\n const [paid, setPaid] = useState(false);\n const brand = cardBrand(card);\n const cvcLen = brand === 'AMEX' ? 4 : 3;\n const expErr = expiryError(expiry);\n const ready = Number(amount) > 0 && card.length >= 18 && expErr === null && cvc.length === cvcLen;\n return (\n <Card title=\"Add funds\" subtitle=\"Charged securely — you can cancel anytime.\" screen={screen}>\n <FloatingInput label=\"Amount\" prefix=\"₹\" suffix=\"INR\" keyboardType=\"decimal-pad\" value={amount} onChangeText={setAmount} />\n <FloatingInput\n label=\"Card number\"\n keyboardType=\"number-pad\"\n autoComplete=\"cc-number\"\n value={card}\n onChangeText={(v) => setCard(formatCard(v))}\n maxLength={19}\n suffix={brand}\n success={card.length === 19}\n />\n <View style={{ flexDirection: 'row', gap: 10, alignItems: 'flex-start' }}>\n <FloatingInput\n label=\"MM/YY\"\n keyboardType=\"number-pad\"\n autoComplete=\"cc-exp\"\n value={expiry}\n onChangeText={(v) => setExpiry(formatExpiry(v))}\n maxLength={5}\n error={expErr || undefined}\n success={expErr === null}\n style={{ flex: 1 }}\n />\n <FloatingInput\n label=\"CVC\"\n keyboardType=\"number-pad\"\n autoComplete=\"cc-csc\"\n secureTextEntry\n value={cvc}\n onChangeText={(v) => setCvc(v.replace(/\\D/g, '').slice(0, cvcLen))}\n maxLength={cvcLen}\n helper={`${cvcLen} digits on the ${brand === 'AMEX' ? 'front' : 'back'}`}\n style={{ flex: 1 }}\n />\n </View>\n <Pressable\n disabled={!ready}\n onPress={() => setPaid(true)}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled: !ready }}\n style={({ pressed }) => ({\n height: 50,\n marginTop: 4,\n borderRadius: radius.md,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: ready ? colors.accent : colors.muted,\n opacity: pressed ? 0.85 : 1,\n })}\n >\n <Text style={{ fontSize: 16, fontWeight: '400', color: ready ? readableOn(colors.accent) : colors.mutedForeground }}>\n {paid ? 'Paid ✓' : `Pay ${rupees(Number(amount) || 0)}`}\n </Text>\n </Pressable>\n </Card>\n );\n}\n"
|
|
159
179
|
},
|
|
160
180
|
{
|
|
161
181
|
"name": "Variants",
|
|
@@ -170,7 +190,7 @@
|
|
|
170
190
|
{
|
|
171
191
|
"name": "Website",
|
|
172
192
|
"title": "Website",
|
|
173
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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={
|
|
193
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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 : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, 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 Website({ screen }: DemoProps) {\n const [slug, setSlug] = useState('');\n return (\n <Card title=\"Your public page\" screen={screen}>\n <FloatingInput\n label=\"Website\"\n prefix=\"https://\"\n keyboardType=\"url\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n clearable\n />\n <FloatingInput\n label=\"Handle\"\n prefix=\"@\"\n suffix=\".expo.page\"\n value={slug}\n onChangeText={(v) => setSlug(v.toLowerCase().replace(/[^a-z0-9-]/g, ''))}\n autoCapitalize=\"none\"\n maxLength={20}\n counter\n helper=\"Letters, numbers and dashes\"\n />\n </Card>\n );\n}\n"
|
|
174
194
|
},
|
|
175
195
|
{
|
|
176
196
|
"name": "Sizes",
|
|
@@ -180,12 +200,12 @@
|
|
|
180
200
|
{
|
|
181
201
|
"name": "LabelAbove",
|
|
182
202
|
"title": "Label Above",
|
|
183
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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={
|
|
203
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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 : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, 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\nconst isEmail = (v: string) => /^\\S+@\\S+\\.\\S{2,}$/.test(v);\n\nexport default function LabelAbove({ screen }: DemoProps) {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [bio, setBio] = useState('');\n return (\n <Card title=\"Edit profile\" subtitle=\"This is how others will see you.\" screen={screen}>\n <FloatingInput floatingLabel={false} label=\"Full name\" placeholder=\"Priya Sharma\" value={name} onChangeText={setName} autoComplete=\"name\" clearable />\n <FloatingInput\n floatingLabel={false}\n label=\"Email\"\n placeholder=\"you@example.com\"\n value={email}\n onChangeText={setEmail}\n keyboardType=\"email-address\"\n autoCapitalize=\"none\"\n autoCorrect={false}\n error={email.length > 0 && !isEmail(email) ? 'Enter a valid email address' : undefined}\n helper=\"We'll never share it.\"\n />\n <FloatingInput\n floatingLabel={false}\n label=\"Bio\"\n placeholder=\"A line about you\"\n value={bio}\n onChangeText={setBio}\n maxLength={80}\n counter\n />\n </Card>\n );\n}\n"
|
|
184
204
|
},
|
|
185
205
|
{
|
|
186
206
|
"name": "CustomStyles",
|
|
187
207
|
"title": "Custom Styles",
|
|
188
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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={
|
|
208
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View } from 'react-native';\nimport { FloatingInput } from '@/components/ui/floating-input';\nimport { readableOn, 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 : { borderRadius: radius.xl, borderWidth: StyleSheet.hairlineWidth, borderColor: colors.border, 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 CustomStyles({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const [handle, setHandle] = useState('priya.codes');\n return (\n <Card title=\"Custom styles\" subtitle=\"fieldStyle, labelStyle, inputStyle, messageStyle.\" screen={screen}>\n <FloatingInput\n label=\"Username\"\n prefix=\"@\"\n value={handle}\n onChangeText={setHandle}\n autoCapitalize=\"none\"\n autoCorrect={false}\n helper=\"Letters, numbers and dots.\"\n fieldStyle={{ borderWidth: 2, borderColor: colors.border, borderRadius: radius.lg, backgroundColor: colors.card }}\n surface={colors.card}\n labelStyle={{ fontSize: 15, fontWeight: '400', letterSpacing: 0.2 }}\n inputStyle={{ fontSize: 17, fontWeight: '400', letterSpacing: 0.3 }}\n prefixStyle={{ color: colors.accent, fontWeight: '400' }}\n messageStyle={{ fontStyle: 'italic' }}\n />\n </Card>\n );\n}\n"
|
|
189
209
|
}
|
|
190
210
|
]
|
|
191
211
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "food-app",
|
|
3
|
+
"category": "Templates",
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"exportName": null,
|
|
6
|
+
"files": [
|
|
7
|
+
"src/app/(tabs)/_layout.tsx",
|
|
8
|
+
"src/app/(tabs)/bag.tsx",
|
|
9
|
+
"src/app/(tabs)/index.tsx",
|
|
10
|
+
"src/app/(tabs)/offers.tsx",
|
|
11
|
+
"src/app/(tabs)/profile.tsx",
|
|
12
|
+
"src/app/_layout.tsx",
|
|
13
|
+
"src/app/onboarding.tsx",
|
|
14
|
+
"src/app/settings.tsx",
|
|
15
|
+
"src/app/sign-in.tsx",
|
|
16
|
+
"src/components/food-app/tabs.tsx",
|
|
17
|
+
"src/lib/food-app/cart.tsx",
|
|
18
|
+
"src/lib/food-app/data.tsx",
|
|
19
|
+
"src/lib/food-app/session.tsx"
|
|
20
|
+
],
|
|
21
|
+
"summary": null,
|
|
22
|
+
"props": [],
|
|
23
|
+
"behavior": [
|
|
24
|
+
[
|
|
25
|
+
"Flow",
|
|
26
|
+
"Onboarding shows once, then sign in, then the tabs. Signing out returns to sign in. The session is saved on the device (AsyncStorage) and guarded with Expo Router’s Stack.Protected."
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
"Tabs",
|
|
30
|
+
"Menu (rolling donut shelf), Offers (coupons that unlock with the bag total), Bag (checkout) and Profile. The kit’s BottomNav is the tab bar, with the bag count as a badge."
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
"Bag",
|
|
34
|
+
"Donuts added on the Menu land in the bag; a coupon picked on Offers is applied at checkout. Pay is a stand-in — wire it to your payment sheet."
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
"Settings",
|
|
38
|
+
"Pushed from Profile. Appearance (System / Light / Dark) re-themes every kit component instantly."
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
"Your backend",
|
|
42
|
+
"Auth handlers in app/sign-in.tsx and payment in app/(tabs)/bag.tsx are stand-ins that wait and succeed. Menu, coupons and the user live in lib/food-app/data.tsx."
|
|
43
|
+
]
|
|
44
|
+
],
|
|
45
|
+
"usage": null,
|
|
46
|
+
"examples": []
|
|
47
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/gift-card.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A photo gift card that tilts toward your finger and flips to reveal its code.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"amount",
|
|
@@ -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 over to the redeem code. The copy button calls onCopy and reads \"Copied ✓\" for a moment."
|
|
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, amount and redeemed state; the code is added to the label once it is flipped."
|
|
120
|
+
]
|
|
121
|
+
],
|
|
122
|
+
"usage": null,
|
|
107
123
|
"examples": []
|
|
108
124
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"src/components/ui/glass-button.tsx"
|
|
12
12
|
],
|
|
13
|
+
"summary": "Liquid Glass buttons and toolbars that spring down under your finger.",
|
|
13
14
|
"props": [
|
|
14
15
|
[
|
|
15
16
|
"label",
|
|
@@ -114,5 +115,28 @@
|
|
|
114
115
|
"As on GlassButton; accessibilityLabel names the toolbar."
|
|
115
116
|
]
|
|
116
117
|
],
|
|
118
|
+
"behavior": [
|
|
119
|
+
[
|
|
120
|
+
"Motion",
|
|
121
|
+
"Buttons spring down to 0.94 and toolbar icons to 0.86 while pressed, and an active toolbar item springs in a soft bubble. On iOS 26 a GlassButton lets the native glass bounce instead."
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"Reduced motion",
|
|
125
|
+
"Press springs are skipped and the active bubble appears without a spring."
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
"Haptics",
|
|
129
|
+
"A light impact on every press, unless haptics is false."
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
"Screen readers",
|
|
133
|
+
"Each button has the button role with its label and disabled state; toolbar items also report selected. The toolbar itself has the toolbar role."
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
"Platforms",
|
|
137
|
+
"iOS 26 shows real interactive Liquid Glass, tinted natively, and floating toolbar circles melt together. Elsewhere it is blurred glass with a stronger colour wash for tinted buttons."
|
|
138
|
+
]
|
|
139
|
+
],
|
|
140
|
+
"usage": null,
|
|
117
141
|
"examples": []
|
|
118
142
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/glass-nav-bar.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "An iOS 26 glass top bar that fades in as content scrolls under it.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"title",
|
|
@@ -74,5 +75,28 @@
|
|
|
74
75
|
"Bar row height, and the full height the bar covers — use it as your content's paddingTop."
|
|
75
76
|
]
|
|
76
77
|
],
|
|
78
|
+
"behavior": [
|
|
79
|
+
[
|
|
80
|
+
"Motion",
|
|
81
|
+
"With scrollY the bar starts transparent and its glass fades in as content passes under it. A large title scrolls away while the small centred title fades in, all on the native driver."
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"Touch",
|
|
85
|
+
"Back and action buttons spring down under the finger on emulated glass; on iOS 26 the interactive glass bounces natively."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"Reduced motion",
|
|
89
|
+
"The large title no longer scales on pull-down or collapse, and the button press springs are off."
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
"Screen readers",
|
|
93
|
+
"The title is a header, with the small title hidden while the large one shows. The back button reads backLabel or \"Back\", and actions use their accessibilityLabel."
|
|
94
|
+
],
|
|
95
|
+
[
|
|
96
|
+
"Platforms",
|
|
97
|
+
"Real Liquid Glass on iOS 26, where the action buttons merge together. Blur on older iOS, Android and web."
|
|
98
|
+
]
|
|
99
|
+
],
|
|
100
|
+
"usage": null,
|
|
77
101
|
"examples": []
|
|
78
102
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/glass-search-bar.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A floating glass search pill that swells on focus as a cancel button splits off.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"value / defaultValue / onChangeText",
|
|
@@ -86,5 +87,28 @@
|
|
|
86
87
|
"editable, returnKeyType, onFocus, onBlur, onSubmitEditing, … (ref forwards to the TextInput)."
|
|
87
88
|
]
|
|
88
89
|
],
|
|
90
|
+
"behavior": [
|
|
91
|
+
[
|
|
92
|
+
"Motion",
|
|
93
|
+
"The pill swells a touch on focus and a clear button pops in once there is text. With showCancel, a glass cancel button springs in beside it while searching."
|
|
94
|
+
],
|
|
95
|
+
[
|
|
96
|
+
"Reduced motion",
|
|
97
|
+
"The pill no longer swells, and the clear and cancel buttons fade in with a short timing instead of a spring."
|
|
98
|
+
],
|
|
99
|
+
[
|
|
100
|
+
"Keyboard",
|
|
101
|
+
"The return key reads Search and calls onSubmit with the query. Cancel clears the text and dismisses the keyboard."
|
|
102
|
+
],
|
|
103
|
+
[
|
|
104
|
+
"Screen readers",
|
|
105
|
+
"The field has the search role and is labelled by its placeholder. The clear and cancel buttons read \"Clear search\" and cancelLabel (or \"Cancel search\")."
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"Platforms",
|
|
109
|
+
"Real Liquid Glass on iOS 26, where the pill and cancel button melt together. Blur or frosted glass everywhere else."
|
|
110
|
+
]
|
|
111
|
+
],
|
|
112
|
+
"usage": null,
|
|
89
113
|
"examples": []
|
|
90
114
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/glass-segmented.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A glass segmented control whose thumb stretches toward the new segment like a drop.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"options",
|
|
@@ -62,5 +63,32 @@
|
|
|
62
63
|
"Style for the glass track."
|
|
63
64
|
]
|
|
64
65
|
],
|
|
66
|
+
"behavior": [
|
|
67
|
+
[
|
|
68
|
+
"Touch",
|
|
69
|
+
"Tap a segment, or press the thumb and drag it across. It follows your finger and snaps to the nearest segment on release."
|
|
70
|
+
],
|
|
71
|
+
[
|
|
72
|
+
"Motion",
|
|
73
|
+
"The thumb springs to the new segment, stretching in the direction of travel before it settles. It lifts slightly while you drag it."
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"Reduced motion",
|
|
77
|
+
"The thumb slides over in a short timing with no stretch, and does not lift when dragged."
|
|
78
|
+
],
|
|
79
|
+
[
|
|
80
|
+
"Haptics",
|
|
81
|
+
"A selection tick on change and each time a drag crosses into another segment."
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"Screen readers",
|
|
85
|
+
"The control is a tablist and each segment a tab with its label and selected state."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"Platforms",
|
|
89
|
+
"Built on Glass: real Liquid Glass on iOS 26, blurred or frosted glass elsewhere."
|
|
90
|
+
]
|
|
91
|
+
],
|
|
92
|
+
"usage": null,
|
|
65
93
|
"examples": []
|
|
66
94
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/glass-sheet.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A floating glass bottom sheet that follows your finger and snaps with velocity.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"open",
|
|
@@ -104,5 +105,32 @@
|
|
|
104
105
|
"Sheet content; scrolls at the top snap when taller than the sheet."
|
|
105
106
|
]
|
|
106
107
|
],
|
|
108
|
+
"behavior": [
|
|
109
|
+
[
|
|
110
|
+
"Touch",
|
|
111
|
+
"Drag from the grabber or the content. Release velocity picks the snap point, and a fling down or a backdrop tap dismisses it."
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
"Motion",
|
|
115
|
+
"It springs up over a fading dim and the grabber widens while held. Without snapPoints it sizes to its content, and taller content scrolls."
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
"Reduced motion",
|
|
119
|
+
"Snapping, opening and closing use short timings instead of springs."
|
|
120
|
+
],
|
|
121
|
+
[
|
|
122
|
+
"Haptics",
|
|
123
|
+
"A light tap on open and a selection tick each time it settles on a snap point."
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
"Screen readers",
|
|
127
|
+
"The sheet is modal and the escape gesture closes it. The grabber is adjustable: increment and decrement step between snap points, and decrement from the lowest one closes it."
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
"Platforms",
|
|
131
|
+
"Real Liquid Glass on iOS 26, material blur on older iOS and web, and a frosted surface on Android. Android back closes it."
|
|
132
|
+
]
|
|
133
|
+
],
|
|
134
|
+
"usage": null,
|
|
107
135
|
"examples": []
|
|
108
136
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"src/components/ui/glass-tab-bar.tsx"
|
|
12
12
|
],
|
|
13
|
+
"summary": "A floating glass tab bar whose selection bubble stretches as it springs between tabs.",
|
|
13
14
|
"props": [
|
|
14
15
|
[
|
|
15
16
|
"tabs",
|
|
@@ -72,5 +73,28 @@
|
|
|
72
73
|
"Exported height of the bar (and the trailing circle) — pad your scroll content by it."
|
|
73
74
|
]
|
|
74
75
|
],
|
|
76
|
+
"behavior": [
|
|
77
|
+
[
|
|
78
|
+
"Motion",
|
|
79
|
+
"The lighter bubble springs to the selected tab, stretching as it travels and settling when it lands. The selected icon lifts, and buttons spring down while pressed."
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"Reduced motion",
|
|
83
|
+
"The bubble jumps to the new tab without stretching, icons switch without a spring and press springs are off."
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"Haptics",
|
|
87
|
+
"A selection tick when the tab changes and a light tap on the trailing button."
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
"Screen readers",
|
|
91
|
+
"The bar is a tablist; each tab is a tab with its selected state, and the badge count is read after the label."
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
"Platforms",
|
|
95
|
+
"Real Liquid Glass on iOS 26, where the trailing button melts into the bar. Blur everywhere else."
|
|
96
|
+
]
|
|
97
|
+
],
|
|
98
|
+
"usage": null,
|
|
75
99
|
"examples": []
|
|
76
100
|
}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
"name": "glass",
|
|
3
3
|
"category": "Glass",
|
|
4
4
|
"aliases": [],
|
|
5
|
-
"exportName": "
|
|
5
|
+
"exportName": "Glass",
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/glass.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A Liquid Glass surface: native on iOS 26, emulated with blur and a rim elsewhere.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"variant",
|
|
@@ -74,5 +75,20 @@
|
|
|
74
75
|
"Size, padding and layout."
|
|
75
76
|
]
|
|
76
77
|
],
|
|
78
|
+
"behavior": [
|
|
79
|
+
[
|
|
80
|
+
"Touch",
|
|
81
|
+
"With interactive, iOS 26 glass shimmers and bounces under the finger. Elsewhere the prop is ignored."
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"Platforms",
|
|
85
|
+
"iOS 26 renders real Liquid Glass that GlassGroup can merge; older iOS uses a system material blur. Android blurs inside GlassProvider + GlassBackdrop and falls back to a frosted fill."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"Web",
|
|
89
|
+
"Blurs what is behind it with a CSS backdrop blur. Wherever glass is emulated it adds a specular rim, a hairline edge and a soft shadow."
|
|
90
|
+
]
|
|
91
|
+
],
|
|
92
|
+
"usage": null,
|
|
77
93
|
"examples": []
|
|
78
94
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "grain",
|
|
3
|
+
"category": "Display",
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"exportName": "GrainGradient",
|
|
6
|
+
"files": [
|
|
7
|
+
"src/components/ui/grain.tsx"
|
|
8
|
+
],
|
|
9
|
+
"summary": "A soft blob gradient with real film grain, plus a grain overlay for anything.",
|
|
10
|
+
"props": [
|
|
11
|
+
[
|
|
12
|
+
"palette",
|
|
13
|
+
"sunset | ocean | aurora | dusk | peach | graphite | ember | mint | lavender | candy | forest | noir",
|
|
14
|
+
"\"sunset\"",
|
|
15
|
+
"Built-in colour set."
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"colors",
|
|
19
|
+
"string[]",
|
|
20
|
+
"—",
|
|
21
|
+
"Base colour first, then up to four blob colours. Overrides palette."
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
"grain",
|
|
25
|
+
"number",
|
|
26
|
+
"0.55",
|
|
27
|
+
"Grain strength, 0–1."
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
"seed",
|
|
31
|
+
"number",
|
|
32
|
+
"0",
|
|
33
|
+
"Shuffles where the blobs sit."
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"style",
|
|
37
|
+
"StyleProp<ViewStyle>",
|
|
38
|
+
"—",
|
|
39
|
+
"Root style; give it a size or flex: 1."
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"GrainOverlay grain",
|
|
43
|
+
"number",
|
|
44
|
+
"0.55",
|
|
45
|
+
"Grain only, laid over its parent."
|
|
46
|
+
]
|
|
47
|
+
],
|
|
48
|
+
"behavior": [
|
|
49
|
+
[
|
|
50
|
+
"Gradient",
|
|
51
|
+
"A base colour with up to four radial blobs, drawn with react-native-svg so it scales to any size."
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
"Grain",
|
|
55
|
+
"A tiny tiling noise image drawn at 2×, so the speckle stays fine on every screen; grain sets its strength."
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"Touch",
|
|
59
|
+
"The gradient and grain never take touches; children render on top."
|
|
60
|
+
]
|
|
61
|
+
],
|
|
62
|
+
"usage": "import { GrainGradient, GrainOverlay } from '@/components/ui/grain';\n\n<GrainGradient palette=\"aurora\" style={{ flex: 1 }}>\n {/* your screen */}\n</GrainGradient>",
|
|
63
|
+
"examples": [
|
|
64
|
+
{
|
|
65
|
+
"name": "Hero",
|
|
66
|
+
"title": "Hero",
|
|
67
|
+
"code": "import { Text, View } from 'react-native';\nimport { GRAIN_PALETTES, GrainGradient } from '@/components/ui/grain';\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\nexport default function Hero({ screen }: DemoProps) {\n const { radius } = useKit();\n return (\n <GrainGradient palette=\"ember\" seed={1} style={screen ? { flex: 1 } : { height: 460, borderRadius: radius.xl }}>\n <View style={{ flex: 1, justifyContent: 'flex-end', padding: 24, gap: 6 }}>\n <Text style={{ color: '#ffffff', fontSize: 34, fontWeight: '700', letterSpacing: -0.8 }}>Golden hour</Text>\n <Text style={{ color: 'rgba(255,255,255,0.8)', fontSize: 15 }}>Warm light, soft grain, no photo needed.</Text>\n </View>\n </GrainGradient>\n );\n}\n"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "Palettes",
|
|
71
|
+
"title": "Palettes",
|
|
72
|
+
"code": "import { Text, View } from 'react-native';\nimport { GRAIN_PALETTES, GrainGradient } from '@/components/ui/grain';\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\nexport default function Palettes({ screen }: DemoProps) {\n const { radius } = useKit();\n return (\n <View style={[{ flexDirection: 'row', flexWrap: 'wrap', gap: 12 }, screen && { padding: 16 }]}>\n {GRAIN_PALETTES.map((p, i) => (\n <GrainGradient key={p} palette={p} seed={i} style={{ width: '47%', flexGrow: 1, height: 120, borderRadius: radius.lg }}>\n <Text style={{ margin: 12, color: ['peach', 'mint', 'lavender'].includes(p) ? '#1d1a26' : '#ffffff', fontWeight: '600', textTransform: 'capitalize' }}>{p}</Text>\n </GrainGradient>\n ))}\n </View>\n );\n}\n"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"name": "Custom",
|
|
76
|
+
"title": "Custom",
|
|
77
|
+
"code": "import { GRAIN_PALETTES, GrainGradient } from '@/components/ui/grain';\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\nexport default function Custom({ screen }: DemoProps) {\n const { radius } = useKit();\n return (\n <GrainGradient colors={['#0c0a1f', '#ff4d6d', '#ffd166', '#06d6a0']} grain={0.9} seed={2} style={screen ? { flex: 1 } : { height: 400, borderRadius: radius.xl }} />\n );\n}\n"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
package/registry/_docs/kit.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/list-item.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "Settings, contact and inbox rows with a press highlight that fades in fast, out slow.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"title",
|
|
@@ -170,6 +171,21 @@
|
|
|
170
171
|
"Draw the inset hairline under the last row too."
|
|
171
172
|
]
|
|
172
173
|
],
|
|
174
|
+
"behavior": [
|
|
175
|
+
[
|
|
176
|
+
"Touch",
|
|
177
|
+
"Pressable rows get a UIKit-style highlight that fades in fast and out slowly, and a chevron by default. onLongPress is supported too."
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
"Screen readers",
|
|
181
|
+
"Pressable rows are buttons labelled with the title, subtitle, value and badge count, with disabled and checked states. ListGroup and ListSection headers are headers."
|
|
182
|
+
],
|
|
183
|
+
[
|
|
184
|
+
"Platforms",
|
|
185
|
+
"Plain React Native views, so rows look the same on iOS, Android and web. ListGroup gives the iOS inset-grouped card on every platform."
|
|
186
|
+
]
|
|
187
|
+
],
|
|
188
|
+
"usage": "import { ListGroup, ListItem } from '@/components/ui/list-item';\n\n<ListGroup header=\"Account\">\n <ListItem icon=\"user\" title=\"Profile\" value=\"Amelia Hart\" onPress={openProfile} />\n <ListItem icon=\"bell\" title=\"Notifications\" badge={3} onPress={openNotifications} />\n</ListGroup>",
|
|
173
189
|
"examples": [
|
|
174
190
|
{
|
|
175
191
|
"name": "Settings",
|