create-expo-stack 2.7.0-next.e4d108e → 2.7.1-next.7228e17

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