chore: migrate to monorepo

This commit is contained in:
Satyajit Sahoo
2020-02-07 23:20:57 +01:00
parent a7305b1413
commit 72e8160537
477 changed files with 155789 additions and 170280 deletions

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import { Text, View, Button, StyleSheet } from 'react-native';
import createAnimatedSwitchNavigator, {
NavigationAnimatedSwitchProp,
} from 'react-navigation-animated-switch';
import { Transition } from 'react-native-reanimated';
function Home({ navigation }: { navigation: NavigationAnimatedSwitchProp }) {
return (
<View style={styles.content}>
<Text>Home screen</Text>
<Button
title="Go to settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
);
}
function Settings({
navigation,
}: {
navigation: NavigationAnimatedSwitchProp;
}) {
return (
<View style={styles.content}>
<Text>Settings screen</Text>
<Button title="Go to home" onPress={() => navigation.navigate('Home')} />
<Button
title="Go back to examples"
onPress={() => navigation.navigate('Index')}
/>
</View>
);
}
const MySwitch = createAnimatedSwitchNavigator(
{
Home,
Settings,
},
{
transition: (
<Transition.Together>
<Transition.Out
type="slide-bottom"
durationMs={400}
interpolation="easeIn"
/>
<Transition.In type="fade" durationMs={500} />
</Transition.Together>
),
}
);
const styles = StyleSheet.create({
content: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export default MySwitch;

View File

@@ -0,0 +1,80 @@
import * as React from 'react';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { MaterialIcons } from '@expo/vector-icons';
import Albums from './Shared/Albums';
import Article from './Shared/Article';
import Chat from './Shared/Chat';
import Contacts from './Shared/Contacts';
// @ts-ignore
import TouchableBounce from 'react-native/Libraries/Components/Touchable/TouchableBounce';
const tabBarIcon = (name: string) => ({
tintColor,
horizontal,
}: {
tintColor: string;
horizontal: boolean;
}) => (
<MaterialIcons name={name} color={tintColor} size={horizontal ? 17 : 24} />
);
class AlbumsScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Albums',
tabBarIcon: tabBarIcon('photo-album'),
tabBarButtonComponent: TouchableBounce,
};
render() {
return <Albums />;
}
}
class ArticleScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Article',
tabBarIcon: tabBarIcon('chrome-reader-mode'),
tabBarButtonComponent: TouchableBounce,
};
render() {
return <Article />;
}
}
class ChatScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Chat',
tabBarIcon: tabBarIcon('chat-bubble'),
tabBarButtonComponent: TouchableBounce,
};
render() {
return <Chat />;
}
}
class ContactsScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Contacts',
tabBarIcon: tabBarIcon('contacts'),
tabBarButtonComponent: TouchableBounce,
};
render() {
return <Contacts />;
}
}
export default createBottomTabNavigator(
{
AlbumsScreen,
ArticleScreen,
ChatScreen,
ContactsScreen,
},
{
initialRouteName: 'AlbumsScreen',
}
);

216
example/src/CustomTabUI.tsx Normal file
View File

@@ -0,0 +1,216 @@
import React from 'react';
import {
Alert,
TouchableOpacity,
LayoutAnimation,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import {
Themed,
ThemeContext,
NavigationScreenProp,
NavigationState,
SafeAreaView,
} from 'react-navigation';
import {
createMaterialTopTabNavigator,
MaterialTopTabBar,
} from 'react-navigation-tabs';
import { Button } from './Shared/ButtonWithMargin';
interface Props {
navigation: NavigationScreenProp<NavigationState>;
}
class MyHomeScreen extends React.Component<Props> {
static navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({
tintColor,
focused,
horizontal,
}: {
tintColor: string;
focused: boolean;
horizontal: boolean;
}) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home'}
size={horizontal ? 20 : 26}
style={{ color: tintColor }}
/>
),
};
render() {
const { navigation } = this.props;
return (
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
<Themed.Text>Home Screen</Themed.Text>
<Button
onPress={() => navigation.navigate('Home')}
title="Go to home tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
);
}
}
class StarredScreen extends React.Component<Props> {
static navigationOptions = {
tabBarLabel: 'Starred',
tabBarIcon: ({
tintColor,
focused,
horizontal,
}: {
tintColor: string;
focused: boolean;
horizontal: boolean;
}) => (
<Ionicons
name={focused ? 'ios-people' : 'ios-people'}
size={horizontal ? 20 : 26}
style={{ color: tintColor }}
/>
),
};
render() {
const { navigation } = this.props;
return (
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
<Themed.Text>Starred Screen</Themed.Text>
<Button
onPress={() => navigation.navigate('Home')}
title="Go to home tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
);
}
}
type MaterialTopTabBarProps = React.ComponentProps<typeof MaterialTopTabBar>;
class MaterialTopTabBarWrapper extends React.Component<MaterialTopTabBarProps> {
render() {
return (
<SafeAreaView
style={{ backgroundColor: '#000' }}
forceInset={{ top: 'always', horizontal: 'never', bottom: 'never' }}
>
<MaterialTopTabBar {...this.props} />
</SafeAreaView>
);
}
}
class FeaturedScreen extends React.Component<Props> {
static navigationOptions = {
tabBarLabel: 'Featured',
tabBarIcon: ({
tintColor,
focused,
horizontal,
}: {
tintColor: string;
focused: boolean;
horizontal: boolean;
}) => (
<Ionicons
name={focused ? 'ios-star' : 'ios-star'}
size={horizontal ? 20 : 26}
style={{ color: tintColor }}
/>
),
};
render() {
const { navigation } = this.props;
return (
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
<Themed.Text>Featured Screen</Themed.Text>
<Button
onPress={() => navigation.navigate('Home')}
title="Go to home tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
);
}
}
const SimpleTabs = createMaterialTopTabNavigator(
{
Home: MyHomeScreen,
Starred: StarredScreen,
Featured: FeaturedScreen,
},
{
tabBarComponent: MaterialTopTabBarWrapper,
tabBarOptions: {
style: {
backgroundColor: '#000',
},
},
}
);
class TabNavigator extends React.Component<Props> {
// eslint-disable-next-line react/sort-comp
static contextType = ThemeContext;
static router = SimpleTabs.router;
componentWillUpdate() {
LayoutAnimation.easeInEaseOut();
}
render() {
const { navigation } = this.props;
const { routes, index } = navigation.state;
const activeRoute = routes[index];
let bottom = null;
if (activeRoute.routeName !== 'Home') {
bottom = (
<View
style={{
height: 50,
borderTopWidth: StyleSheet.hairlineWidth,
backgroundColor: this.context === 'light' ? '#000' : '#fff',
alignItems: 'center',
justifyContent: 'center',
}}
>
<TouchableOpacity
onPress={() => {
Alert.alert('hello!');
//
}}
>
<Text
style={{
fontSize: 20,
color: this.context === 'light' ? '#fff' : '#000',
fontWeight: 'bold',
}}
>
Check out
</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={{ flex: 1 }}>
<StatusBar barStyle="light-content" />
<SimpleTabs navigation={navigation} />
{bottom}
</View>
);
}
}
export default TabNavigator;

139
example/src/CustomTabs.tsx Normal file
View File

@@ -0,0 +1,139 @@
import React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import { BorderlessButton } from 'react-native-gesture-handler';
import {
createNavigator,
NavigationState,
SafeAreaView,
TabRouter,
Themed,
useTheme,
createAppContainer,
NavigationScreenProp,
} from 'react-navigation';
import { Button } from './Shared/ButtonWithMargin';
import SampleText from './Shared/SampleText';
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationScreenProp<NavigationState>;
banner: string;
}) => (
<ScrollView>
<SafeAreaView forceInset={{ horizontal: 'always' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => {
navigation.goBack(null);
}}
title="Go back"
/>
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
const MyHomeScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => <MyNavScreen banner="Home Screen" navigation={navigation} />;
const MyNotificationsScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => <MyNavScreen banner="Notifications Screen" navigation={navigation} />;
const MySettingsScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => <MyNavScreen banner="Settings Screen" navigation={navigation} />;
const CustomTabBar = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => {
const { routes } = navigation.state;
return (
<SafeAreaView style={styles.tabContainer}>
{routes.map(route => (
<BorderlessButton
onPress={() => navigation.navigate(route.routeName)}
style={styles.tab}
key={route.routeName}
>
<Themed.Text>{route.routeName}</Themed.Text>
</BorderlessButton>
))}
</SafeAreaView>
);
};
// @todo - how does the type definition for a custom navigator work?
class CustomTabView extends React.Component<any> {
render() {
const { navigation, descriptors } = this.props;
const { routes, index } = navigation.state;
const descriptor = descriptors[routes[index].key];
const ActiveScreen = descriptor.getComponent();
return (
<SafeAreaView forceInset={{ top: 'always' }}>
<CustomTabBar navigation={navigation} />
<ActiveScreen navigation={descriptor.navigation} />
</SafeAreaView>
);
}
}
const CustomTabRouter = TabRouter(
{
Home: {
path: '',
screen: MyHomeScreen,
},
Notifications: {
path: 'notifications',
screen: MyNotificationsScreen,
},
Settings: {
path: 'settings',
screen: MySettingsScreen,
},
},
{
// Change this to start on a different tab
initialRouteName: 'Home',
}
);
const CustomTabs = createAppContainer(
createNavigator(CustomTabView, CustomTabRouter, {})
);
const styles = StyleSheet.create({
tab: {
alignItems: 'center',
borderColor: '#ddd',
borderRadius: 4,
borderWidth: 1,
flex: 1,
justifyContent: 'center',
margin: 4,
},
tabContainer: {
flexDirection: 'row',
height: 48,
},
});
export default () => {
// Need to thread the theme through to detached nested navigator
let theme = useTheme();
return <CustomTabs detached theme={theme} />;
};

View File

@@ -0,0 +1,48 @@
import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import { NavigationStackScreenComponent } from 'react-navigation-stack';
const HEIGHT = Dimensions.get('screen').height;
const DragLimitedToModal: NavigationStackScreenComponent = () => (
<View style={styles.modal}>
<Text style={styles.text}>Adjusts to the size of text</Text>
</View>
);
DragLimitedToModal.navigationOptions = {
cardStyle: { backgroundColor: 'transparent' },
gestureDirection: 'vertical',
gestureResponseDistance: { vertical: HEIGHT },
cardStyleInterpolator: ({ current }) => {
const translateY = current.progress.interpolate({
inputRange: [0, 1],
outputRange: [HEIGHT, 0],
});
return {
cardStyle: {
transform: [{ translateY }],
flex: undefined,
},
containerStyle: {
alignItems: 'center',
justifyContent: 'center',
},
};
},
};
const styles = StyleSheet.create({
modal: {
padding: 30,
borderRadius: 15,
backgroundColor: '#000',
},
text: {
fontSize: 18,
color: '#fff',
},
});
export default DragLimitedToModal;

126
example/src/Drawer.tsx Normal file
View File

@@ -0,0 +1,126 @@
import React from 'react';
import { ScrollView, StyleProp, TextStyle } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
import {
Themed,
SafeAreaView,
NavigationScreenProp,
NavigationState,
} from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import {
createDrawerNavigator,
NavigationDrawerScreenProps,
} from 'react-navigation-drawer';
import { Button } from './Shared/ButtonWithMargin';
import SampleText from './Shared/SampleText';
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationScreenProp<NavigationState>;
banner: string;
}) => (
<ScrollView>
<SafeAreaView forceInset={{ top: 'always' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => {
// @ts-ignore
navigation.openDrawer();
}}
title="Open drawer"
/>
<Button
onPress={() => navigation.navigate('Email')}
title="Open other screen"
/>
<Button onPress={() => navigation.navigate('Index')} title="Go back" />
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
const InboxScreen = ({ navigation }: NavigationDrawerScreenProps) => (
<MyNavScreen banner="Inbox Screen" navigation={navigation} />
);
InboxScreen.navigationOptions = {
headerTitle: 'Inbox',
};
const EmailScreen = ({ navigation }: NavigationStackScreenProps) => (
<MyNavScreen banner="Email Screen" navigation={navigation} />
);
const DraftsScreen = ({ navigation }: NavigationStackScreenProps) => (
<MyNavScreen banner="Drafts Screen" navigation={navigation} />
);
DraftsScreen.navigationOptions = {
headerTitle: 'Drafts',
};
const InboxStack = createStackNavigator(
{
Email: { screen: EmailScreen },
Inbox: { screen: InboxScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }: { tintColor: string }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Inbox',
},
}
);
const DraftsStack = createStackNavigator(
{
Drafts: { screen: DraftsScreen },
Email: { screen: EmailScreen },
},
{
navigationOptions: {
drawerIcon: ({ tintColor }: { tintColor: string }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor } as StyleProp<TextStyle>}
/>
),
drawerLabel: 'Drafts',
},
}
);
const DrawerExample = createDrawerNavigator(
{
Drafts: {
path: '/sent',
screen: DraftsStack,
},
Inbox: {
path: '/',
screen: InboxStack,
},
},
{
contentOptions: {
activeTintColor: '#e91e63',
},
initialRouteName: 'Drafts',
}
);
export default DrawerExample;

136
example/src/EventsStack.tsx Normal file
View File

@@ -0,0 +1,136 @@
import React from 'react';
import { Button, ScrollView, View, Text } from 'react-native';
import {
createStackNavigator,
NavigationStackProp,
NavigationStackScreenProps,
} from 'react-navigation-stack';
const getColorOfEvent = (evt: string) => {
switch (evt) {
case 'willFocus':
return 'purple';
case 'didFocus':
return 'blue';
case 'willBlur':
return 'brown';
default:
return 'black';
}
};
class FocusTag extends React.Component<NavigationStackScreenProps> {
state = { mode: 'didBlur' };
componentDidMount() {
this.props.navigation.addListener('willFocus', () => {
this.setMode('willFocus');
});
this.props.navigation.addListener('willBlur', () => {
this.setMode('willBlur');
});
this.props.navigation.addListener('didFocus', () => {
this.setMode('didFocus');
});
this.props.navigation.addListener('didBlur', () => {
this.setMode('didBlur');
});
}
setMode = (mode: string) => {
this.setState({ mode });
};
render() {
const key = this.props.navigation.state.key;
return (
<View
style={{
padding: 20,
backgroundColor: getColorOfEvent(this.state.mode),
}}
>
<Text style={{ color: 'white' }}>
{key} {String(this.state.mode)}
</Text>
</View>
);
}
}
class SampleScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = ({
navigation,
}: {
navigation: NavigationStackProp;
}) => ({
title: 'Lorem Ipsum',
headerRight: navigation.getParam('nextPage')
? () => (
<Button
title="Next"
onPress={() => navigation.navigate(navigation.getParam('nextPage'))}
/>
)
: undefined,
});
componentDidMount() {
this.props.navigation.addListener('refocus', () => {
if (this.props.navigation.isFocused()) {
this.scrollView.current?.scrollTo({ x: 0, y: 0 });
}
});
}
private scrollView = React.createRef<ScrollView>();
render() {
return (
<ScrollView ref={this.scrollView} style={{ flex: 1 }}>
<FocusTag {...this.props} />
<Button
title="Push"
onPress={() => {
this.props.navigation.push('PageTwo');
}}
/>
<Button
title="Push and Pop Quickly"
onPress={() => {
const { push, goBack } = this.props.navigation;
push('PageTwo');
setTimeout(() => {
goBack(null);
}, 150);
}}
/>
<Button
title="Back to Examples"
onPress={() => {
this.props.navigation.navigate('Index');
}}
/>
</ScrollView>
);
}
}
const SimpleStack = createStackNavigator(
{
PageOne: {
screen: SampleScreen,
},
PageTwo: {
screen: SampleScreen,
},
},
{
initialRouteName: 'PageOne',
}
);
export default SimpleStack;

View File

@@ -0,0 +1,15 @@
import * as React from 'react';
import { View } from 'react-native';
import { createStackNavigator } from 'react-navigation-stack';
class Screen extends React.Component {
static navigationOptions = {
headerShown: false,
};
render() {
return <View style={{ flex: 1, backgroundColor: 'red' }} />;
}
}
export default createStackNavigator({ Screen });

View File

@@ -0,0 +1,93 @@
import * as React from 'react';
import { Button, View } from 'react-native';
import { withNavigation } from 'react-navigation';
import {
createDrawerNavigator,
DrawerGestureContext,
NavigationDrawerProp,
} from 'react-navigation-drawer';
import MapView from 'react-native-maps';
import { WebView } from 'react-native-webview';
import { NativeViewGestureHandler } from 'react-native-gesture-handler';
const ContainerWithButtons = withNavigation(
({
children,
navigation,
}: {
children: React.ReactNode;
navigation: NavigationDrawerProp;
}) => (
<View style={{ flex: 1 }}>
{children}
<View
style={{
position: 'absolute',
paddingBottom: 30,
bottom: 0,
paddingTop: 10,
paddingHorizontal: 10,
left: 0,
flexDirection: 'row',
right: 0,
backgroundColor: 'rgba(255,255,255,0.7)',
justifyContent: 'space-between',
}}
>
<Button title="Open drawer" onPress={() => navigation.openDrawer()} />
<Button title="Go back" onPress={() => navigation.navigate('Index')} />
</View>
</View>
)
);
const MapScreen = () => (
<ContainerWithButtons>
<DrawerGestureContext.Consumer>
{ref => (
<NativeViewGestureHandler waitFor={ref}>
<MapView style={{ flex: 1 }} />
</NativeViewGestureHandler>
)}
</DrawerGestureContext.Consumer>
</ContainerWithButtons>
);
MapScreen.navigationOptions = {
title: 'MapView',
};
const WebViewScreen = () => (
<ContainerWithButtons>
<DrawerGestureContext.Consumer>
{ref => (
<NativeViewGestureHandler waitFor={ref}>
<WebView
style={{ flex: 1 }}
source={{ uri: 'https://news.google.com' }}
/>
</NativeViewGestureHandler>
)}
</DrawerGestureContext.Consumer>
</ContainerWithButtons>
);
WebViewScreen.navigationOptions = {
title: 'WebView',
};
const DrawerExample = createDrawerNavigator(
{
Map: MapScreen,
Web: WebViewScreen,
},
{
edgeWidth: 70,
minSwipeDistance: 3,
contentOptions: {
activeTintColor: '#e91e63',
},
}
);
export default DrawerExample;

View File

@@ -0,0 +1,123 @@
import * as React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import {
createStackNavigator,
TransitionPresets,
HeaderStyleInterpolators,
NavigationStackScreenProps,
} from 'react-navigation-stack';
function createHeaderBackgroundExample(options = {}) {
return createStackNavigator(
{
Login: {
screen: ({ navigation }: NavigationStackScreenProps) => (
<View style={styles.container}>
<Text
style={styles.tips}
onPress={() => navigation.navigate('Games')}
>
Login Screen
</Text>
</View>
),
navigationOptions: {
headerTitle: 'Login Screen',
headerTintColor: '#fff',
headerBackground: () => (
<View style={{ flex: 1, backgroundColor: '#FF0066' }} />
),
},
},
Games: {
screen: ({ navigation }: NavigationStackScreenProps) => (
<View style={styles.container}>
<Text
style={styles.tips}
onPress={() => navigation.navigate('Main')}
>
Games Screen
</Text>
</View>
),
navigationOptions: {
headerTitle: 'Games Screen',
headerTintColor: '#fff',
headerBackground: () => (
<View style={{ flex: 1, backgroundColor: '#3388FF' }} />
),
},
},
Main: {
screen: ({ navigation }: NavigationStackScreenProps) => (
<View style={styles.container}>
<Text style={styles.tips} onPress={() => navigation.navigate('My')}>
Main Screen
</Text>
</View>
),
navigationOptions: {
headerTitle: 'Main Screen',
},
},
My: {
screen: ({ navigation }: NavigationStackScreenProps) => (
<View style={styles.container}>
<Text
style={styles.tips}
onPress={() => navigation.navigate('News')}
>
My Screen
</Text>
</View>
),
navigationOptions: {
headerTitle: 'My Screen',
},
},
News: {
screen: () => (
<View style={styles.container}>
<Text style={styles.tips} onPress={() => {}}>
News Screen
</Text>
</View>
),
navigationOptions: {
headerTitle: 'News Screen',
},
},
},
{
initialRouteName: 'Login',
...options,
}
);
}
export const HeaderBackgroundDefault = createHeaderBackgroundExample({
defaultNavigationOptions: {
...TransitionPresets.SlideFromRightIOS,
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
},
headerMode: 'float',
});
export const HeaderBackgroundFade = createHeaderBackgroundExample({
defaultNavigationOptions: {
...TransitionPresets.SlideFromRightIOS,
headerStyleInterpolator: HeaderStyleInterpolators.forFade,
},
headerMode: 'float',
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
justifyContent: 'center',
alignItems: 'center',
},
tips: {
fontSize: 20,
},
});

View File

@@ -0,0 +1,120 @@
import * as React from 'react';
import { Button, StatusBar, StyleProp, ViewStyle } from 'react-native';
import { SafeAreaView } from 'react-navigation';
import {
createStackNavigator,
TransitionPresets,
HeaderStyleInterpolators,
NavigationStackScreenProps,
} from 'react-navigation-stack';
class HomeScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigation } = this.props;
const { push } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => push('Other')} title="Push another screen" />
<Button
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
class OtherScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Your title here',
};
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button
onPress={() => push('ScreenWithLongTitle')}
title="Push another screen"
/>
<Button
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
class ScreenWithLongTitle extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: "Another title that's kind of long",
};
render() {
const { navigation } = this.props;
const { pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
class ScreenWithNoHeader extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'No Header',
headerShown: false,
};
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => push('Other')} title="Push another screen" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
);
}
}
const StackWithHeaderPreset = createStackNavigator(
{
Home: HomeScreen,
Other: OtherScreen,
ScreenWithNoHeader: ScreenWithNoHeader,
ScreenWithLongTitle: ScreenWithLongTitle,
},
{
headerMode: 'float',
defaultNavigationOptions: {
...TransitionPresets.SlideFromRightIOS,
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
// @ts-ignore
headerTitleContainerStyle: { left: null } as StyleProp<ViewStyle>,
gestureEnabled: true,
},
}
);
export default StackWithHeaderPreset;

64
example/src/IconTabs.tsx Normal file
View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import {
createMaterialBottomTabNavigator,
NavigationMaterialBottomTabOptions,
} from 'react-navigation-material-bottom-tabs';
import PhotoGrid from './Shared/PhotoGrid';
import tabBarIcon from './Shared/tabBarIcon';
class Album extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('photo-album'),
};
render() {
return <PhotoGrid id="album" />;
}
}
class Library extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('inbox'),
tabBarBadge: true,
};
render() {
return <PhotoGrid id="library" />;
}
}
class Favorites extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('favorite'),
};
render() {
return <PhotoGrid id="favorites" />;
}
}
class Purchased extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('shop'),
};
render() {
return <PhotoGrid id="purchased" />;
}
}
export default createMaterialBottomTabNavigator(
{
Album,
Library,
Favorites,
Purchased,
},
{
shifting: false,
labeled: false,
activeColor: '#f0edf6',
inactiveColor: '#3e2465',
barStyle: { backgroundColor: '#694fad' },
}
);

View File

@@ -0,0 +1,92 @@
import * as React from 'react';
import { Dimensions, Button, Image, View } from 'react-native';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import { FlatList, BorderlessButton } from 'react-native-gesture-handler';
class ListScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = ({ navigation }: NavigationStackScreenProps) => ({
title: 'Image list',
headerBackTitle: 'Back',
headerLeft: () => (
<Button title="Back" onPress={() => navigation.navigate('Index')} />
),
});
state = {
items: Array.apply(null, Array(60)).map((_, i) => {
return {
id: i,
src: `https://source.unsplash.com/random/400x${400 + i}`,
};
}),
};
render() {
return (
<FlatList
data={this.state.items}
renderItem={({ item }) => (
<View style={{ flex: 1, flexDirection: 'column', margin: 1 }}>
<BorderlessButton
onPress={() =>
this.props.navigation.navigate('Details', {
id: item.id,
src: item.src,
})
}
>
<Image style={{ height: 100 }} source={{ uri: item.src }} />
</BorderlessButton>
</View>
)}
numColumns={3}
keyExtractor={(_, index) => String(index)}
style={{ flex: 1, backgroundColor: '#fff' }}
/>
);
}
}
class DetailsScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Random image from Unsplash',
};
render() {
let id = this.props.navigation.getParam('id', 0);
return (
<View
style={{
flex: 1,
backgroundColor: '#fff',
}}
>
<Image
source={{
uri: `https://source.unsplash.com/random/1080x${1920 + id}`,
}}
style={{ width: Dimensions.get('window').width, height: 400 }}
resizeMode="cover"
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'List',
}
);

View File

@@ -0,0 +1,105 @@
import * as React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
class ScreenOne extends React.Component<NavigationStackScreenProps> {
componentDidMount() {
setTimeout(() => {
this.props.navigation.navigate('Screen2');
}, 0);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>Here is Screen One!</Text>
<TouchableOpacity
style={styles.button}
onPress={() => {
this.props.navigation.navigate('Screen2');
}}
>
<Text style={{ color: 'white', fontSize: 24 }}>Press me!</Text>
</TouchableOpacity>
</View>
);
}
}
class ScreenTwo extends React.Component<NavigationStackScreenProps> {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>Here is Screen Two!</Text>
<TouchableOpacity
style={styles.button}
onPress={() => {
this.props.navigation.navigate('Screen3');
}}
>
<Text style={{ color: 'white', fontSize: 24 }}>Press me!</Text>
</TouchableOpacity>
</View>
);
}
}
class ScreenThree extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>Here is Screen Three!</Text>
</View>
);
}
}
export const Stack = createStackNavigator(
{
Screen1: { screen: ScreenOne },
Screen2: { screen: ScreenTwo },
Screen3: { screen: ScreenThree },
},
{
initialRouteName: 'Screen1',
defaultNavigationOptions: {
headerShown: false,
},
}
);
const PrimaryStack = createAppContainer(Stack);
export default PrimaryStack;
const styles = StyleSheet.create({
button: {
height: 50,
width: 200,
backgroundColor: 'dodgerblue',
justifyContent: 'center',
alignItems: 'center',
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import { Button, Text, View, StyleSheet } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { withNavigationFocus } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenComponent,
NavigationStackScreenProps,
} from 'react-navigation-stack';
const HomeScreen: NavigationStackScreenComponent = ({ navigation }) => (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Go to BarCodeScanner"
onPress={() => navigation.navigate('BarCode')}
/>
<Button
title="Return to other examples"
onPress={() => navigation.navigate('Index')}
/>
</View>
);
HomeScreen.navigationOptions = {
title: 'Lifecycle Interactions',
};
const BarCodeScreenBase = (
props: NavigationStackScreenProps & { isFocused: boolean }
) => {
return (
<View style={{ flex: 1 }}>
<BarCodeScanner
onBarCodeScanned={
props.isFocused
? data => {
console.log('scanned...');
props.navigation.navigate('Info', { data });
}
: () => {}
}
style={StyleSheet.absoluteFill}
/>
</View>
);
};
BarCodeScreenBase.navigationOptions = {
title: 'BarCodeView',
};
const BarCodeScreen = withNavigationFocus(BarCodeScreenBase);
const InfoScreen: NavigationStackScreenComponent = props => {
return (
<View style={{ flex: 1 }}>
<Text>{JSON.stringify(props.navigation.getParam('data'))}</Text>
</View>
);
};
InfoScreen.navigationOptions = {
title: 'Info',
};
export default createStackNavigator(
{
Home: HomeScreen,
BarCode: BarCodeScreen,
Info: InfoScreen,
},
{
initialRouteName: 'Home',
}
);

View File

@@ -0,0 +1,49 @@
import * as React from 'react';
import { createMaterialTopTabNavigator } from 'react-navigation-tabs';
import Albums from './Shared/Albums';
import Article from './Shared/Article';
import Contacts from './Shared/Contacts';
class AlbumsScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Albums',
};
render() {
return <Albums />;
}
}
class ArticleScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Article',
};
render() {
return <Article />;
}
}
class ContactsScreen extends React.Component {
static navigationOptions = {
tabBarLabel: 'Contacts',
};
render() {
return <Contacts />;
}
}
export default createMaterialTopTabNavigator(
{
AlbumsScreen,
ArticleScreen,
ContactsScreen,
},
{
lazy: true,
tabBarOptions: {
style: { backgroundColor: '#5620E4' },
},
}
);

View File

@@ -0,0 +1,75 @@
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import {
createStackNavigator,
TransitionPresets,
NavigationStackScreenProps,
} from 'react-navigation-stack';
class ListScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'My Modal',
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>List Screen</Text>
<Text>A list may go here</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
<Button
title="Go back to all examples"
onPress={() => this.props.navigation.navigate('Index')}
/>
</View>
);
}
}
class DetailsScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
headerShown: false,
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
<Button
title="Go to List"
onPress={() => this.props.navigation.navigate('List')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
<Button
title="Go back to all examples"
onPress={() => this.props.navigation.navigate('Index')}
/>
</View>
);
}
}
export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
},
{
mode: 'modal',
defaultNavigationOptions: {
...TransitionPresets.ModalPresentationIOS,
cardOverlayEnabled: true,
gestureEnabled: true,
},
}
);

188
example/src/ModalStack.tsx Normal file
View File

@@ -0,0 +1,188 @@
import * as React from 'react';
import {
Button,
View,
Text,
Dimensions,
Switch,
TextInput,
} from 'react-native';
import {
createStackNavigator,
CardStyleInterpolators,
NavigationStackScreenProps,
StackCardStyleInterpolator,
} from 'react-navigation-stack';
const gestureResponseDistance = {
vertical: Dimensions.get('window').height,
};
const forVerticalInvertedIOS: StackCardStyleInterpolator = ({
current: { progress },
layouts: { screen },
}) => {
const translateY = progress.interpolate({
inputRange: [0, 1],
outputRange: [-screen.height, 0],
});
return {
cardStyle: {
transform: [
// Translation for the animation of the current card
{ translateY },
],
},
};
};
class Modal extends React.Component<NavigationStackScreenProps> {
static navigationOptions = ({ navigation }: NavigationStackScreenProps) => {
return {
title: 'Modal',
cardStyleInterpolator:
navigation.getParam('gestureDirection', 'vertical') ===
'vertical-inverted'
? forVerticalInvertedIOS
: CardStyleInterpolators.forVerticalIOS,
gestureDirection: navigation.getParam('gestureDirection', 'vertical'),
cardTransparent: true,
gestureResponseDistance,
};
};
render() {
return (
<View
style={{
backgroundColor: 'white',
paddingVertical: 20,
paddingHorizontal: 20,
height: Dimensions.get('screen').height,
shadowColor: '#000',
shadowOffset: { width: 0, height: 10 },
shadowOpacity: 0.2,
shadowRadius: 4,
}}
/>
);
}
}
class ListScreen extends React.Component<
NavigationStackScreenProps,
{ isInverted: boolean }
> {
// eslint-disable-next-line react/sort-comp
static navigationOptions = {
title: 'My Modal',
};
state = { isInverted: false };
onSwitch = () =>
this.setState(prevState => ({ isInverted: !prevState.isInverted }));
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>List Screen</Text>
<Text>A list may go here</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
<Button
title="Go back to all examples"
onPress={() => this.props.navigation.navigate('Index')}
/>
<Text>Invert modal gesture direction:</Text>
<Switch
style={{ margin: 10 }}
onValueChange={this.onSwitch}
value={this.state.isInverted}
/>
<Button
title="Show Modal"
onPress={() =>
this.props.navigation.push('Modal', {
gestureDirection: this.state.isInverted
? 'vertical-inverted'
: 'vertical',
})
}
/>
</View>
);
}
}
class DetailsScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
// Uncomment below to test inverted modal gesture
// gestureDirection: 'inverted',
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
<Button
title="Go to inputs..."
onPress={() => this.props.navigation.push('Inputs')}
/>
<Button
title="Go to List"
onPress={() => this.props.navigation.navigate('List')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
<Button
title="Go back to all examples"
onPress={() => this.props.navigation.navigate('Index')}
/>
</View>
);
}
}
function InputsScreen({ navigation }: NavigationStackScreenProps) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Inputs Screen</Text>
<TextInput
defaultValue="sample"
autoFocus
style={{ backgroundColor: 'blue' }}
/>
<TextInput defaultValue="sample" style={{ backgroundColor: 'red' }} />
<TextInput defaultValue="sample" style={{ backgroundColor: 'green' }} />
<Button
title="Go to inputs... again"
onPress={() => navigation.push('Inputs')}
/>
</View>
);
}
export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
Modal: Modal,
Inputs: {
screen: InputsScreen,
navigationOptions: { gestureDirection: 'vertical' },
},
},
{
initialRouteName: 'List',
mode: 'modal',
}
);

View File

@@ -0,0 +1,265 @@
import React from 'react';
import {
Button,
Dimensions,
TouchableOpacity,
ScrollView,
StyleSheet,
View,
} from 'react-native';
import {
ThemeColors,
useTheme,
Themed,
SafeAreaView,
NavigationRoute,
} from 'react-navigation';
import {
createDrawerNavigator,
DrawerContentComponentProps,
NavigationDrawerOptions,
NavigationDrawerProp,
NavigationDrawerScreenComponent,
} from 'react-navigation-drawer';
import Animated from 'react-native-reanimated';
import { MaterialIcons } from '@expo/vector-icons';
type Params = { drawerLockMode: 'unlocked' | 'locked-open' | 'locked-closed' };
const SampleText = ({ children }: { children: React.ReactNode }) => (
<Themed.Text>{children}</Themed.Text>
);
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationDrawerProp<NavigationRoute, Params>;
banner: string;
}) => {
let theme = useTheme();
return (
<ScrollView>
<SafeAreaView forceInset={{ top: 'always' }}>
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
>
<SampleText>{banner}</SampleText>
</View>
<Themed.TextInput
style={{
flex: 1,
height: 35,
marginHorizontal: 10,
marginVertical: 10,
borderWidth: StyleSheet.hairlineWidth,
borderColor: ThemeColors[theme].bodyBorder,
textAlign: 'center',
}}
placeholder="Focus this TextInput then drag the drawer!"
/>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
<Button
onPress={() => navigation.toggleDrawer()}
title="Toggle drawer"
/>
<Button
onPress={() => {
navigation.openDrawer();
navigation.closeDrawer();
}}
title="Open and immediately close"
/>
<Button
onPress={() => {
navigation.closeDrawer();
navigation.openDrawer();
}}
title="Close and immediately open"
/>
<Button
onPress={() => {
navigation.openDrawer();
setTimeout(() => {
navigation.closeDrawer();
}, 150);
}}
title="Open then close drawer shortly after"
/>
<Button
onPress={() => navigation.navigate('Email')}
title="Open other screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Button
onPress={() => navigation.navigate('Index')}
title="Go back to list"
/>
{
{
'locked-open': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-closed' })
}
title="Set locked-closed"
/>
),
'locked-closed': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'unlocked' })
}
title="Set unlocked"
/>
),
unlocked: (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-open' })
}
title="Set locked-open"
/>
),
}[navigation.getParam('drawerLockMode', 'unlocked')]
}
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
};
const InboxScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Inbox Screen" navigation={navigation} />;
const EmailScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Email Screen" navigation={navigation} />;
const DraftsScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Drafts Screen" navigation={navigation} />;
const DrawerContents = ({
drawerOpenProgress,
descriptors,
navigation,
}: DrawerContentComponentProps) => {
// `contentComponent` is passed an Animated.Value called drawerOpenProgress
// that can be used to do interesting things like a simple parallax drawe
const translateX = Animated.interpolate(drawerOpenProgress, {
inputRange: [0, 1],
outputRange: [-100, 0],
});
return (
<Animated.View style={{ transform: [{ translateX }] }}>
<ScrollView>
<SafeAreaView forceInset={{ top: 'always' }}>
{navigation.state.routes.map(route => (
<DrawerItem
key={route.key}
navigation={descriptors[route.key].navigation}
item={route.routeName}
/>
))}
</SafeAreaView>
</ScrollView>
</Animated.View>
);
};
const DrawerItem = (props: {
navigation: NavigationDrawerProp;
item: string;
}) => {
return (
<TouchableOpacity onPress={() => props.navigation.navigate(props.item)}>
<Themed.Text style={{ padding: 10, fontSize: 18, fontWeight: '600' }}>
{props.item}
</Themed.Text>
</TouchableOpacity>
);
};
function createDrawerExample(options = {}) {
let DrawerExample = createDrawerNavigator(
{
Inbox: {
path: '/',
screen: InboxScreen,
navigationOptions: ({ navigation }) => {
const options: NavigationDrawerOptions = {
drawerLabel: 'Inbox',
drawerLockMode: (
navigation.state.routes[navigation.state.index].params || {}
).drawerLockMode,
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor }}
/>
),
};
return options;
},
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
navigationOptions: ({ navigation }) => {
const options: NavigationDrawerOptions = {
drawerLabel: 'Drafts',
drawerLockMode: (
navigation.state.routes[navigation.state.index].params || {}
).drawerLockMode,
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor }}
/>
),
};
return options;
},
},
Email: {
path: '/sent',
screen: EmailScreen,
},
},
{
overlayColor: 'rgba(0,0,0,0)',
drawerType: 'back',
drawerBackgroundColor: {
light: '#eee',
dark: '#888',
},
screenContainerStyle: {
shadowColor: '#000000',
shadowOpacity: 0.4,
shadowRadius: 8,
shadowOffset: { height: 0, width: -4 },
},
contentComponent: DrawerContents,
drawerWidth: Dimensions.get('window').width * 0.8,
navigationOptions: {
headerShown: false,
},
contentOptions: {
activeTintColor: '#e91e63',
},
...options,
}
);
return DrawerExample;
}
export default createDrawerExample();

View File

@@ -0,0 +1,137 @@
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import {
createStackNavigator,
TransitionPresets,
TransitionSpecs,
NavigationStackScreenProps,
} from 'react-navigation-stack';
function SlideScreen({ navigation }: NavigationStackScreenProps) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Slide Screen</Text>
<Button title="Go to Modal" onPress={() => navigation.push('Modal')} />
<Button title="Go to Reveal" onPress={() => navigation.push('Reveal')} />
<Button
title="Go to Transparent"
onPress={() => navigation.push('Transparent')}
/>
<Button
title="Go back to all examples"
onPress={() => navigation.navigate('Index')}
/>
</View>
);
}
function ModalScreen({ navigation }: NavigationStackScreenProps) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Slide Screen</Text>
<Button title="Go to Reveal" onPress={() => navigation.push('Reveal')} />
<Button title="Go to Slide" onPress={() => navigation.push('Slide')} />
<Button
title="Go to Transparent"
onPress={() => navigation.push('Transparent')}
/>
<Button
title="Go back to all examples"
onPress={() => navigation.navigate('Index')}
/>
</View>
);
}
function RevealScreen({ navigation }: NavigationStackScreenProps) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Slide Screen</Text>
<Button title="Go to Slide" onPress={() => navigation.push('Slide')} />
<Button title="Go to Modal" onPress={() => navigation.push('Modal')} />
<Button
title="Go to Transparent"
onPress={() => navigation.push('Transparent')}
/>
<Button
title="Go back to all examples"
onPress={() => navigation.navigate('Index')}
/>
</View>
);
}
function TransparentScreen({ navigation }: NavigationStackScreenProps) {
return (
<View
style={{
backgroundColor: 'rgba(0, 0, 0, .7)',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}
>
<View
style={{
backgroundColor: 'white',
borderRadius: 4,
padding: 16,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text>Transparent Screen</Text>
<Button title="Go to Slide" onPress={() => navigation.push('Slide')} />
<Button title="Go to Modal" onPress={() => navigation.push('Modal')} />
<Button
title="Go to Reveal"
onPress={() => navigation.push('Reveal')}
/>
<Button
title="Go back to all examples"
onPress={() => navigation.navigate('Index')}
/>
<Button title="Close" onPress={() => navigation.goBack()} />
</View>
</View>
);
}
export default createStackNavigator(
{
Slide: {
screen: SlideScreen,
navigationOptions: TransitionPresets.SlideFromRightIOS,
},
Modal: {
screen: ModalScreen,
navigationOptions: TransitionPresets.ModalSlideFromBottomIOS,
},
Reveal: {
screen: RevealScreen,
navigationOptions: TransitionPresets.RevealFromBottomAndroid,
},
Transparent: {
screen: TransparentScreen,
navigationOptions: {
cardStyle: { backgroundColor: 'transparent' },
headerShown: false,
gestureEnabled: false,
transitionSpec: {
open: TransitionSpecs.TransitionIOSSpec,
close: TransitionSpecs.TransitionIOSSpec,
},
cardStyleInterpolator: ({ current: { progress } }) => ({
cardStyle: { opacity: progress },
}),
},
},
},
{
headerMode: 'screen',
defaultNavigationOptions: {
cardOverlayEnabled: true,
gestureEnabled: true,
},
}
);

126
example/src/RTLDrawer.tsx Normal file
View File

@@ -0,0 +1,126 @@
import React, { Component } from 'react';
import {
Text,
View,
ScrollView,
Dimensions,
TouchableOpacity,
} from 'react-native';
import { Themed, NavigationActions } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenComponent,
} from 'react-navigation-stack';
import {
createDrawerNavigator,
DrawerContentComponentProps,
DrawerActions,
} from 'react-navigation-drawer';
class RightDrawer extends Component<DrawerContentComponentProps> {
state = {
categories: [
{ i: 'c1', n: 'name1' },
{ i: 'c2', n: 'name2' },
],
};
render() {
return (
<View style={{ backgroundColor: 'white', flex: 1 }}>
<ScrollView
style={{ height: '100%', width: '100%', backgroundColor: '#333333' }}
>
{this.state.categories.map(key => {
return (
<TouchableOpacity
key={key.n}
onPress={() => {
let nid = key.i;
this.props.navigation.dispatch(
NavigationActions.navigate({
routeName: 'CategoryScreen',
params: {
id: nid,
title: key.n,
},
})
);
this.props.navigation.dispatch(DrawerActions.closeDrawer());
}}
>
<View
style={{
width: '100%',
height: 60,
justifyContent: 'center',
}}
>
<Text
style={{
color: 'white',
height: 32.5,
width: '100%',
paddingRight: 20,
fontSize: 20,
}}
>
{key.n}
</Text>
</View>
</TouchableOpacity>
);
})}
</ScrollView>
<Themed.StatusBar barStyle="light-content" />
</View>
);
}
}
const CategoryScreen: NavigationStackScreenComponent = ({ navigation }) => {
return (
<View>
<Themed.Text>CategoryScreen {navigation.getParam('title')}</Themed.Text>
</View>
);
};
const AppNavigator = createStackNavigator(
{
CategoryScreen,
},
{
defaultNavigationOptions: {
title: 'RTL Test',
headerStyle: {
backgroundColor: '#0f5599',
},
headerTintColor: 'white',
headerBackTitleStyle: {
color: 'white',
},
},
}
);
const DrawerNavigator = createDrawerNavigator(
{
Item1: {
screen: AppNavigator,
},
},
{
contentComponent: RightDrawer,
drawerLockMode: 'unlocked',
drawerPosition: 'right',
drawerWidth: () => {
return Dimensions.get('window').width - 150;
},
drawerType: 'slide',
drawerBackgroundColor: '#333333',
backBehavior: 'none',
}
);
export default DrawerNavigator;

138
example/src/RevealStack.tsx Normal file
View File

@@ -0,0 +1,138 @@
import * as React from 'react';
import { Dimensions, Button, View, Text } from 'react-native';
import { withNavigation } from 'react-navigation';
import {
createStackNavigator,
TransitionPresets,
NavigationStackScreenProps,
NavigationStackProp,
} from 'react-navigation-stack';
const Buttons = withNavigation((props: { navigation: NavigationStackProp }) => (
<React.Fragment>
<Button
title="Go to Details"
onPress={() => props.navigation.navigate('Details')}
/>
<Button
title="Go and then go to details quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.navigate('Details');
}, 100);
}}
/>
<Button
title="Go to Headerless"
onPress={() => props.navigation.navigate('Headerless')}
/>
<Button title="Go back" onPress={() => props.navigation.goBack()} />
<Button
title="Go back quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.pop();
}, 100);
}}
/>
<Button
title="Go back to all examples"
onPress={() => props.navigation.navigate('Index')}
/>
</React.Fragment>
));
class ListScreen extends React.Component {
static navigationOptions = {
title: 'List',
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>List Screen</Text>
<Text>A list may go here</Text>
<Buttons />
</View>
);
}
}
class DetailsScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Details',
gestureResponseDistance: {
horizontal: Dimensions.get('window').width,
},
};
_goBackInTwoSeconds = () => {
setTimeout(() => {
this.props.navigation.goBack();
}, 2000);
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>Details Screen</Text>
<Button title="Go back in 2s" onPress={this._goBackInTwoSeconds} />
<Buttons />
</View>
);
}
}
class HeaderlessScreen extends React.Component {
static navigationOptions = {
headerShown: false,
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>Headerless Screen</Text>
<Buttons />
</View>
);
}
}
export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
Headerless: HeaderlessScreen,
},
{
initialRouteName: 'List',
headerMode: 'screen',
defaultNavigationOptions: {
...TransitionPresets.RevealFromBottomAndroid,
cardOverlayEnabled: true,
},
}
);

View File

@@ -0,0 +1,45 @@
/* eslint-disable import/no-commonjs */
import * as React from 'react';
import { Image, Dimensions, ScrollView, StyleSheet } from 'react-native';
const COVERS = [
require('../assets/album-art-1.jpg'),
require('../assets/album-art-2.jpg'),
require('../assets/album-art-3.jpg'),
require('../assets/album-art-4.jpg'),
require('../assets/album-art-5.jpg'),
require('../assets/album-art-6.jpg'),
require('../assets/album-art-7.jpg'),
require('../assets/album-art-8.jpg'),
];
export default class Albums extends React.Component {
render() {
return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.content}
>
{COVERS.map((source, i) => (
// eslint-disable-next-line react/no-array-index-key
<Image key={i} source={source} style={styles.cover} />
))}
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#343C46',
},
content: {
flexDirection: 'row',
flexWrap: 'wrap',
},
cover: {
width: '50%',
height: Dimensions.get('window').width / 2,
},
});

View File

@@ -0,0 +1,99 @@
import * as React from 'react';
import { View, Text, Image, ScrollView, StyleSheet } from 'react-native';
export default class Article extends React.Component {
render() {
return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.content}
>
<View style={styles.author}>
<Image
style={styles.avatar}
source={require('../assets/avatar-1.png')}
/>
<View style={styles.meta}>
<Text style={styles.name}>Knowledge Bot</Text>
<Text style={styles.timestamp}>1st Jan 2025</Text>
</View>
</View>
<Text style={styles.title}>Lorem Ipsum</Text>
<Text style={styles.paragraph}>
Contrary to popular belief, Lorem Ipsum is not simply random text. It
has roots in a piece of classical Latin literature from 45 BC, making
it over 2000 years old.
</Text>
<Image style={styles.image} source={require('../assets/book.jpg')} />
<Text style={styles.paragraph}>
Richard McClintock, a Latin professor at Hampden-Sydney College in
Virginia, looked up one of the more obscure Latin words, consectetur,
from a Lorem Ipsum passage, and going through the cites of the word in
classical literature, discovered the undoubtable source.
</Text>
<Text style={styles.paragraph}>
Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of &quot;de
Finibus Bonorum et Malorum&quot; (The Extremes of Good and Evil) by
Cicero, written in 45 BC. This book is a treatise on the theory of
ethics, very popular during the Renaissance. The first line of Lorem
Ipsum, &quot;Lorem ipsum dolor sit amet..&quot;, comes from a line in
section 1.10.32.
</Text>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
content: {
paddingVertical: 16,
},
author: {
flexDirection: 'row',
marginVertical: 8,
marginHorizontal: 16,
},
meta: {
marginHorizontal: 8,
justifyContent: 'center',
},
name: {
color: '#000',
fontWeight: 'bold',
fontSize: 16,
lineHeight: 24,
},
timestamp: {
color: '#999',
fontSize: 14,
lineHeight: 21,
},
avatar: {
height: 48,
width: 48,
borderRadius: 24,
},
title: {
color: '#000',
fontWeight: 'bold',
fontSize: 36,
marginVertical: 8,
marginHorizontal: 16,
},
paragraph: {
color: '#000',
fontSize: 16,
lineHeight: 24,
marginVertical: 8,
marginHorizontal: 16,
},
image: {
width: '100%',
height: 200,
resizeMode: 'cover',
marginVertical: 8,
},
});

View File

@@ -0,0 +1,156 @@
import React from 'react';
import {
AccessibilityStates,
Platform,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
export interface ButtonProps {
/**
* Text to display inside the button
*/
title: string;
/**
* Handler to be called when the user taps the button
*/
onPress: (event?: any) => void;
/**
* Color of the text (iOS), or background color of the button (Android)
*/
color?: string;
/**
* TV preferred focus (see documentation for the View component).
*/
hasTVPreferredFocus?: boolean;
/**
* Text to display for blindness accessibility features
*/
accessibilityLabel?: string;
/**
* If true, disable all interactions for this component.
*/
disabled?: boolean;
/**
* Used to locate this view in end-to-end tests.
*/
testID?: string;
}
/**
* A basic button component that should render nicely on any platform. Supports
* a minimal level of customization.
*
* <center><img src="img/buttonExample.png"></img></center>
*
* This button is built using TouchableOpacity
*
* Example usage:
*
* ```
* import { Button } from 'react-native';
* ...
*
* <Button
* onPress={onPressLearnMore}
* title="Learn More"
* color="#841584"
* accessibilityLabel="Learn more about this purple button"
* />
* ```
*
*/
export default class Button extends React.Component<ButtonProps> {
render() {
const {
accessibilityLabel,
color,
onPress,
title,
disabled,
testID,
} = this.props;
const buttonStyles: any = [styles.button];
const textStyles: any = [styles.text];
if (color) {
if (Platform.OS === 'ios') {
textStyles.push({ color });
} else {
buttonStyles.push({ backgroundColor: color });
}
}
const accessibilityStates: AccessibilityStates[] = [];
if (disabled) {
buttonStyles.push(styles.buttonDisabled);
textStyles.push(styles.textDisabled);
accessibilityStates.push('disabled');
}
const formattedTitle =
Platform.OS === 'android' ? title.toUpperCase() : title;
return (
<TouchableOpacity
accessibilityLabel={accessibilityLabel}
accessibilityRole="button"
accessibilityStates={accessibilityStates}
testID={testID}
disabled={disabled}
onPress={onPress}
>
<View style={buttonStyles}>
<Text style={textStyles}>{formattedTitle}</Text>
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
button: Platform.select({
default: {
backgroundColor: '#2196F3',
borderRadius: 2,
elevation: 4,
// Material design blue from https://material.google.com/style/color.html#color-color-palette
},
ios: {},
}),
buttonDisabled: Platform.select({
default: {
backgroundColor: '#dfdfdf',
elevation: 0,
},
ios: {},
}),
text: {
padding: 8,
textAlign: 'center',
...Platform.select({
default: {
color: 'white',
fontWeight: '500',
},
ios: {
// iOS blue from https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/
color: '#007AFF',
fontSize: 18,
},
}),
},
textDisabled: Platform.select({
default: {
color: '#a1a1a1',
},
ios: {
color: '#cdcdcd',
},
}),
});

View File

@@ -0,0 +1,19 @@
import React from 'react';
import { Platform, StyleSheet, View } from 'react-native';
import BaseButton, { ButtonProps } from './Button';
export const Button = (props: ButtonProps) => (
<View style={styles.margin}>
<BaseButton {...props} />
</View>
);
const styles = StyleSheet.create({
margin: {
...Platform.select({
android: {
margin: 10,
},
}),
},
});

View File

@@ -0,0 +1,97 @@
import * as React from 'react';
import { View, Image, Text, ScrollView, StyleSheet } from 'react-native';
const MESSAGES = [
'okay',
'sudo make me a sandwich',
'what? make it yourself',
'make me a sandwich',
];
export default class Albums extends React.Component {
render() {
return (
<View style={styles.container}>
<ScrollView
style={styles.inverted}
contentContainerStyle={styles.content}
>
{MESSAGES.map((text, i) => {
const odd = i % 2;
return (
<View
// eslint-disable-next-line react/no-array-index-key
key={i}
style={[odd ? styles.odd : styles.even, styles.inverted]}
>
<Image
style={styles.avatar}
source={
odd
? require('../assets/avatar-2.png')
: require('../assets/avatar-1.png')
}
/>
<View
style={[styles.bubble, odd ? styles.received : styles.sent]}
>
<Text style={odd ? styles.receivedText : styles.sentText}>
{text}
</Text>
</View>
</View>
);
})}
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#eceff1',
},
inverted: {
transform: [{ scaleY: -1 }],
},
content: {
padding: 16,
},
even: {
flexDirection: 'row',
},
odd: {
flexDirection: 'row-reverse',
},
avatar: {
marginVertical: 8,
marginHorizontal: 6,
height: 40,
width: 40,
borderRadius: 20,
borderColor: 'rgba(0, 0, 0, .16)',
borderWidth: StyleSheet.hairlineWidth,
},
bubble: {
marginVertical: 8,
marginHorizontal: 6,
paddingVertical: 12,
paddingHorizontal: 16,
borderRadius: 20,
},
sent: {
backgroundColor: '#cfd8dc',
},
received: {
backgroundColor: '#2196F3',
},
sentText: {
color: 'black',
},
receivedText: {
color: 'white',
},
});

View File

@@ -0,0 +1,133 @@
import * as React from 'react';
import { View, Text, StyleSheet, FlatList } from 'react-native';
type Item = { name: string; number: number };
const CONTACTS: Item[] = [
{ name: 'Marissa Castillo', number: 7766398169 },
{ name: 'Denzel Curry', number: 9394378449 },
{ name: 'Miles Ferguson', number: 8966872888 },
{ name: 'Desiree Webster', number: 6818656371 },
{ name: 'Samantha Young', number: 6538288534 },
{ name: 'Irene Hunter', number: 2932176249 },
{ name: 'Annie Ryan', number: 4718456627 },
{ name: 'Sasha Oliver', number: 9743195919 },
{ name: 'Jarrod Avila', number: 8339212305 },
{ name: 'Griffin Weaver', number: 6059349721 },
{ name: 'Emilee Moss', number: 7382905180 },
{ name: 'Angelique Oliver', number: 9689298436 },
{ name: 'Emanuel Little', number: 6673376805 },
{ name: 'Wayne Day', number: 6918839582 },
{ name: 'Lauren Reese', number: 4652613201 },
{ name: 'Kailey Ward', number: 2232609512 },
{ name: 'Gabrielle Newman', number: 2837997127 },
{ name: 'Luke Strickland', number: 8404732322 },
{ name: 'Payton Garza', number: 7916140875 },
{ name: 'Anna Moss', number: 3504954657 },
{ name: 'Kailey Vazquez', number: 3002136330 },
{ name: 'Jennifer Coleman', number: 5469629753 },
{ name: 'Cindy Casey', number: 8446175026 },
{ name: 'Dillon Doyle', number: 5614510703 },
{ name: 'Savannah Garcia', number: 5634775094 },
{ name: 'Kailey Hudson', number: 3289239675 },
{ name: 'Ariel Green', number: 2103492196 },
{ name: 'Weston Perez', number: 2984221823 },
{ name: 'Kari Juarez', number: 9502125065 },
{ name: 'Sara Sanders', number: 7696668206 },
{ name: 'Griffin Le', number: 3396937040 },
{ name: 'Fernando Valdez', number: 9124257306 },
{ name: 'Taylor Marshall', number: 9656072372 },
{ name: 'Elias Dunn', number: 9738536473 },
{ name: 'Diane Barrett', number: 6886824829 },
{ name: 'Samuel Freeman', number: 5523948094 },
{ name: 'Irene Garza', number: 2077694008 },
{ name: 'Devante Alvarez', number: 9897002645 },
{ name: 'Sydney Floyd', number: 6462897254 },
{ name: 'Toni Dixon', number: 3775448213 },
{ name: 'Anastasia Spencer', number: 4548212752 },
{ name: 'Reid Cortez', number: 6668056507 },
{ name: 'Ramon Duncan', number: 8889157751 },
{ name: 'Kenny Moreno', number: 5748219540 },
{ name: 'Shelby Craig', number: 9473708675 },
{ name: 'Jordyn Brewer', number: 7552277991 },
{ name: 'Tanya Walker', number: 4308189657 },
{ name: 'Nolan Figueroa', number: 9173443776 },
{ name: 'Sophia Gibbs', number: 6435942770 },
{ name: 'Vincent Sandoval', number: 2606111495 },
];
class ContactItem extends React.PureComponent<{
item: Item;
}> {
render() {
const { item } = this.props;
return (
<View style={styles.item}>
<View style={styles.avatar}>
<Text style={styles.letter}>
{item.name.slice(0, 1).toUpperCase()}
</Text>
</View>
<View style={styles.details}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.number}>{item.number}</Text>
</View>
</View>
);
}
}
export default class Contacts extends React.Component {
_renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />;
_ItemSeparator = () => <View style={styles.separator} />;
render() {
return (
<FlatList
data={CONTACTS}
keyExtractor={(_, i) => String(i)}
renderItem={this._renderItem}
ItemSeparatorComponent={this._ItemSeparator}
/>
);
}
}
const styles = StyleSheet.create({
item: {
backgroundColor: 'white',
flexDirection: 'row',
alignItems: 'center',
padding: 8,
},
avatar: {
height: 36,
width: 36,
borderRadius: 18,
backgroundColor: '#e91e63',
alignItems: 'center',
justifyContent: 'center',
},
letter: {
color: 'white',
fontWeight: 'bold',
},
details: {
margin: 8,
},
name: {
fontWeight: 'bold',
fontSize: 14,
color: 'black',
},
number: {
fontSize: 12,
color: '#999',
},
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: 'rgba(0, 0, 0, .08)',
},
});

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import {
HeaderButtons as DefaultHeaderButtons,
Item,
} from 'react-navigation-header-buttons';
export class HeaderButtons extends React.PureComponent {
static Item = Item;
render() {
return (
<DefaultHeaderButtons
// color={Platform.OS === 'ios' ? '#037aff' : 'black'}
{...this.props}
/>
);
}
}

View File

@@ -0,0 +1,86 @@
import * as React from 'react';
import {
View,
Image,
ScrollView,
Dimensions,
StyleSheet,
StyleProp,
ViewStyle,
ScrollViewProperties,
} from 'react-native';
import {
withNavigation,
NavigationScreenProp,
NavigationRoute,
NavigationEventSubscription,
} from 'react-navigation';
class NavigationAwareScrollViewBase extends React.Component<{
navigation: NavigationScreenProp<NavigationRoute>;
contentContainerStyle: StyleProp<ViewStyle>;
}> {
componentDidMount() {
this.subscription = this.props.navigation.addListener('refocus', () => {
if (this.props.navigation.isFocused()) {
this.root.current && this.root.current.scrollTo({ x: 0, y: 0 });
}
});
}
componentWillUnmount() {
this.subscription && this.subscription.remove();
}
setNativeProps(props: ScrollViewProperties) {
// @ts-ignore
this.root.current.setNativeProps(props);
}
getNode() {
return this.root.current;
}
private subscription: NavigationEventSubscription | undefined;
private root = React.createRef<ScrollView>();
render() {
return <ScrollView {...this.props} ref={this.root} />;
}
}
const NavigationAwareScrollView = withNavigation(NavigationAwareScrollViewBase);
export default function PhotoGrid({ id }: { id: string }) {
const PHOTOS = Array.from({ length: 24 }).map(
(_, i) => `https://unsplash.it/300/300/?random&__id=${id}${i}`
);
return (
<NavigationAwareScrollView contentContainerStyle={styles.content}>
{PHOTOS.map(uri => (
<View key={uri} style={styles.item}>
<Image source={{ uri }} style={styles.photo} />
</View>
))}
</NavigationAwareScrollView>
);
}
const styles = StyleSheet.create({
content: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: 4,
},
item: {
height: Dimensions.get('window').width / 2,
width: '50%',
padding: 4,
},
photo: {
flex: 1,
resizeMode: 'cover',
},
});

View File

@@ -0,0 +1,19 @@
import React, { ReactNode } from 'react';
import { StyleSheet } from 'react-native';
import { Themed } from 'react-navigation';
/**
* Used across examples as a screen placeholder.
*/
const SampleText = ({ children }: { children?: ReactNode }) => (
<Themed.Text style={styles.sampleText}>{children}</Themed.Text>
);
export default SampleText;
const styles = StyleSheet.create({
sampleText: {
margin: 14,
},
});

View File

@@ -0,0 +1,13 @@
import * as React from 'react';
import { StyleSheet } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
const tabBarIcon = (name: string) => ({ tintColor }: { tintColor: string }) => (
<MaterialIcons style={styles.icon} name={name} color={tintColor} size={24} />
);
export default tabBarIcon;
const styles = StyleSheet.create({
icon: { backgroundColor: 'transparent' },
});

View File

@@ -0,0 +1,64 @@
import * as React from 'react';
import {
createMaterialBottomTabNavigator,
NavigationMaterialBottomTabOptions,
} from 'react-navigation-material-bottom-tabs';
import PhotoGrid from './Shared/PhotoGrid';
import tabBarIcon from './Shared/tabBarIcon';
class Album extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarColor: '#6200ee',
tabBarIcon: tabBarIcon('photo-album'),
};
render() {
return <PhotoGrid id="album" />;
}
}
class Library extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarColor: '#2962ff',
tabBarIcon: tabBarIcon('inbox'),
};
render() {
return <PhotoGrid id="library" />;
}
}
class Favorites extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarColor: '#00796b',
tabBarIcon: tabBarIcon('favorite'),
};
render() {
return <PhotoGrid id="favorites" />;
}
}
class Purchased extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarColor: '#c51162',
tabBarIcon: tabBarIcon('shop'),
tabBarBadge: 'test',
};
render() {
return <PhotoGrid id="purchased" />;
}
}
export default createMaterialBottomTabNavigator(
{
Album,
Library,
Favorites,
Purchased,
},
{
shifting: true,
}
);

View File

@@ -0,0 +1,201 @@
import React from 'react';
import { Button, ScrollView, StyleSheet, View } from 'react-native';
import {
ThemeColors,
useTheme,
Themed,
SafeAreaView,
NavigationRoute,
} from 'react-navigation';
import {
createDrawerNavigator,
NavigationDrawerOptions,
NavigationDrawerScreenProps,
NavigationDrawerProp,
NavigationDrawerScreenComponent,
} from 'react-navigation-drawer';
import { MaterialIcons } from '@expo/vector-icons';
const SampleText = ({ children }: { children: React.ReactNode }) => (
<Themed.Text>{children}</Themed.Text>
);
type Params = { drawerLockMode: 'unlocked' | 'locked-open' | 'locked-closed' };
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationDrawerProp<NavigationRoute, Params>;
banner: string;
}) => {
let theme = useTheme();
return (
<ScrollView>
<SafeAreaView forceInset={{ top: 'always' }}>
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}
>
<SampleText>{banner}</SampleText>
</View>
<Themed.TextInput
style={{
flex: 1,
height: 35,
marginHorizontal: 10,
marginVertical: 10,
borderWidth: StyleSheet.hairlineWidth,
borderColor: ThemeColors[theme].bodyBorder,
textAlign: 'center',
}}
placeholder="Focus this TextInput then drag the drawer!"
/>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
<Button
onPress={() => navigation.toggleDrawer()}
title="Toggle drawer"
/>
<Button
onPress={() => {
navigation.openDrawer();
navigation.closeDrawer();
}}
title="Open and immediately close"
/>
<Button
onPress={() => {
navigation.closeDrawer();
navigation.openDrawer();
}}
title="Close and immediately open"
/>
<Button
onPress={() => {
navigation.openDrawer();
setTimeout(() => {
navigation.closeDrawer();
}, 150);
}}
title="Open then close drawer shortly after"
/>
<Button
onPress={() => navigation.navigate('Email')}
title="Open other screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Button
onPress={() => navigation.navigate('Index')}
title="Go back to list"
/>
{
{
'locked-open': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-closed' })
}
title="Set locked-closed"
/>
),
'locked-closed': (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'unlocked' })
}
title="Set unlocked"
/>
),
unlocked: (
<Button
onPress={() =>
navigation.setParams({ drawerLockMode: 'locked-open' })
}
title="Set locked-open"
/>
),
}[navigation.getParam('drawerLockMode', 'unlocked')]
}
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
};
const InboxScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Inbox Screen" navigation={navigation} />;
const EmailScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Email Screen" navigation={navigation} />;
const DraftsScreen: NavigationDrawerScreenComponent<Params> = ({
navigation,
}) => <MyNavScreen banner="Drafts Screen" navigation={navigation} />;
function createDrawerExample(options = {}) {
let DrawerExample = createDrawerNavigator(
{
Inbox: {
path: '/',
screen: InboxScreen,
navigationOptions: ({ navigation }: NavigationDrawerScreenProps) => {
const options: NavigationDrawerOptions = {
drawerLabel: 'Inbox',
drawerLockMode: navigation.state.params?.drawerLockMode,
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor }}
/>
),
};
return options;
},
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
navigationOptions: ({ navigation }: NavigationDrawerScreenProps) => {
const options: NavigationDrawerOptions = {
drawerLabel: 'Drafts',
drawerLockMode: navigation.state.params?.drawerLockMode,
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="drafts"
size={24}
style={{ color: tintColor }}
/>
),
};
return options;
},
},
Email: {
screen: EmailScreen,
},
},
{
initialRouteName: 'Drafts',
drawerWidth: 210,
navigationOptions: {
headerShown: false,
},
contentOptions: {
activeTintColor: '#e91e63',
},
...options,
}
);
return DrawerExample;
}
export const SimpleDrawer = createDrawerExample();
export const SimpleDrawerUnmountInactive = createDrawerExample({
unmountInactiveRoutes: true,
});

141
example/src/SimpleStack.tsx Normal file
View File

@@ -0,0 +1,141 @@
import * as React from 'react';
import { Dimensions, Button, View, Text } from 'react-native';
import { withNavigation } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
NavigationStackProp,
} from 'react-navigation-stack';
const Buttons = withNavigation((props: { navigation: NavigationStackProp }) => (
<React.Fragment>
<Button
title="Push Details"
onPress={() => props.navigation.push('Details')}
/>
<Button title="PopToTop" onPress={() => props.navigation.popToTop()} />
<Button
title="Go to Details"
onPress={() => props.navigation.navigate('Details')}
/>
<Button
title="Replace with List"
onPress={() => props.navigation.replace('List')}
/>
<Button
title="Go and then go to details quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.navigate('Details');
}, 100);
}}
/>
<Button
title="Go to Headerless"
onPress={() => props.navigation.navigate('Headerless')}
/>
<Button title="Go back" onPress={() => props.navigation.goBack()} />
<Button
title="Go back quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.pop();
}, 100);
}}
/>
<Button
title="Go back to all examples"
onPress={() => props.navigation.navigate('Index')}
/>
</React.Fragment>
));
class ListScreen extends React.Component {
static navigationOptions = {
title: 'List',
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>List Screen</Text>
<Text>A list may go here</Text>
<Buttons />
</View>
);
}
}
class DetailsScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Details',
gestureResponseDistance: {
horizontal: Dimensions.get('window').width,
},
};
_goBackInTwoSeconds = () => {
setTimeout(() => {
this.props.navigation.goBack();
}, 2000);
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>Details Screen</Text>
<Button title="Go back in 2s" onPress={this._goBackInTwoSeconds} />
<Buttons />
</View>
);
}
}
class HeaderlessScreen extends React.Component {
static navigationOptions = {
headerShown: false,
};
render() {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#fff',
}}
>
<Text>Headerless Screen</Text>
<Buttons />
</View>
);
}
}
export default createStackNavigator(
{
List: ListScreen,
Details: DetailsScreen,
Headerless: HeaderlessScreen,
},
{
initialRouteName: 'List',
}
);

View File

@@ -0,0 +1,69 @@
import * as React from 'react';
import { StyleSheet } from 'react-native';
import {
createMaterialBottomTabNavigator,
NavigationMaterialBottomTabOptions,
} from 'react-navigation-material-bottom-tabs';
import PhotoGrid from './Shared/PhotoGrid';
import tabBarIcon from './Shared/tabBarIcon';
class Album extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('photo-album'),
};
render() {
return <PhotoGrid id="album" />;
}
}
class Library extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('inbox'),
};
render() {
return <PhotoGrid id="library" />;
}
}
class Favorites extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('favorite'),
};
render() {
return <PhotoGrid id="favorites" />;
}
}
class Purchased extends React.Component {
static navigationOptions: NavigationMaterialBottomTabOptions = {
tabBarIcon: tabBarIcon('shop'),
tabBarBadge: 12,
};
render() {
return <PhotoGrid id="purchased" />;
}
}
export default createMaterialBottomTabNavigator(
{
Album,
Library,
Favorites,
Purchased,
},
{
shifting: false,
activeColor: '#6200ee',
inactiveColor: '#828792',
barStyle: {
backgroundColor: '#f8f7f9',
borderTopWidth: StyleSheet.hairlineWidth,
borderStyle: 'solid',
borderColor: '#d0cfd0',
},
}
);

View File

@@ -0,0 +1,113 @@
import * as React from 'react';
import { Animated, Button, View } from 'react-native';
import {
createStackNavigator,
NavigationStackScreenProps,
CardAnimationContext,
} from 'react-navigation-stack';
const ListScreen = (props: NavigationStackScreenProps) => (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button
title="Push to another screen"
onPress={() => props.navigation.push('Another')}
/>
<Button
title="Push to yet another screen"
onPress={() => props.navigation.push('YetAnother')}
/>
<Button
title="Go back to all examples"
onPress={() => props.navigation.navigate('Index')}
/>
</View>
);
const AnotherScreen = () => (
<CardAnimationContext.Consumer>
{value => {
const scale = value
? value.current.progress.interpolate({
inputRange: [0, 1],
outputRange: [0.25, 1],
})
: 1;
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'honeydew',
}}
>
<Animated.Text
style={{
fontSize: 32,
opacity: value ? value.current.progress : 1,
transform: [{ scale }],
}}
>
Animates on progress
</Animated.Text>
</View>
);
}}
</CardAnimationContext.Consumer>
);
const YetAnotherScreen = () => (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'papayawhip',
}}
>
<CardAnimationContext.Consumer>
{value => (
<Animated.Text
style={{
fontSize: 24,
opacity: value
? value.swiping.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
})
: 1,
}}
>
Disappears when swiping
</Animated.Text>
)}
</CardAnimationContext.Consumer>
<CardAnimationContext.Consumer>
{value => (
<Animated.Text
style={{
fontSize: 24,
opacity: value
? value.closing.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
})
: 1,
}}
>
Disappears only when closing
</Animated.Text>
)}
</CardAnimationContext.Consumer>
</View>
);
export default createStackNavigator(
{
List: ListScreen,
Another: AnotherScreen,
YetAnother: YetAnotherScreen,
},
{ initialRouteName: 'List' }
);

View File

@@ -0,0 +1,158 @@
import * as React from 'react';
import { Button, Image, StyleSheet } from 'react-native';
import {
NavigationScreenProp,
NavigationState,
Themed,
SafeAreaView,
} from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import SampleText from './Shared/SampleText';
interface MyNavScreenProps {
navigation: NavigationScreenProp<NavigationState>;
banner: React.ReactNode;
}
class MyCustomHeaderBackImage extends React.Component<any, any> {
render() {
const source = require('./assets/back.png');
return (
<Image
source={source}
style={[styles.myCustomHeaderBackImage, this.props.style]}
/>
);
}
}
class MyNavScreen extends React.Component<MyNavScreenProps> {
render() {
const { navigation, banner } = this.props;
return (
<SafeAreaView>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
title="Navigate to a photos screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
interface MyHomeScreenProps {
navigation: NavigationScreenProp<NavigationState>;
}
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
static navigationOptions = {
headerBackTitleVisible: false,
title: 'Welcome',
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
}
}
interface MyPhotosScreenProps {
navigation: NavigationScreenProp<NavigationState>;
}
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
static navigationOptions = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => ({
headerBackTitleVisible: false,
title: `${navigation.state.params!.name}'s photos`,
});
render() {
const { navigation } = this.props;
return (
<SafeAreaView>
<SampleText>{`${navigation.state.params!.name}'s Photos`}</SampleText>
<Button
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
title="Navigate to a profile screen"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
interface MyProfileScreenProps {
navigation: NavigationScreenProp<NavigationState>;
}
class MyProfileScreen extends React.Component<MyProfileScreenProps> {
static navigationOptions = {
title: 'Profile',
};
render() {
const { navigation } = this.props;
return (
<SafeAreaView>
<SampleText>{`${navigation.state.params!.name}'s Profile`}</SampleText>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
const StackWithCustomHeaderBackImage = createStackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
Profile: {
path: 'profile/:name',
screen: MyProfileScreen,
},
},
{
defaultNavigationOptions: ({ theme }: NavigationStackScreenProps) => ({
headerBackImage: () => (
<MyCustomHeaderBackImage
style={[
styles.myCustomHeaderBackImageAlt,
{
tintColor: theme === 'light' ? '#000' : '#fff',
},
]}
/>
),
}),
}
);
export default StackWithCustomHeaderBackImage;
const styles = StyleSheet.create({
myCustomHeaderBackImage: {
height: 14.5,
marginLeft: 9,
marginRight: 12,
marginVertical: 12,
resizeMode: 'contain',
width: 24,
},
myCustomHeaderBackImageAlt: {},
});

View File

@@ -0,0 +1,72 @@
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import {
createDrawerNavigator,
DrawerContentComponentProps,
} from 'react-navigation-drawer';
import {
createBottomTabNavigator,
NavigationTabScreenProps,
} from 'react-navigation-tabs';
function Menu({ navigation }: DrawerContentComponentProps) {
return (
<View style={{ flex: 1 }}>
<Button
title="Open on top"
onPress={() => {
// @ts-ignore
navigation.navigate('Top');
}}
/>
</View>
);
}
class Fake extends React.Component<
NavigationTabScreenProps | NavigationStackScreenProps
> {
static navigationOptions = ({
navigation,
}: NavigationTabScreenProps | NavigationStackScreenProps) => ({
title: navigation.getParam('title'),
});
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20 }}>
{this.props.navigation.getParam('title')}
</Text>
</View>
);
}
}
const Tab = createBottomTabNavigator({
Home: { screen: Fake, params: { title: 'Home' } },
Other: { screen: Fake, params: { title: 'Other' } },
});
const Drawer = createDrawerNavigator(
{
TabScreen: {
screen: Tab,
},
},
{
contentComponent: props => <Menu {...props} />,
navigationOptions: { title: 'Example' },
}
);
const App = createStackNavigator({
Drawer: { screen: Drawer },
Top: { screen: Fake, params: { title: 'Top' } },
});
export default App;

View File

@@ -0,0 +1,117 @@
import * as React from 'react';
import { SafeAreaView, Themed } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
TransitionPresets,
HeaderStyleInterpolators,
} from 'react-navigation-stack';
import { Button } from './Shared/ButtonWithMargin';
class HomeScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigation } = this.props;
const { push } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => push('Other')} title="Push another screen" />
<Button
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
class OtherScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Your title here',
};
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button
onPress={() => push('ScreenWithLongTitle')}
title="Push another screen"
/>
<Button
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
class ScreenWithLongTitle extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: "Another title that's kind of long",
};
render() {
const { navigation } = this.props;
const { pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
class ScreenWithNoHeader extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
headerShown: false,
title: 'No Header',
};
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => push('Other')} title="Push another screen" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</SafeAreaView>
);
}
}
const StackWithHeaderPreset = createStackNavigator(
{
Home: HomeScreen,
Other: OtherScreen,
ScreenWithLongTitle,
ScreenWithNoHeader,
},
{
defaultNavigationOptions: {
...TransitionPresets.SlideFromRightIOS,
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
},
}
);
export default StackWithHeaderPreset;

View File

@@ -0,0 +1,61 @@
import * as React from 'react';
import { Button, TextInput, View } from 'react-native';
import {
createStackNavigator,
CardStyleInterpolators,
NavigationStackScreenProps,
} from 'react-navigation-stack';
class Input extends React.Component {
static navigationOptions = {
title: 'Input screen',
};
render() {
return (
<TextInput
placeholder="Type something"
style={{
backgroundColor: 'white',
paddingVertical: 12,
paddingHorizontal: 16,
margin: 24,
}}
/>
);
}
}
class Home extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Home',
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
onPress={() => this.props.navigation.push('Input')}
title="Push screen with input"
/>
</View>
);
}
}
const App = createStackNavigator(
{
Home: { screen: Home },
Input: { screen: Input },
},
{
headerMode: 'screen',
defaultNavigationOptions: {
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
gestureDirection: 'horizontal',
gestureEnabled: true,
},
}
);
export default App;

View File

@@ -0,0 +1,246 @@
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { BlurView } from 'expo-blur';
import { getStatusBarHeight } from 'react-native-iphone-x-helper';
import {
NavigationEventPayload,
NavigationEventSubscription,
Themed,
SupportedThemes,
} from 'react-navigation';
import {
createStackNavigator,
HeaderStyleInterpolators,
NavigationStackScreenProps,
NavigationStackProp,
TransitionPresets,
} from 'react-navigation-stack';
import { Button } from './Shared/ButtonWithMargin';
import { HeaderButtons } from './Shared/HeaderButtons';
import SampleText from './Shared/SampleText';
interface MyNavScreenProps {
navigation: NavigationStackProp;
banner: React.ReactNode;
}
class MyNavScreen extends React.Component<MyNavScreenProps> {
// Inset to compensate for navigation bar being transparent.
// And improved abstraction for this will be built in to react-navigation
// at some point.
getHeaderInset(): any {
const HEADER_HEIGHT =
getStatusBarHeight() + Platform.select({ ios: 44, default: 56 });
return Platform.select({
android: {
contentContainerStyle: {
paddingTop: HEADER_HEIGHT,
},
},
ios: {
contentInset: { top: HEADER_HEIGHT },
contentOffset: { y: -HEADER_HEIGHT },
},
});
}
render() {
const { navigation, banner } = this.props;
const { push, replace, popToTop, pop } = navigation;
return (
<ScrollView style={{ flex: 1 }} {...this.getHeaderInset()}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => push('Profile', { name: 'Jane' })}
title="Push a profile screen"
/>
<Button
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
title="Navigate to a photos screen"
/>
<Button
onPress={() => replace('Profile', { name: 'Lucy' })}
title="Replace with profile"
/>
<Button onPress={() => popToTop()} title="Pop to top" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Themed.StatusBar />
</ScrollView>
);
}
}
interface MyHomeScreenProps {
navigation: NavigationStackProp;
}
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
// eslint-disable-next-line react/sort-comp
static navigationOptions = {
title: 'Welcome',
};
s0: NavigationEventSubscription | null = null;
s1: NavigationEventSubscription | null = null;
s2: NavigationEventSubscription | null = null;
s3: NavigationEventSubscription | null = null;
componentDidMount() {
this.s0 = this.props.navigation.addListener('willFocus', this.onWF);
this.s1 = this.props.navigation.addListener('didFocus', this.onDF);
this.s2 = this.props.navigation.addListener('willBlur', this.onWB);
this.s3 = this.props.navigation.addListener('didBlur', this.onDB);
}
componentWillUnmount() {
this.s0!.remove();
this.s1!.remove();
this.s2!.remove();
this.s3!.remove();
}
onWF = (a: NavigationEventPayload) => {
console.log('willFocus HomeScreen', a);
};
onDF = (a: NavigationEventPayload) => {
console.log('didFocus HomeScreen', a);
};
onWB = (a: NavigationEventPayload) => {
console.log('willBlur HomeScreen', a);
};
onDB = (a: NavigationEventPayload) => {
console.log('didBlur HomeScreen', a);
};
render() {
const { navigation } = this.props;
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
}
}
interface MyPhotosScreenProps {
navigation: NavigationStackProp;
}
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
static navigationOptions = {
title: 'Photos',
};
s0: NavigationEventSubscription | null = null;
s1: NavigationEventSubscription | null = null;
s2: NavigationEventSubscription | null = null;
s3: NavigationEventSubscription | null = null;
componentDidMount() {
this.s0 = this.props.navigation.addListener('willFocus', this.onWF);
this.s1 = this.props.navigation.addListener('didFocus', this.onDF);
this.s2 = this.props.navigation.addListener('willBlur', this.onWB);
this.s3 = this.props.navigation.addListener('didBlur', this.onDB);
}
componentWillUnmount() {
this.s0!.remove();
this.s1!.remove();
this.s2!.remove();
this.s3!.remove();
}
onWF = (a: NavigationEventPayload) => {
console.log('willFocus PhotosScreen', a);
};
onDF = (a: NavigationEventPayload) => {
console.log('didFocus PhotosScreen', a);
};
onWB = (a: NavigationEventPayload) => {
console.log('willBlur PhotosScreen', a);
};
onDB = (a: NavigationEventPayload) => {
console.log('didBlur PhotosScreen', a);
};
render() {
const { navigation } = this.props;
return (
<MyNavScreen
banner={`${navigation.state.params!.name}'s Photos`}
navigation={navigation}
/>
);
}
}
const MyProfileScreen = ({
navigation,
}: {
navigation: NavigationStackProp;
}) => (
<MyNavScreen
banner={`${navigation.state.params!.mode === 'edit' ? 'Now Editing ' : ''}${
navigation.state.params!.name
}'s Profile`}
navigation={navigation}
/>
);
MyProfileScreen.navigationOptions = (props: {
navigation: NavigationStackProp;
theme: SupportedThemes;
}) => {
const { navigation, theme } = props;
const { state, setParams } = navigation;
const { params } = state;
return {
headerBackImage: params!.headerBackImage
? () => params!.headerBackImage
: undefined,
// Render a button on the right side of the header.
// When pressed switches the screen to edit mode.
headerRight: () => (
<HeaderButtons>
<HeaderButtons.Item
color={theme === 'light' ? '#000' : '#fff'}
title={params!.mode === 'edit' ? 'Done' : 'Edit'}
onPress={() =>
setParams({ mode: params!.mode === 'edit' ? '' : 'edit' })
}
/>
</HeaderButtons>
),
headerTitle: `${params!.name}'s Profile!`,
};
};
const StackWithTranslucentHeader = createStackNavigator(
{
Home: {
screen: MyHomeScreen,
},
Photos: {
path: 'photos/:name',
screen: MyPhotosScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
},
{
defaultNavigationOptions: ({ theme }: NavigationStackScreenProps) => ({
...TransitionPresets.SlideFromRightIOS,
headerBackground: () =>
Platform.OS === 'ios' ? (
<BlurView
style={{ flex: 1 }}
blurType={theme === 'light' ? 'light' : 'dark'}
/>
) : (
<View style={{ flex: 1, backgroundColor: 'rgba(255,255,255,0.7)' }} />
),
headerStyle: {
borderBottomColor: theme === 'light' ? '#A7A7AA' : 'transparent',
borderBottomWidth: StyleSheet.hairlineWidth,
},
headerTransparent: true,
headerStyleInterpolator: HeaderStyleInterpolators.forUIKit,
}),
}
);
export default StackWithTranslucentHeader;

View File

@@ -0,0 +1,109 @@
import React from 'react';
import { Text, View } from 'react-native';
import { Themed } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import { Button } from './Shared/ButtonWithMargin';
class HomeScreen extends React.Component<NavigationStackScreenProps> {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home</Text>
<Button
title="Navigate to 'Profile' with key 'A'"
onPress={() =>
this.props.navigation.navigate({
key: 'A',
params: { homeKey: this.props.navigation.state.key },
routeName: 'Profile',
})
}
/>
<Button
title="Go back to other examples"
onPress={() => this.props.navigation.goBack(null)}
/>
<Themed.StatusBar />
</View>
);
}
}
class ProfileScreen extends React.Component<
NavigationStackScreenProps<{ homeKey: string }>
> {
render() {
const homeKey = this.props.navigation.getParam('homeKey');
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile</Text>
<Button
title="Navigate to 'Settings' with key 'B'"
onPress={() =>
this.props.navigation.navigate({
key: 'B',
params: { homeKey },
routeName: 'Settings',
})
}
/>
<Button
title={`Navigate back to 'Home' with key ${homeKey}`}
onPress={() =>
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
}
/>
</View>
);
}
}
class SettingsScreen extends React.Component<NavigationStackScreenProps> {
render() {
const { homeKey } = this.props.navigation.state.params!;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Settings</Text>
<Button
title={`Navigate back to 'Home' with key ${homeKey}`}
onPress={() =>
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
}
/>
<Button
title="Navigate back to 'Profile' with key 'A'"
onPress={() =>
this.props.navigation.navigate({
key: 'A',
routeName: 'Profile',
})
}
/>
</View>
);
}
}
const Stack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Profile: {
screen: ProfileScreen,
},
Settings: {
screen: SettingsScreen,
},
},
{
headerMode: 'none',
}
);
export default Stack;

View File

@@ -0,0 +1,164 @@
import React from 'react';
import { Text } from 'react-native';
import {
Themed,
NavigationScreenProp,
NavigationState,
SafeAreaView,
ScrollView,
} from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
NavigationStackProp,
} from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { Ionicons } from '@expo/vector-icons';
import { Button } from './Shared/ButtonWithMargin';
import SampleText from './Shared/SampleText';
const TEXT = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla a hendrerit dui, id consectetur nulla. Curabitur mattis sapien nunc, quis dignissim eros venenatis sit amet. Praesent rutrum dapibus diam quis eleifend. Donec vulputate quis purus sed vulputate. Fusce ipsum felis, cursus at congue vel, consectetur tincidunt purus. Pellentesque et fringilla lorem. In at augue malesuada, sollicitudin ex ut, convallis elit. Curabitur metus nibh, consequat vel libero sit amet, iaculis congue nisl. Maecenas eleifend sodales sapien, fringilla sagittis nisi ornare volutpat. Integer tellus enim, volutpat vitae nisl et, dignissim pharetra leo. Sed sit amet efficitur sapien, at tristique sapien. Aenean dignissim semper sagittis. Nullam sit amet volutpat mi.
Curabitur auctor orci et justo molestie iaculis. Integer elementum tortor ac ipsum egestas pharetra. Etiam ultrices elementum pharetra. Maecenas lobortis ultrices risus dignissim luctus. Nunc malesuada cursus posuere. Vestibulum tristique lectus pretium pellentesque pellentesque. Nunc ac nisi lacus. Duis ultrices dui ac viverra ullamcorper. Morbi placerat laoreet lacus sit amet ullamcorper.
Nulla convallis pulvinar hendrerit. Nulla mattis sem et aliquam ultrices. Nam egestas magna leo, nec luctus turpis sollicitudin ac. Sed id leo luctus, lobortis tortor ut, rhoncus ex. Aliquam gravida enim ac dapibus ultricies. Vestibulum at interdum est, et vehicula nibh. Phasellus dignissim iaculis rhoncus. Vestibulum tempus leo lectus, quis euismod metus ullamcorper quis. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut id ipsum at enim eleifend porttitor id quis metus. Proin bibendum ornare iaculis. Duis elementum lacus vel cursus efficitur. Nunc eu tortor sed risus lacinia scelerisque.
Praesent lobortis elit sit amet mauris pulvinar, viverra condimentum massa pellentesque. Curabitur massa ex, dignissim eget neque at, fringilla consectetur justo. Cras sollicitudin vel ligula sed cursus. Aliquam porta sem hendrerit diam porta ultricies. Sed eu mi erat. Curabitur id justo vel tortor hendrerit vestibulum id eget est. Morbi eros magna, placerat id diam ut, varius sollicitudin mi. Curabitur pretium finibus accumsan.`;
interface Props {
navigation: NavigationStackProp;
banner: string;
}
class MyNavScreen extends React.Component<Props> {
render() {
const { navigation } = this.props;
const banner = navigation.getParam('banner');
return (
<ScrollView style={{ flex: 1 }}>
<SafeAreaView forceInset={{ horizontal: 'always' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
title="Open profile screen"
/>
<Button
onPress={() => navigation.navigate('NotifSettings')}
title="Open notifications screen"
/>
<Button
onPress={() => navigation.navigate('SettingsTab')}
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
{TEXT.split('\n').map((p, n) => (
// eslint-disable-next-line react/no-array-index-key
<Text key={n} style={{ marginVertical: 10, marginHorizontal: 8 }}>
{p}
</Text>
))}
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
}
}
const MyProfileScreen = ({ navigation }: NavigationStackScreenProps) => (
<MyNavScreen
banner={`${navigation.state.params!.name}s Profile`}
navigation={navigation}
/>
);
const MainTab = createStackNavigator({
Home: {
navigationOptions: {
title: 'Welcome',
},
params: { banner: 'Home Screen' },
path: '/',
screen: MyNavScreen,
},
Profile: {
navigationOptions: ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => ({
title: `${navigation.state.params!.name}'s Profile!`,
}),
path: '/people/:name',
screen: MyProfileScreen,
},
});
const SettingsTab = createStackNavigator({
NotifSettings: {
navigationOptions: {
title: 'Notifications',
},
params: { banner: 'Notifications Screen' },
screen: MyNavScreen,
},
Settings: {
navigationOptions: () => ({
title: 'Settings',
}),
params: { banner: 'Settings Screen' },
path: '/',
screen: MyNavScreen,
},
});
const StacksInTabs = createBottomTabNavigator(
{
MainTab: {
navigationOptions: {
tabBarIcon: ({
tintColor,
focused,
}: {
tintColor: string;
focused: boolean;
}) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Home',
},
path: '/',
screen: MainTab,
},
SettingsTab: {
screen: SettingsTab,
path: '/settings',
navigationOptions: {
tabBarLabel: 'Settings',
tabBarIcon: ({
tintColor,
focused,
}: {
tintColor: string;
focused: boolean;
}) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings'}
size={26}
style={{ color: tintColor }}
/>
),
},
},
},
{
tabBarOptions: {
showLabel: false,
},
}
);
export default StacksInTabs;

View File

@@ -0,0 +1,151 @@
import React from 'react';
import { ScrollView, StatusBar } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import {
getActiveChildNavigationOptions,
NavigationScreenProp,
NavigationState,
SafeAreaView,
} from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { Button } from './Shared/ButtonWithMargin';
import SampleText from './Shared/SampleText';
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationScreenProp<NavigationState>;
banner: string;
}) => (
<ScrollView>
<SafeAreaView forceInset={{ horizontal: 'always', vertical: 'never' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
title="Open profile screen"
/>
<Button
onPress={() => navigation.navigate('NotifSettings')}
title="Open notifications screen"
/>
<Button
onPress={() => navigation.navigate('SettingsTab')}
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle="default" />
</ScrollView>
);
const MyHomeScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => <MyNavScreen banner="Home Screen" navigation={navigation} />;
const MyProfileScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => (
<MyNavScreen
banner={`${navigation.state.params!.name}s Profile`}
navigation={navigation}
/>
);
const MyNotificationsSettingsScreen = ({
navigation,
}: NavigationStackScreenProps) => (
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => <MyNavScreen banner="Settings Screen" navigation={navigation} />;
const TabNav = createBottomTabNavigator({
MainTab: {
navigationOptions: {
tabBarIcon: ({
tintColor,
focused,
}: {
tintColor: string;
focused: boolean;
}) => (
<Ionicons
name={focused ? 'ios-home' : 'ios-home'}
size={26}
style={{ color: tintColor }}
/>
),
tabBarLabel: 'Home',
title: 'Welcome',
},
path: '/',
screen: MyHomeScreen,
},
SettingsTab: {
navigationOptions: {
tabBarIcon: ({
tintColor,
focused,
}: {
tintColor: string;
focused: boolean;
}) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings'}
size={26}
style={{ color: tintColor }}
/>
),
title: 'Settings',
},
path: '/settings',
screen: MySettingsScreen,
},
});
TabNav.navigationOptions = ({
navigation,
screenProps,
}: {
navigation: NavigationScreenProp<NavigationState>;
screenProps: { [key: string]: any };
}) => {
const childOptions = getActiveChildNavigationOptions(navigation, screenProps);
return {
title: childOptions.title,
};
};
const StacksOverTabs = createStackNavigator({
NotifSettings: {
navigationOptions: {
title: 'Notifications',
},
screen: MyNotificationsSettingsScreen,
},
Profile: {
navigationOptions: ({ navigation }: NavigationStackScreenProps) => ({
title: `${navigation.state.params!.name}'s Profile!`,
}),
path: '/people/:name',
screen: MyProfileScreen,
},
Root: {
screen: TabNav,
},
});
export default StacksOverTabs;

View File

@@ -0,0 +1,173 @@
import React from 'react';
import {
ScrollView,
StatusBar,
StatusBarStyle,
StyleSheet,
View,
} from 'react-native';
import {
NavigationScreenProp,
NavigationState,
SafeAreaView,
} from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
import {
createMaterialTopTabNavigator,
MaterialTopTabBar,
} from 'react-navigation-tabs';
import { Button } from './Shared/ButtonWithMargin';
import SampleText from './Shared/SampleText';
const HEADER_HEIGHT = 64;
const MyNavScreen = ({
navigation,
banner,
statusBarStyle,
}: {
navigation: NavigationScreenProp<NavigationState>;
banner: string;
statusBarStyle?: StatusBarStyle;
}) => (
<ScrollView>
<SafeAreaView forceInset={{ horizontal: 'always' }}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
title="Open profile screen"
/>
<Button
onPress={() => navigation.navigate('NotifSettings')}
title="Open notifications screen"
/>
<Button
onPress={() => navigation.navigate('SettingsTab')}
title="Go to settings tab"
/>
<Button onPress={() => navigation.goBack(null)} title="Go back" />
</SafeAreaView>
<StatusBar barStyle={statusBarStyle || 'default'} />
</ScrollView>
);
const MyHomeScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => (
<MyNavScreen
banner="Home Screen"
navigation={navigation}
statusBarStyle="light-content"
/>
);
const MyProfileScreen = ({ navigation }: NavigationStackScreenProps) => (
<MyNavScreen
banner={`${navigation.state.params!.name}s Profile`}
navigation={navigation}
/>
);
const MyNotificationsSettingsScreen = ({
navigation,
}: NavigationStackScreenProps) => (
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
);
const MySettingsScreen = ({
navigation,
}: {
navigation: NavigationScreenProp<NavigationState>;
}) => (
<MyNavScreen
banner="Settings Screen"
navigation={navigation}
statusBarStyle="light-content"
/>
);
const styles = StyleSheet.create({
stackHeader: {
height: HEADER_HEIGHT,
},
tab: {
height: HEADER_HEIGHT,
},
});
function MaterialTopTabBarWithStatusBar(props: any) {
return (
<View
style={{
paddingTop: 20,
backgroundColor: '#2196f3',
}}
>
<MaterialTopTabBar
{...props}
jumpToIndex={() => {
//
}}
/>
</View>
);
}
const TabNavigator = createMaterialTopTabNavigator(
{
MainTab: {
screen: MyHomeScreen,
navigationOptions: {
title: 'Welcome',
},
},
SettingsTab: {
screen: MySettingsScreen,
navigationOptions: {
title: 'Settings',
},
},
},
{
tabBarComponent: MaterialTopTabBarWithStatusBar,
tabBarOptions: {
tabStyle: styles.tab,
},
}
);
const StackNavigator = createStackNavigator(
{
Root: {
screen: TabNavigator,
navigationOptions: {
headerShown: false,
},
},
NotifSettings: {
screen: MyNotificationsSettingsScreen,
navigationOptions: {
title: 'Notifications',
},
},
Profile: {
screen: MyProfileScreen,
navigationOptions: ({ navigation }: NavigationStackScreenProps) => ({
title: `${navigation.state.params!.name}'s Profile!`,
}),
},
},
{
defaultNavigationOptions: {
headerStyle: styles.stackHeader,
},
}
);
export default StackNavigator;

View File

@@ -0,0 +1,98 @@
import React from 'react';
import { Button, ScrollView } from 'react-native';
import { Themed, SafeAreaView } from 'react-navigation';
import {
createDrawerNavigator,
NavigationDrawerScreenComponent,
NavigationDrawerProp,
} from 'react-navigation-drawer';
import { MaterialIcons } from '@expo/vector-icons';
const SampleText = ({ children }: { children: React.ReactNode }) => (
<Themed.Text>{children}</Themed.Text>
);
const MyNavScreen = ({
navigation,
banner,
}: {
navigation: NavigationDrawerProp;
banner: string;
}) => (
<ScrollView style={{ backgroundColor: '#eee' }}>
<SafeAreaView forceInset={{ top: 'always' }}>
<SampleText>{banner}</SampleText>
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
<Button
onPress={() => navigation.navigate('Email')}
title="Open other screen"
/>
<Button onPress={() => navigation.navigate('Index')} title="Go back" />
</SafeAreaView>
<Themed.StatusBar />
</ScrollView>
);
const InboxScreen: NavigationDrawerScreenComponent = ({ navigation }) => (
<MyNavScreen banner="Inbox Screen" navigation={navigation} />
);
const EmailScreen: NavigationDrawerScreenComponent = ({ navigation }) => (
<MyNavScreen banner="Email Screen" navigation={navigation} />
);
const DraftsScreen: NavigationDrawerScreenComponent = ({ navigation }) => (
<MyNavScreen banner="Drafts Screen" navigation={navigation} />
);
const DrawerExample = createDrawerNavigator(
{
Inbox: {
path: '/',
screen: InboxScreen,
navigationOptions: {
drawerLabel: 'Inbox',
drawerIcon: ({ tintColor }) => (
<MaterialIcons
name="move-to-inbox"
size={24}
style={{ color: tintColor }}
/>
),
},
},
Drafts: {
path: '/sent',
screen: DraftsScreen,
navigationOptions: {
drawerLabel: 'Drafts',
drawerIcon: ({ tintColor }) => (
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
),
},
},
Email: {
path: '/sent',
screen: EmailScreen,
},
},
{
drawerBackgroundColor: {
light: '#eee',
dark: 'rgba(40,40,40,1)',
},
initialRouteName: 'Drafts',
contentOptions: {
activeTintColor: '#e91e63',
},
drawerType: 'back',
overlayColor: '#00000000',
hideStatusBar: true,
}
);
DrawerExample.navigationOptions = {
headerShown: false,
};
export default DrawerExample;

View File

@@ -0,0 +1,121 @@
import * as React from 'react';
import {
ActivityIndicator,
Button,
AsyncStorage,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import { createSwitchNavigator } from 'react-navigation';
import {
createStackNavigator,
NavigationStackScreenProps,
} from 'react-navigation-stack';
class SignInScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Please sign in',
};
_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('Index');
};
render() {
return (
<View style={styles.container}>
<Button title="Sign in!" onPress={this._signInAsync} />
<Button
title="Go back to other examples"
onPress={() => this.props.navigation.goBack(null)}
/>
<StatusBar barStyle="default" />
</View>
);
}
}
class HomeScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Welcome to the app!',
};
_showMoreApp = () => {
this.props.navigation.navigate('Other');
};
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
render() {
return (
<View style={styles.container}>
<Button title="Show me more of the app" onPress={this._showMoreApp} />
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}
}
class OtherScreen extends React.Component<NavigationStackScreenProps> {
static navigationOptions = {
title: 'Lots of features here',
};
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
render() {
return (
<View style={styles.container}>
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
<StatusBar barStyle="default" />
</View>
);
}
}
class LoadingScreen extends React.Component<NavigationStackScreenProps> {
componentDidMount() {
this._bootstrapAsync();
}
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');
let initialRouteName = userToken ? 'App' : 'Auth';
this.props.navigation.navigate(initialRouteName);
};
render() {
return (
<View style={styles.container}>
<ActivityIndicator />
<StatusBar barStyle="default" />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
export default createSwitchNavigator({
Loading: LoadingScreen,
App: AppStack,
Auth: AuthStack,
});

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { MaterialIcons } from '@expo/vector-icons';
import { createDrawerNavigator } from 'react-navigation-drawer';
import SimpleTabs from './SimpleTabs';
import StacksOverTabs from './StacksOverTabs';
const TabsInDrawer = createDrawerNavigator({
SimpleTabs: {
navigationOptions: {
drawerIcon: ({ tintColor }: { tintColor: string }) => (
<MaterialIcons name="filter-1" size={24} style={{ color: tintColor }} />
),
drawerLabel: 'Simple tabs',
},
screen: SimpleTabs,
},
StacksOverTabs: {
navigationOptions: {
drawerIcon: ({ tintColor }: { tintColor: string }) => (
<MaterialIcons name="filter-2" size={24} style={{ color: tintColor }} />
),
drawerLabel: 'Stacks Over Tabs',
},
screen: StacksOverTabs,
},
});
export default TabsInDrawer;

View File

@@ -0,0 +1,90 @@
import * as React from 'react';
import { Button, View, Text } from 'react-native';
import {
createStackNavigator,
NavigationStackScreenComponent,
} from 'react-navigation-stack';
const ListScreen: NavigationStackScreenComponent = function(props) {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
}}
>
<Text>List Screen</Text>
<Text>A list may go here</Text>
<Button
title="Open Dialog"
onPress={() => props.navigation.navigate('ModalDialog')}
/>
<Button
title="Go back to all examples"
onPress={() => props.navigation.navigate('Index')}
/>
</View>
);
};
const ModalDialogScreen: NavigationStackScreenComponent = function(props) {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
}}
>
<View
style={{
backgroundColor: 'white',
padding: 16,
width: '90%',
maxWidth: 500,
minHeight: 300,
borderRadius: 6,
elevation: 6,
shadowColor: 'black',
shadowOpacity: 0.15,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 10,
}}
>
<Text style={{ flex: 1, fontSize: 16 }}>Dialog</Text>
<Button title="Close" onPress={() => props.navigation.goBack()} />
</View>
</View>
);
};
export default createStackNavigator(
{
List: ListScreen,
ModalDialog: ModalDialogScreen,
},
{
initialRouteName: 'List',
mode: 'modal',
headerMode: 'none',
defaultNavigationOptions: {
cardStyle: { backgroundColor: 'transparent' },
gestureEnabled: false,
cardStyleInterpolator: ({ current: { progress } }) => {
const opacity = progress.interpolate({
inputRange: [0, 0.5, 0.9, 1],
outputRange: [0, 0.25, 0.7, 1],
});
return {
cardStyle: {
opacity,
},
};
},
},
}
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
example/src/assets/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

BIN
example/src/assets/book.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
example/src/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB