mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-09 09:13:32 +08:00
feat: export types for ScreenProps amd ScreenComponent
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"import/named": "off"
|
||||
"import/named": "off",
|
||||
"import/default": "off",
|
||||
"import/namespace": "off",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { View, TouchableOpacity, StyleSheet } from 'react-native';
|
||||
import {
|
||||
Assets as StackAssets,
|
||||
createStackNavigator,
|
||||
NavigationStackScreenProps,
|
||||
} from 'react-navigation-stack';
|
||||
import {
|
||||
Themed,
|
||||
@@ -20,7 +21,7 @@ import MaterialTopTabs from './src/MaterialTopTabs';
|
||||
// Load the back button etc
|
||||
Asset.loadAsync(StackAssets);
|
||||
|
||||
const Home = props => {
|
||||
const Home = (props: NavigationStackScreenProps) => {
|
||||
let theme = useTheme();
|
||||
|
||||
return (
|
||||
@@ -62,7 +63,7 @@ const List = createStackNavigator({
|
||||
const Navigation = createAppContainer(List);
|
||||
|
||||
const App = () => {
|
||||
let [theme, setTheme] = React.useState('light');
|
||||
let [theme, setTheme] = React.useState<'light' | 'dark'>('light');
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -97,7 +98,7 @@ const styles = {
|
||||
flex: 1,
|
||||
},
|
||||
buttonContainer: {
|
||||
position: 'absolute',
|
||||
position: 'absolute' as const,
|
||||
bottom: 60,
|
||||
right: 20,
|
||||
},
|
||||
@@ -111,8 +112,8 @@ const styles = {
|
||||
borderRadius: 25,
|
||||
width: 50,
|
||||
height: 50,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center' as const,
|
||||
justifyContent: 'center' as const,
|
||||
elevation: 5,
|
||||
borderWidth: 1,
|
||||
},
|
||||
@@ -130,4 +131,5 @@ const styles = {
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
registerRootComponent(App);
|
||||
@@ -14,12 +14,12 @@
|
||||
"expo-asset": "^6.0.0",
|
||||
"expo-constants": "~5.0.1",
|
||||
"react": "16.8.3",
|
||||
"react-navigation": "^4.0.3",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz",
|
||||
"react-native-safe-area-view": "0.13.1",
|
||||
"react-native-screens": "1.0.0-alpha.22",
|
||||
"react-native-tab-view": "^2.10.0",
|
||||
"react-navigation-stack": "1.5.3"
|
||||
"react-navigation": "^4.0.4",
|
||||
"react-navigation-stack": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-module-resolver": "^3.2.0",
|
||||
|
||||
@@ -6,10 +6,16 @@ import Article from './Shared/Article';
|
||||
import Chat from './Shared/Chat';
|
||||
import Contacts from './Shared/Contacts';
|
||||
|
||||
// eslint-disable-next-line import/default
|
||||
// @ts-ignore
|
||||
import TouchableBounce from 'react-native/Libraries/Components/Touchable/TouchableBounce';
|
||||
|
||||
const tabBarIcon = name => ({ tintColor, horizontal }) => (
|
||||
const tabBarIcon = (name: string) => ({
|
||||
tintColor,
|
||||
horizontal,
|
||||
}: {
|
||||
tintColor: string;
|
||||
horizontal: boolean;
|
||||
}) => (
|
||||
<MaterialIcons name={name} color={tintColor} size={horizontal ? 17 : 24} />
|
||||
);
|
||||
|
||||
@@ -61,9 +67,14 @@ class ContactsScreen extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default createBottomTabNavigator({
|
||||
AlbumsScreen,
|
||||
ArticleScreen,
|
||||
ChatScreen,
|
||||
ContactsScreen,
|
||||
});
|
||||
export default createBottomTabNavigator(
|
||||
{
|
||||
AlbumsScreen,
|
||||
ArticleScreen,
|
||||
ChatScreen,
|
||||
ContactsScreen,
|
||||
},
|
||||
{
|
||||
initialRouteName: 'AlbumsScreen',
|
||||
}
|
||||
);
|
||||
@@ -1,5 +1,3 @@
|
||||
/* @flow */
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image, Dimensions, ScrollView, StyleSheet } from 'react-native';
|
||||
|
||||
@@ -14,7 +12,7 @@ const COVERS = [
|
||||
require('../../assets/album-art-8.jpg'),
|
||||
];
|
||||
|
||||
export default class Albums extends React.Component<*> {
|
||||
export default class Albums extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
@@ -1,9 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
import * as React from 'react';
|
||||
import { View, Text, Image, ScrollView, StyleSheet } from 'react-native';
|
||||
|
||||
export default class Article extends React.Component<*> {
|
||||
export default class Article extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
@@ -1,5 +1,3 @@
|
||||
/* @flow */
|
||||
|
||||
import * as React from 'react';
|
||||
import { View, Image, Text, ScrollView, StyleSheet } from 'react-native';
|
||||
|
||||
@@ -10,7 +8,7 @@ const MESSAGES = [
|
||||
'make me a sandwich',
|
||||
];
|
||||
|
||||
export default class Albums extends React.Component<*> {
|
||||
export default class Albums extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -1,9 +1,9 @@
|
||||
/* @flow */
|
||||
|
||||
import * as React from 'react';
|
||||
import { View, Text, StyleSheet, FlatList } from 'react-native';
|
||||
|
||||
const CONTACTS = [
|
||||
type Item = { name: string; number: number };
|
||||
|
||||
const CONTACTS: Item[] = [
|
||||
{ name: 'Marissa Castillo', number: 7766398169 },
|
||||
{ name: 'Denzel Curry', number: 9394378449 },
|
||||
{ name: 'Miles Ferguson', number: 8966872888 },
|
||||
@@ -57,7 +57,7 @@ const CONTACTS = [
|
||||
];
|
||||
|
||||
class ContactItem extends React.PureComponent<{
|
||||
item: { name: string, number: number },
|
||||
item: Item;
|
||||
}> {
|
||||
render() {
|
||||
const { item } = this.props;
|
||||
@@ -78,8 +78,8 @@ class ContactItem extends React.PureComponent<{
|
||||
}
|
||||
}
|
||||
|
||||
export default class Contacts extends React.Component<*> {
|
||||
_renderItem = ({ item }) => <ContactItem item={item} />;
|
||||
export default class Contacts extends React.Component {
|
||||
_renderItem = ({ item }: { item: Item }) => <ContactItem item={item} />;
|
||||
|
||||
_ItemSeparator = () => <View style={styles.separator} />;
|
||||
|
||||
@@ -87,7 +87,7 @@ export default class Contacts extends React.Component<*> {
|
||||
return (
|
||||
<FlatList
|
||||
data={CONTACTS}
|
||||
keyExtractor={(item, i) => String(i)}
|
||||
keyExtractor={(_, i) => String(i)}
|
||||
renderItem={this._renderItem}
|
||||
ItemSeparatorComponent={this._ItemSeparator}
|
||||
/>
|
||||
@@ -1,78 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { View, Image, ScrollView, Dimensions, StyleSheet } from 'react-native';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
|
||||
@withNavigation
|
||||
class NavigationAwareScrollView extends React.Component {
|
||||
componentDidMount() {
|
||||
this.props.navigation.addListener('willFocus', () => {
|
||||
this._isFocused = true;
|
||||
});
|
||||
|
||||
this.props.navigation.addListener('willBlur', () => {
|
||||
this._isFocused = false;
|
||||
});
|
||||
|
||||
this.props.navigation.addListener('refocus', () => {
|
||||
if (this._isFocused) {
|
||||
this._component.scrollTo({ x: 0, y: 0 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setNativeProps(props) {
|
||||
this._component.setNativeProps(props);
|
||||
}
|
||||
|
||||
_setComponentRef(c) {
|
||||
this._component = c;
|
||||
}
|
||||
|
||||
getNode() {
|
||||
return this._component;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
{...this.props}
|
||||
ref={view => {
|
||||
this._component = view;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function PhotoGrid({ id }) {
|
||||
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',
|
||||
},
|
||||
});
|
||||
86
packages/tabs/example/src/Shared/PhotoGrid.tsx
Normal file
86
packages/tabs/example/src/Shared/PhotoGrid.tsx
Normal 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',
|
||||
},
|
||||
});
|
||||
@@ -4587,17 +4587,17 @@ react-native-webview@5.8.1:
|
||||
xmldoc "^0.4.0"
|
||||
yargs "^9.0.0"
|
||||
|
||||
react-navigation-stack@1.5.3:
|
||||
version "1.5.3"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-1.5.3.tgz#cdc9f5a6dbdc55509a15f60d765722573dec1997"
|
||||
integrity sha512-MQcwDVbZUYsTtDJb5cFOSm+K+e7KpUCoROaGoUOR+JHWE3uuaJ3pd/Nu+32a57J98TNBf4qq0+2TPJWl6z6IBg==
|
||||
react-navigation-stack@^1.7.2:
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-1.7.2.tgz#d7cf7a7dc76c2390024be6358fc65461c848a034"
|
||||
integrity sha512-72oL9rVXUFvFayoA7k+OgXcwP/6e5BAtCSpUXfKX+lZYrJe3BvuhZz2KDhEjdfbuP/sNok55ZRzc3/X1kh5mxQ==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-navigation@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.0.3.tgz#ba2cacb71db56e22ee50d774829ebc7fa95a0724"
|
||||
integrity sha512-oASR5gHwd6se1Mw8AM4Ie8GicD5mKzRiYP6oaQujiQroQzQPij9sXxkRSqOscd/Kw1/Hf3htvBX3ZRPbOkWsfA==
|
||||
react-navigation@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.0.4.tgz#afa43c7183891d38708cf57f1d4394fed1d4c2ad"
|
||||
integrity sha512-MZeVkYkFTKZobhrXMV3Hgeg0HHeokCrYsbxActVfO0n6zfzm0/La6EiC2mIHiwOymvb1ZygyFf90vryLUMEBNA==
|
||||
dependencies:
|
||||
"@react-navigation/core" "^3.5.0"
|
||||
"@react-navigation/native" "^3.6.2"
|
||||
|
||||
@@ -74,18 +74,18 @@
|
||||
"react-native": "~0.57.1",
|
||||
"react-native-gesture-handler": "^1.4.1",
|
||||
"react-native-reanimated": "^1.2.0",
|
||||
"react-navigation": "^4.0.3",
|
||||
"react-navigation": "^4.0.4",
|
||||
"react-test-renderer": "16.5.0",
|
||||
"release-it": "^10.3.1",
|
||||
"typescript": "^3.5.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-navigation": "^4.0.3",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": "^1.0.0",
|
||||
"react-native-reanimated": "^1.0.0-alpha",
|
||||
"react-native-screens": "^1.0.0 || ^1.0.0-alpha"
|
||||
"react-native-screens": "^1.0.0 || ^1.0.0-alpha",
|
||||
"react-navigation": "^4.0.4"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
||||
@@ -22,10 +22,12 @@ export { default as createTabNavigator } from './utils/createTabNavigator';
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
|
||||
export {
|
||||
NavigationTabState,
|
||||
NavigationTabProp,
|
||||
NavigationTabScreenProps,
|
||||
NavigationBottomTabOptions,
|
||||
NavigationMaterialTabOptions,
|
||||
NavigationBottomTabScreenComponent,
|
||||
NavigationMaterialTabScreenComponent,
|
||||
} from './types';
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
NavigationScreenProp,
|
||||
NavigationParams,
|
||||
NavigationDescriptor,
|
||||
NavigationScreenConfig,
|
||||
SupportedThemes,
|
||||
} from 'react-navigation';
|
||||
|
||||
export type NavigationTabState = NavigationState;
|
||||
@@ -178,6 +180,35 @@ export type NavigationMaterialTabOptions = NavigationCommonTabOptions & {
|
||||
swipeEnabled?: boolean | ((state: NavigationState) => boolean);
|
||||
};
|
||||
|
||||
export type NavigationTabScreenProps<
|
||||
Params = NavigationParams,
|
||||
ScreenProps = unknown
|
||||
> = {
|
||||
theme: SupportedThemes;
|
||||
navigation: NavigationTabProp<NavigationRoute, Params>;
|
||||
screenProps: ScreenProps;
|
||||
};
|
||||
|
||||
export type NavigationMaterialTabScreenComponent<
|
||||
Params = NavigationParams,
|
||||
ScreenProps = unknown
|
||||
> = React.ComponentType<NavigationTabScreenProps<Params, ScreenProps>> & {
|
||||
navigationOptions?: NavigationScreenConfig<
|
||||
NavigationMaterialTabOptions,
|
||||
NavigationTabProp<NavigationRoute, Params>
|
||||
>;
|
||||
};
|
||||
|
||||
export type NavigationBottomTabScreenComponent<
|
||||
Params = NavigationParams,
|
||||
ScreenProps = unknown
|
||||
> = React.ComponentType<NavigationTabScreenProps<Params, ScreenProps>> & {
|
||||
navigationOptions?: NavigationScreenConfig<
|
||||
NavigationBottomTabOptions,
|
||||
NavigationTabProp<NavigationRoute, Params>
|
||||
>;
|
||||
};
|
||||
|
||||
export type SceneDescriptorMap = {
|
||||
[key: string]: NavigationDescriptor<
|
||||
NavigationParams,
|
||||
|
||||
@@ -58,7 +58,12 @@ export default function createTabNavigator<
|
||||
TabView: React.ComponentType<Props>
|
||||
): (
|
||||
routes: RouteConfig<Options>,
|
||||
config: Options
|
||||
config?: CreateNavigatorConfig<
|
||||
{},
|
||||
NavigationTabRouterConfig,
|
||||
Partial<Options>,
|
||||
NavigationTabProp
|
||||
>
|
||||
) => React.ComponentType<
|
||||
Pick<Props, Exclude<keyof Props, keyof NavigationViewProps>> & ExtraProps
|
||||
> {
|
||||
@@ -256,7 +261,8 @@ export default function createTabNavigator<
|
||||
config: CreateNavigatorConfig<
|
||||
{},
|
||||
NavigationTabRouterConfig,
|
||||
Partial<Options>
|
||||
Partial<Options>,
|
||||
NavigationTabProp
|
||||
> = {}
|
||||
) => {
|
||||
const router = TabRouter(routes, config as any);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"react-navigation-tabs": ["./src/index"]
|
||||
},
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"esModuleInterop": true,
|
||||
@@ -15,6 +19,7 @@
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "esnext"
|
||||
}
|
||||
|
||||
@@ -7672,10 +7672,10 @@ react-native@~0.57.1:
|
||||
xmldoc "^0.4.0"
|
||||
yargs "^9.0.0"
|
||||
|
||||
react-navigation@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.0.3.tgz#ba2cacb71db56e22ee50d774829ebc7fa95a0724"
|
||||
integrity sha512-oASR5gHwd6se1Mw8AM4Ie8GicD5mKzRiYP6oaQujiQroQzQPij9sXxkRSqOscd/Kw1/Hf3htvBX3ZRPbOkWsfA==
|
||||
react-navigation@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.0.4.tgz#afa43c7183891d38708cf57f1d4394fed1d4c2ad"
|
||||
integrity sha512-MZeVkYkFTKZobhrXMV3Hgeg0HHeokCrYsbxActVfO0n6zfzm0/La6EiC2mIHiwOymvb1ZygyFf90vryLUMEBNA==
|
||||
dependencies:
|
||||
"@react-navigation/core" "^3.5.0"
|
||||
"@react-navigation/native" "^3.6.2"
|
||||
|
||||
Reference in New Issue
Block a user