mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-10 22:47:02 +08:00
wip
This commit is contained in:
72
packages/bottom-tabs/src/types.tsx
Normal file
72
packages/bottom-tabs/src/types.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export type Route = {
|
||||
key: string;
|
||||
routeName: string;
|
||||
} & (NavigationState | undefined);
|
||||
|
||||
export type NavigationEventName =
|
||||
| 'willFocus'
|
||||
| 'didFocus'
|
||||
| 'willBlur'
|
||||
| 'didBlur';
|
||||
|
||||
export type NavigationState = {
|
||||
key: string;
|
||||
index: number;
|
||||
routes: Route[];
|
||||
isTransitioning?: boolean;
|
||||
params?: { [key: string]: unknown };
|
||||
};
|
||||
|
||||
export type NavigationProp<RouteName = string, Params = object> = {
|
||||
emit(eventName: string): void;
|
||||
navigate(routeName: RouteName): void;
|
||||
goBack(): void;
|
||||
goBack(key: string | null): void;
|
||||
addListener: (
|
||||
event: NavigationEventName,
|
||||
callback: () => void
|
||||
) => { remove: () => void };
|
||||
isFocused(): boolean;
|
||||
state: NavigationState;
|
||||
setParams(params: Params): void;
|
||||
getParam(): Params;
|
||||
dispatch(action: { type: string }): void;
|
||||
dangerouslyGetParent(): NavigationProp | undefined;
|
||||
};
|
||||
|
||||
export type NavigationTabOptions = {
|
||||
title?: string;
|
||||
tabBarLabel?: React.ReactNode;
|
||||
tabBarIcon?:
|
||||
| React.ReactNode
|
||||
| ((props: {
|
||||
focused: boolean;
|
||||
tintColor: string;
|
||||
horizontal: boolean;
|
||||
}) => React.ReactNode);
|
||||
tabBarTestID?: string;
|
||||
tabBarOnPress?: (props: {
|
||||
navigation: NavigationProp;
|
||||
defaultHandler: () => void;
|
||||
}) => void;
|
||||
tabBarOnLongPress?: (props: {
|
||||
navigation: NavigationProp;
|
||||
defaultHandler: () => void;
|
||||
}) => void;
|
||||
tabBarAccessibilityLabel?: string;
|
||||
};
|
||||
|
||||
export type SceneDescriptor = {
|
||||
key: string;
|
||||
options: NavigationTabOptions;
|
||||
navigation: NavigationProp;
|
||||
getComponent(): React.ComponentType;
|
||||
};
|
||||
|
||||
export type Screen = React.ComponentType<any> & {
|
||||
navigationOptions?: NavigationTabOptions & {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
@@ -1,206 +0,0 @@
|
||||
/* @flow */
|
||||
|
||||
import * as React from 'react';
|
||||
import {
|
||||
TabRouter,
|
||||
StackActions,
|
||||
SceneView,
|
||||
createNavigator,
|
||||
SwitchActions,
|
||||
} from '@react-navigation/core';
|
||||
|
||||
export type InjectedProps = {|
|
||||
getLabelText: (props: { route: any }) => any,
|
||||
getAccessibilityLabel: (props: { route: any }) => string,
|
||||
getTestID: (props: { route: any }) => string,
|
||||
renderIcon: (props: {
|
||||
route: any,
|
||||
focused: boolean,
|
||||
tintColor: string,
|
||||
horizontal?: boolean,
|
||||
}) => React.Node,
|
||||
renderScene: (props: { route: any }) => ?React.Node,
|
||||
onIndexChange: (index: number) => any,
|
||||
onTabPress: (props: { route: any }) => mixed,
|
||||
onTabLongPress: (props: { route: any }) => mixed,
|
||||
navigation: any,
|
||||
descriptors: any,
|
||||
screenProps?: any,
|
||||
|};
|
||||
|
||||
export default function createTabNavigator(TabView: React.ComponentType<*>) {
|
||||
class NavigationView extends React.Component<*, *> {
|
||||
_renderScene = ({ route }) => {
|
||||
const { screenProps, descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const TabComponent = descriptor.getComponent();
|
||||
return (
|
||||
<SceneView
|
||||
screenProps={screenProps}
|
||||
navigation={descriptor.navigation}
|
||||
component={TabComponent}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_renderIcon = ({ route, focused, tintColor, horizontal = false }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
if (options.tabBarIcon) {
|
||||
return typeof options.tabBarIcon === 'function'
|
||||
? options.tabBarIcon({ focused, tintColor, horizontal })
|
||||
: options.tabBarIcon;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
_getLabelText = ({ route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
if (options.tabBarLabel) {
|
||||
return options.tabBarLabel;
|
||||
}
|
||||
|
||||
if (typeof options.title === 'string') {
|
||||
return options.title;
|
||||
}
|
||||
|
||||
return route.routeName;
|
||||
};
|
||||
|
||||
_getAccessibilityLabel = ({ route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
if (typeof options.tabBarAccessibilityLabel !== 'undefined') {
|
||||
return options.tabBarAccessibilityLabel;
|
||||
}
|
||||
|
||||
const label = this._getLabelText({ route });
|
||||
|
||||
if (typeof label === 'string') {
|
||||
const { routes } = this.props.navigation.state;
|
||||
return `${label}, tab, ${routes.indexOf(route) + 1} of ${
|
||||
routes.length
|
||||
}`;
|
||||
}
|
||||
};
|
||||
|
||||
_getTestID = ({ route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = descriptor.options;
|
||||
|
||||
return options.tabBarTestID;
|
||||
};
|
||||
|
||||
_makeDefaultHandler = ({ route, navigation }) => () => {
|
||||
if (navigation.isFocused()) {
|
||||
if (route.hasOwnProperty('index') && route.index > 0) {
|
||||
// If current tab has a nested navigator, pop to top
|
||||
navigation.dispatch(StackActions.popToTop({ key: route.key }));
|
||||
} else {
|
||||
navigation.emit('refocus');
|
||||
}
|
||||
} else {
|
||||
this._jumpTo(route.routeName);
|
||||
}
|
||||
};
|
||||
|
||||
_handleTabPress = ({ route }) => {
|
||||
this._isTabPress = true;
|
||||
|
||||
// After tab press, handleIndexChange will be called synchronously
|
||||
// So we reset it in promise callback
|
||||
Promise.resolve().then(() => (this._isTabPress = false));
|
||||
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const { navigation, options } = descriptor;
|
||||
|
||||
const defaultHandler = this._makeDefaultHandler({ route, navigation });
|
||||
|
||||
if (options.tabBarOnPress) {
|
||||
options.tabBarOnPress({ navigation, defaultHandler });
|
||||
} else {
|
||||
defaultHandler();
|
||||
}
|
||||
};
|
||||
|
||||
_handleTabLongPress = ({ route }) => {
|
||||
const { descriptors } = this.props;
|
||||
const descriptor = descriptors[route.key];
|
||||
const { navigation, options } = descriptor;
|
||||
|
||||
const defaultHandler = this._makeDefaultHandler({ route, navigation });
|
||||
|
||||
if (options.tabBarOnLongPress) {
|
||||
options.tabBarOnLongPress({ navigation, defaultHandler });
|
||||
} else {
|
||||
defaultHandler();
|
||||
}
|
||||
};
|
||||
|
||||
_handleIndexChange = index => {
|
||||
if (this._isTabPress) {
|
||||
this._isTabPress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this._jumpTo(this.props.navigation.state.routes[index].routeName);
|
||||
};
|
||||
|
||||
_jumpTo = routeName => {
|
||||
const { navigation } = this.props;
|
||||
|
||||
navigation.dispatch(
|
||||
SwitchActions.jumpTo({
|
||||
routeName,
|
||||
key: navigation.state.key,
|
||||
preserveFocus: true,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
_isTabPress: boolean = false;
|
||||
|
||||
render() {
|
||||
const { descriptors, navigation, screenProps } = this.props;
|
||||
const { state } = navigation;
|
||||
const route = state.routes[state.index];
|
||||
const descriptor = descriptors[route.key];
|
||||
const options = {
|
||||
...this.props.navigationConfig,
|
||||
...descriptor.options,
|
||||
};
|
||||
|
||||
return (
|
||||
<TabView
|
||||
{...options}
|
||||
getLabelText={this._getLabelText}
|
||||
getAccessibilityLabel={this._getAccessibilityLabel}
|
||||
getTestID={this._getTestID}
|
||||
renderIcon={this._renderIcon}
|
||||
renderScene={this._renderScene}
|
||||
onIndexChange={this._handleIndexChange}
|
||||
onTabPress={this._handleTabPress}
|
||||
onTabLongPress={this._handleTabLongPress}
|
||||
navigation={navigation}
|
||||
descriptors={descriptors}
|
||||
screenProps={screenProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (routes: *, config: * = {}) => {
|
||||
const router = TabRouter(routes, config);
|
||||
return createNavigator(NavigationView, router, config);
|
||||
};
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Dimensions } from 'react-native';
|
||||
import hoistNonReactStatic from 'hoist-non-react-statics';
|
||||
|
||||
export const isOrientationLandscape = ({ width, height }) => width > height;
|
||||
|
||||
export default function withDimensions(WrappedComponent) {
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
class EnhancedComponent extends React.Component {
|
||||
static displayName = `withDimensions(${WrappedComponent.displayName})`;
|
||||
|
||||
state = {
|
||||
dimensions: { width, height },
|
||||
isLandscape: isOrientationLandscape({ width, height }),
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
Dimensions.addEventListener('change', this.handleOrientationChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Dimensions.removeEventListener('change', this.handleOrientationChange);
|
||||
}
|
||||
|
||||
handleOrientationChange = ({ window }) => {
|
||||
const isLandscape = isOrientationLandscape(window);
|
||||
this.setState({ isLandscape });
|
||||
};
|
||||
|
||||
render() {
|
||||
return <WrappedComponent {...this.props} {...this.state} />;
|
||||
}
|
||||
}
|
||||
|
||||
return hoistNonReactStatic(EnhancedComponent, WrappedComponent);
|
||||
}
|
||||
Reference in New Issue
Block a user