├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── README.md ├── example ├── bottom-toolbar-demo │ ├── .babelrc │ ├── .gitignore │ ├── .watchmanconfig │ ├── App.js │ ├── app.json │ ├── assets │ │ ├── icon.png │ │ └── splash.png │ ├── package.json │ ├── screens │ │ ├── UsageCustom.js │ │ ├── UsageWithBottomSheet.js │ │ ├── UsageWithIcons.js │ │ └── index.js │ └── yarn.lock ├── one.png ├── three.png └── two.png ├── index.js └── package.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [vonovak] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-bottom-toolbar 2 | 3 | Bottom toolbar styled as in iOS, implemented in JS, typed with Flow. Highly configurable with text or icons (I recommend `react-native-vector-icons`) and nested actions that display in ActionSheetIOS (iOS only). You can also render your own components as content. 4 | 5 | ### Expo demo 6 | 7 | [here](https://expo.io/@vonovak/bottom-toolbar-demo), code for the demo is in the `example` folder 8 | 9 | ### Installation & usage 10 | 11 | `npm i react-native-bottom-toolbar` 12 | or 13 | `yarn add react-native-bottom-toolbar` 14 | 15 | ``` 16 | import BottomToolbar from 'react-native-bottom-toolbar' 17 | 18 | 19 | 22 | console.warn(index + ' ' + JSON.stringify(propsOfThisAction))} 23 | /> 24 | 27 | console.warn(index + ' ' + JSON.stringify(propsOfThisAction))} 28 | /> 29 | 32 | console.warn(index + ' ' + JSON.stringify(propsOfThisAction))} 33 | /> 34 | 35 | ``` 36 | 37 | 38 | 39 | ### Configuration 40 | 41 | The component accepts these props: 42 | 43 | ``` 44 | type BottomToolbarProps = { 45 | IconComponent?: React.ComponentType<*>, // use this together with `color` prop and `iconName` from `BottomToolbar.Action` 46 | iconSize: number, 47 | onPress: (number, Object) => any, 48 | wrapperStyle?: ViewStyleProp, 49 | textStyle?: ViewStyleProp, 50 | buttonStyle?: ViewStyleProp, 51 | color: string, 52 | disabledColor: string, 53 | showIf: boolean, 54 | children: React.Node, 55 | }; 56 | 57 | type ActionProps = { 58 | IconElement?: React.Node, // use this to provide your own custom react element (e.g. icon with text) 59 | IconComponent?: React.ComponentType<*>, // overrides `IconComponent` from `BottomToolbar` 60 | title: string, 61 | iconName?: string, 62 | disabled?: boolean, 63 | onPress?: (number, Object) => any, 64 | color?: string, 65 | testID?: string, 66 | iconSize?: number, 67 | actionSheetTitle?: string, 68 | actionSheetMessage?: string, 69 | }; 70 | 71 | type NestedActionProps = { 72 | title: string, 73 | onPress?: (number, Object) => any, 74 | style?: 'cancel' | 'destructive', 75 | }; 76 | ``` 77 | 78 | The `onPress` function can be specified on three different levels: you may pass it as a prop to the component itself (see the first example), you may include it in the `BottomToolbar.Action` (see the first example), or may include it in the `BottomToolbar.NestedAction` (see the second example). 79 | 80 | The function has to be specified on at least one level. You may combine the levels together - the `onPress` of a `BottomToolbar.NestedAction` overrides the `onPress` of an `BottomToolbar.Action`, and the `onPress` of a `BottomToolbar.Action` overrides the `onPress` of the component. This gives you a lot of flexibility - you can have one event handler for all actions and nested actions, or you can specify the handlers separately. The `onPress` function always receives the `action` / `nested action` it was triggered from, so you can easily distinguish the event source. 81 | 82 | I suggest you pick an approach that works best for a given scenario and stick with it so you keep you code easy to understand. 83 | 84 | ### License 85 | 86 | MIT 87 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["babel-preset-expo"], 3 | "env": { 4 | "development": { 5 | "plugins": ["transform-react-jsx-source"] 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/App.js: -------------------------------------------------------------------------------- 1 | import { UsageCustom, UsageWithIcons, UsageWithBottomSheet } from './screens'; 2 | import { StackNavigator } from 'react-navigation'; 3 | 4 | export default StackNavigator({ 5 | UsageWithIcons: { 6 | screen: UsageWithIcons, 7 | }, 8 | UsageWithBottomSheet: { 9 | screen: UsageWithBottomSheet, 10 | }, 11 | UsageCustom: { 12 | screen: UsageCustom, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "bottom-toolbar-demo", 4 | "description": "This project is really great.", 5 | "slug": "bottom-toolbar-demo", 6 | "privacy": "public", 7 | "sdkVersion": "25.0.0", 8 | "platforms": ["ios", "android"], 9 | "version": "1.0.0", 10 | "orientation": "portrait", 11 | "icon": "./assets/icon.png", 12 | "splash": { 13 | "image": "./assets/splash.png", 14 | "resizeMode": "contain", 15 | "backgroundColor": "#ffffff" 16 | }, 17 | "ios": { 18 | "supportsTablet": true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vonovak/react-native-bottom-toolbar/07cd1c9626fa5aca527d183052606a4a06f4f056/example/bottom-toolbar-demo/assets/icon.png -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vonovak/react-native-bottom-toolbar/07cd1c9626fa5aca527d183052606a4a06f4f056/example/bottom-toolbar-demo/assets/splash.png -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "private": true, 4 | "dependencies": { 5 | "expo": "^25.0.0", 6 | "react": "16.2.0", 7 | "react-native": "https://github.com/expo/react-native/archive/sdk-25.0.0.tar.gz", 8 | "react-native-bottom-toolbar": "file:../../", 9 | "react-navigation": "^1.0.0-beta.29" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/bottom-toolbar-demo/screens/UsageCustom.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text, View, Button, SafeAreaView } from 'react-native'; 3 | import BottomToolbar from 'react-native-bottom-toolbar'; 4 | import { Ionicons, MaterialIcons } from '@expo/vector-icons'; 5 | import { withNavigation } from 'react-navigation'; 6 | 7 | @withNavigation 8 | export class UsageCustom extends React.Component { 9 | static navigationOptions = { 10 | title: 'Usage with Text', 11 | }; 12 | render() { 13 | return ( 14 | 15 | 16 |