@expokit/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/bin/expo-kit.js +86 -24
- package/bin/mcp.mjs +8 -1
- package/package.json +8 -3
- 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/avatar.json +24 -0
- package/registry/_docs/badge.json +35 -4
- package/registry/_docs/bottom-nav.json +24 -0
- package/registry/_docs/bottom-sheet.json +28 -0
- package/registry/_docs/bullet.json +3 -0
- package/registry/_docs/button-3d.json +16 -0
- package/registry/_docs/button.json +16 -0
- package/registry/_docs/calendar.json +16 -0
- 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 +3 -0
- package/registry/_docs/chip-group.json +16 -0
- package/registry/_docs/color-swatch.json +16 -0
- package/registry/_docs/confetti.json +20 -0
- 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 +20 -0
- package/registry/_docs/dialog.json +24 -0
- package/registry/_docs/drawer.json +28 -0
- package/registry/_docs/fab.json +24 -0
- package/registry/_docs/flip-card.json +16 -0
- package/registry/_docs/floating-input.json +20 -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 +16 -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/kpi-card.json +3 -0
- package/registry/_docs/like-button.json +20 -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/morph-button.json +20 -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/otp-input.json +24 -0
- package/registry/_docs/pagination-dots.json +20 -0
- package/registry/_docs/parallax-layers.json +20 -0
- package/registry/_docs/parallax-scroll.json +24 -0
- package/registry/_docs/password-input.json +20 -0
- 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/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 +20 -0
- package/registry/_docs/search-results.json +3 -0
- package/registry/_docs/segmented-control.json +20 -0
- package/registry/_docs/select.json +26 -1
- package/registry/_docs/settings.json +3 -0
- package/registry/_docs/shimmer-button.json +20 -0
- package/registry/_docs/sign-in.json +3 -0
- package/registry/_docs/skeleton.json +20 -0
- package/registry/_docs/slide-to-confirm.json +24 -0
- package/registry/_docs/slider.json +21 -1
- 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 +16 -0
- 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/tag-input.json +20 -0
- package/registry/_docs/text-animation.json +141 -0
- package/registry/_docs/textarea.json +16 -0
- package/registry/_docs/ticket-card.json +20 -0
- package/registry/_docs/ticket-shape.json +3 -0
- package/registry/_docs/tilt-card.json +16 -0
- package/registry/_docs/time-picker.json +16 -0
- package/registry/_docs/timeline-chart.json +3 -0
- package/registry/_docs/timeline.json +16 -0
- package/registry/_docs/toast.json +24 -0
- package/registry/_docs/treemap.json +3 -0
- package/registry/_docs/waterfall.json +3 -0
- package/registry/_docs/wheel-list.json +20 -0
- package/registry/badge/files/src/components/ui/badge.tsx +327 -17
- package/registry/badge.json +1 -1
- package/registry/chat.json +18 -0
- package/registry/spinner/files/src/components/ui/spinner.tsx +435 -22
- package/registry/spinner.json +1 -1
- package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +532 -0
- package/registry/stateful-button/files/src/lib/kit.tsx +219 -0
- package/registry/stateful-button.json +18 -0
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +650 -0
- package/registry/text-animation/files/src/lib/kit.tsx +219 -0
- package/registry/text-animation.json +15 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/shimmer-button.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A call-to-action with a looping light sweep, breathing glow or orbiting beam.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"variant",
|
|
@@ -74,5 +75,24 @@
|
|
|
74
75
|
"onPress, disabled, …"
|
|
75
76
|
]
|
|
76
77
|
],
|
|
78
|
+
"behavior": [
|
|
79
|
+
[
|
|
80
|
+
"Motion",
|
|
81
|
+
"'shimmer' sweeps a light band across on a loop, 'glow' breathes a soft halo and 'border-beam' sends a bright comet around the border. speed sets the loop length."
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"Touch",
|
|
85
|
+
"Pressing scales the button down on a bouncy spring."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"Reduced motion",
|
|
89
|
+
"With Reduce Motion on, or while disabled, the loop stops and the button rests in a still state."
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
"Screen readers",
|
|
93
|
+
"A button with its disabled state. Other Pressable props, such as accessibilityLabel, pass through."
|
|
94
|
+
]
|
|
95
|
+
],
|
|
96
|
+
"usage": null,
|
|
77
97
|
"examples": []
|
|
78
98
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/blocks/sign-in.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": null,
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"methods",
|
|
@@ -194,5 +195,7 @@
|
|
|
194
195
|
"Aliases of onEmailPassword / onOAuth; providers (apple / google) sets the OAuth part of methods when methods isn't given."
|
|
195
196
|
]
|
|
196
197
|
],
|
|
198
|
+
"behavior": [],
|
|
199
|
+
"usage": null,
|
|
197
200
|
"examples": []
|
|
198
201
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/skeleton.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "Loading placeholders swept by one angled light band across the whole screen.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"width / height",
|
|
@@ -92,6 +93,25 @@
|
|
|
92
93
|
"Style for the block (composites apply it to their wrapper)."
|
|
93
94
|
]
|
|
94
95
|
],
|
|
96
|
+
"behavior": [
|
|
97
|
+
[
|
|
98
|
+
"Motion",
|
|
99
|
+
"Every block reads one shared native-driver clock, so the shimmer band, wave or pulse moves across a Skeleton.Group (or the window) as a single sweep."
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
"Reduced motion",
|
|
103
|
+
"Every variant renders static, and Skeleton.Reveal swaps the skeleton for content instantly."
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
"Screen readers",
|
|
107
|
+
"Placeholder blocks are hidden from screen readers. Skeleton.Reveal is marked busy and exposes a progressbar named by loadingLabel; the content arrives in a polite live region."
|
|
108
|
+
],
|
|
109
|
+
[
|
|
110
|
+
"Platforms",
|
|
111
|
+
"Plain Animated views plus a react-native-svg gradient, so it runs the same on iOS, Android and web."
|
|
112
|
+
]
|
|
113
|
+
],
|
|
114
|
+
"usage": "import { Skeleton } from '@/components/ui/skeleton';\n\n<Skeleton.Group style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>\n <Skeleton.Avatar size={44} />\n <Skeleton.Text lines={2} style={{ flex: 1 }} />\n</Skeleton.Group>",
|
|
95
115
|
"examples": [
|
|
96
116
|
{
|
|
97
117
|
"name": "Shimmer",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/slide-to-confirm.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A slide-to-pay track whose thumb drags a glowing trail and ticks with haptics.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"label",
|
|
@@ -80,5 +81,28 @@
|
|
|
80
81
|
"Style for the track (merged over its height, radius and colour)."
|
|
81
82
|
]
|
|
82
83
|
],
|
|
84
|
+
"behavior": [
|
|
85
|
+
[
|
|
86
|
+
"Touch",
|
|
87
|
+
"Drag past the threshold, or flick fast past the halfway point, to confirm; anything less springs back. If onConfirm returns a promise the thumb spins until it settles."
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
"Motion",
|
|
91
|
+
"The thumb swells while held and a check draws on success; a rejected promise shakes the track and slides it back."
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
"Reduced motion",
|
|
95
|
+
"The idle nudge and the chevron shimmer on the thumb are turned off."
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
"Haptics",
|
|
99
|
+
"Selection ticks at 25, 50 and 75 percent of the drag, a medium impact on release, then a success or error notification."
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
"Screen readers",
|
|
103
|
+
"A button whose label switches to confirmedLabel when done, with busy and disabled state. The 'activate' action (double tap) confirms without dragging."
|
|
104
|
+
]
|
|
105
|
+
],
|
|
106
|
+
"usage": null,
|
|
83
107
|
"examples": []
|
|
84
108
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slider",
|
|
3
3
|
"category": "Inputs",
|
|
4
|
-
"aliases": [
|
|
4
|
+
"aliases": [
|
|
5
|
+
"range-slider",
|
|
6
|
+
"range",
|
|
7
|
+
"dual-slider"
|
|
8
|
+
],
|
|
5
9
|
"exportName": "Slider",
|
|
6
10
|
"files": [
|
|
7
11
|
"src/components/ui/slider.tsx"
|
|
8
12
|
],
|
|
13
|
+
"summary": "A native-driver slider with a swelling thumb, tap-to-seek and a two-thumb range mode.",
|
|
9
14
|
"props": [
|
|
10
15
|
[
|
|
11
16
|
"value / defaultValue",
|
|
@@ -122,6 +127,21 @@
|
|
|
122
127
|
"Root, inactive track, active fill, thumb and value text."
|
|
123
128
|
]
|
|
124
129
|
],
|
|
130
|
+
"behavior": [
|
|
131
|
+
[
|
|
132
|
+
"Touch",
|
|
133
|
+
"Tap anywhere on the track to seek, or grab a thumb and drag. Built-in leftIcon and rightIcon names step the value down or up when tapped."
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
"Motion",
|
|
137
|
+
"Thumb and fill move on the native driver; the thumb swells under your finger and values spring-snap to the step."
|
|
138
|
+
],
|
|
139
|
+
[
|
|
140
|
+
"Screen readers",
|
|
141
|
+
"Single mode is one adjustable element with min, max, current value and increment / decrement actions. In range mode each thumb is its own adjustable, labelled 'minimum' and 'maximum'."
|
|
142
|
+
]
|
|
143
|
+
],
|
|
144
|
+
"usage": "import { useState } from 'react';\nimport { Slider } from '@/components/ui/slider';\n\nconst [price, setPrice] = useState<[number, number]>([20, 80]);\n<Slider range value={price} onValueChange={setPrice} accessibilityLabel=\"Price\" />",
|
|
125
145
|
"examples": [
|
|
126
146
|
{
|
|
127
147
|
"name": "ControlCenter",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/spin-wheel.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A prize wheel whose flapper ticks over every divider as it eases onto the win.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"segments",
|
|
@@ -110,5 +111,28 @@
|
|
|
110
111
|
"Spin from your own button (optionally onto a fixed index), or cancel and turn back to the start."
|
|
111
112
|
]
|
|
112
113
|
],
|
|
114
|
+
"behavior": [
|
|
115
|
+
[
|
|
116
|
+
"Touch",
|
|
117
|
+
"Tap the SPIN hub or flick the wheel; a harder flick throws it further. A slow drag just springs back to rest."
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
"Motion",
|
|
121
|
+
"It keeps turning while getResult resolves, then eases onto the chosen wedge; the other wedges dim and the winner glows while the rim lights flash."
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"Reduced motion",
|
|
125
|
+
"The idle chasing lights, the win celebration and the winner pulse are skipped; the spin itself still plays."
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
"Haptics",
|
|
129
|
+
"A selection tick each time the flapper crosses a divider, a light impact on the hub, and a success notification on the win (skipped on web)."
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
"Screen readers",
|
|
133
|
+
"The wheel is an image whose label lists every prize; the hub is a button with busy state while spinning, and the result is announced."
|
|
134
|
+
]
|
|
135
|
+
],
|
|
136
|
+
"usage": null,
|
|
113
137
|
"examples": []
|
|
114
138
|
}
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spinner",
|
|
3
3
|
"category": "Feedback",
|
|
4
|
-
"aliases": [
|
|
4
|
+
"aliases": [
|
|
5
|
+
"loader",
|
|
6
|
+
"loading",
|
|
7
|
+
"activity-indicator",
|
|
8
|
+
"progress-indicator"
|
|
9
|
+
],
|
|
5
10
|
"exportName": "Spinner",
|
|
6
11
|
"files": [
|
|
7
12
|
"src/components/ui/spinner.tsx"
|
|
8
13
|
],
|
|
14
|
+
"summary": "Twelve loaders — ring, dots, bars, pulse, orbit, typing, line and more — from one API.",
|
|
9
15
|
"props": [
|
|
10
16
|
[
|
|
11
17
|
"variant",
|
|
12
|
-
"\"ring\" | \"dots\"",
|
|
18
|
+
"\"ring\" | \"dots\" | \"bars\" | \"pulse\" | \"orbit\" | \"bounce\" | \"wave\" | \"grid\" | \"typing\" | \"arc\" | \"square\" | \"line\"",
|
|
13
19
|
"\"ring\"",
|
|
14
|
-
"Indicator style."
|
|
20
|
+
"Indicator style — 12 loaders. \"line\" is an indeterminate bar size × 4 wide (override with style.width)."
|
|
15
21
|
],
|
|
16
22
|
[
|
|
17
23
|
"size",
|
|
18
24
|
"\"sm\" | \"md\" | \"lg\" | \"xl\" | number",
|
|
19
25
|
"\"md\"",
|
|
20
|
-
"16 / 24 / 36 / 52pt, or any number."
|
|
26
|
+
"16 / 24 / 36 / 52pt, or any number. Every variant scales from it."
|
|
21
27
|
],
|
|
22
28
|
[
|
|
23
29
|
"color",
|
|
@@ -47,7 +53,7 @@
|
|
|
47
53
|
"track",
|
|
48
54
|
"boolean",
|
|
49
55
|
"false",
|
|
50
|
-
"Faint full circle
|
|
56
|
+
"Faint guide behind the motion: full circle (ring, orbit, arc), rail (line) or ghost bars (bars)."
|
|
51
57
|
],
|
|
52
58
|
[
|
|
53
59
|
"style",
|
|
@@ -56,36 +62,60 @@
|
|
|
56
62
|
"Style for the root view (the square, or the spinner + label row/column)."
|
|
57
63
|
]
|
|
58
64
|
],
|
|
65
|
+
"behavior": [
|
|
66
|
+
[
|
|
67
|
+
"Motion",
|
|
68
|
+
"Every variant loops on the native driver (rotation, scale, translate, opacity); the ring's arc-length breathing is the only SVG prop animation and runs on its own JS-driven node."
|
|
69
|
+
],
|
|
70
|
+
[
|
|
71
|
+
"Reduced motion",
|
|
72
|
+
"Loops stop and each loader holds a still, clearly-busy frame (staggered dots, a lit diagonal, a mid-line segment); the ring keeps a plain steady spin."
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
"Screen readers",
|
|
76
|
+
"Announced as a progress bar with state busy and your label (default \"Loading\"); the visual is one accessible element."
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
"Platforms",
|
|
80
|
+
"Pure React Native Animated plus react-native-svg — iOS, Android, Expo Go and web, no native setup."
|
|
81
|
+
]
|
|
82
|
+
],
|
|
83
|
+
"usage": "import { Spinner } from '@/components/ui/spinner';\n\nexport function Saving() {\n return <Spinner variant=\"bars\" size=\"lg\" label=\"Saving changes\" labelPosition=\"right\" />;\n}",
|
|
59
84
|
"examples": [
|
|
60
85
|
{
|
|
61
86
|
"name": "Variants",
|
|
62
87
|
"title": "Variants",
|
|
63
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport default function Variants() {\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 40 }}>\n <Spinner variant=\"ring\" size=\"lg\" track />\n <Spinner variant=\"ring\" size=\"lg\" />\n <Spinner variant=\"dots\" size=\"lg\" />\n </View>\n );\n}\n"
|
|
88
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\n\nexport default function Variants() {\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 40 }}>\n <Spinner variant=\"ring\" size=\"lg\" track />\n <Spinner variant=\"ring\" size=\"lg\" />\n <Spinner variant=\"dots\" size=\"lg\" />\n </View>\n );\n}\n"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"name": "LoaderGallery",
|
|
92
|
+
"title": "Loader Gallery",
|
|
93
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nconst LOADERS: SpinnerVariant[] = ['ring', 'dots', 'bars', 'pulse', 'orbit', 'bounce', 'wave', 'grid', 'typing', 'arc', 'square', 'line'];\n\nexport default function LoaderGallery() {\n const { colors, radius } = useKit();\n return (\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', rowGap: 12 }}>\n {LOADERS.map((variant) => (\n <View key={variant} style={{ width: '33.33%', alignItems: 'center', gap: 8, paddingHorizontal: 4 }}>\n <View\n style={{\n alignSelf: 'stretch',\n height: 64,\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: radius.md,\n backgroundColor: colors.muted,\n }}\n >\n <Spinner\n variant={variant}\n size={variant === 'line' ? 'sm' : 'lg'}\n track={variant === 'line'}\n label={`${variant} loader`}\n style={variant === 'line' ? { width: '72%' } : undefined}\n />\n </View>\n <Text style={{ fontSize: 12, color: colors.mutedForeground }}>{variant}</Text>\n </View>\n ))}\n </View>\n );\n}\n"
|
|
64
94
|
},
|
|
65
95
|
{
|
|
66
96
|
"name": "InButton",
|
|
67
97
|
"title": "In Button",
|
|
68
|
-
"code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function InButton() {\n const { colors, radius } = useKit();\n const [busy, setBusy] = useState(false);\n const fg = readableOn(colors.accent);\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityState={{ busy }}\n onPress={() => {\n setBusy(true);\n setTimeout(() => setBusy(false), 2200);\n }}\n style={{\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n alignSelf: 'stretch',\n }}\n >\n {busy ? (\n <Spinner size=\"sm\" color={fg} label=\"Placing order\" labelPosition=\"right\" />\n ) : (\n <Text style={{ color: fg, fontSize: 16, fontWeight: '400' }}>Place order · ₹749</Text>\n )}\n </Pressable>\n );\n}\n"
|
|
98
|
+
"code": "import React, { useState } from 'react';\nimport { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function InButton() {\n const { colors, radius } = useKit();\n const [busy, setBusy] = useState(false);\n const fg = readableOn(colors.accent);\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityState={{ busy }}\n onPress={() => {\n setBusy(true);\n setTimeout(() => setBusy(false), 2200);\n }}\n style={{\n height: 48,\n borderRadius: radius.capsule(48),\n backgroundColor: colors.accent,\n alignItems: 'center',\n justifyContent: 'center',\n alignSelf: 'stretch',\n }}\n >\n {busy ? (\n <Spinner size=\"sm\" color={fg} label=\"Placing order\" labelPosition=\"right\" />\n ) : (\n <Text style={{ color: fg, fontSize: 16, fontWeight: '400' }}>Place order · ₹749</Text>\n )}\n </Pressable>\n );\n}\n"
|
|
69
99
|
},
|
|
70
100
|
{
|
|
71
101
|
"name": "LoadingCard",
|
|
72
102
|
"title": "Loading Card",
|
|
73
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function LoadingCard() {\n const { colors, radius } = useKit();\n return (\n <View\n style={{\n alignSelf: 'stretch',\n alignItems: 'center',\n gap: 6,\n paddingVertical: 32,\n paddingHorizontal: 20,\n borderRadius: radius.lg,\n backgroundColor: colors.card,\n borderWidth: 1,\n borderColor: colors.border,\n }}\n >\n <Spinner size=\"xl\" track label=\"Preparing your itinerary\" labelPosition=\"bottom\" />\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>\n Checking 3 flights and 2 hotels\n </Text>\n </View>\n );\n}\n"
|
|
103
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function LoadingCard() {\n const { colors, radius } = useKit();\n return (\n <View\n style={{\n alignSelf: 'stretch',\n alignItems: 'center',\n gap: 6,\n paddingVertical: 32,\n paddingHorizontal: 20,\n borderRadius: radius.lg,\n backgroundColor: colors.card,\n borderWidth: 1,\n borderColor: colors.border,\n }}\n >\n <Spinner size=\"xl\" track label=\"Preparing your itinerary\" labelPosition=\"bottom\" />\n <Text style={{ fontSize: 13, color: colors.mutedForeground, textAlign: 'center' }}>\n Checking 3 flights and 2 hotels\n </Text>\n </View>\n );\n}\n"
|
|
74
104
|
},
|
|
75
105
|
{
|
|
76
106
|
"name": "InlineStatus",
|
|
77
107
|
"title": "Inline Status",
|
|
78
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport default function InlineStatus() {\n return (\n <View style={{ gap: 16 }}>\n <Spinner size=\"sm\" label=\"Syncing 128 photos\" labelPosition=\"right\" />\n <Spinner variant=\"dots\" size=\"md\" label=\"Maya is typing\" labelPosition=\"right\" />\n </View>\n );\n}\n"
|
|
108
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\n\nexport default function InlineStatus() {\n return (\n <View style={{ gap: 16 }}>\n <Spinner size=\"sm\" label=\"Syncing 128 photos\" labelPosition=\"right\" />\n <Spinner variant=\"dots\" size=\"md\" label=\"Maya is typing\" labelPosition=\"right\" />\n </View>\n );\n}\n"
|
|
79
109
|
},
|
|
80
110
|
{
|
|
81
111
|
"name": "Colors",
|
|
82
112
|
"title": "Colors",
|
|
83
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function Colors() {\n const { colors } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', gap: 20 }}>\n <Spinner size=\"lg\" color={colors.success} track />\n <Spinner variant=\"dots\" size=\"lg\" color={colors.warning} />\n <Spinner size=\"lg\" color={colors.danger} />\n </View>\n );\n}\n"
|
|
113
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\nimport { readableOn, useKit } from '@/lib/kit';\n\nexport default function Colors() {\n const { colors } = useKit();\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', gap: 20 }}>\n <Spinner size=\"lg\" color={colors.success} track />\n <Spinner variant=\"dots\" size=\"lg\" color={colors.warning} />\n <Spinner size=\"lg\" color={colors.danger} />\n </View>\n );\n}\n"
|
|
84
114
|
},
|
|
85
115
|
{
|
|
86
116
|
"name": "Sizes",
|
|
87
117
|
"title": "Sizes",
|
|
88
|
-
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner } from '@/components/ui/spinner';\n\nexport default function Sizes() {\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 24 }}>\n <Spinner size=\"sm\" />\n <Spinner size=\"md\" />\n <Spinner size=\"lg\" />\n <Spinner size=\"xl\" />\n </View>\n );\n}\n"
|
|
118
|
+
"code": "import { Pressable, Text, View } from 'react-native';\nimport { Spinner, type SpinnerVariant } from '@/components/ui/spinner';\n\nexport default function Sizes() {\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 24 }}>\n <Spinner size=\"sm\" />\n <Spinner size=\"md\" />\n <Spinner size=\"lg\" />\n <Spinner size=\"xl\" />\n </View>\n );\n}\n"
|
|
89
119
|
}
|
|
90
120
|
]
|
|
91
121
|
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stateful-button",
|
|
3
|
+
"category": "Buttons",
|
|
4
|
+
"aliases": [
|
|
5
|
+
"loading-button",
|
|
6
|
+
"async-button",
|
|
7
|
+
"status-button"
|
|
8
|
+
],
|
|
9
|
+
"exportName": "StatefulButton",
|
|
10
|
+
"files": [
|
|
11
|
+
"src/components/ui/stateful-button.tsx"
|
|
12
|
+
],
|
|
13
|
+
"summary": "Button whose label rolls and width springs through loading, success and error.",
|
|
14
|
+
"props": [
|
|
15
|
+
[
|
|
16
|
+
"children",
|
|
17
|
+
"string",
|
|
18
|
+
"—",
|
|
19
|
+
"Label while idle."
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"state",
|
|
23
|
+
"\"idle\" | \"loading\" | \"success\" | \"error\"",
|
|
24
|
+
"—",
|
|
25
|
+
"Controlled state. Omit it to let a Promise from onPress drive the button."
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"onPress",
|
|
29
|
+
"() => void | Promise<unknown>",
|
|
30
|
+
"—",
|
|
31
|
+
"Resolve → success, reject → error, then back to idle (when state is not set)."
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
"loadingText",
|
|
35
|
+
"string",
|
|
36
|
+
"children",
|
|
37
|
+
"Label while loading."
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
"successText",
|
|
41
|
+
"string",
|
|
42
|
+
"\"Done\"",
|
|
43
|
+
"Label after success."
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
"errorText",
|
|
47
|
+
"string",
|
|
48
|
+
"\"Failed\"",
|
|
49
|
+
"Label after an error."
|
|
50
|
+
],
|
|
51
|
+
[
|
|
52
|
+
"variant",
|
|
53
|
+
"\"primary\" | \"secondary\" | \"outline\" | \"ghost\"",
|
|
54
|
+
"\"primary\"",
|
|
55
|
+
"Idle look; success and error tint it green / red."
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"size",
|
|
59
|
+
"\"sm\" | \"md\" | \"lg\"",
|
|
60
|
+
"\"md\"",
|
|
61
|
+
"36 / 46 / 54pt tall."
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"color",
|
|
65
|
+
"string",
|
|
66
|
+
"theme primary",
|
|
67
|
+
"Tint for the idle look."
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
"resetAfter",
|
|
71
|
+
"number",
|
|
72
|
+
"1600",
|
|
73
|
+
"ms the result shows before returning to idle (self-driving only)."
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"minLoading",
|
|
77
|
+
"number",
|
|
78
|
+
"500",
|
|
79
|
+
"Minimum ms of spinner (self-driving only)."
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"onStateChange",
|
|
83
|
+
"(state) => void",
|
|
84
|
+
"—",
|
|
85
|
+
"Called on every state change."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"pill",
|
|
89
|
+
"boolean",
|
|
90
|
+
"false",
|
|
91
|
+
"Fully rounded ends."
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
"block",
|
|
95
|
+
"boolean",
|
|
96
|
+
"false",
|
|
97
|
+
"Stretch to the parent's width (no width animation)."
|
|
98
|
+
],
|
|
99
|
+
[
|
|
100
|
+
"disabled",
|
|
101
|
+
"boolean",
|
|
102
|
+
"false",
|
|
103
|
+
"Blocks presses and dims the button."
|
|
104
|
+
],
|
|
105
|
+
[
|
|
106
|
+
"haptics",
|
|
107
|
+
"boolean",
|
|
108
|
+
"true",
|
|
109
|
+
"Taps on press, success and error."
|
|
110
|
+
],
|
|
111
|
+
[
|
|
112
|
+
"accessibilityLabel",
|
|
113
|
+
"string",
|
|
114
|
+
"current label",
|
|
115
|
+
"Override what screen readers hear."
|
|
116
|
+
],
|
|
117
|
+
[
|
|
118
|
+
"textStyle",
|
|
119
|
+
"StyleProp<TextStyle>",
|
|
120
|
+
"—",
|
|
121
|
+
"Style for the label letters."
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"style",
|
|
125
|
+
"StyleProp<ViewStyle>",
|
|
126
|
+
"—",
|
|
127
|
+
"Style for the outer wrapper (margins, alignment)."
|
|
128
|
+
]
|
|
129
|
+
],
|
|
130
|
+
"behavior": [
|
|
131
|
+
[
|
|
132
|
+
"Touch",
|
|
133
|
+
"Springs to 96% on press; at least 44pt tall to touch (hitSlop on the small size). Presses are ignored while loading and, when self-driving, until it returns to idle."
|
|
134
|
+
],
|
|
135
|
+
[
|
|
136
|
+
"Motion",
|
|
137
|
+
"Label letters roll on the native driver; width, colour and the check / cross stroke spring or ease on the JS driver on separate views."
|
|
138
|
+
],
|
|
139
|
+
[
|
|
140
|
+
"Reduced motion",
|
|
141
|
+
"Labels crossfade instead of rolling and the width changes instantly."
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
"Haptics",
|
|
145
|
+
"Light tap on press, success / error notification on the result (expo-haptics; turn off with haptics={false})."
|
|
146
|
+
],
|
|
147
|
+
[
|
|
148
|
+
"Screen readers",
|
|
149
|
+
"Button role with busy and disabled state; every new label (Saving…, Saved, Failed) is announced."
|
|
150
|
+
],
|
|
151
|
+
[
|
|
152
|
+
"Platforms",
|
|
153
|
+
"iOS, Android and web."
|
|
154
|
+
]
|
|
155
|
+
],
|
|
156
|
+
"usage": "import { StatefulButton } from '@/components/ui/stateful-button';\n\n<StatefulButton loadingText=\"Saving…\" successText=\"Saved\" onPress={() => save()}>\n Save changes\n</StatefulButton>\n\n<StatefulButton state={state} errorText=\"Retry\">Upload</StatefulButton>",
|
|
157
|
+
"examples": [
|
|
158
|
+
{
|
|
159
|
+
"name": "SaveChanges",
|
|
160
|
+
"title": "Save Changes",
|
|
161
|
+
"code": "import { StatefulButton, type StatefulButtonState } from '@/components/ui/stateful-button';\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport default function SaveChanges() {\n return (\n <StatefulButton loadingText=\"Saving…\" successText=\"Saved\" onPress={() => sleep(1200)}>\n Save changes\n </StatefulButton>\n );\n}\n"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"name": "PaymentRetry",
|
|
165
|
+
"title": "Payment Retry",
|
|
166
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StatefulButton, type StatefulButtonState } from '@/components/ui/stateful-button';\nimport { useKit } from '@/lib/kit';\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport default function PaymentRetry() {\n const { colors } = useKit();\n const attempts = useRef(0);\n const [note, setNote] = useState('First attempt is declined, the retry goes through.');\n return (\n <View style={{ gap: 10 }}>\n <StatefulButton\n block\n size=\"lg\"\n loadingText=\"Processing…\"\n successText=\"Paid ₹1,299\"\n errorText=\"Card declined\"\n onPress={async () => {\n attempts.current += 1;\n await sleep(1300);\n if (attempts.current % 2 === 1) {\n setNote('Declined by the bank. Tap again to retry.');\n throw new Error('declined');\n }\n setNote('Payment received.');\n }}\n >\n Pay ₹1,299\n </StatefulButton>\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>{note}</Text>\n </View>\n );\n}\n"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"name": "Controlled",
|
|
170
|
+
"title": "Controlled",
|
|
171
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StatefulButton, type StatefulButtonState } from '@/components/ui/stateful-button';\nimport { useKit } from '@/lib/kit';\n\nconst ORDER: StatefulButtonState[] = ['idle', 'loading', 'success', 'error'];\n\nexport default function Controlled() {\n const { colors, radius } = useKit();\n const [state, setState] = useState<StatefulButtonState>('idle');\n return (\n <View style={{ gap: 14 }}>\n <StatefulButton state={state} loadingText=\"Uploading\" successText=\"Uploaded\" errorText=\"Retry upload\">\n Upload\n </StatefulButton>\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>\n {ORDER.map((s) => (\n <Text\n key={s}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: s === state }}\n onPress={() => setState(s)}\n style={{\n paddingHorizontal: 12,\n paddingVertical: 8,\n borderRadius: radius.capsule(34),\n overflow: 'hidden',\n fontSize: 13,\n color: s === state ? colors.accentForeground : colors.foreground,\n backgroundColor: s === state ? colors.accent : colors.muted,\n }}\n >\n {s}\n </Text>\n ))}\n </View>\n </View>\n );\n}\n"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"name": "VariantsAndSizes",
|
|
175
|
+
"title": "Variants And Sizes",
|
|
176
|
+
"code": "import { Text, View } from 'react-native';\nimport { StatefulButton, type StatefulButtonState } from '@/components/ui/stateful-button';\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport default function VariantsAndSizes() {\n return (\n <View style={{ gap: 12 }}>\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 10 }}>\n <StatefulButton onPress={() => sleep(1000)}>Publish</StatefulButton>\n <StatefulButton variant=\"secondary\" onPress={() => sleep(1000)}>Sync</StatefulButton>\n <StatefulButton variant=\"outline\" onPress={() => sleep(1000)}>Export</StatefulButton>\n <StatefulButton variant=\"ghost\" onPress={() => sleep(1000)}>Archive</StatefulButton>\n </View>\n <View style={{ flexDirection: 'row', flexWrap: 'wrap', alignItems: 'center', gap: 10 }}>\n <StatefulButton size=\"sm\" pill onPress={() => sleep(1000)}>Small</StatefulButton>\n <StatefulButton size=\"md\" pill onPress={() => sleep(1000)}>Medium</StatefulButton>\n <StatefulButton size=\"lg\" pill onPress={() => sleep(1000)}>Large</StatefulButton>\n </View>\n </View>\n );\n}\n"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"name": "FollowToggle",
|
|
180
|
+
"title": "Follow Toggle",
|
|
181
|
+
"code": "import React, { useRef, useState } from 'react';\nimport { Text, View } from 'react-native';\nimport { StatefulButton, type StatefulButtonState } from '@/components/ui/stateful-button';\nimport { useKit } from '@/lib/kit';\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport default function FollowToggle() {\n const { colors } = useKit();\n const [following, setFollowing] = useState(false);\n return (\n <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>\n <View style={{ flexShrink: 1 }}>\n <Text style={{ fontSize: 16, fontWeight: '600', color: colors.foreground }}>Expo</Text>\n <Text style={{ fontSize: 13, color: colors.mutedForeground }}>@expo · 214K followers</Text>\n </View>\n <StatefulButton\n pill\n size=\"sm\"\n variant=\"secondary\"\n successText={following ? 'Following' : 'Unfollowed'}\n resetAfter={900}\n onPress={async () => {\n await sleep(700);\n setFollowing((f) => !f);\n }}\n >\n {following ? 'Following' : 'Follow'}\n </StatefulButton>\n </View>\n );\n}\n"
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/stepper.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A quantity stepper whose digits roll up or down as the number changes.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"value / defaultValue",
|
|
@@ -128,6 +129,21 @@
|
|
|
128
129
|
"Applied to the number (fontSize, colour, weight)."
|
|
129
130
|
]
|
|
130
131
|
],
|
|
132
|
+
"behavior": [
|
|
133
|
+
[
|
|
134
|
+
"Touch",
|
|
135
|
+
"Hold a button to keep stepping, speeding up as you hold. The cart variant opens from a single + into − 1 +, with a trash can at 1."
|
|
136
|
+
],
|
|
137
|
+
[
|
|
138
|
+
"Motion",
|
|
139
|
+
"Each changed character slides out as the new one slides in; buttons spring on press and a press past min or max gives a small bump."
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
"Screen readers",
|
|
143
|
+
"One adjustable element with min, max and the formatted value (suffix included), plus 'Increase' and 'Decrease' actions."
|
|
144
|
+
]
|
|
145
|
+
],
|
|
146
|
+
"usage": "import { useState } from 'react';\nimport { Stepper } from '@/components/ui/stepper';\n\nconst [guests, setGuests] = useState(2);\n<Stepper value={guests} onValueChange={setGuests} min={1} max={16} label=\"Guests\" />",
|
|
131
147
|
"examples": [
|
|
132
148
|
{
|
|
133
149
|
"name": "Cart",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/swipe-deck.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A card stack you swipe left or right; the top card leans in 3D and stamps a label.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"data",
|
|
@@ -98,5 +99,20 @@
|
|
|
98
99
|
"Style for the root view."
|
|
99
100
|
]
|
|
100
101
|
],
|
|
102
|
+
"behavior": [
|
|
103
|
+
[
|
|
104
|
+
"Touch",
|
|
105
|
+
"Drag the top card past the threshold or flick it to throw it off; a short drag springs back. A ref exposes swipe, undo and reset for buttons."
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"Motion",
|
|
109
|
+
"The card follows your finger, rotates and tilts in 3D, washes in the right or left colour and shows the stamp, while the next card rises."
|
|
110
|
+
],
|
|
111
|
+
[
|
|
112
|
+
"Screen readers",
|
|
113
|
+
"Only the top card is exposed. It offers the right and left labels as accessibility actions, which throw the card that way."
|
|
114
|
+
]
|
|
115
|
+
],
|
|
116
|
+
"usage": null,
|
|
101
117
|
"examples": []
|
|
102
118
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swipeable-row",
|
|
3
3
|
"category": "Display",
|
|
4
|
-
"aliases": [
|
|
4
|
+
"aliases": [
|
|
5
|
+
"swipeable-list",
|
|
6
|
+
"swipe-actions"
|
|
7
|
+
],
|
|
5
8
|
"exportName": "SwipeableRow",
|
|
6
9
|
"files": [
|
|
7
10
|
"src/components/ui/swipeable-row.tsx"
|
|
8
11
|
],
|
|
12
|
+
"summary": "A mail-style row whose actions fan out and grow as you drag it sideways.",
|
|
9
13
|
"props": [
|
|
10
14
|
[
|
|
11
15
|
"leftActions",
|
|
@@ -68,5 +72,24 @@
|
|
|
68
72
|
"Style for the outer row that holds the actions behind the sliding content."
|
|
69
73
|
]
|
|
70
74
|
],
|
|
75
|
+
"behavior": [
|
|
76
|
+
[
|
|
77
|
+
"Touch",
|
|
78
|
+
"Drag sideways to reveal the actions; a full swipe past half the row fires the edge action. Tap the open row to close it."
|
|
79
|
+
],
|
|
80
|
+
[
|
|
81
|
+
"Motion",
|
|
82
|
+
"Actions fan out and grow with your finger, the edge action stretches across on a full swipe, and destructive actions slide away and collapse the row."
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"Screen readers",
|
|
86
|
+
"Every action is offered as a named accessibility action on the row, and each revealed action is a labelled button."
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
"Web",
|
|
90
|
+
"Built on PanResponder, so a mouse drag works too; the row shows a grab cursor and text selection is turned off."
|
|
91
|
+
]
|
|
92
|
+
],
|
|
93
|
+
"usage": null,
|
|
71
94
|
"examples": []
|
|
72
95
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"files": [
|
|
7
7
|
"src/components/ui/switch.tsx"
|
|
8
8
|
],
|
|
9
|
+
"summary": "A toggle whose thumb squashes and stretches toward the other side while held.",
|
|
9
10
|
"props": [
|
|
10
11
|
[
|
|
11
12
|
"value / onValueChange",
|
|
@@ -74,6 +75,25 @@
|
|
|
74
75
|
"Style for the pressable — the switch itself, or the whole settings row when label is set."
|
|
75
76
|
]
|
|
76
77
|
],
|
|
78
|
+
"behavior": [
|
|
79
|
+
[
|
|
80
|
+
"Touch",
|
|
81
|
+
"Tap to flip, or drag the thumb across. Passing label (and description) turns it into a settings row."
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"Motion",
|
|
85
|
+
"The thumb stretches toward its destination while pressed, springs over with a soft halo, and the track cross-fades."
|
|
86
|
+
],
|
|
87
|
+
[
|
|
88
|
+
"Haptics",
|
|
89
|
+
"A light impact on every flip; turn it off with haptics={false}."
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
"Screen readers",
|
|
93
|
+
"A switch role with checked and disabled state, labelled by accessibilityLabel or label."
|
|
94
|
+
]
|
|
95
|
+
],
|
|
96
|
+
"usage": "import { useState } from 'react';\nimport { Switch } from '@/components/ui/switch';\n\nconst [wifi, setWifi] = useState(true);\n<Switch label=\"Wi-Fi\" value={wifi} onValueChange={setWifi} />",
|
|
77
97
|
"examples": [
|
|
78
98
|
{
|
|
79
99
|
"name": "IOS",
|