create-expo-stack 2.6.5 → 2.7.0-next.2960d96
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 +23 -9
- package/build/templates/base/App.tsx.ejs +3 -0
- package/build/templates/base/babel.config.js.ejs +1 -1
- package/build/templates/base/package.json.ejs +40 -3
- package/build/templates/base/prettier.config.js.ejs +1 -1
- package/build/templates/base/tsconfig.json.ejs +10 -6
- package/build/templates/packages/expo-router/drawer/app/_layout.tsx.ejs +4 -1
- package/build/templates/packages/expo-router/stack/app/_layout.tsx.ejs +4 -1
- package/build/templates/packages/expo-router/tabs/app/_layout.tsx.ejs +4 -1
- package/build/templates/packages/nativewindui/app/+not-found.tsx.ejs +18 -0
- package/build/templates/packages/nativewindui/app/_layout.tsx.ejs +85 -0
- package/build/templates/packages/nativewindui/app/index.tsx.ejs +652 -0
- package/build/templates/packages/nativewindui/app/modal.tsx.ejs +32 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/ActivityIndicator.tsx.ejs +10 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Avatar.tsx.ejs +139 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/DatePicker.android.tsx.ejs +66 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/DatePicker.tsx.ejs +10 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Picker.tsx.ejs +39 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/ProgressIndicator.tsx.ejs +95 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/SegmentedControl.tsx.ejs +22 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Sheet.tsx.ejs +59 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Slider.tsx.ejs +28 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Text.tsx.ejs +55 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/ThemeToggle.tsx.ejs +39 -0
- package/build/templates/packages/nativewindui/components/nativewind-ui/Toggle.tsx.ejs +17 -0
- package/build/templates/packages/nativewindui/expo-env.d.ts.ejs +3 -0
- package/build/templates/packages/nativewindui/global.css.ejs +91 -0
- package/build/templates/packages/nativewindui/lib/cn.ts.ejs +6 -0
- package/build/templates/packages/nativewindui/lib/useColorScheme.tsx.ejs +14 -0
- package/build/templates/packages/nativewindui/lib/useHeaderSearchBar.tsx.ejs +31 -0
- package/build/templates/packages/nativewindui/metro.config.js.ejs +10 -0
- package/build/templates/packages/nativewindui/nativewind-env.d.ts.ejs +1 -0
- package/build/templates/packages/nativewindui/tailwind.config.js.ejs +66 -0
- package/build/templates/packages/nativewindui/theme/colors.ts.ejs +71 -0
- package/build/templates/packages/nativewindui/theme/index.ts.ejs +29 -0
- package/build/templates/packages/react-navigation/App.tsx.ejs +4 -1
- package/build/types/types.d.ts +4 -2
- package/build/types.js +2 -1
- package/build/utilities/configureProjectFiles.js +265 -197
- package/build/utilities/generateProjectFiles.js +18 -13
- package/build/utilities/printOutput.js +5 -5
- package/build/utilities/runCLI.js +99 -22
- package/package.json +67 -67
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
import { useHeaderHeight } from '@react-navigation/elements';
|
|
2
|
+
import { FlashList } from '@shopify/flash-list';
|
|
3
|
+
import { cssInterop } from 'nativewind';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import {
|
|
6
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('alert')) { %>
|
|
7
|
+
Alert,
|
|
8
|
+
<% } %>
|
|
9
|
+
Button as RNButton,
|
|
10
|
+
ButtonProps,
|
|
11
|
+
Linking,
|
|
12
|
+
Platform,
|
|
13
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('dropdown-menu')) { %>
|
|
14
|
+
Pressable,
|
|
15
|
+
<% } %>
|
|
16
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('activity-view')) { %>
|
|
17
|
+
Share,
|
|
18
|
+
<% } %>
|
|
19
|
+
View,
|
|
20
|
+
} from 'react-native';
|
|
21
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('action-sheet')) { %>
|
|
22
|
+
import { useActionSheet } from '@expo/react-native-action-sheet';
|
|
23
|
+
<% } %>
|
|
24
|
+
import { Icon } from '@roninoss/icons';
|
|
25
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('ratings-indicator')) { %>
|
|
26
|
+
import * as StoreReview from 'expo-store-review';
|
|
27
|
+
<% } %>
|
|
28
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('context-menu')) { %>
|
|
29
|
+
import * as ContextMenu from 'zeego/context-menu';
|
|
30
|
+
<% } %>
|
|
31
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('dropdown-menu')) { %>
|
|
32
|
+
import * as DropdownMenu from 'zeego/dropdown-menu';
|
|
33
|
+
<% } %>
|
|
34
|
+
|
|
35
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('activity-indicator')) { %>
|
|
36
|
+
import { ActivityIndicator } from '~/components/nativewind-ui/ActivityIndicator';
|
|
37
|
+
<% } %>
|
|
38
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('avatar')) { %>
|
|
39
|
+
import { Avatar, AvatarFallback, AvatarImage } from '~/components/nativewind-ui/Avatar';
|
|
40
|
+
<% } %>
|
|
41
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('date-picker')) { %>
|
|
42
|
+
import { DatePicker } from '~/components/nativewind-ui/DatePicker';
|
|
43
|
+
<% } %>
|
|
44
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('picker')) { %>
|
|
45
|
+
import { Picker, PickerItem } from '~/components/nativewind-ui/Picker';
|
|
46
|
+
<% } %>
|
|
47
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('progress-indicator')) { %>
|
|
48
|
+
import { ProgressIndicator } from '~/components/nativewind-ui/ProgressIndicator';
|
|
49
|
+
<% } %>
|
|
50
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('segmented-control')) { %>
|
|
51
|
+
import { SegmentedControl } from '~/components/nativewind-ui/SegmentedControl';
|
|
52
|
+
<% } %>
|
|
53
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('bottom-sheet')) { %>
|
|
54
|
+
import { Sheet, useSheetRef } from '~/components/nativewind-ui/Sheet';
|
|
55
|
+
<% } %>
|
|
56
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('slider')) { %>
|
|
57
|
+
import { Slider } from '~/components/nativewind-ui/Slider';
|
|
58
|
+
<% } %>
|
|
59
|
+
import { Text } from '~/components/nativewind-ui/Text';
|
|
60
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('toggle')) { %>
|
|
61
|
+
import { Toggle } from '~/components/nativewind-ui/Toggle';
|
|
62
|
+
<% } %>
|
|
63
|
+
import { useColorScheme } from '~/lib/useColorScheme';
|
|
64
|
+
import { useHeaderSearchBar } from '~/lib/useHeaderSearchBar';
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
cssInterop(FlashList, {
|
|
68
|
+
className: 'style',
|
|
69
|
+
contentContainerClassName: 'contentContainerStyle',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
function DefaultButton({ color, ...props }: ButtonProps) {
|
|
73
|
+
const { colors } = useColorScheme();
|
|
74
|
+
return <RNButton color={color ?? colors.primary} {...props} />;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default function Screen() {
|
|
78
|
+
const searchValue = useHeaderSearchBar();
|
|
79
|
+
|
|
80
|
+
const data = searchValue
|
|
81
|
+
? COMPONENTS.filter((c) => c.name.toLowerCase().includes(searchValue.toLowerCase()))
|
|
82
|
+
: COMPONENTS;
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<FlashList
|
|
86
|
+
contentInsetAdjustmentBehavior="automatic"
|
|
87
|
+
keyboardShouldPersistTaps="handled"
|
|
88
|
+
data={data}
|
|
89
|
+
estimatedItemSize={200}
|
|
90
|
+
contentContainerClassName="py-4"
|
|
91
|
+
centerContent={data.length === 0}
|
|
92
|
+
extraData={searchValue}
|
|
93
|
+
removeClippedSubviews={false} // used for selecting text on android
|
|
94
|
+
keyExtractor={keyExtractor}
|
|
95
|
+
ItemSeparatorComponent={renderItemSeparator}
|
|
96
|
+
renderItem={renderItem}
|
|
97
|
+
ListEmptyComponent={ListEmptyComponent}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const SEARCH_BAR_HEIGHT = 52;
|
|
103
|
+
|
|
104
|
+
function ListEmptyComponent() {
|
|
105
|
+
const insets = useSafeAreaInsets();
|
|
106
|
+
const headerHeight = useHeaderHeight();
|
|
107
|
+
const { colors } = useColorScheme();
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
{Platform.OS === 'ios' && (
|
|
111
|
+
<View style={{ height: headerHeight + SEARCH_BAR_HEIGHT + insets.top - insets.bottom }} />
|
|
112
|
+
)}
|
|
113
|
+
<View className='flex-1 items-center justify-center px-12 gap-1'>
|
|
114
|
+
<Icon name='folder-plus-outline' size={42} color={colors.grey} />
|
|
115
|
+
<Text variant='title3' className='pb-1 text-center font-semibold'>
|
|
116
|
+
No Components Installed
|
|
117
|
+
</Text>
|
|
118
|
+
<Text color='tertiary' variant='subhead' className='pb-4 text-center'>
|
|
119
|
+
You can install any of the free components from the{' '}
|
|
120
|
+
<Text
|
|
121
|
+
onPress={() => Linking.openURL('https://nativewindui.com')}
|
|
122
|
+
variant='subhead'
|
|
123
|
+
className='text-primary'
|
|
124
|
+
>
|
|
125
|
+
NativeWindUI
|
|
126
|
+
</Text>
|
|
127
|
+
{' website.'}
|
|
128
|
+
</Text>
|
|
129
|
+
</View>
|
|
130
|
+
</>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
type ComponentItem = { name: string; component: () => React.JSX.Element };
|
|
135
|
+
|
|
136
|
+
function keyExtractor(item: ComponentItem) {
|
|
137
|
+
return item.name;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function renderItemSeparator() {
|
|
141
|
+
return <View className="p-2" />;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function renderItem({ item }: { item: ComponentItem }) {
|
|
145
|
+
return (
|
|
146
|
+
<Card title={item.name}>
|
|
147
|
+
<item.component />
|
|
148
|
+
</Card>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function Card({ children, title }: { children: React.ReactNode; title: string }) {
|
|
153
|
+
return (
|
|
154
|
+
<View className="px-4">
|
|
155
|
+
<View className="gap-4 rounded-xl border border-border bg-card p-4 pb-6 shadow-sm shadow-black/10 dark:shadow-none">
|
|
156
|
+
<Text className="text-center text-sm font-medium tracking-wider opacity-60">{title}</Text>
|
|
157
|
+
{children}
|
|
158
|
+
</View>
|
|
159
|
+
</View>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const COMPONENTS: ComponentItem[] = [
|
|
164
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('picker')) { %>
|
|
165
|
+
{
|
|
166
|
+
name: 'Picker',
|
|
167
|
+
component: () => {
|
|
168
|
+
const { colors } = useColorScheme();
|
|
169
|
+
const [picker, setPicker] = React.useState('blue');
|
|
170
|
+
return (
|
|
171
|
+
<Picker
|
|
172
|
+
selectedValue={picker}
|
|
173
|
+
onValueChange={(itemValue) => setPicker(itemValue)}
|
|
174
|
+
>
|
|
175
|
+
<PickerItem
|
|
176
|
+
label='Red'
|
|
177
|
+
value='red'
|
|
178
|
+
color={colors.foreground}
|
|
179
|
+
style={{
|
|
180
|
+
backgroundColor: colors.root,
|
|
181
|
+
}}
|
|
182
|
+
/>
|
|
183
|
+
<PickerItem
|
|
184
|
+
label='Blue'
|
|
185
|
+
value='blue'
|
|
186
|
+
color={colors.foreground}
|
|
187
|
+
style={{
|
|
188
|
+
backgroundColor: colors.root,
|
|
189
|
+
}}
|
|
190
|
+
/>
|
|
191
|
+
<PickerItem
|
|
192
|
+
label='Green'
|
|
193
|
+
value='green'
|
|
194
|
+
color={colors.foreground}
|
|
195
|
+
style={{
|
|
196
|
+
backgroundColor: colors.root,
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
</Picker>
|
|
200
|
+
);
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
<% } %>
|
|
204
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('date-picker')) { %>
|
|
205
|
+
{
|
|
206
|
+
name: 'Date Picker',
|
|
207
|
+
component: () => {
|
|
208
|
+
const [date, setDate] = React.useState(new Date());
|
|
209
|
+
return (
|
|
210
|
+
<View className='items-center'>
|
|
211
|
+
<DatePicker
|
|
212
|
+
value={date}
|
|
213
|
+
mode='datetime'
|
|
214
|
+
onChange={(ev) => {
|
|
215
|
+
setDate(new Date(ev.nativeEvent.timestamp));
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
</View>
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
<% } %>
|
|
223
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('segmented-control')) { %>
|
|
224
|
+
{
|
|
225
|
+
name: 'Segmented Controls',
|
|
226
|
+
component: () => {
|
|
227
|
+
const [segment, setSegment] = React.useState(0);
|
|
228
|
+
return (
|
|
229
|
+
<SegmentedControl
|
|
230
|
+
values={['red', 'green', 'blue']}
|
|
231
|
+
selectedIndex={segment}
|
|
232
|
+
onChange={(event) => {
|
|
233
|
+
setSegment(event.nativeEvent.selectedSegmentIndex);
|
|
234
|
+
}}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
<% } %>
|
|
240
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('slider')) { %>
|
|
241
|
+
{
|
|
242
|
+
name: 'Slider',
|
|
243
|
+
component: () => {
|
|
244
|
+
const [sliderValue, setSliderValue] = React.useState(0.5);
|
|
245
|
+
return <Slider value={sliderValue} onValueChange={setSliderValue} />;
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
<% } %>
|
|
249
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('toggle')) { %>
|
|
250
|
+
{
|
|
251
|
+
name: 'Toggle',
|
|
252
|
+
component: () => {
|
|
253
|
+
const [switchValue, setSwitchValue] = React.useState(true);
|
|
254
|
+
return (
|
|
255
|
+
<View className='items-center'>
|
|
256
|
+
<Toggle value={switchValue} onValueChange={setSwitchValue} />
|
|
257
|
+
</View>
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
<% } %>
|
|
262
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('context-menu')) { %>
|
|
263
|
+
{
|
|
264
|
+
name: 'Context Menu',
|
|
265
|
+
component: () => {
|
|
266
|
+
const [isChecked, setIsChecked] = React.useState(true);
|
|
267
|
+
return (
|
|
268
|
+
<View>
|
|
269
|
+
<ContextMenu.Root style={{ borderRadius: 12 }}>
|
|
270
|
+
<ContextMenu.Trigger>
|
|
271
|
+
<View className='w-full h-36 rounded-xl border border-foreground border-dashed justify-center items-center'>
|
|
272
|
+
<Text>Press and hold me</Text>
|
|
273
|
+
</View>
|
|
274
|
+
</ContextMenu.Trigger>
|
|
275
|
+
<ContextMenu.Content>
|
|
276
|
+
<ContextMenu.Label children='Label 1' />
|
|
277
|
+
<ContextMenu.Item key='item-1'>
|
|
278
|
+
<ContextMenu.ItemTitle>Item 1</ContextMenu.ItemTitle>
|
|
279
|
+
</ContextMenu.Item>
|
|
280
|
+
<ContextMenu.Group>
|
|
281
|
+
<ContextMenu.Item key='item-2'>
|
|
282
|
+
<ContextMenu.ItemTitle>Item 2</ContextMenu.ItemTitle>
|
|
283
|
+
</ContextMenu.Item>
|
|
284
|
+
<ContextMenu.CheckboxItem
|
|
285
|
+
key='checkbox-example'
|
|
286
|
+
value={isChecked}
|
|
287
|
+
onValueChange={(val) => {
|
|
288
|
+
setIsChecked(val === 'on');
|
|
289
|
+
}}
|
|
290
|
+
>
|
|
291
|
+
<ContextMenu.ItemTitle>Item 3</ContextMenu.ItemTitle>
|
|
292
|
+
<ContextMenu.ItemIndicator />
|
|
293
|
+
</ContextMenu.CheckboxItem>
|
|
294
|
+
</ContextMenu.Group>
|
|
295
|
+
<ContextMenu.Separator />
|
|
296
|
+
</ContextMenu.Content>
|
|
297
|
+
</ContextMenu.Root>
|
|
298
|
+
</View>
|
|
299
|
+
);
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
<% } %>
|
|
303
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('dropdown-menu')) { %>
|
|
304
|
+
{
|
|
305
|
+
name: 'Dropdown Menu',
|
|
306
|
+
component: () => {
|
|
307
|
+
const { colors } = useColorScheme();
|
|
308
|
+
const [menu, setMenu] = React.useState<'blue' | 'red'>('blue');
|
|
309
|
+
|
|
310
|
+
return (
|
|
311
|
+
<View className='items-center'>
|
|
312
|
+
<DropdownMenu.Root>
|
|
313
|
+
<DropdownMenu.Trigger>
|
|
314
|
+
<Pressable className='flex-row items-center gap-1.5 android:gap-3'>
|
|
315
|
+
<Text>
|
|
316
|
+
Selected: <Text style={{ color: colors[menu] }}>{menu}</Text>
|
|
317
|
+
</Text>
|
|
318
|
+
<View className='pl-0.5 opacity-70'>
|
|
319
|
+
<Icon
|
|
320
|
+
name='chevron-down'
|
|
321
|
+
color={colors.foreground}
|
|
322
|
+
size={21}
|
|
323
|
+
/>
|
|
324
|
+
</View>
|
|
325
|
+
</Pressable>
|
|
326
|
+
</DropdownMenu.Trigger>
|
|
327
|
+
<DropdownMenu.Content>
|
|
328
|
+
<DropdownMenu.CheckboxItem
|
|
329
|
+
key='red'
|
|
330
|
+
value={menu === 'red'}
|
|
331
|
+
onValueChange={() => {
|
|
332
|
+
setMenu('red');
|
|
333
|
+
}}
|
|
334
|
+
>
|
|
335
|
+
<DropdownMenu.ItemIndicator />
|
|
336
|
+
<DropdownMenu.ItemTitle children='red' />
|
|
337
|
+
</DropdownMenu.CheckboxItem>
|
|
338
|
+
<DropdownMenu.CheckboxItem
|
|
339
|
+
key='blue'
|
|
340
|
+
value={menu === 'blue'}
|
|
341
|
+
onValueChange={() => {
|
|
342
|
+
setMenu('blue');
|
|
343
|
+
}}
|
|
344
|
+
>
|
|
345
|
+
<DropdownMenu.ItemIndicator />
|
|
346
|
+
<DropdownMenu.ItemTitle children='blue' />
|
|
347
|
+
</DropdownMenu.CheckboxItem>
|
|
348
|
+
</DropdownMenu.Content>
|
|
349
|
+
</DropdownMenu.Root>
|
|
350
|
+
</View>
|
|
351
|
+
);
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
<% } %>
|
|
355
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('progress-indicator')) { %>
|
|
356
|
+
{
|
|
357
|
+
name: 'Progress Indicator',
|
|
358
|
+
component: () => {
|
|
359
|
+
const [progress, setProgress] = React.useState(13);
|
|
360
|
+
let id: ReturnType<typeof setInterval> | null = null;
|
|
361
|
+
React.useEffect(() => {
|
|
362
|
+
if (!id) {
|
|
363
|
+
id = setInterval(() => {
|
|
364
|
+
setProgress((prev) => (prev >= 99 ? 0 : prev + 5));
|
|
365
|
+
}, Math.random() * 3000);
|
|
366
|
+
}
|
|
367
|
+
return () => {
|
|
368
|
+
if (id) clearInterval(id);
|
|
369
|
+
};
|
|
370
|
+
}, []);
|
|
371
|
+
return (
|
|
372
|
+
<View className='p-4'>
|
|
373
|
+
<ProgressIndicator value={progress} />
|
|
374
|
+
</View>
|
|
375
|
+
);
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
<% } %>
|
|
379
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('activity-indicator')) { %>
|
|
380
|
+
{
|
|
381
|
+
name: 'Activity Indicator',
|
|
382
|
+
component: () => {
|
|
383
|
+
return (
|
|
384
|
+
<View className='p-4 items-center'>
|
|
385
|
+
<ActivityIndicator />
|
|
386
|
+
</View>
|
|
387
|
+
);
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
<% } %>
|
|
391
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('alert')) { %>
|
|
392
|
+
{
|
|
393
|
+
name: 'Alert',
|
|
394
|
+
component: () => {
|
|
395
|
+
const { colors } = useColorScheme();
|
|
396
|
+
return (
|
|
397
|
+
<View className='items-center'>
|
|
398
|
+
<DefaultButton
|
|
399
|
+
color={colors.red}
|
|
400
|
+
onPress={() => {
|
|
401
|
+
if (Platform.OS == 'ios') {
|
|
402
|
+
Alert.prompt(
|
|
403
|
+
'Delete account?',
|
|
404
|
+
'Enter your password to delete your account.',
|
|
405
|
+
[
|
|
406
|
+
{
|
|
407
|
+
text: 'Cancel',
|
|
408
|
+
onPress: () => console.log('Cancel Pressed'),
|
|
409
|
+
style: 'cancel',
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
text: 'Delete',
|
|
413
|
+
style: 'destructive',
|
|
414
|
+
onPress: () => console.log('Delete Pressed'),
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
'secure-text',
|
|
418
|
+
'',
|
|
419
|
+
'default'
|
|
420
|
+
);
|
|
421
|
+
} else {
|
|
422
|
+
Alert.alert(
|
|
423
|
+
'Delete account?',
|
|
424
|
+
'Enter your password to delete your account.',
|
|
425
|
+
[
|
|
426
|
+
{
|
|
427
|
+
text: 'Cancel',
|
|
428
|
+
onPress: () => console.log('Cancel Pressed'),
|
|
429
|
+
style: 'cancel',
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
text: 'Delete',
|
|
433
|
+
style: 'destructive',
|
|
434
|
+
onPress: () => console.log('Delete Pressed'),
|
|
435
|
+
},
|
|
436
|
+
]
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
}}
|
|
440
|
+
title='Delete account'
|
|
441
|
+
/>
|
|
442
|
+
</View>
|
|
443
|
+
);
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
<% } %>
|
|
447
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('action-sheet')) { %>
|
|
448
|
+
{
|
|
449
|
+
name: 'Action Sheet',
|
|
450
|
+
component: () => {
|
|
451
|
+
const { colorScheme, colors } = useColorScheme();
|
|
452
|
+
const { showActionSheetWithOptions } = useActionSheet();
|
|
453
|
+
return (
|
|
454
|
+
<View className='items-center'>
|
|
455
|
+
<DefaultButton
|
|
456
|
+
color={'grey'}
|
|
457
|
+
onPress={async () => {
|
|
458
|
+
const options = ['Delete', 'Save', 'Cancel'];
|
|
459
|
+
const destructiveButtonIndex = 0;
|
|
460
|
+
const cancelButtonIndex = 2;
|
|
461
|
+
|
|
462
|
+
showActionSheetWithOptions(
|
|
463
|
+
{
|
|
464
|
+
options,
|
|
465
|
+
cancelButtonIndex,
|
|
466
|
+
destructiveButtonIndex,
|
|
467
|
+
containerStyle: {
|
|
468
|
+
backgroundColor: colorScheme === 'dark' ? 'black' : 'white',
|
|
469
|
+
},
|
|
470
|
+
textStyle: {
|
|
471
|
+
color: colors.foreground,
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
(selectedIndex) => {
|
|
475
|
+
switch (selectedIndex) {
|
|
476
|
+
case 1:
|
|
477
|
+
// Save
|
|
478
|
+
break;
|
|
479
|
+
|
|
480
|
+
case destructiveButtonIndex:
|
|
481
|
+
// Delete
|
|
482
|
+
break;
|
|
483
|
+
|
|
484
|
+
case cancelButtonIndex:
|
|
485
|
+
// Canceled
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
);
|
|
489
|
+
}}
|
|
490
|
+
title='Open action sheet'
|
|
491
|
+
/>
|
|
492
|
+
</View>
|
|
493
|
+
);
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
<% } %>
|
|
497
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('text')) { %>
|
|
498
|
+
{
|
|
499
|
+
name: 'Text',
|
|
500
|
+
component: () => (
|
|
501
|
+
<View className='gap-2'>
|
|
502
|
+
<Text variant='largeTitle' className='text-center'>
|
|
503
|
+
Large Title
|
|
504
|
+
</Text>
|
|
505
|
+
<Text variant='title1' className='text-center'>
|
|
506
|
+
Title 1
|
|
507
|
+
</Text>
|
|
508
|
+
<Text variant='title2' className='text-center'>
|
|
509
|
+
Title 2
|
|
510
|
+
</Text>
|
|
511
|
+
<Text variant='title3' className='text-center'>
|
|
512
|
+
Title 3
|
|
513
|
+
</Text>
|
|
514
|
+
<Text variant='heading' className='text-center'>
|
|
515
|
+
Heading
|
|
516
|
+
</Text>
|
|
517
|
+
<Text variant='body' className='text-center'>
|
|
518
|
+
Body
|
|
519
|
+
</Text>
|
|
520
|
+
<Text variant='callout' className='text-center'>
|
|
521
|
+
Callout
|
|
522
|
+
</Text>
|
|
523
|
+
<Text variant='subhead' className='text-center'>
|
|
524
|
+
Subhead
|
|
525
|
+
</Text>
|
|
526
|
+
<Text variant='footnote' className='text-center'>
|
|
527
|
+
Footnote
|
|
528
|
+
</Text>
|
|
529
|
+
<Text variant='caption1' className='text-center'>
|
|
530
|
+
Caption 1
|
|
531
|
+
</Text>
|
|
532
|
+
<Text variant='caption2' className='text-center'>
|
|
533
|
+
Caption 2
|
|
534
|
+
</Text>
|
|
535
|
+
</View>
|
|
536
|
+
),
|
|
537
|
+
},
|
|
538
|
+
<% } %>
|
|
539
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('actionable-text')) { %>
|
|
540
|
+
{
|
|
541
|
+
name: 'Actionable Text',
|
|
542
|
+
component: () => {
|
|
543
|
+
return (
|
|
544
|
+
<Text uiTextView selectable>
|
|
545
|
+
Long press or double press this text
|
|
546
|
+
</Text>
|
|
547
|
+
);
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
<% } %>
|
|
551
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('ratings-indicator')) { %>
|
|
552
|
+
{
|
|
553
|
+
name: 'Ratings Indicator',
|
|
554
|
+
component: () => (
|
|
555
|
+
<View className='items-center'>
|
|
556
|
+
<DefaultButton
|
|
557
|
+
color='orange'
|
|
558
|
+
onPress={async () => {
|
|
559
|
+
if (await StoreReview.hasAction()) {
|
|
560
|
+
StoreReview.requestReview();
|
|
561
|
+
}
|
|
562
|
+
if (Platform.OS === 'android') {
|
|
563
|
+
Alert.alert(
|
|
564
|
+
'Android Demo',
|
|
565
|
+
'Store review is not available for Android demo'
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}}
|
|
569
|
+
title='Rate this app'
|
|
570
|
+
/>
|
|
571
|
+
</View>
|
|
572
|
+
),
|
|
573
|
+
},
|
|
574
|
+
<% } %>
|
|
575
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('activity-view')) { %>
|
|
576
|
+
{
|
|
577
|
+
name: 'Activity View',
|
|
578
|
+
component: () => (
|
|
579
|
+
<View className='items-center'>
|
|
580
|
+
<DefaultButton
|
|
581
|
+
onPress={async () => {
|
|
582
|
+
try {
|
|
583
|
+
const result = await Share.share({
|
|
584
|
+
message: 'NativeWindUI | Familiar interface, native feel.',
|
|
585
|
+
});
|
|
586
|
+
if (result.action === Share.sharedAction) {
|
|
587
|
+
if (result.activityType) {
|
|
588
|
+
// shared with activity type of result.activityType
|
|
589
|
+
} else {
|
|
590
|
+
// shared
|
|
591
|
+
}
|
|
592
|
+
} else if (result.action === Share.dismissedAction) {
|
|
593
|
+
// dismissed
|
|
594
|
+
}
|
|
595
|
+
} catch (error: any) {
|
|
596
|
+
Alert.alert(error.message);
|
|
597
|
+
}
|
|
598
|
+
}}
|
|
599
|
+
title='Share a message'
|
|
600
|
+
/>
|
|
601
|
+
</View>
|
|
602
|
+
),
|
|
603
|
+
},
|
|
604
|
+
<% } %>
|
|
605
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('bottom-sheet')) { %>
|
|
606
|
+
{
|
|
607
|
+
name: 'Bottom Sheet',
|
|
608
|
+
component: () => {
|
|
609
|
+
const { colorScheme } = useColorScheme();
|
|
610
|
+
const bottomSheetModalRef = useSheetRef();
|
|
611
|
+
|
|
612
|
+
return (
|
|
613
|
+
<View className='items-center'>
|
|
614
|
+
<DefaultButton
|
|
615
|
+
color={
|
|
616
|
+
colorScheme === 'dark' && Platform.OS === 'ios'
|
|
617
|
+
? 'white'
|
|
618
|
+
: 'black'
|
|
619
|
+
}
|
|
620
|
+
title='Open Bottom Sheet'
|
|
621
|
+
onPress={() => bottomSheetModalRef.current?.present()}
|
|
622
|
+
/>
|
|
623
|
+
<Sheet ref={bottomSheetModalRef} snapPoints={[200]}>
|
|
624
|
+
<View className='flex-1 justify-center items-center pb-8'>
|
|
625
|
+
<Text>@gorhom/bottom-sheet 🎉</Text>
|
|
626
|
+
</View>
|
|
627
|
+
</Sheet>
|
|
628
|
+
</View>
|
|
629
|
+
);
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
<% } %>
|
|
633
|
+
<% if (props.stylingPackage?.options.selectedComponents.includes('avatar')) { %>
|
|
634
|
+
{
|
|
635
|
+
name: 'Avatar',
|
|
636
|
+
component: () => {
|
|
637
|
+
const GITHUB_AVATAR_URI = 'https://github.com/mrzachnugent.png';
|
|
638
|
+
return (
|
|
639
|
+
<View className='items-center'>
|
|
640
|
+
<Avatar alt="Zach Nugent's Avatar">
|
|
641
|
+
<AvatarImage source={{ uri: GITHUB_AVATAR_URI }} />
|
|
642
|
+
<AvatarFallback>
|
|
643
|
+
<Text>ZN</Text>
|
|
644
|
+
</AvatarFallback>
|
|
645
|
+
</Avatar>
|
|
646
|
+
</View>
|
|
647
|
+
);
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
<% } %>
|
|
651
|
+
];
|
|
652
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Text } from '~/components/nativewind-ui/Text';
|
|
2
|
+
import { Link } from 'expo-router';
|
|
3
|
+
import { StatusBar } from 'expo-status-bar';
|
|
4
|
+
import { useColorScheme } from 'nativewind';
|
|
5
|
+
import { Platform, View } from 'react-native';
|
|
6
|
+
|
|
7
|
+
export default function ModalScreen() {
|
|
8
|
+
const { colorScheme } = useColorScheme();
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
<StatusBar
|
|
12
|
+
style={
|
|
13
|
+
Platform.OS === 'ios'
|
|
14
|
+
? 'light'
|
|
15
|
+
: colorScheme === 'dark'
|
|
16
|
+
? 'light'
|
|
17
|
+
: 'dark'
|
|
18
|
+
}
|
|
19
|
+
/>
|
|
20
|
+
<View className='flex-1 justify-center items-center gap-8 pb-12'>
|
|
21
|
+
<View className='items-center gap-2'>
|
|
22
|
+
<Text variant='largeTitle' className='font-bold'>
|
|
23
|
+
NativeWindUI
|
|
24
|
+
</Text>
|
|
25
|
+
<Link href={'https://nativewindui.com/'}>
|
|
26
|
+
<Text className='text-primary'>https://nativewindui.com/</Text>
|
|
27
|
+
</Link>
|
|
28
|
+
</View>
|
|
29
|
+
</View>
|
|
30
|
+
</>
|
|
31
|
+
);
|
|
32
|
+
}
|
package/build/templates/packages/nativewindui/components/nativewind-ui/ActivityIndicator.tsx.ejs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ActivityIndicator as RNActivityIndicator } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { useColorScheme } from '~/lib/useColorScheme';
|
|
4
|
+
|
|
5
|
+
export function ActivityIndicator(
|
|
6
|
+
props: React.ComponentPropsWithoutRef<typeof RNActivityIndicator>
|
|
7
|
+
) {
|
|
8
|
+
const { colors } = useColorScheme();
|
|
9
|
+
return <RNActivityIndicator color={colors.blue} {...props} />;
|
|
10
|
+
}
|