@expokit/cli 0.3.0 → 0.4.1
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 +8 -4
- package/bin/expo-kit.js +137 -24
- package/bin/lib.mjs +110 -1
- package/bin/mcp.mjs +40 -18
- package/package.json +2 -2
- package/registry/_docs/accordion.json +1 -1
- package/registry/_docs/assistant-app.json +47 -0
- package/registry/_docs/avatar.json +6 -6
- package/registry/_docs/badge.json +4 -4
- package/registry/_docs/bottom-nav.json +6 -6
- package/registry/_docs/bottom-sheet.json +3 -3
- package/registry/_docs/bullet.json +6 -0
- package/registry/_docs/button-3d.json +3 -3
- package/registry/_docs/button.json +2 -2
- package/registry/_docs/calendar.json +5 -5
- package/registry/_docs/card.json +1 -1
- package/registry/_docs/checkout.json +7 -1
- package/registry/_docs/chip-group.json +1 -1
- package/registry/_docs/confetti.json +3 -3
- package/registry/_docs/date-picker.json +4 -4
- package/registry/_docs/donut-shop.json +88 -0
- package/registry/_docs/drawer.json +4 -4
- package/registry/_docs/fintech-app.json +49 -0
- package/registry/_docs/flip-card.json +4 -4
- package/registry/_docs/floating-input.json +5 -5
- package/registry/_docs/food-app.json +47 -0
- package/registry/_docs/glass.json +1 -1
- package/registry/_docs/grain.json +80 -0
- package/registry/_docs/isometric-bar.json +6 -0
- package/registry/_docs/liquidglass-tab.json +1 -1
- package/registry/_docs/morphing-button-group.json +96 -0
- package/registry/_docs/orb-reveal.json +132 -0
- package/registry/_docs/otp-input.json +4 -4
- package/registry/_docs/password-input.json +3 -3
- package/registry/_docs/payment-card.json +3 -3
- package/registry/_docs/pixel-bar.json +6 -0
- package/registry/_docs/polar-area.json +6 -0
- package/registry/_docs/progress-steps.json +4 -4
- package/registry/_docs/progress.json +2 -2
- package/registry/_docs/qr-code-button.json +122 -0
- package/registry/_docs/radio-group.json +1 -1
- package/registry/_docs/search-bar.json +4 -4
- package/registry/_docs/segmented-control.json +1 -1
- package/registry/_docs/select.json +7 -7
- package/registry/_docs/settings.json +6 -0
- package/registry/_docs/skeleton.json +3 -3
- package/registry/_docs/slider.json +6 -6
- package/registry/_docs/spinner.json +3 -3
- package/registry/_docs/stateful-button.json +1 -1
- package/registry/_docs/stepper.json +7 -7
- package/registry/_docs/tabs.json +2 -2
- package/registry/_docs/text-animation.json +4 -4
- package/registry/_docs/textarea.json +3 -3
- package/registry/_docs/ticket-shape.json +1 -1
- package/registry/_docs/tilt-card.json +4 -4
- package/registry/_docs/time-picker.json +6 -6
- package/registry/_docs/timeline-chart.json +6 -0
- package/registry/_docs/timeline.json +6 -6
- package/registry/_docs/toast.json +8 -8
- package/registry/_docs/treemap.json +6 -0
- package/registry/_docs/waterfall.json +6 -0
- package/registry/accordion/files/src/components/ui/accordion.tsx +36 -7
- package/registry/accordion/files/src/lib/kit.tsx +8 -5
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +12 -8
- package/registry/action-sheet/files/src/lib/kit.tsx +8 -5
- package/registry/alert/files/src/components/ui/alert.tsx +11 -5
- package/registry/alert/files/src/components/ui/button.tsx +35 -6
- 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 +23 -9
- package/registry/badge/files/src/lib/kit.tsx +8 -5
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +21 -8
- 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 +35 -6
- package/registry/button/files/src/lib/kit.tsx +8 -5
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +35 -7
- package/registry/button-3d/files/src/lib/kit.tsx +8 -5
- package/registry/calendar/files/src/components/ui/calendar.tsx +68 -19
- package/registry/calendar/files/src/lib/kit.tsx +8 -5
- package/registry/card/files/src/components/ui/card.tsx +32 -10
- package/registry/card/files/src/lib/kit.tsx +8 -5
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +31 -8
- package/registry/checkbox/files/src/lib/kit.tsx +8 -5
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +39 -7
- 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 +55 -28
- package/registry/coupon/files/src/components/ui/flip-card.tsx +23 -4
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +59 -18
- package/registry/coupon/files/src/lib/kit.tsx +8 -5
- package/registry/date-picker/files/src/components/ui/calendar.tsx +68 -19
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +98 -44
- package/registry/date-picker/files/src/lib/kit.tsx +8 -5
- package/registry/dialog/files/src/components/ui/dialog.tsx +19 -9
- 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 +31 -21
- 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 +23 -4
- package/registry/flip-card/files/src/lib/kit.tsx +8 -5
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +91 -32
- 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 +2 -2
- package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +1 -1
- package/registry/list-item/files/src/components/ui/list-item.tsx +28 -17
- 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 +57 -24
- package/registry/otp-input/files/src/lib/kit.tsx +8 -5
- package/registry/password-input/files/src/components/ui/floating-input.tsx +91 -32
- package/registry/password-input/files/src/components/ui/password-input.tsx +55 -21
- package/registry/password-input/files/src/lib/kit.tsx +8 -5
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +23 -4
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +35 -18
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +59 -18
- package/registry/payment-card/files/src/lib/kit.tsx +8 -5
- package/registry/progress/files/src/components/ui/progress.tsx +16 -6
- package/registry/progress/files/src/lib/kit.tsx +8 -5
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +22 -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 +48 -17
- package/registry/radio-group/files/src/lib/kit.tsx +8 -5
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +81 -26
- package/registry/search-bar/files/src/lib/kit.tsx +8 -5
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +40 -10
- package/registry/segmented-control/files/src/lib/kit.tsx +8 -5
- package/registry/select/files/src/components/ui/select.tsx +161 -86
- 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 +56 -27
- package/registry/slider/files/src/lib/kit.tsx +8 -5
- package/registry/spinner/files/src/components/ui/spinner.tsx +17 -12
- package/registry/spinner/files/src/lib/kit.tsx +8 -5
- package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +12 -4
- package/registry/stateful-button/files/src/lib/kit.tsx +8 -5
- package/registry/stepper/files/src/components/ui/stepper.tsx +83 -29
- package/registry/stepper/files/src/lib/kit.tsx +8 -5
- package/registry/switch/files/src/components/ui/switch.tsx +60 -22
- package/registry/switch/files/src/lib/kit.tsx +8 -5
- package/registry/tabs/files/src/components/ui/tabs.tsx +15 -10
- package/registry/tabs/files/src/lib/kit.tsx +8 -5
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +11 -6
- package/registry/text-animation/files/src/lib/kit.tsx +8 -5
- package/registry/textarea/files/src/components/ui/textarea.tsx +115 -45
- 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 +59 -18
- package/registry/tilt-card/files/src/lib/kit.tsx +8 -5
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +156 -75
- 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 +19 -12
- package/registry/timeline/files/src/lib/kit.tsx +8 -5
- package/registry/toast/files/src/components/ui/button.tsx +35 -6
- package/registry/toast/files/src/components/ui/toast.tsx +25 -14
- package/registry/toast/files/src/lib/kit.tsx +8 -5
- package/schema/components.schema.json +1 -1
- package/registry/_docs/color-swatch.json +0 -82
- package/registry/_docs/kpi-card.json +0 -14
- package/registry/_docs/like-button.json +0 -92
- package/registry/_docs/morph-button.json +0 -128
- package/registry/_docs/pagination-dots.json +0 -108
- package/registry/_docs/shimmer-button.json +0 -98
- package/registry/_docs/tag-input.json +0 -148
- 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/files/src/lib/kit.tsx +0 -219
- 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
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
{
|
|
106
106
|
"name": "GradientAndGlow",
|
|
107
107
|
"title": "Gradient And Glow",
|
|
108
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function GradientAndGlow() {\n const { colors } = useKit();\n return (\n <View style={{ gap: 12 }}>\n <Button\n variant=\"gradient\"\n size=\"lg\"\n block\n pill\n right={<Text style={{ color: readableOn(colors.accent), fontSize: 18 }}>→</Text>}\n >\n Get started\n </Button>\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Button variant=\"glow\" pill style={{ flex: 1 }}>\n Go live\n </Button>\n <Button variant=\"gradient\" pill style={{ flex: 1 }}>\n Boost\n </Button>\n </View>\n </View>\n );\n}\n"
|
|
108
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\nimport { readableOn, useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\nexport default function GradientAndGlow() {\n const { colors } = useKit();\n return (\n <View style={{ gap: 12 }}>\n <Button\n variant=\"gradient\"\n size=\"lg\"\n block\n pill\n right={<Text maxFontSizeMultiplier={FONT_CAP} style={{ color: readableOn(colors.accent), fontSize: 18 }}>→</Text>}\n >\n Get started\n </Button>\n <View style={{ flexDirection: 'row', gap: 10 }}>\n <Button variant=\"glow\" pill style={{ flex: 1 }}>\n Go live\n </Button>\n <Button variant=\"gradient\" pill style={{ flex: 1 }}>\n Boost\n </Button>\n </View>\n </View>\n );\n}\n"
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
111
|
"name": "DynamicColor",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
{
|
|
116
116
|
"name": "Sizes",
|
|
117
117
|
"title": "Sizes",
|
|
118
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\n\nexport default function Sizes() {\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>\n <Button size=\"sm\">Small</Button>\n <Button size=\"md\">Medium</Button>\n <Button size=\"lg\">Large</Button>\n <Button size=\"icon\" variant=\"outline\">\n <Text style={{ fontSize: 18 }}>♥</Text>\n </Button>\n </View>\n );\n}\n"
|
|
118
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Button } from '@/components/ui/button';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\nexport default function Sizes() {\n return (\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', gap: 10 }}>\n <Button size=\"sm\">Small</Button>\n <Button size=\"md\">Medium</Button>\n <Button size=\"lg\">Large</Button>\n <Button size=\"icon\" variant=\"outline\">\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ fontSize: 18 }}>♥</Text>\n </Button>\n </View>\n );\n}\n"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"name": "Loading",
|
|
@@ -172,27 +172,27 @@
|
|
|
172
172
|
{
|
|
173
173
|
"name": "Single",
|
|
174
174
|
"title": "Single",
|
|
175
|
-
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\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 <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Single() {\n const [date, setDate] = useState<Date>(addDays(today, 3));\n return (\n <Card>\n <Ink style={s.title}>Delivery day</Ink>\n <Calendar value={date} onChange={setDate} minDate={today} />\n <View style={s.summary}>\n <Ink tone=\"muted\" style={s.muted}>Arriving</Ink>\n <Ink style={s.strong}>{day(date)}</Ink>\n </View>\n </Card>\n );\n}\n"
|
|
175
|
+
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. In `screen` mode it is the page itself. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n if (screen) return <View style={[s.screen, { backgroundColor: colors.background }, style]} {...rest} />;\n return <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n screen: { flex: 1, justifyContent: 'center', padding: 16, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', columnGap: 12, rowGap: 2 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Single({ screen }: DemoProps) {\n const [date, setDate] = useState<Date>(addDays(today, 3));\n return (\n <Card screen={screen}>\n <Ink style={s.title}>Delivery day</Ink>\n <Calendar value={date} onChange={setDate} minDate={today} />\n <View style={s.summary}>\n <Ink tone=\"muted\" style={s.muted}>Arriving</Ink>\n <Ink style={[s.strong, { flexShrink: 1 }]}>{day(date)}</Ink>\n </View>\n </Card>\n );\n}\n"
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
178
|
"name": "Range",
|
|
179
179
|
"title": "Range",
|
|
180
|
-
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\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 <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Range() {\n const [stay, setStay] = useState<DateRange>({ start: addDays(today, 4), end: addDays(today, 8) });\n const { colors, radius } = useKit();\n const nights = stay.start && stay.end ? Math.round((stay.end.getTime() - stay.start.getTime()) / 86400000) : 0;\n return (\n <Card>\n <Ink style={s.title}>Your stay · Lisbon</Ink>\n <Calendar mode=\"range\" value={stay} onChange={setStay} minDate={today} />\n <View style={s.row}>\n <View style={s.col}>\n <Ink tone=\"muted\" style={s.muted}>Check-in</Ink>\n <Ink style={s.strong}>{day(stay.start)}</Ink>\n </View>\n <View style={s.col}>\n <Ink tone=\"muted\" style={s.muted}>Check-out</Ink>\n <Ink style={s.strong}>{stay.end ? day(stay.end) : 'Select a date'}</Ink>\n </View>\n <View style={[s.pill, { opacity: nights ? 1 : 0.4, backgroundColor: alpha(colors.accent, 0.14), borderRadius: radius.capsule(30) }]}>\n <Text style={[s.pillText, { color: colors.accent }]}>{nights ? `${nights} night${nights > 1 ? 's' : ''}` : '0 nights'}</Text>\n </View>\n </View>\n </Card>\n );\n}\n"
|
|
180
|
+
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. In `screen` mode it is the page itself. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n if (screen) return <View style={[s.screen, { backgroundColor: colors.background }, style]} {...rest} />;\n return <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n screen: { flex: 1, justifyContent: 'center', padding: 16, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', columnGap: 12, rowGap: 2 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Range({ screen }: DemoProps) {\n const [stay, setStay] = useState<DateRange>({ start: addDays(today, 4), end: addDays(today, 8) });\n const { colors, radius } = useKit();\n const nights = stay.start && stay.end ? Math.round((stay.end.getTime() - stay.start.getTime()) / 86400000) : 0;\n return (\n <Card screen={screen}>\n <Ink style={s.title}>Your stay · Lisbon</Ink>\n <Calendar mode=\"range\" value={stay} onChange={setStay} minDate={today} />\n <View style={s.row}>\n <View style={s.col}>\n <Ink tone=\"muted\" style={s.muted}>Check-in</Ink>\n <Ink style={s.strong}>{day(stay.start)}</Ink>\n </View>\n <View style={s.col}>\n <Ink tone=\"muted\" style={s.muted}>Check-out</Ink>\n <Ink style={s.strong}>{stay.end ? day(stay.end) : 'Select a date'}</Ink>\n </View>\n <View style={[s.pill, { opacity: nights ? 1 : 0.4, backgroundColor: alpha(colors.accent, 0.14), borderRadius: radius.capsule(30) }]}>\n <Text maxFontSizeMultiplier={FONT_CAP} style={[s.pillText, { color: colors.accent }]}>{nights ? `${nights} night${nights > 1 ? 's' : ''}` : '0 nights'}</Text>\n </View>\n </View>\n </Card>\n );\n}\n"
|
|
181
181
|
},
|
|
182
182
|
{
|
|
183
183
|
"name": "Marked",
|
|
184
184
|
"title": "Marked",
|
|
185
|
-
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\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 <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst MEETING = '#38bdf8';\n\nconst BIRTHDAY = '#f472b6';\n\nconst TRIP = '#f59e0b';\n\nconst DONE = '#22c55e';\n\nconst DUE = '#ef4444';\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Marked() {\n const [date, setDate] = useState<Date>(today);\n const { highlights, marks } = useMemo(() => {\n const y = today.getFullYear();\n const m = today.getMonth();\n const k = (d: number) => toDateKey(new Date(y, m, d));\n return {\n // Whole-day fills: who / what owns the day.\n highlights: { [k(2)]: MEETING, [k(14)]: BIRTHDAY, [k(18)]: TRIP, [k(21)]: MEETING, [k(31)]: BIRTHDAY },\n // Dots underneath: smaller things on that day.\n marks: { [k(3)]: DONE, [k(8)]: DUE, [k(12)]: DONE, [k(17)]: DONE, [k(22)]: [DONE, DUE], [k(26)]: DUE },\n };\n }, []);\n return (\n <Card>\n <Ink style={s.title}>Schedule</Ink>\n <Calendar value={date} onChange={setDate} highlightedDates={highlights} markedDates={marks} weekStartsOn={1} />\n <View style={s.legend}>\n {[\n ['Meeting', MEETING],\n ['Birthday', BIRTHDAY],\n ['Trip', TRIP],\n ['Done', DONE],\n ['Due', DUE],\n ].map(([label, color]) => (\n <View key={label} style={s.legendItem}>\n <View style={[s.dot, { backgroundColor: color }]} />\n <Ink tone=\"muted\" style={s.muted}>{label}</Ink>\n </View>\n ))}\n </View>\n </Card>\n );\n}\n"
|
|
185
|
+
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. In `screen` mode it is the page itself. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n if (screen) return <View style={[s.screen, { backgroundColor: colors.background }, style]} {...rest} />;\n return <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst MEETING = '#38bdf8';\n\nconst BIRTHDAY = '#f472b6';\n\nconst TRIP = '#f59e0b';\n\nconst DONE = '#22c55e';\n\nconst DUE = '#ef4444';\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n screen: { flex: 1, justifyContent: 'center', padding: 16, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', columnGap: 12, rowGap: 2 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Marked({ screen }: DemoProps) {\n const [date, setDate] = useState<Date>(today);\n const { highlights, marks } = useMemo(() => {\n const y = today.getFullYear();\n const m = today.getMonth();\n const k = (d: number) => toDateKey(new Date(y, m, d));\n return {\n // Whole-day fills: who / what owns the day.\n highlights: { [k(2)]: MEETING, [k(14)]: BIRTHDAY, [k(18)]: TRIP, [k(21)]: MEETING, [k(31)]: BIRTHDAY },\n // Dots underneath: smaller things on that day.\n marks: { [k(3)]: DONE, [k(8)]: DUE, [k(12)]: DONE, [k(17)]: DONE, [k(22)]: [DONE, DUE], [k(26)]: DUE },\n };\n }, []);\n return (\n <Card screen={screen}>\n <Ink style={s.title}>Schedule</Ink>\n <Calendar value={date} onChange={setDate} highlightedDates={highlights} markedDates={marks} weekStartsOn={1} />\n <View style={s.legend}>\n {[\n ['Meeting', MEETING],\n ['Birthday', BIRTHDAY],\n ['Trip', TRIP],\n ['Done', DONE],\n ['Due', DUE],\n ].map(([label, color]) => (\n <View key={label} style={s.legendItem}>\n <View style={[s.dot, { backgroundColor: color }]} />\n <Ink tone=\"muted\" style={s.muted}>{label}</Ink>\n </View>\n ))}\n </View>\n </Card>\n );\n}\n"
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"name": "Booking",
|
|
189
189
|
"title": "Booking",
|
|
190
|
-
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\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 <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Booking() {\n const booked = useMemo(() => new Set([2, 5, 6, 11, 19].map((n) => toDateKey(addDays(today, n)))), []);\n const [date, setDate] = useState<Date | null>(null);\n return (\n <Card>\n <Ink style={s.title}>Book a consultation</Ink>\n <Calendar\n value={date}\n onChange={setDate}\n minDate={today}\n maxDate={addDays(today, 45)}\n isDateDisabled={(d) => d.getDay() === 0 || booked.has(toDateKey(d))}\n showOutsideDays\n fixedWeeks\n />\n <Ink tone=\"muted\" style={s.muted}>\n {date ? `Next: choose a time on ${day(date)}` : 'Faded days are fully booked or closed on Sundays.'}\n </Ink>\n </Card>\n );\n}\n"
|
|
190
|
+
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. In `screen` mode it is the page itself. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n if (screen) return <View style={[s.screen, { backgroundColor: colors.background }, style]} {...rest} />;\n return <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n screen: { flex: 1, justifyContent: 'center', padding: 16, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', columnGap: 12, rowGap: 2 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function Booking({ screen }: DemoProps) {\n const booked = useMemo(() => new Set([2, 5, 6, 11, 19].map((n) => toDateKey(addDays(today, n)))), []);\n const [date, setDate] = useState<Date | null>(null);\n return (\n <Card screen={screen}>\n <Ink style={s.title}>Book a consultation</Ink>\n <Calendar\n value={date}\n onChange={setDate}\n minDate={today}\n maxDate={addDays(today, 45)}\n isDateDisabled={(d) => d.getDay() === 0 || booked.has(toDateKey(d))}\n showOutsideDays\n fixedWeeks\n />\n <Ink tone=\"muted\" style={s.muted}>\n {date ? `Next: choose a time on ${day(date)}` : 'Faded days are fully booked or closed on Sundays.'}\n </Ink>\n </Card>\n );\n}\n"
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
193
|
"name": "WeekStartsMonday",
|
|
194
194
|
"title": "Week Starts Monday",
|
|
195
|
-
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\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 <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function WeekStartsMonday() {\n const [days, setDays] = useState<Date[]>([addDays(today, 1), addDays(today, 3)]);\n return (\n <Card>\n <Ink style={s.title}>Training days · pick up to 3</Ink>\n <Calendar mode=\"multiple\" value={days} onChange={setDays} max={3} weekStartsOn={1} locale=\"en-GB\" showOutsideDays />\n <Ink tone=\"muted\" style={s.muted}>{days.length ? days.map((d) => day(d)).join(' · ') : 'No sessions planned'}</Ink>\n </Card>\n );\n}\n"
|
|
195
|
+
"code": "import React, { useMemo, useState } from 'react';\nimport { StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { Calendar, addDays, startOfDay, toDateKey, type DateRange } from '@/components/ui/calendar';\nimport { alpha, useKit } from '@/lib/kit';\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\nconst today = startOfDay(new Date());\n\nconst day = (d: Date | null) => (d ? d.toLocaleDateString(undefined, { weekday: 'short', day: 'numeric', month: 'short' }) : '—');\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. In `screen` mode it is the page itself. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n if (screen) return <View style={[s.screen, { backgroundColor: colors.background }, style]} {...rest} />;\n return <View style={[s.card, { backgroundColor: colors.card, borderColor: colors.border, borderRadius: radius.xl }, style]} {...rest} />;\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth, gap: 12 },\n screen: { flex: 1, justifyContent: 'center', padding: 16, gap: 12 },\n title: { fontSize: 15, fontWeight: '400' },\n summary: { flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-between', alignItems: 'center', columnGap: 12, rowGap: 2 },\n row: { flexDirection: 'row', alignItems: 'center', gap: 12 },\n col: { flex: 1, gap: 2 },\n muted: { fontSize: 13 },\n strong: { fontSize: 15, fontWeight: '400' },\n pill: { paddingHorizontal: 10, paddingVertical: 6 },\n pillText: { fontSize: 13, fontWeight: '400' },\n legend: { flexDirection: 'row', flexWrap: 'wrap', columnGap: 14, rowGap: 6, justifyContent: 'center' },\n legendItem: { flexDirection: 'row', alignItems: 'center', gap: 6 },\n dot: { width: 8, height: 8, borderRadius: 4 },\n});\n\nexport default function WeekStartsMonday({ screen }: DemoProps) {\n const [days, setDays] = useState<Date[]>([addDays(today, 1), addDays(today, 3)]);\n return (\n <Card screen={screen}>\n <Ink style={s.title}>Training days · pick up to 3</Ink>\n <Calendar mode=\"multiple\" value={days} onChange={setDays} max={3} weekStartsOn={1} locale=\"en-GB\" showOutsideDays />\n <Ink tone=\"muted\" style={s.muted}>{days.length ? days.map((d) => day(d)).join(' · ') : 'No sessions planned'}</Ink>\n </Card>\n );\n}\n"
|
|
196
196
|
}
|
|
197
197
|
]
|
|
198
198
|
}
|
package/registry/_docs/card.json
CHANGED
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
{
|
|
111
111
|
"name": "Default",
|
|
112
112
|
"title": "Default",
|
|
113
|
-
"code": "import { Text, View } from 'react-native';\nimport { Card } from '@/components/ui/card';\nimport { Button } from '@/components/ui/button';\nimport { useKit } from '@/lib/kit';\n\nexport default function Default() {\n const { colors } = useKit();\n return (\n <Card>\n <Card.Header action={<Text style={{ fontSize: 18, color: colors.mutedForeground }}>⋯</Text>}>\n <Card.Title>Invite your team</Card.Title>\n <Card.Description>Collaborators can edit boards, leave comments and see version history.</Card.Description>\n </Card.Header>\n <Card.Content>\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>3 of 10 seats used on the Starter plan</Text>\n </Card.Content>\n <Card.Footer>\n <Button variant=\"outline\" size=\"sm\">Copy link</Button>\n <Button variant=\"accent\" size=\"sm\">Send invites</Button>\n </Card.Footer>\n </Card>\n );\n}\n"
|
|
113
|
+
"code": "import { Text, View } from 'react-native';\nimport { Card } from '@/components/ui/card';\nimport { Button } from '@/components/ui/button';\nimport { useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\nexport default function Default() {\n const { colors } = useKit();\n return (\n <Card>\n <Card.Header action={<Text maxFontSizeMultiplier={FONT_CAP} style={{ fontSize: 18, color: colors.mutedForeground }}>⋯</Text>}>\n <Card.Title>Invite your team</Card.Title>\n <Card.Description>Collaborators can edit boards, leave comments and see version history.</Card.Description>\n </Card.Header>\n <Card.Content>\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>3 of 10 seats used on the Starter plan</Text>\n </Card.Content>\n <Card.Footer>\n <Button variant=\"outline\" size=\"sm\">Copy link</Button>\n <Button variant=\"accent\" size=\"sm\">Send invites</Button>\n </Card.Footer>\n </Card>\n );\n}\n"
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
116
|
"name": "Variants",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"items",
|
|
13
13
|
"{ id, name, variant?, price, quantity, image? }[]",
|
|
14
14
|
"3 sample products",
|
|
15
|
-
"Initial bag. Quantities and removals are kept in state."
|
|
15
|
+
"Initial bag. Quantities and removals are kept in state. Each item can carry a `thumbnail` node (your own drawing) instead of an `image` URL."
|
|
16
16
|
],
|
|
17
17
|
[
|
|
18
18
|
"onItemsChange",
|
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
"—",
|
|
51
51
|
"Return the discount fraction (0.1 = 10%) or null. Omit to hide the promo row."
|
|
52
52
|
],
|
|
53
|
+
[
|
|
54
|
+
"defaultPromo",
|
|
55
|
+
"string",
|
|
56
|
+
"—",
|
|
57
|
+
"A code to apply on mount (checked with onApplyPromo), e.g. a coupon picked on another screen."
|
|
58
|
+
],
|
|
53
59
|
[
|
|
54
60
|
"taxRate",
|
|
55
61
|
"number",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
{
|
|
122
122
|
"name": "Scrollable",
|
|
123
123
|
"title": "Scrollable",
|
|
124
|
-
"code": "import React, { useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { ChipGroup } from '@/components/ui/chip-group';\n\nexport default function Scrollable() {\n const [picked, setPicked] = useState<string[]>(['all']);\n return (\n <ChipGroup\n scrollable\n deselectable={false}\n value={picked}\n onValueChange={setPicked}\n options={[\n { value: 'all', label: 'All' },\n { value: 'coffee', label: 'Coffee', icon: <Text>☕️</Text> },\n { value: 'bakery', label: 'Bakery', icon: <Text>🥐</Text> },\n { value: 'brunch', label: 'Brunch', icon: <Text>🍳</Text> },\n { value: 'pizza', label: 'Pizza', icon: <Text>🍕</Text> },\n { value: 'sushi', label: 'Sushi', icon: <Text>🍣</Text> },\n ]}\n />\n );\n}\n"
|
|
124
|
+
"code": "import React, { useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { ChipGroup } from '@/components/ui/chip-group';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\nexport default function Scrollable() {\n const [picked, setPicked] = useState<string[]>(['all']);\n return (\n <ChipGroup\n scrollable\n deselectable={false}\n value={picked}\n onValueChange={setPicked}\n options={[\n { value: 'all', label: 'All' },\n { value: 'coffee', label: 'Coffee', icon: <Text maxFontSizeMultiplier={FONT_CAP}>☕️</Text> },\n { value: 'bakery', label: 'Bakery', icon: <Text maxFontSizeMultiplier={FONT_CAP}>🥐</Text> },\n { value: 'brunch', label: 'Brunch', icon: <Text maxFontSizeMultiplier={FONT_CAP}>🍳</Text> },\n { value: 'pizza', label: 'Pizza', icon: <Text maxFontSizeMultiplier={FONT_CAP}>🍕</Text> },\n { value: 'sushi', label: 'Sushi', icon: <Text maxFontSizeMultiplier={FONT_CAP}>🍣</Text> },\n ]}\n />\n );\n}\n"
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
"name": "Sizes",
|
|
@@ -86,17 +86,17 @@
|
|
|
86
86
|
{
|
|
87
87
|
"name": "Celebrate",
|
|
88
88
|
"title": "Celebrate",
|
|
89
|
-
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\nexport default function Celebrate() {\n const { colors, radius } = useKit();\n const confetti = useRef<ConfettiHandle>(null);\n return (\n <View
|
|
89
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\n/** Control text stops at iOS's largest standard size. */\nconst FONT_CAP = 1.35;\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 Celebrate({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const confetti = useRef<ConfettiHandle>(null);\n return (\n <View\n style={[\n { overflow: 'hidden', alignItems: 'center', justifyContent: 'center', gap: 10, padding: 24 },\n screen ? { flex: 1, backgroundColor: colors.background } : { height: 420, borderRadius: radius.xl, backgroundColor: colors.muted },\n ]}\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ fontSize: 44 }}>🎉</Text>\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ color: colors.foreground, fontSize: 24, fontWeight: '800', letterSpacing: -0.5 }}>Order placed!</Text>\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ color: colors.mutedForeground, fontSize: 14, textAlign: 'center' }}>You saved ₹240 with coupon GLOW50. Arriving Thursday.</Text>\n <Pressable\n onPress={() => confetti.current?.burst()}\n accessibilityRole=\"button\"\n style={{ marginTop: 12, paddingHorizontal: 22, paddingVertical: 13, borderRadius: 999, backgroundColor: colors.primary }}\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ color: colors.primaryForeground, fontSize: 15, fontWeight: '700' }}>Celebrate again</Text>\n </Pressable>\n <Confetti ref={confetti} autoplay />\n </View>\n );\n}\n"
|
|
90
90
|
},
|
|
91
91
|
{
|
|
92
92
|
"name": "Rain",
|
|
93
93
|
"title": "Rain",
|
|
94
|
-
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\nexport default function Rain() {\n const { colors, radius } = useKit();\n const [shower, setShower] = useState(0);\n return (\n <View
|
|
94
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\n/** Control text stops at iOS's largest standard size. */\nconst FONT_CAP = 1.35;\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 Rain({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const [shower, setShower] = useState(0);\n return (\n <View\n style={[\n { overflow: 'hidden', alignItems: 'center', justifyContent: 'center' },\n screen ? { flex: 1, backgroundColor: colors.background } : { height: 360, borderRadius: radius.xl, backgroundColor: colors.muted },\n ]}\n >\n <Pressable onPress={() => setShower((n) => n + 1)} accessibilityRole=\"button\" style={{ paddingHorizontal: 22, paddingVertical: 13, borderRadius: 999, borderWidth: 1.5, borderColor: colors.foreground }}>\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ color: colors.foreground, fontSize: 15, fontWeight: '700' }}>Make it rain</Text>\n </Pressable>\n <Confetti origin=\"top\" count={120} trigger={shower} colors={['#ffd23f', '#ffb000', '#fff3b0', '#ffffff']} />\n </View>\n );\n}\n"
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
"name": "TapToPop",
|
|
98
98
|
"title": "Tap To Pop",
|
|
99
|
-
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\nexport default function TapToPop() {\n const { colors, radius } = useKit();\n const confetti = useRef<ConfettiHandle>(null);\n return (\n <Pressable\n onPress={(e) => confetti.current?.burst({ origin: 'center', x: e.nativeEvent.locationX, y: e.nativeEvent.locationY, count: 50 })}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Tap to pop confetti\"\n style={{
|
|
99
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Confetti, type ConfettiHandle } from '@/components/ui/confetti';\nimport { useKit } from '@/lib/kit';\n\n/** Control text stops at iOS's largest standard size. */\nconst FONT_CAP = 1.35;\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 TapToPop({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const confetti = useRef<ConfettiHandle>(null);\n return (\n <Pressable\n onPress={(e) => confetti.current?.burst({ origin: 'center', x: e.nativeEvent.locationX, y: e.nativeEvent.locationY, count: 50 })}\n accessibilityRole=\"button\"\n accessibilityLabel=\"Tap to pop confetti\"\n style={[\n { overflow: 'hidden', alignItems: 'center', justifyContent: 'center' },\n screen ? { flex: 1, backgroundColor: colors.background } : { height: 360, borderRadius: radius.xl, backgroundColor: colors.muted },\n ]}\n >\n {/* Not touchable, so locationX/Y are always relative to the panel. */}\n <View pointerEvents=\"none\">\n <Text maxFontSizeMultiplier={FONT_CAP} style={{ color: colors.mutedForeground, fontSize: 15, fontWeight: '600' }}>Tap anywhere</Text>\n </View>\n <Confetti ref={confetti} />\n </Pressable>\n );\n}\n"
|
|
100
100
|
}
|
|
101
101
|
]
|
|
102
102
|
}
|
|
@@ -248,22 +248,22 @@
|
|
|
248
248
|
{
|
|
249
249
|
"name": "Birthday",
|
|
250
250
|
"title": "Birthday",
|
|
251
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth
|
|
251
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : [s.cardFrame, { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card }],\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, gap: 14 },\n cardFrame: { borderWidth: StyleSheet.hairlineWidth },\n header: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: 10 },\n title: { flexShrink: 1, fontSize: 15, fontWeight: '400' },\n switch: { flexDirection: 'row', padding: 3 },\n switchItem: { minHeight: 28, paddingHorizontal: 10, alignItems: 'center', justifyContent: 'center' },\n switchText: { fontSize: 12.5, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n button: { minHeight: 46, alignItems: 'center', justifyContent: 'center' },\n buttonText: { fontSize: 15, fontWeight: '400' },\n});\n\nexport default function Birthday({ screen }: DemoProps) {\n const [date, setDate] = useState<Date | null>(new Date(1994, 5, 12));\n const age = date ? Math.floor((today.getTime() - date.getTime()) / (365.25 * 86400000)) : null;\n const [opens, setOpens] = useState<Opens>('sheet');\n return (\n <Card screen={screen}>\n <Header title=\"Profile\" opens={opens} onOpens={setOpens} />\n <DatePicker\n key={opens}\n presentation={opens}\n label=\"Date of birth\"\n value={date}\n onChange={setDate}\n maxDate={today}\n formatOptions={{ day: 'numeric', month: 'long', year: 'numeric' }}\n helper={age !== null ? `You're ${age}. Tap the month title to jump years.` : 'Used to personalise your plan.'}\n />\n </Card>\n );\n}\n"
|
|
252
252
|
},
|
|
253
253
|
{
|
|
254
254
|
"name": "TripDates",
|
|
255
255
|
"title": "Trip Dates",
|
|
256
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth
|
|
256
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : [s.cardFrame, { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card }],\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, gap: 14 },\n cardFrame: { borderWidth: StyleSheet.hairlineWidth },\n header: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: 10 },\n title: { flexShrink: 1, fontSize: 15, fontWeight: '400' },\n switch: { flexDirection: 'row', padding: 3 },\n switchItem: { minHeight: 28, paddingHorizontal: 10, alignItems: 'center', justifyContent: 'center' },\n switchText: { fontSize: 12.5, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n button: { minHeight: 46, alignItems: 'center', justifyContent: 'center' },\n buttonText: { fontSize: 15, fontWeight: '400' },\n});\n\nexport default function TripDates({ screen }: DemoProps) {\n const [trip, setTrip] = useState<DateRange | null>(null);\n const nights = trip?.start && trip.end ? Math.round((trip.end.getTime() - trip.start.getTime()) / 86400000) : 0;\n const [opens, setOpens] = useState<Opens>('dialog');\n return (\n <Card screen={screen}>\n <Header title=\"Trip · Kyoto\" opens={opens} onOpens={setOpens} />\n <DatePicker\n key={opens}\n presentation={opens}\n mode=\"range\"\n label=\"Check-in – Check-out\"\n title=\"When are you travelling?\"\n placeholder=\"Add dates\"\n value={trip}\n onChange={setTrip}\n presets\n confirm\n clearable\n minDate={today}\n success={nights ? `${nights} night${nights > 1 ? 's' : ''} · free cancellation until 48h before` : undefined}\n />\n </Card>\n );\n}\n"
|
|
257
257
|
},
|
|
258
258
|
{
|
|
259
259
|
"name": "Deadline",
|
|
260
260
|
"title": "Deadline",
|
|
261
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth
|
|
261
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Controls stop at iOS's largest standard text size; content text stays uncapped. */\nconst FONT_CAP = 1.35;\n\n/** From the Expo Go viewer: `screen` = this IS the phone screen, so no mock frame; `bottomInset` = home indicator. */\ntype DemoProps = { screen?: boolean; bottomInset?: number };\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : [s.cardFrame, { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card }],\n style,\n ]}\n {...rest}\n />\n );\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\ntype Opens = Exclude<DatePickerPresentation, 'auto'>;\n\nconst OPENS: { key: Opens; label: string }[] = [\n { key: 'sheet', label: 'Sheet' },\n { key: 'dialog', label: 'Modal' },\n { key: 'popover', label: 'Popover' },\n];\n\n/** Card header with a compact switch for how the picker opens. */\nfunction Header({ title, opens, onOpens }: { title: string; opens: Opens; onOpens: (o: Opens) => void }) {\n const { colors, radius } = useKit();\n return (\n <View style={s.header}>\n <Text style={[s.title, { color: colors.foreground }]} numberOfLines={1}>\n {title}\n </Text>\n <View style={[s.switch, { backgroundColor: colors.muted, borderRadius: radius.md }]} accessibilityRole=\"radiogroup\">\n {OPENS.map((o) => {\n const on = o.key === opens;\n return (\n <Pressable\n key={o.key}\n onPress={() => onOpens(o.key)}\n accessibilityRole=\"radio\"\n accessibilityState={{ checked: on }}\n accessibilityLabel={`Open as ${o.label}`}\n style={[s.switchItem, { borderRadius: Math.max(0, radius.md - 3) }, on && { backgroundColor: colors.background }]}\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={[s.switchText, { color: on ? colors.foreground : colors.mutedForeground }]}>{o.label}</Text>\n </Pressable>\n );\n })}\n </View>\n </View>\n );\n}\n\nconst s = StyleSheet.create({\n card: { padding: 16, gap: 14 },\n cardFrame: { borderWidth: StyleSheet.hairlineWidth },\n header: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: 10 },\n title: { flexShrink: 1, fontSize: 15, fontWeight: '400' },\n switch: { flexDirection: 'row', padding: 3 },\n switchItem: { minHeight: 28, paddingHorizontal: 10, alignItems: 'center', justifyContent: 'center' },\n switchText: { fontSize: 12.5, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n button: { minHeight: 46, alignItems: 'center', justifyContent: 'center' },\n buttonText: { fontSize: 15, fontWeight: '400' },\n});\n\nexport default function Deadline({ screen }: DemoProps) {\n const { colors, radius } = useKit();\n const [due, setDue] = useState<Date | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const [opens, setOpens] = useState<Opens>('popover');\n return (\n <Card screen={screen}>\n <Header title=\"New task\" opens={opens} onOpens={setOpens} />\n <DatePicker\n key={opens}\n presentation={opens}\n label=\"Due date\"\n value={due}\n onChange={setDue}\n minDate={today}\n isDateDisabled={(d) => d.getDay() === 0 || d.getDay() === 6}\n presets={[\n { label: 'Tomorrow', value: () => new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1) },\n { label: 'End of month', value: () => new Date(today.getFullYear(), today.getMonth() + 1, 0) },\n ]}\n error={submitted && !due ? 'Pick a due date so the team can plan around it' : undefined}\n helper=\"Weekdays only.\"\n />\n <Pressable\n onPress={() => setSubmitted(true)}\n style={({ pressed }) => [s.button, { backgroundColor: colors.accent, borderRadius: radius.md, opacity: pressed ? 0.85 : 1 }]}\n accessibilityRole=\"button\"\n >\n <Text maxFontSizeMultiplier={FONT_CAP} style={[s.buttonText, { color: colors.accentForeground }]}>Create task</Text>\n </Pressable>\n </Card>\n );\n}\n"
|
|
262
262
|
},
|
|
263
263
|
{
|
|
264
264
|
"name": "Sizes",
|
|
265
265
|
"title": "Sizes",
|
|
266
|
-
"code": "import { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\nimport { useKit } from '@/lib/kit';\n\n/** Demo card that follows the kit theme, so the docs radius / accent picker reshapes it too. */\nfunction Card({ style, ...rest }: ViewProps) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card },\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\nconst s = StyleSheet.create({\n card: { padding: 16, borderWidth: StyleSheet.hairlineWidth
|
|
266
|
+
"code": "import { Pressable, StyleSheet, Text, View, type TextProps, type ViewProps } from 'react-native';\nimport { DatePicker, type DatePickerPresentation, type DateRange } from '@/components/ui/date-picker';\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({ screen, style, ...rest }: ViewProps & { screen?: boolean }) {\n const { colors, radius } = useKit();\n return (\n <View\n style={[\n s.card,\n screen\n ? { flex: 1, backgroundColor: colors.background }\n : [s.cardFrame, { borderRadius: radius.xl, borderColor: colors.border, backgroundColor: colors.card }],\n style,\n ]}\n {...rest}\n />\n );\n}\n\n/** Text in the kit's ink: `tone=\"muted\"` for secondary copy. */\nfunction Ink({ tone, style, ...rest }: TextProps & { tone?: 'muted' }) {\n const { colors } = useKit();\n return <Text style={[{ color: tone === 'muted' ? colors.mutedForeground : colors.foreground }, style]} {...rest} />;\n}\n\nconst today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate());\n\nconst s = StyleSheet.create({\n card: { padding: 16, gap: 14 },\n cardFrame: { borderWidth: StyleSheet.hairlineWidth },\n header: { flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'space-between', gap: 10 },\n title: { flexShrink: 1, fontSize: 15, fontWeight: '400' },\n switch: { flexDirection: 'row', padding: 3 },\n switchItem: { minHeight: 28, paddingHorizontal: 10, alignItems: 'center', justifyContent: 'center' },\n switchText: { fontSize: 12.5, fontWeight: '400' },\n label: { fontSize: 12, fontWeight: '400', letterSpacing: 0.4, textTransform: 'uppercase', marginBottom: -6 },\n button: { minHeight: 46, alignItems: 'center', justifyContent: 'center' },\n buttonText: { fontSize: 15, fontWeight: '400' },\n});\n\nexport default function Sizes({ screen }: DemoProps) {\n const d = new Date(today.getFullYear(), today.getMonth(), 24);\n return (\n <Card screen={screen}>\n <Ink tone=\"muted\" style={s.label}>Small</Ink>\n <DatePicker size=\"sm\" label=\"Invoice date\" defaultValue={d} />\n <Ink tone=\"muted\" style={s.label}>Medium</Ink>\n <DatePicker size=\"md\" label=\"Invoice date\" defaultValue={d} />\n <Ink tone=\"muted\" style={s.label}>Large</Ink>\n <DatePicker size=\"lg\" label=\"Invoice date\" defaultValue={d} />\n <Ink tone=\"muted\" style={s.label}>Disabled</Ink>\n <DatePicker disabled label=\"Invoice date\" defaultValue={d} />\n </Card>\n );\n}\n"
|
|
267
267
|
}
|
|
268
268
|
]
|
|
269
269
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "donut-shop",
|
|
3
|
+
"category": "Blocks",
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"exportName": "DonutShop",
|
|
6
|
+
"files": [
|
|
7
|
+
"src/components/blocks/donut-shop.tsx"
|
|
8
|
+
],
|
|
9
|
+
"summary": "Donuts roll across a carousel and zoom into a detail view beside their nutrition.",
|
|
10
|
+
"props": [
|
|
11
|
+
[
|
|
12
|
+
"items",
|
|
13
|
+
"DonutItem[]",
|
|
14
|
+
"5 donuts",
|
|
15
|
+
"{ name, price, icing, topping?, toppingColor?, image?, nutrition? }."
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
"title",
|
|
19
|
+
"string",
|
|
20
|
+
"'Dunats'",
|
|
21
|
+
"Shop name, in a script face."
|
|
22
|
+
],
|
|
23
|
+
[
|
|
24
|
+
"currency",
|
|
25
|
+
"string",
|
|
26
|
+
"'$'",
|
|
27
|
+
"Prefix for prices."
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
"background",
|
|
31
|
+
"string",
|
|
32
|
+
"soft pink",
|
|
33
|
+
"Page colour in light mode."
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"initialIndex",
|
|
37
|
+
"number",
|
|
38
|
+
"0",
|
|
39
|
+
"Donut shown first."
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"onIndexChange",
|
|
43
|
+
"(index: number) => void",
|
|
44
|
+
"—",
|
|
45
|
+
"The centred donut changed."
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
"onAddToCart",
|
|
49
|
+
"(item, quantity) => void",
|
|
50
|
+
"—",
|
|
51
|
+
"Add to Cart pressed."
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
"style",
|
|
55
|
+
"StyleProp<ViewStyle>",
|
|
56
|
+
"flex: 1",
|
|
57
|
+
"Root style."
|
|
58
|
+
]
|
|
59
|
+
],
|
|
60
|
+
"behavior": [
|
|
61
|
+
[
|
|
62
|
+
"Swipe",
|
|
63
|
+
"Donuts roll a full turn per circumference travelled and snap to the nearest; the centre one is larger."
|
|
64
|
+
],
|
|
65
|
+
[
|
|
66
|
+
"+",
|
|
67
|
+
"Grows into a + 01 − stepper; an add-to-cart bar with the running total rises from the bottom."
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
"Detail",
|
|
71
|
+
"Tap the donut: the list pushes away, the donut zooms to the right edge and keeps turning, the name and nutrition chips slide in. Back reverses it."
|
|
72
|
+
],
|
|
73
|
+
[
|
|
74
|
+
"Art",
|
|
75
|
+
"Drawn donuts per item (icing colour, sprinkles / drizzle / specks), or your own image per item."
|
|
76
|
+
],
|
|
77
|
+
[
|
|
78
|
+
"Haptics",
|
|
79
|
+
"A tick on each snap and a medium impact on Add to Cart."
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"Reduced motion",
|
|
83
|
+
"The detail donut stops its idle spin."
|
|
84
|
+
]
|
|
85
|
+
],
|
|
86
|
+
"usage": null,
|
|
87
|
+
"examples": []
|
|
88
|
+
}
|