@codyswann/lisa 2.111.0 → 2.112.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/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.mcp.json +3 -3
- package/plugins/lisa-expo/THIRD-PARTY-NOTICES.md +57 -0
- package/plugins/lisa-expo/skills/add-app-clip/SKILL.md +280 -0
- package/plugins/lisa-expo/skills/add-app-clip/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/add-app-clip/references/native-module.md +96 -0
- package/plugins/lisa-expo/skills/building-native-ui/SKILL.md +321 -0
- package/plugins/lisa-expo/skills/building-native-ui/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/animations.md +220 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/controls.md +272 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/form-sheet.md +253 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/gradients.md +106 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/icons.md +213 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/media.md +198 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/route-structure.md +229 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/search.md +248 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/storage.md +121 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/tabs.md +433 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/visual-effects.md +197 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/webgpu-three.md +605 -0
- package/plugins/lisa-expo/skills/building-native-ui/references/zoom-transitions.md +158 -0
- package/plugins/lisa-expo/skills/eas-update-insights/SKILL.md +228 -0
- package/plugins/lisa-expo/skills/eas-update-insights/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
- package/plugins/lisa-expo/skills/eas-update-insights/references/update-insights-schema.md +69 -0
- package/plugins/lisa-expo/skills/expo-api-routes/SKILL.md +369 -0
- package/plugins/lisa-expo/skills/expo-api-routes/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-brownfield/SKILL.md +54 -0
- package/plugins/lisa-expo/skills/expo-brownfield/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
- package/plugins/lisa-expo/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
- package/plugins/lisa-expo/skills/expo-brownfield/references/comparison.md +63 -0
- package/plugins/lisa-expo/skills/expo-brownfield/references/troubleshooting.md +88 -0
- package/plugins/lisa-expo/skills/expo-cicd-workflows/SKILL.md +92 -0
- package/plugins/lisa-expo/skills/expo-cicd-workflows/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
- package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/package.json +11 -0
- package/plugins/lisa-expo/skills/expo-cicd-workflows/scripts/validate.js +85 -0
- package/plugins/lisa-expo/skills/expo-deployment/SKILL.md +190 -0
- package/plugins/lisa-expo/skills/expo-deployment/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-deployment/references/app-store-metadata.md +479 -0
- package/plugins/lisa-expo/skills/expo-deployment/references/ios-app-store.md +355 -0
- package/plugins/lisa-expo/skills/expo-deployment/references/play-store.md +246 -0
- package/plugins/lisa-expo/skills/expo-deployment/references/testflight.md +58 -0
- package/plugins/lisa-expo/skills/expo-deployment/references/workflows.md +200 -0
- package/plugins/lisa-expo/skills/expo-dev-client/SKILL.md +164 -0
- package/plugins/lisa-expo/skills/expo-dev-client/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-module/SKILL.md +141 -0
- package/plugins/lisa-expo/skills/expo-module/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-module/references/config-plugin.md +90 -0
- package/plugins/lisa-expo/skills/expo-module/references/create-expo-module.md +206 -0
- package/plugins/lisa-expo/skills/expo-module/references/lifecycle.md +127 -0
- package/plugins/lisa-expo/skills/expo-module/references/module-config.md +48 -0
- package/plugins/lisa-expo/skills/expo-module/references/native-module.md +286 -0
- package/plugins/lisa-expo/skills/expo-module/references/native-view.md +171 -0
- package/plugins/lisa-expo/skills/expo-tailwind-setup/SKILL.md +480 -0
- package/plugins/lisa-expo/skills/expo-tailwind-setup/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
- package/plugins/lisa-expo/skills/expo-ui-jetpack-compose/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/expo-ui-swift-ui/SKILL.md +39 -0
- package/plugins/lisa-expo/skills/expo-ui-swift-ui/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/native-data-fetching/SKILL.md +507 -0
- package/plugins/lisa-expo/skills/native-data-fetching/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
- package/plugins/lisa-expo/skills/upgrading-expo/SKILL.md +134 -0
- package/plugins/lisa-expo/skills/upgrading-expo/agents/openai.yaml +4 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/native-tabs.md +124 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/new-architecture.md +79 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/react-19.md +79 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/react-compiler.md +59 -0
- package/plugins/lisa-expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
- package/plugins/lisa-expo/skills/use-dom/SKILL.md +417 -0
- package/plugins/lisa-expo/skills/use-dom/agents/openai.yaml +4 -0
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/src/expo/.mcp.json +3 -3
- package/plugins/src/expo/THIRD-PARTY-NOTICES.md +57 -0
- package/plugins/src/expo/skills/add-app-clip/SKILL.md +280 -0
- package/plugins/src/expo/skills/add-app-clip/references/native-module.md +96 -0
- package/plugins/src/expo/skills/building-native-ui/SKILL.md +321 -0
- package/plugins/src/expo/skills/building-native-ui/references/animations.md +220 -0
- package/plugins/src/expo/skills/building-native-ui/references/controls.md +272 -0
- package/plugins/src/expo/skills/building-native-ui/references/form-sheet.md +253 -0
- package/plugins/src/expo/skills/building-native-ui/references/gradients.md +106 -0
- package/plugins/src/expo/skills/building-native-ui/references/icons.md +213 -0
- package/plugins/src/expo/skills/building-native-ui/references/media.md +198 -0
- package/plugins/src/expo/skills/building-native-ui/references/route-structure.md +229 -0
- package/plugins/src/expo/skills/building-native-ui/references/search.md +248 -0
- package/plugins/src/expo/skills/building-native-ui/references/storage.md +121 -0
- package/plugins/src/expo/skills/building-native-ui/references/tabs.md +433 -0
- package/plugins/src/expo/skills/building-native-ui/references/toolbar-and-headers.md +284 -0
- package/plugins/src/expo/skills/building-native-ui/references/visual-effects.md +197 -0
- package/plugins/src/expo/skills/building-native-ui/references/webgpu-three.md +605 -0
- package/plugins/src/expo/skills/building-native-ui/references/zoom-transitions.md +158 -0
- package/plugins/src/expo/skills/eas-update-insights/SKILL.md +228 -0
- package/plugins/src/expo/skills/eas-update-insights/references/channel-insights-schema.md +47 -0
- package/plugins/src/expo/skills/eas-update-insights/references/update-insights-schema.md +69 -0
- package/plugins/src/expo/skills/expo-api-routes/SKILL.md +369 -0
- package/plugins/src/expo/skills/expo-brownfield/SKILL.md +54 -0
- package/plugins/src/expo/skills/expo-brownfield/references/brownfield-integrated.md +526 -0
- package/plugins/src/expo/skills/expo-brownfield/references/brownfield-isolated.md +402 -0
- package/plugins/src/expo/skills/expo-brownfield/references/comparison.md +63 -0
- package/plugins/src/expo/skills/expo-brownfield/references/troubleshooting.md +88 -0
- package/plugins/src/expo/skills/expo-cicd-workflows/SKILL.md +92 -0
- package/plugins/src/expo/skills/expo-cicd-workflows/scripts/fetch.js +113 -0
- package/plugins/src/expo/skills/expo-cicd-workflows/scripts/package.json +11 -0
- package/plugins/src/expo/skills/expo-cicd-workflows/scripts/validate.js +85 -0
- package/plugins/src/expo/skills/expo-deployment/SKILL.md +190 -0
- package/plugins/src/expo/skills/expo-deployment/references/app-store-metadata.md +479 -0
- package/plugins/src/expo/skills/expo-deployment/references/ios-app-store.md +355 -0
- package/plugins/src/expo/skills/expo-deployment/references/play-store.md +246 -0
- package/plugins/src/expo/skills/expo-deployment/references/testflight.md +58 -0
- package/plugins/src/expo/skills/expo-deployment/references/workflows.md +200 -0
- package/plugins/src/expo/skills/expo-dev-client/SKILL.md +164 -0
- package/plugins/src/expo/skills/expo-module/SKILL.md +141 -0
- package/plugins/src/expo/skills/expo-module/references/config-plugin.md +90 -0
- package/plugins/src/expo/skills/expo-module/references/create-expo-module.md +206 -0
- package/plugins/src/expo/skills/expo-module/references/lifecycle.md +127 -0
- package/plugins/src/expo/skills/expo-module/references/module-config.md +48 -0
- package/plugins/src/expo/skills/expo-module/references/native-module.md +286 -0
- package/plugins/src/expo/skills/expo-module/references/native-view.md +171 -0
- package/plugins/src/expo/skills/expo-tailwind-setup/SKILL.md +480 -0
- package/plugins/src/expo/skills/expo-ui-jetpack-compose/SKILL.md +40 -0
- package/plugins/src/expo/skills/expo-ui-swift-ui/SKILL.md +39 -0
- package/plugins/src/expo/skills/native-data-fetching/SKILL.md +507 -0
- package/plugins/src/expo/skills/native-data-fetching/references/expo-router-loaders.md +344 -0
- package/plugins/src/expo/skills/upgrading-expo/SKILL.md +134 -0
- package/plugins/src/expo/skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
- package/plugins/src/expo/skills/upgrading-expo/references/expo-av-to-video.md +160 -0
- package/plugins/src/expo/skills/upgrading-expo/references/native-tabs.md +124 -0
- package/plugins/src/expo/skills/upgrading-expo/references/new-architecture.md +79 -0
- package/plugins/src/expo/skills/upgrading-expo/references/react-19.md +79 -0
- package/plugins/src/expo/skills/upgrading-expo/references/react-compiler.md +59 -0
- package/plugins/src/expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
- package/plugins/src/expo/skills/use-dom/SKILL.md +417 -0
- package/scripts/generate-codex-plugin-artifacts.mjs +7 -2
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Native Controls
|
|
2
|
+
|
|
3
|
+
Native iOS controls provide built-in haptics, accessibility, and platform-appropriate styling.
|
|
4
|
+
|
|
5
|
+
## Switch
|
|
6
|
+
|
|
7
|
+
Use for binary on/off settings. Has built-in haptics.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Switch } from "react-native";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
|
|
13
|
+
const [enabled, setEnabled] = useState(false);
|
|
14
|
+
|
|
15
|
+
<Switch value={enabled} onValueChange={setEnabled} />;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Customization
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<Switch
|
|
22
|
+
value={enabled}
|
|
23
|
+
onValueChange={setEnabled}
|
|
24
|
+
trackColor={{ false: "#767577", true: "#81b0ff" }}
|
|
25
|
+
thumbColor={enabled ? "#f5dd4b" : "#f4f3f4"}
|
|
26
|
+
ios_backgroundColor="#3e3e3e"
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Segmented Control
|
|
31
|
+
|
|
32
|
+
Use for non-navigational tabs or mode selection. Avoid changing default colors.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import SegmentedControl from "@react-native-segmented-control/segmented-control";
|
|
36
|
+
import { useState } from "react";
|
|
37
|
+
|
|
38
|
+
const [index, setIndex] = useState(0);
|
|
39
|
+
|
|
40
|
+
<SegmentedControl
|
|
41
|
+
values={["All", "Active", "Done"]}
|
|
42
|
+
selectedIndex={index}
|
|
43
|
+
onChange={({ nativeEvent }) => setIndex(nativeEvent.selectedSegmentIndex)}
|
|
44
|
+
/>;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Rules
|
|
48
|
+
|
|
49
|
+
- Maximum 4 options — use a picker for more
|
|
50
|
+
- Keep labels short (1-2 words)
|
|
51
|
+
- Avoid custom colors — native styling adapts to dark mode
|
|
52
|
+
|
|
53
|
+
### With Icons (iOS 14+)
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<SegmentedControl
|
|
57
|
+
values={[
|
|
58
|
+
{ label: "List", icon: "list.bullet" },
|
|
59
|
+
{ label: "Grid", icon: "square.grid.2x2" },
|
|
60
|
+
]}
|
|
61
|
+
selectedIndex={index}
|
|
62
|
+
onChange={({ nativeEvent }) => setIndex(nativeEvent.selectedSegmentIndex)}
|
|
63
|
+
/>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Slider
|
|
67
|
+
|
|
68
|
+
Continuous value selection.
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import Slider from "@react-native-community/slider";
|
|
72
|
+
import { useState } from "react";
|
|
73
|
+
|
|
74
|
+
const [value, setValue] = useState(0.5);
|
|
75
|
+
|
|
76
|
+
<Slider
|
|
77
|
+
value={value}
|
|
78
|
+
onValueChange={setValue}
|
|
79
|
+
minimumValue={0}
|
|
80
|
+
maximumValue={1}
|
|
81
|
+
/>;
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Customization
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
<Slider
|
|
88
|
+
value={value}
|
|
89
|
+
onValueChange={setValue}
|
|
90
|
+
minimumValue={0}
|
|
91
|
+
maximumValue={100}
|
|
92
|
+
step={1}
|
|
93
|
+
minimumTrackTintColor="#007AFF"
|
|
94
|
+
maximumTrackTintColor="#E5E5EA"
|
|
95
|
+
thumbTintColor="#007AFF"
|
|
96
|
+
/>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Discrete Steps
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Slider
|
|
103
|
+
value={value}
|
|
104
|
+
onValueChange={setValue}
|
|
105
|
+
minimumValue={0}
|
|
106
|
+
maximumValue={10}
|
|
107
|
+
step={1}
|
|
108
|
+
/>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Date/Time Picker
|
|
112
|
+
|
|
113
|
+
Compact pickers with popovers. Has built-in haptics.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
import DateTimePicker from "@react-native-community/datetimepicker";
|
|
117
|
+
import { useState } from "react";
|
|
118
|
+
|
|
119
|
+
const [date, setDate] = useState(new Date());
|
|
120
|
+
|
|
121
|
+
<DateTimePicker
|
|
122
|
+
value={date}
|
|
123
|
+
onChange={(event, selectedDate) => {
|
|
124
|
+
if (selectedDate) setDate(selectedDate);
|
|
125
|
+
}}
|
|
126
|
+
mode="datetime"
|
|
127
|
+
/>;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Modes
|
|
131
|
+
|
|
132
|
+
- `date` — Date only
|
|
133
|
+
- `time` — Time only
|
|
134
|
+
- `datetime` — Date and time
|
|
135
|
+
|
|
136
|
+
### Display Styles
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// Compact inline (default)
|
|
140
|
+
<DateTimePicker value={date} mode="date" />
|
|
141
|
+
|
|
142
|
+
// Spinner wheel
|
|
143
|
+
<DateTimePicker
|
|
144
|
+
value={date}
|
|
145
|
+
mode="date"
|
|
146
|
+
display="spinner"
|
|
147
|
+
style={{ width: 200, height: 150 }}
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
// Full calendar
|
|
151
|
+
<DateTimePicker value={date} mode="date" display="inline" />
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Time Intervals
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<DateTimePicker
|
|
158
|
+
value={date}
|
|
159
|
+
mode="time"
|
|
160
|
+
minuteInterval={15}
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Min/Max Dates
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<DateTimePicker
|
|
168
|
+
value={date}
|
|
169
|
+
mode="date"
|
|
170
|
+
minimumDate={new Date(2020, 0, 1)}
|
|
171
|
+
maximumDate={new Date(2030, 11, 31)}
|
|
172
|
+
/>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Stepper
|
|
176
|
+
|
|
177
|
+
> Note: `Stepper` is not exported by React Native core. Use a maintained community package (e.g. `react-native-ui-stepper`) or build one from primitives. The snippet below illustrates the intended API.
|
|
178
|
+
|
|
179
|
+
Increment/decrement numeric values.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
import { Stepper } from "react-native";
|
|
183
|
+
import { useState } from "react";
|
|
184
|
+
|
|
185
|
+
const [count, setCount] = useState(0);
|
|
186
|
+
|
|
187
|
+
<Stepper
|
|
188
|
+
value={count}
|
|
189
|
+
onValueChange={setCount}
|
|
190
|
+
minimumValue={0}
|
|
191
|
+
maximumValue={10}
|
|
192
|
+
/>;
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## TextInput
|
|
196
|
+
|
|
197
|
+
Native text input with various keyboard types.
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import { TextInput } from "react-native";
|
|
201
|
+
|
|
202
|
+
<TextInput
|
|
203
|
+
placeholder="Enter text..."
|
|
204
|
+
placeholderTextColor="#999"
|
|
205
|
+
style={{
|
|
206
|
+
padding: 12,
|
|
207
|
+
fontSize: 16,
|
|
208
|
+
borderRadius: 8,
|
|
209
|
+
backgroundColor: "#f0f0f0",
|
|
210
|
+
}}
|
|
211
|
+
/>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Keyboard Types
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
// Email
|
|
218
|
+
<TextInput keyboardType="email-address" autoCapitalize="none" />
|
|
219
|
+
|
|
220
|
+
// Phone
|
|
221
|
+
<TextInput keyboardType="phone-pad" />
|
|
222
|
+
|
|
223
|
+
// Number
|
|
224
|
+
<TextInput keyboardType="numeric" />
|
|
225
|
+
|
|
226
|
+
// Password
|
|
227
|
+
<TextInput secureTextEntry />
|
|
228
|
+
|
|
229
|
+
// Search
|
|
230
|
+
<TextInput
|
|
231
|
+
returnKeyType="search"
|
|
232
|
+
enablesReturnKeyAutomatically
|
|
233
|
+
/>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Multiline
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
<TextInput
|
|
240
|
+
multiline
|
|
241
|
+
numberOfLines={4}
|
|
242
|
+
textAlignVertical="top"
|
|
243
|
+
style={{ minHeight: 100 }}
|
|
244
|
+
/>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Picker (Wheel)
|
|
248
|
+
|
|
249
|
+
For selection from many options (5+ items).
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
import { Picker } from "@react-native-picker/picker";
|
|
253
|
+
import { useState } from "react";
|
|
254
|
+
|
|
255
|
+
const [selected, setSelected] = useState("js");
|
|
256
|
+
|
|
257
|
+
<Picker selectedValue={selected} onValueChange={setSelected}>
|
|
258
|
+
<Picker.Item label="JavaScript" value="js" />
|
|
259
|
+
<Picker.Item label="TypeScript" value="ts" />
|
|
260
|
+
<Picker.Item label="Python" value="py" />
|
|
261
|
+
<Picker.Item label="Go" value="go" />
|
|
262
|
+
</Picker>;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Best Practices
|
|
266
|
+
|
|
267
|
+
- **Haptics**: Switch and DateTimePicker have built-in haptics — don't add extra
|
|
268
|
+
- **Accessibility**: Native controls have proper accessibility labels by default
|
|
269
|
+
- **Dark Mode**: Avoid custom colors — native styling adapts automatically
|
|
270
|
+
- **Spacing**: Use consistent padding around controls (12-16pt)
|
|
271
|
+
- **Labels**: Place labels above or to the left of controls
|
|
272
|
+
- **Grouping**: Group related controls in sections with headers
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Form Sheets in Expo Router
|
|
2
|
+
|
|
3
|
+
This skill covers implementing form sheets with footers using Expo Router's Stack navigator and react-native-screens.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Form sheets are modal presentations that appear as a card sliding up from the bottom of the screen. They're ideal for:
|
|
8
|
+
|
|
9
|
+
- Quick actions and confirmations
|
|
10
|
+
- Settings panels
|
|
11
|
+
- Login/signup flows
|
|
12
|
+
- Action sheets with custom content
|
|
13
|
+
|
|
14
|
+
**Requirements:**
|
|
15
|
+
|
|
16
|
+
- Expo Router Stack navigator
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
### Form Sheet with Footer
|
|
21
|
+
|
|
22
|
+
Configure the Stack.Screen with transparent backgrounds and sheet presentation:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
// app/_layout.tsx
|
|
26
|
+
import { Stack } from "expo-router";
|
|
27
|
+
|
|
28
|
+
export default function Layout() {
|
|
29
|
+
return (
|
|
30
|
+
<Stack>
|
|
31
|
+
<Stack.Screen name="index" />
|
|
32
|
+
<Stack.Screen
|
|
33
|
+
name="about"
|
|
34
|
+
options={{
|
|
35
|
+
presentation: "formSheet",
|
|
36
|
+
sheetAllowedDetents: [0.25],
|
|
37
|
+
headerTransparent: true,
|
|
38
|
+
contentStyle: { backgroundColor: "transparent" },
|
|
39
|
+
sheetGrabberVisible: true,
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
<Stack.Header style={{ backgroundColor: "transparent" }}></Stack.Header>
|
|
43
|
+
</Stack.Screen>
|
|
44
|
+
</Stack>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Form Sheet Screen Content
|
|
50
|
+
|
|
51
|
+
> Requires Expo SDK 55 or later.
|
|
52
|
+
|
|
53
|
+
Use `flex: 1` to allow the content to fill available space, enabling footer positioning:
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// app/about.tsx
|
|
57
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
58
|
+
|
|
59
|
+
export default function AboutSheet() {
|
|
60
|
+
return (
|
|
61
|
+
<View style={styles.container}>
|
|
62
|
+
{/* Main content */}
|
|
63
|
+
<View style={styles.content}>
|
|
64
|
+
<Text>Sheet Content</Text>
|
|
65
|
+
</View>
|
|
66
|
+
|
|
67
|
+
{/* Footer - stays at bottom */}
|
|
68
|
+
<View style={styles.footer}>
|
|
69
|
+
<Text>Footer Content</Text>
|
|
70
|
+
</View>
|
|
71
|
+
</View>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const styles = StyleSheet.create({
|
|
76
|
+
container: {
|
|
77
|
+
flex: 1,
|
|
78
|
+
},
|
|
79
|
+
content: {
|
|
80
|
+
flex: 1,
|
|
81
|
+
padding: 16,
|
|
82
|
+
},
|
|
83
|
+
footer: {
|
|
84
|
+
padding: 16,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Formsheet with interactive content below
|
|
90
|
+
|
|
91
|
+
Use `sheetLargestUndimmedDetentIndex` (zero-indexed) to keep content behind the form sheet interactive — e.g. letting users pan a map beneath it. Setting it to `1` allows interaction at the first two detents but dims on the third.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
// app/_layout.tsx
|
|
95
|
+
import { Stack } from 'expo-router';
|
|
96
|
+
|
|
97
|
+
export default function Layout() {
|
|
98
|
+
return (
|
|
99
|
+
<Stack screenOptions={{ headerShown: false }}>
|
|
100
|
+
<Stack.Screen name="index" />
|
|
101
|
+
<Stack.Screen
|
|
102
|
+
name="info-sheet"
|
|
103
|
+
options={{
|
|
104
|
+
presentation: "formSheet",
|
|
105
|
+
sheetAllowedDetents: [0.2, 0.5, 1.0],
|
|
106
|
+
sheetLargestUndimmedDetentIndex: 1,
|
|
107
|
+
/* other options */
|
|
108
|
+
}}
|
|
109
|
+
/>
|
|
110
|
+
</Stack>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Key Options
|
|
116
|
+
|
|
117
|
+
| Option | Type | Description |
|
|
118
|
+
| --------------------- | ---------- | ----------------------------------------------------------- |
|
|
119
|
+
| `presentation` | `string` | Set to `'formSheet'` for sheet presentation |
|
|
120
|
+
| `sheetGrabberVisible` | `boolean` | Shows the drag handle at the top of the sheet |
|
|
121
|
+
| `sheetAllowedDetents` | `number[]` | Array of detent heights (0-1 range, e.g., `[0.25]` for 25%) |
|
|
122
|
+
| `headerTransparent` | `boolean` | Makes header background transparent |
|
|
123
|
+
| `contentStyle` | `object` | Style object for the screen content container |
|
|
124
|
+
| `title` | `string` | Screen title (set to `''` for no title) |
|
|
125
|
+
|
|
126
|
+
## Common Detent Values
|
|
127
|
+
|
|
128
|
+
- `[0.25]` - Quarter sheet (compact actions)
|
|
129
|
+
- `[0.5]` - Half sheet (medium content)
|
|
130
|
+
- `[0.75]` - Three-quarter sheet (detailed forms)
|
|
131
|
+
- `[0.25, 0.5, 1]` - Multiple stops (expandable sheet)
|
|
132
|
+
|
|
133
|
+
## Complete Example
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// _layout.tsx
|
|
137
|
+
import { Stack } from "expo-router";
|
|
138
|
+
|
|
139
|
+
export default function Layout() {
|
|
140
|
+
return (
|
|
141
|
+
<Stack>
|
|
142
|
+
<Stack.Screen name="index" options={{ title: "Home" }} />
|
|
143
|
+
<Stack.Screen
|
|
144
|
+
name="confirm"
|
|
145
|
+
options={{
|
|
146
|
+
contentStyle: { backgroundColor: "transparent" },
|
|
147
|
+
presentation: "formSheet",
|
|
148
|
+
title: "",
|
|
149
|
+
sheetGrabberVisible: true,
|
|
150
|
+
sheetAllowedDetents: [0.25],
|
|
151
|
+
headerTransparent: true,
|
|
152
|
+
}}
|
|
153
|
+
>
|
|
154
|
+
<Stack.Header style={{ backgroundColor: "transparent" }}>
|
|
155
|
+
<Stack.Header.Right />
|
|
156
|
+
</Stack.Header>
|
|
157
|
+
</Stack.Screen>
|
|
158
|
+
</Stack>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
// app/confirm.tsx
|
|
165
|
+
import { View, Text, Pressable, StyleSheet } from "react-native";
|
|
166
|
+
import { router } from "expo-router";
|
|
167
|
+
|
|
168
|
+
export default function ConfirmSheet() {
|
|
169
|
+
return (
|
|
170
|
+
<View style={styles.container}>
|
|
171
|
+
<View style={styles.content}>
|
|
172
|
+
<Text style={styles.title}>Confirm Action</Text>
|
|
173
|
+
<Text style={styles.description}>
|
|
174
|
+
Are you sure you want to proceed?
|
|
175
|
+
</Text>
|
|
176
|
+
</View>
|
|
177
|
+
|
|
178
|
+
<View style={styles.footer}>
|
|
179
|
+
<Pressable style={styles.cancelButton} onPress={() => router.back()}>
|
|
180
|
+
<Text style={styles.cancelText}>Cancel</Text>
|
|
181
|
+
</Pressable>
|
|
182
|
+
<Pressable style={styles.confirmButton} onPress={() => router.back()}>
|
|
183
|
+
<Text style={styles.confirmText}>Confirm</Text>
|
|
184
|
+
</Pressable>
|
|
185
|
+
</View>
|
|
186
|
+
</View>
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const styles = StyleSheet.create({
|
|
191
|
+
container: {
|
|
192
|
+
flex: 1,
|
|
193
|
+
},
|
|
194
|
+
content: {
|
|
195
|
+
flex: 1,
|
|
196
|
+
padding: 20,
|
|
197
|
+
alignItems: "center",
|
|
198
|
+
justifyContent: "center",
|
|
199
|
+
},
|
|
200
|
+
title: {
|
|
201
|
+
fontSize: 18,
|
|
202
|
+
fontWeight: "600",
|
|
203
|
+
marginBottom: 8,
|
|
204
|
+
},
|
|
205
|
+
description: {
|
|
206
|
+
fontSize: 14,
|
|
207
|
+
color: "#666",
|
|
208
|
+
textAlign: "center",
|
|
209
|
+
},
|
|
210
|
+
footer: {
|
|
211
|
+
flexDirection: "row",
|
|
212
|
+
padding: 16,
|
|
213
|
+
gap: 12,
|
|
214
|
+
},
|
|
215
|
+
cancelButton: {
|
|
216
|
+
flex: 1,
|
|
217
|
+
padding: 14,
|
|
218
|
+
borderRadius: 10,
|
|
219
|
+
backgroundColor: "#f0f0f0",
|
|
220
|
+
alignItems: "center",
|
|
221
|
+
},
|
|
222
|
+
cancelText: {
|
|
223
|
+
fontSize: 16,
|
|
224
|
+
fontWeight: "500",
|
|
225
|
+
},
|
|
226
|
+
confirmButton: {
|
|
227
|
+
flex: 1,
|
|
228
|
+
padding: 14,
|
|
229
|
+
borderRadius: 10,
|
|
230
|
+
backgroundColor: "#007AFF",
|
|
231
|
+
alignItems: "center",
|
|
232
|
+
},
|
|
233
|
+
confirmText: {
|
|
234
|
+
fontSize: 16,
|
|
235
|
+
fontWeight: "500",
|
|
236
|
+
color: "white",
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Troubleshooting
|
|
242
|
+
|
|
243
|
+
### Content not filling sheet
|
|
244
|
+
|
|
245
|
+
Make sure the root View uses `flex: 1`:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
<View style={{ flex: 1 }}>{/* content */}</View>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Sheet background showing through
|
|
252
|
+
|
|
253
|
+
Set `contentStyle: { backgroundColor: 'transparent' }` in options and style your content container with the desired background color instead.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# CSS Gradients
|
|
2
|
+
|
|
3
|
+
> **New Architecture Only**: CSS gradients require React Native's New Architecture (Fabric). They are not available in the old architecture or Expo Go.
|
|
4
|
+
|
|
5
|
+
Use CSS gradients with the `experimental_backgroundImage` style property.
|
|
6
|
+
|
|
7
|
+
## Linear Gradients
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
// Top to bottom
|
|
11
|
+
<View style={{
|
|
12
|
+
experimental_backgroundImage: 'linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%)'
|
|
13
|
+
}} />
|
|
14
|
+
|
|
15
|
+
// Left to right
|
|
16
|
+
<View style={{
|
|
17
|
+
experimental_backgroundImage: 'linear-gradient(to right, #ff0000 0%, #0000ff 100%)'
|
|
18
|
+
}} />
|
|
19
|
+
|
|
20
|
+
// Diagonal
|
|
21
|
+
<View style={{
|
|
22
|
+
experimental_backgroundImage: 'linear-gradient(45deg, #ff0000 0%, #00ff00 50%, #0000ff 100%)'
|
|
23
|
+
}} />
|
|
24
|
+
|
|
25
|
+
// Using degrees
|
|
26
|
+
<View style={{
|
|
27
|
+
experimental_backgroundImage: 'linear-gradient(135deg, transparent 0%, black 100%)'
|
|
28
|
+
}} />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Radial Gradients
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// Circle at center
|
|
35
|
+
<View style={{
|
|
36
|
+
experimental_backgroundImage: 'radial-gradient(circle at center, rgba(255, 0, 0, 1) 0%, rgba(0, 0, 255, 1) 100%)'
|
|
37
|
+
}} />
|
|
38
|
+
|
|
39
|
+
// Ellipse
|
|
40
|
+
<View style={{
|
|
41
|
+
experimental_backgroundImage: 'radial-gradient(ellipse at center, #fff 0%, #000 100%)'
|
|
42
|
+
}} />
|
|
43
|
+
|
|
44
|
+
// Positioned
|
|
45
|
+
<View style={{
|
|
46
|
+
experimental_backgroundImage: 'radial-gradient(circle at top left, #ff0000 0%, transparent 70%)'
|
|
47
|
+
}} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Multiple Gradients
|
|
51
|
+
|
|
52
|
+
Stack multiple gradients by comma-separating them:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<View style={{
|
|
56
|
+
experimental_backgroundImage: `
|
|
57
|
+
linear-gradient(to bottom, transparent 0%, black 100%),
|
|
58
|
+
radial-gradient(circle at top right, rgba(255, 0, 0, 0.5) 0%, transparent 50%)
|
|
59
|
+
`
|
|
60
|
+
}} />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Common Patterns
|
|
64
|
+
|
|
65
|
+
### Overlay on Image
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<View style={{ position: 'relative' }}>
|
|
69
|
+
<Image source={{ uri: '...' }} style={{ width: '100%', height: 200 }} />
|
|
70
|
+
<View style={{
|
|
71
|
+
position: 'absolute',
|
|
72
|
+
inset: 0,
|
|
73
|
+
experimental_backgroundImage: 'linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, transparent 50%)'
|
|
74
|
+
}} />
|
|
75
|
+
</View>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Frosted Glass Effect
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<View style={{
|
|
82
|
+
experimental_backgroundImage: 'linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%)',
|
|
83
|
+
backdropFilter: 'blur(10px)',
|
|
84
|
+
}} />
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Button Gradient
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
<Pressable style={{
|
|
91
|
+
experimental_backgroundImage: 'linear-gradient(to bottom, #4CAF50 0%, #388E3C 100%)',
|
|
92
|
+
padding: 16,
|
|
93
|
+
borderRadius: 8,
|
|
94
|
+
}}>
|
|
95
|
+
<Text style={{ color: 'white', textAlign: 'center' }}>Submit</Text>
|
|
96
|
+
</Pressable>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Important Notes
|
|
100
|
+
|
|
101
|
+
- Do NOT use `expo-linear-gradient` — use CSS gradients instead
|
|
102
|
+
- Gradients are strings, not objects
|
|
103
|
+
- Use `rgba()` for transparency, or `transparent` keyword
|
|
104
|
+
- Color stops use percentages (0%, 50%, 100%)
|
|
105
|
+
- Direction keywords: `to top`, `to bottom`, `to left`, `to right`, `to top left`, etc.
|
|
106
|
+
- Degree values: `45deg`, `90deg`, `135deg`, etc.
|