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.
- package/README.md +16 -9
- package/build/commands/create-expo-stack.js +62 -15
- package/build/templates/base/app.json.ejs +5 -1
- package/build/templates/base/package.json.ejs +40 -12
- package/build/templates/base/tsconfig.json.ejs +1 -1
- package/build/templates/packages/nativewindui/app/+not-found.tsx.ejs +1 -1
- package/build/templates/packages/nativewindui/app/_layout.tsx.ejs +46 -39
- package/build/templates/packages/nativewindui/app/index.tsx.ejs +658 -165
- package/build/templates/packages/nativewindui/app/modal.tsx.ejs +20 -19
- 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/{Text.tsx.ejs → nativewind-ui/Text.tsx.ejs} +28 -4
- package/build/templates/packages/nativewindui/components/nativewind-ui/ThemeToggle.tsx.ejs +35 -0
- package/build/templates/packages/nativewindui/components/{Toggle.tsx.ejs → nativewind-ui/Toggle.tsx.ejs} +3 -3
- package/build/templates/packages/nativewindui/global.css.ejs +3 -3
- package/build/templates/packages/nativewindui/lib/useColorScheme.tsx.ejs +47 -6
- package/build/templates/packages/nativewindui/lib/useHeaderSearchBar.tsx.ejs +2 -2
- package/build/templates/packages/nativewindui/metro.config.js.ejs +1 -0
- package/build/templates/packages/nativewindui/tailwind.config.js.ejs +34 -76
- package/build/templates/packages/nativewindui/theme/colors.ts.ejs +8 -8
- package/build/templates/packages/nativewindui/theme/index.ts.ejs +4 -4
- package/build/types/types.d.ts +2 -0
- package/build/types/utilities/clearNavigationPackages.d.ts +2 -0
- package/build/utilities/clearNavigationPackages.js +11 -0
- package/build/utilities/configureProjectFiles.js +64 -35
- package/build/utilities/printOutput.js +32 -14
- package/build/utilities/runCLI.js +80 -26
- package/package.json +1 -1
- package/build/templates/packages/nativewindui/app/bottom-tabs/_layout.tsx.ejs +0 -34
- package/build/templates/packages/nativewindui/app/bottom-tabs/index.tsx.ejs +0 -11
- package/build/templates/packages/nativewindui/app/bottom-tabs/profile.tsx.ejs +0 -11
- package/build/templates/packages/nativewindui/app/drawer/_layout.tsx.ejs +0 -29
- package/build/templates/packages/nativewindui/app/drawer/index.tsx.ejs +0 -11
- package/build/templates/packages/nativewindui/app/top-tabs/_layout.tsx.ejs +0 -71
- package/build/templates/packages/nativewindui/app/top-tabs/following.tsx.ejs +0 -13
- package/build/templates/packages/nativewindui/app/top-tabs/index.tsx.ejs +0 -13
- package/build/templates/packages/nativewindui/app/top-tabs/my-group.tsx.ejs +0 -13
- package/build/templates/packages/nativewindui/components/ThemeToggle.tsx.ejs +0 -53
- /package/build/templates/packages/nativewindui/lib/{utils.ts.ejs → cn.ts.ejs} +0 -0
|
@@ -1,214 +1,707 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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=
|
|
121
|
-
<
|
|
122
|
-
<Text className='
|
|
123
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
147
|
+
type ComponentItem = { name: string; component: React.FC };
|
|
148
|
+
|
|
149
|
+
function keyExtractor(item: ComponentItem) {
|
|
150
|
+
return item.name;
|
|
134
151
|
}
|
|
135
152
|
|
|
136
|
-
|
|
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: '
|
|
152
|
-
component: ()
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
</
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
</
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '
|
|
195
|
-
|
|
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: '
|
|
199
|
-
|
|
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: '
|
|
204
|
-
|
|
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: '
|
|
208
|
-
|
|
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: '
|
|
212
|
-
|
|
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
|
-
|
|
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
|
+
|