Skip to content
This repository has been archived by the owner on Feb 8, 2020. It is now read-only.

Commit

Permalink
feat: implement various navigators
Browse files Browse the repository at this point in the history
  • Loading branch information
satya164 committed Aug 18, 2019
1 parent 4878d18 commit f0b80ce
Show file tree
Hide file tree
Showing 36 changed files with 1,558 additions and 930 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"eslint-config-satya164": "^2.4.1",
"husky": "^2.4.0",
"jest": "^24.8.0",
"lerna": "^3.16.4",
"prettier": "^1.18.2",
"typescript": "^3.5.1"
},
Expand Down
21 changes: 21 additions & 0 deletions packages/bottom-tabs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@navigation-ex/bottom-tabs",
"version": "0.0.1",
"main": "src/index",
"license": "MIT",
"dependencies": {
"@navigation-ex/core": "^0.0.1",
"@navigation-ex/routers": "^0.0.1",
"react-native-safe-area-view": "^0.14.6"
},
"devDependencies": {
"@types/react": "^16.8.24",
"@types/react-native": "^0.60.2",
"react": "16.8.3",
"react-native": "^0.59.8"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
}
8 changes: 2 additions & 6 deletions packages/bottom-tabs/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@
export {
default as createBottomTabNavigator,
} from './navigators/createBottomTabNavigator';
export {
default as createMaterialTopTabNavigator,
} from './navigators/createMaterialTopTabNavigator';

/**
* Views
*/
export { default as BottomTabBar } from './views/BottomTabBar';
export { default as MaterialTopTabBar } from './views/MaterialTopTabBar';

/**
* Utils
* Types
*/
export { default as createTabNavigator } from './utils/createTabNavigator';
export { BottomTabNavigationOptions, BottomTabNavigationProp } from './types';
220 changes: 46 additions & 174 deletions packages/bottom-tabs/src/navigators/createBottomTabNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,181 +1,53 @@
import * as React from 'react';
import {
View,
StyleSheet,
AccessibilityRole,
AccessibilityState,
} from 'react-native';

// eslint-disable-next-line import/no-unresolved
import { ScreenContainer } from 'react-native-screens';

import createTabNavigator, {
NavigationViewProps,
} from '../utils/createTabNavigator';
import BottomTabBar from '../views/BottomTabBar';
import ResourceSavingScene from '../views/ResourceSavingScene';
useNavigationBuilder,
createNavigator,
DefaultNavigatorOptions,
} from '@navigation-ex/core';
import {
TabRouter,
TabRouterOptions,
TabNavigationState,
} from '@navigation-ex/routers';
import BottomTabView from '../views/BottomTabView';
import {
NavigationProp,
Route,
SceneDescriptor,
NavigationBottomTabOptions,
BottomTabBarOptions,
BottomTabNavigationConfig,
BottomTabNavigationOptions,
} from '../types';

type Props = NavigationViewProps & {
getAccessibilityRole: (props: {
route: Route;
}) => AccessibilityRole | undefined;
getAccessibilityStates: (props: {
route: Route;
focused: boolean;
}) => AccessibilityState[];
lazy?: boolean;
tabBarComponent?: React.ComponentType<any>;
tabBarOptions?: BottomTabBarOptions;
navigation: NavigationProp;
descriptors: { [key: string]: SceneDescriptor<NavigationBottomTabOptions> };
screenProps?: unknown;
};

type State = {
loaded: number[];
};

class TabNavigationView extends React.PureComponent<Props, State> {
static defaultProps = {
lazy: true,
getAccessibilityRole: (): AccessibilityRole => 'button',
getAccessibilityStates: ({
focused,
}: {
focused: boolean;
}): AccessibilityState[] => (focused ? ['selected'] : []),
};

static getDerivedStateFromProps(nextProps: Props, prevState: State) {
const { index } = nextProps.navigation.state;

return {
// Set the current tab to be loaded if it was not loaded before
loaded: prevState.loaded.includes(index)
? prevState.loaded
: [...prevState.loaded, index],
};
}

state = {
loaded: [this.props.navigation.state.index],
};

_getButtonComponent = ({ route }: { route: Route }) => {
const { descriptors } = this.props;
const descriptor = descriptors[route.key];
const options = descriptor.options;

if (options.tabBarButtonComponent) {
return options.tabBarButtonComponent;
}

return undefined;
};

_renderTabBar = () => {
const {
tabBarComponent: TabBarComponent = BottomTabBar,
tabBarOptions,
navigation,
screenProps,
getLabelText,
getAccessibilityLabel,
getAccessibilityRole,
getAccessibilityStates,
getTestID,
renderIcon,
onTabPress,
onTabLongPress,
} = this.props;

const { descriptors } = this.props;
const { state } = this.props.navigation;
const route = state.routes[state.index];
const descriptor = descriptors[route.key];
const options = descriptor.options;

if (options.tabBarVisible === false) {
return null;
}

return (
<TabBarComponent
{...tabBarOptions}
jumpTo={this._jumpTo}
navigation={navigation}
screenProps={screenProps}
onTabPress={onTabPress}
onTabLongPress={onTabLongPress}
getLabelText={getLabelText}
getButtonComponent={this._getButtonComponent}
getAccessibilityLabel={getAccessibilityLabel}
getAccessibilityRole={getAccessibilityRole}
getAccessibilityStates={getAccessibilityStates}
getTestID={getTestID}
renderIcon={renderIcon}
/>
);
};

_jumpTo = (key: string) => {
const { navigation, onIndexChange } = this.props;

const index = navigation.state.routes.findIndex(route => route.key === key);

onIndexChange(index);
};

render() {
const { navigation, renderScene, lazy } = this.props;
const { routes } = navigation.state;
const { loaded } = this.state;

return (
<View style={styles.container}>
<ScreenContainer style={styles.pages}>
{routes.map((route, index) => {
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
}

const isFocused = navigation.state.index === index;

return (
<ResourceSavingScene
key={route.key}
style={StyleSheet.absoluteFill}
isVisible={isFocused}
>
{renderScene({ route })}
</ResourceSavingScene>
);
})}
</ScreenContainer>
{this._renderTabBar()}
</View>
);
}
type Props = DefaultNavigatorOptions<BottomTabNavigationOptions> &
TabRouterOptions &
BottomTabNavigationConfig;

function BottomTabNavigator({
initialRouteName,
backBehavior,
children,
screenOptions,
...rest
}: Props) {
const { state, descriptors, navigation } = useNavigationBuilder<
TabNavigationState,
BottomTabNavigationOptions,
TabRouterOptions
>(TabRouter, {
initialRouteName,
backBehavior,
children,
screenOptions,
});

return (
<BottomTabView
{...rest}
state={state}
navigation={navigation}
descriptors={descriptors}
/>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
overflow: 'hidden',
},
pages: {
flex: 1,
},
});

export default createTabNavigator<NavigationBottomTabOptions, Props>(
TabNavigationView
);
export default createNavigator<
BottomTabNavigationOptions,
typeof BottomTabNavigator
>(BottomTabNavigator);
Loading

0 comments on commit f0b80ce

Please sign in to comment.