refactor: upgrade

BREAKING CHANGE: change activeTintColor -> activeColor
This commit is contained in:
satyajit.happy
2019-09-10 12:26:16 +02:00
parent b624c3052e
commit edc6865df0
29 changed files with 7561 additions and 8017 deletions

View File

@@ -2,7 +2,7 @@ version: 2
defaults: &defaults
docker:
- image: circleci/node:7.10
- image: circleci/node:10.9.0
working_directory: ~/project
jobs:
@@ -21,8 +21,7 @@ jobs:
- v1-dependencies-example-{{ checksum "example/package.json" }}
- v1-dependencies-example-
- run: |
yarn install --ignore-engines
yarn install --cwd example
yarn bootstrap
- save_cache:
key: v1-dependencies-{{ checksum "package.json" }}
paths: node_modules
@@ -32,32 +31,39 @@ jobs:
- persist_to_workspace:
root: .
paths: .
lint-and-flow:
lint-and-typecheck:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: |
yarn lint
yarn flow
yarn typescript
unit-tests:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: yarn test -- --coverage
- run: |
yarn test --coverage
- store_artifacts:
path: coverage
destination: coverage
build:
<<: *defaults
steps:
- attach_workspace:
at: ~/project
- run: yarn prepare
workflows:
version: 2
build-and-test:
jobs:
- install-dependencies
- lint-and-flow:
- lint-and-typecheck:
requires:
- install-dependencies
- unit-tests:
- build:
requires:
- install-dependencies

View File

@@ -1,3 +1,6 @@
node_modules/
flow-typed/
dist/
# generated by bob
lib/

View File

@@ -3,8 +3,18 @@
"plugins": ["react-native-globals"],
"settings": {
"react": {
"version": "detect"
}
},
"env": {
"es6": true,
"react-native-globals/all": true,
},
"rules": {
"import/named": "off"
}
}

View File

@@ -1,80 +0,0 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore templates for 'react-native init'
.*/local-cli/templates/.*
; Ignore the Dangerfile
<PROJECT_ROOT>/bots/dangerfile.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore unexpected extra "@providesModule"
.*/node_modules/.*/node_modules/fbjs/.*
; Ignore duplicate module providers
; For RN Apps installed via npm, "Libraries" folder is inside
; "node_modules/react-native" but in the source repo it is in the root
.*/Libraries/react-native/React.js
; Ignore polyfills
.*/Libraries/polyfills/.*
; Ignore metro
.*/node_modules/metro/.*
; Ignore duplicate modules under example/
.*/example/node_modules/fbjs/.*
.*/example/node_modules/fbemitter/.*
.*/example/node_modules/react/.*
.*/example/node_modules/react-native/.*
.*/example/\.buckd/
; Ignore duplicate modules under docs/
.*/docs/node_modules/fbjs/.*
.*/docs/node_modules/react/.*
; Ignore some modules we don't need to parse
.*/node_modules/prettier/.*
.*/node_modules/eslint.*
.*/node_modules/reqwest/tests/fixtures/.*
[untyped]
.*/node_modules/expo/.*
.*/node_modules/xdl/.*
.*/node_modules/react-native-gesture-handler/.*
[include]
[libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow-github
node_modules/react-native/flow
[options]
emoji=true
module.system=haste
munge_underscores=true
module.file_ext=.js
module.file_ext=.android.js
module.file_ext=.ios.js
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*[react_native_oss|react_native_fb][a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*[react_native_oss|react_native_fb][a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[version]
^0.67.1

View File

@@ -7,7 +7,6 @@
# VSCode
.vscode/
tsconfig.json
jsconfig.json
# Xcode
@@ -51,3 +50,6 @@ android/keystores/debug.keystore
# Build
dist/
# generated by bob
lib/

View File

@@ -1,8 +1,5 @@
{
"increment": "conventional:angular",
"changelogCommand": "conventional-changelog -p angular | tail -n +3",
"safeBump": false,
"src": {
"git": {
"commitMessage": "chore: release %s",
"tagName": "v%s"
},
@@ -11,5 +8,10 @@
},
"github": {
"release": true
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular"
}
}
}

View File

@@ -45,8 +45,6 @@ export default createMaterialBottomTabNavigator({
});
```
For more info, see: https://github.com/react-navigation/react-navigation-tabs
## Docs
Documentation can be found on the [React Navigation website](https://reactnavigation.org/docs/material-bottom-tab-navigator.html).

View File

@@ -1,4 +0,0 @@
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });

View File

@@ -0,0 +1,5 @@
/* eslint-disable import/no-commonjs */
module.exports = {
extends: ['@commitlint/config-conventional'],
};

View File

@@ -1,20 +1,23 @@
import * as React from 'react';
import Expo from 'expo';
import { StyleSheet } from 'react-native';
import { registerRootComponent } from 'expo';
import { Asset } from 'expo-asset';
import {
FlatList,
createAppContainer,
createStackNavigator,
NavigationScreenProp,
} from 'react-navigation';
import {
createStackNavigator,
Assets as StackAssets,
} from 'react-navigation-stack';
import { List, Divider } from 'react-native-paper';
// eslint-disable-next-line import/no-unresolved
import { Assets as StackAssets } from 'react-navigation-stack';
import SimpleTabs from './src/SimpleTabs';
import ShiftingTabs from './src/ShiftingTabs';
import IconTabs from './src/IconTabs';
Expo.Asset.loadAsync(StackAssets);
Asset.loadAsync(StackAssets);
const data = [
{ component: ShiftingTabs, title: 'Shifting', routeName: 'ShiftingTabs' },
@@ -22,24 +25,30 @@ const data = [
{ component: IconTabs, title: 'Icons only', routeName: 'IconTabs' },
];
class Home extends React.Component {
type Props = {
navigation: NavigationScreenProp<any>;
};
type Item = { title: string; routeName: string };
class Home extends React.Component<Props> {
static navigationOptions = {
title: 'Examples',
};
_renderItem = ({ item }) => (
_renderItem = ({ item }: { item: Item }) => (
<List.Item
title={item.title}
onPress={() => this.props.navigation.navigate(item.routeName)}
/>
);
_keyExtractor = item => item.routeName;
_keyExtractor = (item: Item) => item.routeName;
render() {
return (
<FlatList
style={{ backgroundColor: '#fff' }}
style={styles.container}
ItemSeparatorComponent={Divider}
renderItem={this._renderItem}
keyExtractor={this._keyExtractor}
@@ -51,7 +60,12 @@ class Home extends React.Component {
const MainStack = createStackNavigator({
Home,
...data.reduce((acc, it) => {
...data.reduce<{
[key: string]: {
screen: React.ComponentType;
navigationOptions: { title: string };
};
}>((acc, it) => {
acc[it.routeName] = {
screen: it.component,
navigationOptions: {
@@ -64,4 +78,12 @@ const MainStack = createStackNavigator({
});
const App = createAppContainer(MainStack);
Expo.registerRootComponent(App);
// @ts-ignore
registerRootComponent(App);
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff',
},
});

View File

@@ -1,8 +1,7 @@
## Run the example
- [View it with Expo](https://expo.io/@satya164/react-navigation-tabs-demos)
- Run the example locally
+ Clone the repository and `cd` to this directory
+ Run `yarn` to install the dependencies
+ Run `yarn start` to start the packager
+ Scan the QR Code with the Expo app
- Clone the repository and `cd` to this directory
- Run `yarn` to install the dependencies
- Run `yarn start` to start the packager
- Scan the QR Code with the Expo app

View File

@@ -3,14 +3,13 @@
"name": "React Navigation Material Bottom Tabs Example",
"description": "Demonstrates the various capabilities of react-navigation-material-bottom-tabs",
"slug": "react-navigation-material-bottom-tabs-demo",
"sdkVersion": "30.0.0",
"sdkVersion": "34.0.0",
"version": "1.0.0",
"primaryColor": "#2196f3",
"packagerOpts": {
"assetExts": [
"ttf"
],
"config": "./rn-cli.config.js",
"projectRoots": ""
}
}

View File

@@ -0,0 +1,29 @@
/* eslint-disable import/no-commonjs, import/no-extraneous-dependencies */
const path = require('path');
const blacklist = require('metro-config/src/defaults/blacklist');
const pak = require('../package.json');
const escape = require('escape-string-regexp');
const dependencies = Object.keys(pak.dependencies);
const peerDependencies = Object.keys(pak.peerDependencies);
module.exports = {
projectRoot: __dirname,
watchFolders: [path.resolve(__dirname, '..')],
resolver: {
blacklistRE: blacklist([
new RegExp(
`^${escape(path.resolve(__dirname, '..', 'node_modules'))}\\/.*$`
),
]),
providesModuleNodeModules: [
'@expo/vector-icons',
'@babel/runtime',
...dependencies,
...peerDependencies,
],
},
};

View File

@@ -2,34 +2,34 @@
"name": "tabviewexample",
"version": "0.0.1",
"private": true,
"main": "App.tsx",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios"
},
"dependencies": {
"@expo/vector-icons": "^8.0.0",
"@react-navigation/core": "^3.0.0-alpha",
"@react-navigation/native": "^3.0.0-alpha",
"expo": "~30.0.0",
"hoist-non-react-statics": "^2.5.0",
"prop-types": "^15.6.0",
"react": "16.3.1",
"react-native": "~0.55.4",
"react-native-paper": "^2.2.2",
"react-navigation": "^3.0.0-rc",
"react-navigation-stack": "^1.0.0-alpha.33"
"@expo/vector-icons": "^10.0.5",
"expo": "~34.0.4",
"expo-asset": "~6.0.0",
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.7.2",
"react": "16.8.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-34.0.0.tar.gz",
"react-native-gesture-handler": "~1.3.0",
"react-native-paper": "^3.0.0-alpha.4",
"react-native-reanimated": "~1.1.0",
"react-navigation": "^4.0.2",
"react-navigation-stack": "^1.5.4"
},
"devDependencies": {
"babel-plugin-module-resolver": "^3.0.0",
"babel-preset-expo": "^4.0.0",
"glob-to-regexp": "^0.3.0"
"babel-plugin-module-resolver": "^3.2.0",
"babel-preset-expo": "^5.2.0",
"glob-to-regexp": "^0.4.1"
},
"main": "App.js",
"resolutions": {
"**/prop-types": "15.6.0",
"**/react-lifecycles-compat": "3.0.4",
"**/hoist-non-react-statics": "2.5.0",
"**/react-native-tab-view": "0.0.78"
"**/hoist-non-react-statics": "2.5.0"
}
}

View File

@@ -1,21 +0,0 @@
/* eslint-disable import/no-commonjs */
const path = require('path');
const glob = require('glob-to-regexp');
const blacklist = require('metro/src/blacklist');
const pak = require('../package.json');
const dependencies = Object.keys(pak.dependencies);
const peerDependencies = Object.keys(pak.peerDependencies);
module.exports = {
getProjectRoots() {
return [__dirname, path.resolve(__dirname, '..')];
},
getProvidesModuleNodeModules() {
return [...dependencies, ...peerDependencies];
},
getBlacklistRE() {
return blacklist([glob(`${path.resolve(__dirname, '..')}/node_modules/*`)]);
},
};

View File

@@ -2,7 +2,7 @@ import * as React from 'react';
import { View, Image, Dimensions, StyleSheet } from 'react-native';
import { ScrollView } from 'react-navigation';
export default function PhotoGrid({ id }) {
export default function PhotoGrid({ id }: { id: string }) {
const PHOTOS = Array.from({ length: 24 }).map(
(_, i) => `https://unsplash.it/300/300/?random&__id=${id}${i}`
);

View File

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

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' },
});

File diff suppressed because it is too large Load Diff

View File

@@ -2,22 +2,20 @@
"name": "react-navigation-material-bottom-tabs",
"version": "1.1.1",
"description": "Material Bottom Tab Navigation component for React Navigation",
"main": "dist/index.js",
"files": [
"dist/",
"src/",
"LICENSE.md",
"README.md"
],
"main": "lib/commonjs/index.js",
"module": "lib/module/index.js",
"react-native": "src/index.js",
"files": [
"src",
"lib"
],
"scripts": {
"test": "jest",
"flow": "flow",
"lint": "eslint .",
"precommit": "yarn lint && yarn flow && yarn test",
"build": "babel --no-babelrc --plugins=transform-es2015-block-scoping,transform-react-jsx,transform-class-properties,transform-object-rest-spread,transform-flow-strip-types src --out-dir dist --ignore '**/__tests__/**'",
"prepare": "yarn build",
"release": "release-it"
"typescript": "tsc --noEmit",
"lint": "eslint --ext .js,.ts,.tsx .",
"bootstrap": "yarn --cwd example && yarn",
"example": "yarn --cwd example",
"release": "yarn release-it",
"prepare": "bob build"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
@@ -41,58 +39,50 @@
"url": "https://github.com/react-navigation/react-navigation-material-bottom-tabs/issues"
},
"homepage": "https://github.com/react-navigation/react-navigation-material-bottom-tabs#readme",
"dependencies": {
"hoist-non-react-statics": "^2.5.0",
"prop-types": "^15.6.0",
"react-navigation-tabs": "~1.2.0"
},
"devDependencies": {
"@expo/vector-icons": "^6.2.0",
"@react-navigation/core": "^3.0.0-alpha",
"@react-navigation/native": "^3.0.0-alpha",
"babel-cli": "^6.26.0",
"babel-jest": "^21.2.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-es2015-block-scoping": "^6.26.0",
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-react-native": "^4.0.0",
"conventional-changelog-cli": "^2.0.11",
"enzyme": "3.2.0",
"enzyme-adapter-react-16": "^1.1.0",
"enzyme-to-json": "^3.2.2",
"eslint": "^4.12.1",
"eslint-config-satya164": "^1.0.1",
"@commitlint/config-conventional": "^7.5.0",
"@expo/vector-icons": "^10.0.1",
"@react-native-community/bob": "^0.6.1",
"@release-it/conventional-changelog": "^1.1.0",
"@types/hoist-non-react-statics": "^3.3.1",
"@types/react": "^16.8.17",
"@types/react-native": "^0.57.57",
"babel-jest": "^24.5.0",
"commitlint": "^7.5.2",
"eslint": "^5.16.0",
"eslint-config-satya164": "^2.4.1",
"eslint-plugin-react-native-globals": "^0.1.0",
"flow-bin": "~0.67.0",
"husky": "^0.14.3",
"jest": "^21.2.1",
"prettier": "^1.8.2",
"react": "16.3.1",
"react-dom": "16.3.1",
"react-native": "~0.55.4",
"react-native-paper": "^2.2.2",
"react-navigation": "^2.1.0",
"react-test-renderer": "16.2.0",
"release-it": "^7.6.2"
"husky": "^1.3.1",
"jest": "^24.5.0",
"prettier": "^1.17.1",
"react": "16.8.3",
"react-native": "~0.59.8",
"react-native-gesture-handler": "^1.4.1",
"react-native-paper": "^3.0.0-alpha.4",
"react-native-reanimated": "^1.2.0",
"react-navigation": "^4.0.1",
"release-it": "^12.3.6",
"typescript": "^3.5.2"
},
"peerDependencies": {
"react": "*",
"react-native": "*",
"react-native-paper": "^2.2.2",
"react-navigation": ">=2.0 || ^2.0.0-beta"
"react-native-paper": "^2.2.2 || ^3.0.0-alpha.1",
"react-navigation": "^4.0.2"
},
"jest": {
"preset": "react-native",
"setupFiles": [
"<rootDir>/__setup__/enzyme.js"
],
"modulePathIgnorePatterns": [
"<rootDir>/example/node_modules"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "yarn lint && yarn typescript"
}
},
"@react-native-community/bob": {
"source": "src",
"output": "lib",
"targets": [
"commonjs",
"module",
"typescript"
]
}
}

View File

@@ -1,5 +1,3 @@
/* @flow */
export {
default as createMaterialBottomTabNavigator,
} from './navigators/createMaterialBottomTabNavigator';

View File

@@ -1,124 +0,0 @@
/* @flow */
import * as React from 'react';
import { ThemeContext } from '@react-navigation/core';
import { BottomNavigation } from 'react-native-paper';
import { createTabNavigator, type InjectedProps } from 'react-navigation-tabs';
type Props = InjectedProps & {
activeTintColor?: string,
activeTintColorLight?: string,
activeTintColorDark?: string,
inactiveTintColor?: string,
inactiveTintColorLight?: string,
inactiveTintColorDark?: string,
// todo: once this is properly typed, add other types for themed props
};
class BottomNavigationView extends React.Component<Props> {
static contextType = ThemeContext;
_getColor = ({ route }) => {
const { descriptors } = this.props;
const descriptor = descriptors[route.key];
const options = descriptor.options;
if (this.context === 'dark' && options.tabBarColorDark) {
return options.tabBarColorDark;
} else if (this.tabBarColorLight) {
return options.tabBarColorLight;
} else {
return options.tabBarColor;
}
};
_getActiveTintColor = () => {
let {
activeTintColor,
activeTintColorLight,
activeTintColorDark,
} = this.props;
if (this.context === 'dark' && activeTintColorDark) {
return activeTintColorDark;
} else if (activeTintColorLight) {
return activeTintColorLight;
} else {
return activeTintColor;
}
};
_getInactiveTintColor = () => {
let {
inactiveTintColor,
inactiveTintColorLight,
inactiveTintColorDark,
} = this.props;
if (this.context === 'dark' && inactiveTintColorDark) {
return inactiveTintColorDark;
} else if (inactiveTintColorLight) {
return inactiveTintColorLight;
} else {
return inactiveTintColor;
}
};
_getBarStyle = () => {
let { barStyle, barStyleLight, barStyleDark } = this.props;
if (this.context === 'dark' && barStyleDark) {
return barStyleDark;
} else if (barStyleLight) {
return barStyleLight;
} else {
return barStyle;
}
};
_isVisible() {
const { navigation, descriptors } = this.props;
const { state } = navigation;
const route = state.routes[state.index];
const options = descriptors[route.key].options;
return options.tabBarVisible;
}
_renderIcon = ({ route, focused, color }) => {
return this.props.renderIcon({ route, focused, tintColor: color });
};
render() {
const {
navigation,
// eslint-disable-next-line no-unused-vars
descriptors,
...rest
} = this.props;
const activeTintColor = this._getActiveTintColor();
const inactiveTintColor = this._getInactiveTintColor();
const barStyle = this._getBarStyle();
const isVisible = this._isVisible();
const extraStyle =
typeof isVisible === 'boolean'
? { display: isVisible ? null : 'none' }
: null;
return (
<BottomNavigation
// Pass these for backward compaibility
{...rest}
activeColor={activeTintColor}
inactiveColor={inactiveTintColor}
renderIcon={this._renderIcon}
barStyle={[barStyle, extraStyle]}
navigationState={navigation.state}
getColor={this._getColor}
/>
);
}
}
export default createTabNavigator(BottomNavigationView);

View File

@@ -0,0 +1,275 @@
import * as React from 'react';
import { StyleProp, ViewStyle } from 'react-native';
import {
TabRouter,
StackActions,
SceneView,
createNavigator,
SwitchActions,
NavigationProp,
NavigationScreenProp,
NavigationRoute,
NavigationDescriptor,
} from 'react-navigation';
import MaterialBottomTabView from '../views/MaterialBottomTabView';
type NavigationMaterialBottomTabOptions = {
shifting?: boolean;
labeled?: boolean;
activeColor?: string;
activeColorLight?: string;
activeColorDark?: string;
inactiveColor?: string;
inactiveColorLight?: string;
inactiveColorDark?: string;
barStyle?: StyleProp<ViewStyle>;
barStyleLight?: StyleProp<ViewStyle>;
barStyleDark?: StyleProp<ViewStyle>;
title?: string;
tabBarLabel?: React.ReactNode;
tabBarVisible?: boolean;
tabBarAccessibilityLabel?: string;
tabBarTestID?: string;
tabBarIcon?:
| React.ReactNode
| ((props: {
focused: boolean;
tintColor?: string;
horizontal?: boolean;
}) => React.ReactNode);
tabBarOnPress?: (props: {
navigation: NavigationScreenProp<any>;
defaultHandler: () => void;
}) => void;
};
type Screen<
Options extends NavigationMaterialBottomTabOptions
> = React.ComponentType<any> & {
navigationOptions?: Options & {
[key: string]: any;
};
};
type RouteConfig<Options> = {
[key: string]:
| Screen<Options>
| ({ screen: Screen<Options> } | { getScreen(): Screen<Options> }) & {
path?: string;
navigationOptions?:
| Options
| ((options: { navigation: NavigationScreenProp<any> }) => Options);
};
};
export type RenderIconProps = {
route: NavigationRoute<any>;
focused: boolean;
tintColor?: string;
horizontal?: boolean;
};
export type NavigationViewProps = {
navigation: NavigationProp<any>;
descriptors: {
[key: string]: NavigationDescriptor<
any,
NavigationMaterialBottomTabOptions
>;
};
screenProps?: unknown;
navigationConfig: any;
getLabelText: (props: { route: NavigationRoute }) => string | undefined;
getAccessibilityLabel: (props: {
route: NavigationRoute;
}) => string | undefined;
getTestID: (props: { route: NavigationRoute }) => string | undefined;
renderIcon: (props: RenderIconProps) => React.ReactNode;
renderScene: (props: { route: NavigationRoute }) => React.ReactNode;
onIndexChange: (index: number) => void;
onTabPress: (props: { route: NavigationRoute }) => void;
};
export default function createMaterialBottomTabNavigator(
routes: RouteConfig<NavigationMaterialBottomTabOptions>,
config: NavigationMaterialBottomTabOptions
) {
class NavigationView extends React.Component<NavigationViewProps> {
_renderScene = ({ route }: { route: { key: string } }) => {
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,
}: RenderIconProps) => {
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 }: { route: NavigationRoute }) => {
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 }: { route: NavigationRoute }) => {
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
}`;
}
return undefined;
};
_getTestID = ({ route }: { route: NavigationRoute }) => {
const { descriptors } = this.props;
const descriptor = descriptors[route.key];
const options = descriptor.options;
return options.tabBarTestID;
};
_makeDefaultHandler = ({
route,
navigation,
}: {
route: NavigationRoute;
navigation: NavigationScreenProp<any>;
}) => () => {
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 {
// @ts-ignore
navigation.emit('refocus');
}
} else {
this._jumpTo(route.routeName);
}
};
_handleTabPress = ({ route }: { route: NavigationRoute }) => {
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();
}
};
_handleIndexChange = (index: number) => {
if (this._isTabPress) {
this._isTabPress = false;
return;
}
this._jumpTo(this.props.navigation.state.routes[index].routeName);
};
_jumpTo = (routeName: string) => {
const { navigation } = this.props;
navigation.dispatch(
SwitchActions.jumpTo({
routeName,
key: navigation.state.key,
})
);
};
_isTabPress: boolean = false;
render() {
const {
descriptors,
navigation,
screenProps,
navigationConfig,
} = this.props;
const { state } = navigation;
const route = state.routes[state.index];
const descriptor = descriptors[route.key];
const options = {
...navigationConfig,
...descriptor.options,
};
return (
<MaterialBottomTabView
{...options}
getLabelText={this._getLabelText}
getAccessibilityLabel={this._getAccessibilityLabel}
getTestID={this._getTestID}
renderIcon={this._renderIcon}
renderScene={this._renderScene}
onIndexChange={this._handleIndexChange}
onTabPress={this._handleTabPress}
navigation={navigation}
descriptors={descriptors}
screenProps={screenProps}
/>
);
}
}
const router = TabRouter(routes, config as any);
// TODO: don't have time to fix it right now
// @ts-ignore
return createNavigator(NavigationView, router, config as any);
}

View File

@@ -0,0 +1,142 @@
import * as React from 'react';
import { StyleProp, ViewStyle } from 'react-native';
import {
ThemeContext,
NavigationRoute,
NavigationProp,
NavigationDescriptor,
} from 'react-navigation';
import { BottomNavigation } from 'react-native-paper';
type Options = {
tabBarVisible?: boolean;
tabBarColor?: string;
tabBarColorLight?: string;
tabBarColorDark?: string;
};
type Props = React.ComponentProps<typeof BottomNavigation> & {
navigation: NavigationProp<any>;
descriptors: { [key: string]: NavigationDescriptor<any, Options> };
screenProps?: unknown;
renderIcon: (options: {
route: NavigationRoute;
focused: boolean;
tintColor: string;
}) => React.ReactNode;
activeColor?: string;
activeColorLight?: string;
activeColorDark?: string;
inactiveColor?: string;
inactiveColorLight?: string;
inactiveColorDark?: string;
barStyle?: StyleProp<ViewStyle>;
barStyleLight?: StyleProp<ViewStyle>;
barStyleDark?: StyleProp<ViewStyle>;
};
export default class MaterialBottomTabView extends React.Component<Props> {
static contextType = ThemeContext;
_getColor = ({ route }: { route: NavigationRoute }) => {
const { descriptors } = this.props;
const descriptor = descriptors[route.key];
const options = descriptor.options;
if (this.context === 'dark' && options.tabBarColorDark) {
return options.tabBarColorDark;
} else if (options.tabBarColorLight) {
return options.tabBarColorLight;
} else {
return options.tabBarColor;
}
};
_getactiveColor = () => {
let { activeColor, activeColorLight, activeColorDark } = this.props;
if (this.context === 'dark' && activeColorDark) {
return activeColorDark;
} else if (activeColorLight) {
return activeColorLight;
} else {
return activeColor;
}
};
_getInactiveColor = () => {
let { inactiveColor, inactiveColorLight, inactiveColorDark } = this.props;
if (this.context === 'dark' && inactiveColorDark) {
return inactiveColorDark;
} else if (inactiveColorLight) {
return inactiveColorLight;
} else {
return inactiveColor;
}
};
_getBarStyle = () => {
let { barStyle, barStyleLight, barStyleDark } = this.props;
if (this.context === 'dark' && barStyleDark) {
return barStyleDark;
} else if (barStyleLight) {
return barStyleLight;
} else {
return barStyle;
}
};
_isVisible() {
const { navigation, descriptors } = this.props;
const { state } = navigation;
const route = state.routes[state.index];
const options = descriptors[route.key].options;
return options.tabBarVisible;
}
_renderIcon = ({
route,
focused,
color,
}: {
route: NavigationRoute;
focused: boolean;
color: string;
}) => {
return this.props.renderIcon({ route, focused, tintColor: color });
};
render() {
const {
navigation,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
descriptors,
...rest
} = this.props;
const activeColor = this._getactiveColor();
const inactiveColor = this._getInactiveColor();
const barStyle = this._getBarStyle();
const isVisible = this._isVisible();
const extraStyle =
typeof isVisible === 'boolean'
? { display: isVisible ? null : 'none' }
: null;
return (
<BottomNavigation
// Pass these for backward compaibility
{...rest}
activeColor={activeColor}
inactiveColor={inactiveColor}
renderIcon={this._renderIcon}
barStyle={[barStyle, extraStyle]}
navigationState={navigation.state}
getColor={this._getColor}
/>
);
}
}

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"react-navigation-material-bottom-tabs": ["./src/index"]
},
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"lib": ["esnext"],
"module": "esnext",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noImplicitUseStrict": false,
"noStrictGenericChecks": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext"
}
}

File diff suppressed because it is too large Load Diff