mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-11 17:30:51 +08:00
refactor: upgrade
BREAKING CHANGE: change activeTintColor -> activeColor
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
node_modules/
|
||||
flow-typed/
|
||||
dist/
|
||||
|
||||
# generated by bob
|
||||
lib/
|
||||
|
||||
@@ -3,8 +3,18 @@
|
||||
|
||||
"plugins": ["react-native-globals"],
|
||||
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
|
||||
"env": {
|
||||
"es6": true,
|
||||
"react-native-globals/all": true,
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"import/named": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
4
packages/material-bottom-tabs/.gitignore
vendored
4
packages/material-bottom-tabs/.gitignore
vendored
@@ -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/
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
5
packages/material-bottom-tabs/commitlint.config.js
Normal file
5
packages/material-bottom-tabs/commitlint.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/* eslint-disable import/no-commonjs */
|
||||
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
};
|
||||
@@ -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',
|
||||
},
|
||||
});
|
||||
@@ -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
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
|
||||
29
packages/material-bottom-tabs/example/metro.config.js
Normal file
29
packages/material-bottom-tabs/example/metro.config.js
Normal 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,
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/*`)]);
|
||||
},
|
||||
};
|
||||
@@ -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}`
|
||||
);
|
||||
@@ -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;
|
||||
@@ -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
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* @flow */
|
||||
|
||||
export {
|
||||
default as createMaterialBottomTabNavigator,
|
||||
} from './navigators/createMaterialBottomTabNavigator';
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
26
packages/material-bottom-tabs/tsconfig.json
Normal file
26
packages/material-bottom-tabs/tsconfig.json
Normal 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
Reference in New Issue
Block a user