diff --git a/example/main.js b/example/main.js
index 0929692..5fb36cf 100644
--- a/example/main.js
+++ b/example/main.js
@@ -2,32 +2,87 @@
import Exponent from 'exponent';
import React, { Component } from 'react';
+import {
+ View,
+ StyleSheet,
+ Platform,
+} from 'react-native';
import {
NavigationProvider,
StackNavigation,
} from '@exponent/ex-navigation';
-import { Colors, ThemeProvider } from 'react-native-paper';
+import { Colors, ThemeProvider, Drawer } from 'react-native-paper';
import Router from './src/Router';
+
+const DrawerItems = [
+ { label: 'Inbox', icon: 'inbox', key: 0 },
+ { label: 'Starred', icon: 'star', key: 1 },
+ { label: 'Sent mail', icon: 'send', key: 2 },
+ { label: 'A very long title that will be truncated', icon: 'delete', key: 3 },
+ { label: 'No Icon', key: 4 },
+];
+
class App extends Component {
+ state = {
+ open: false,
+ drawerItemIndex: 0,
+ }
+
+ _handleOpenDrawer = () => this.setState({ open: true })
+
+ _handleCloseDrawer = () => this.setState({ open: false })
+
+ _setDrawerItem = index => this.setState({ drawerItemIndex: index })
+
+ _renderDrawerItems = () => {
+ return (
+
+
+ {DrawerItems.map((props, index) => (
+ this._setDrawerItem(index)}
+ />))}
+
+
+ );
+ };
+
render() {
return (
-
+
+
+
);
}
}
+const styles = StyleSheet.create({
+ drawerContent: {
+ flex: 1,
+ marginTop: Platform.OS === 'android' ? 25 : 22,
+ },
+});
+
Exponent.registerRootComponent(App);
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..cf850cb
--- /dev/null
+++ b/index.js
@@ -0,0 +1,23 @@
+/* @flow */
+
+export { default as ThemeProvider } from './src/core/ThemeProvider';
+export { default as withTheme } from './src/core/withTheme';
+
+export * as Colors from './src/styles/colors';
+
+export { default as Button } from './src/components/Button';
+export { default as Card } from './src/components/Card';
+export { default as Checkbox } from './src/components/Checkbox';
+export { default as Paper } from './src/components/Paper';
+export { default as RadioButton } from './src/components/RadioButton';
+export { default as TouchableRipple } from './src/components/TouchableRipple';
+
+export { default as Drawer } from './src/components/Drawer';
+export { default as Divider } from './src/components/Divider';
+
+export { default as Caption } from './src/components/Typography/Caption';
+export { default as Headline } from './src/components/Typography/Headline';
+export { default as Paragraph } from './src/components/Typography/Paragraph';
+export { default as Subheading } from './src/components/Typography/Subheading';
+export { default as Title } from './src/components/Typography/Title';
+export { default as Text } from './src/components/Typography/Text';
diff --git a/package.json b/package.json
index 40bf968..5d47ec5 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"react-native-vector-icons": "~3.0.0"
},
"dependencies": {
- "color": "^0.11.4"
+ "color": "^0.11.4",
+ "react-native-drawer": "^2.3.0"
}
}
diff --git a/src/components/Drawer/Drawer.js b/src/components/Drawer/Drawer.js
new file mode 100644
index 0000000..d56014d
--- /dev/null
+++ b/src/components/Drawer/Drawer.js
@@ -0,0 +1,142 @@
+/* @flow */
+
+import RNDrawer from 'react-native-drawer';
+import React, {
+ Component,
+ PropTypes,
+} from 'react';
+import { View, StyleSheet } from 'react-native';
+import DrawerItem from './DrawerItem';
+import DrawerSection from './DrawerSection';
+import { white } from '../../styles/colors';
+
+type Props = {
+ children?: any;
+ content?: any;
+ locked?: boolean;
+ onClose?: Function;
+ onOpen?: Function;
+ open?: boolean;
+ swipeRatio?: number;
+ style?: any;
+ side?: string;
+ width?: number;
+}
+
+type DefaultProps = {
+ locked: boolean;
+ open: boolean;
+ swipeRatio: number;
+ side: string;
+}
+
+class Drawer extends Component {
+ static Item = DrawerItem;
+ static Section = DrawerSection;
+
+ static propTypes = {
+ children: PropTypes.node.isRequired,
+ content: PropTypes.node.isRequired,
+ /*
+ Specifies the lock mode of the drawer. The drawer can be locked in 2 states:
+ - false, meaning that the drawer will respond (open/close) to touch gestures
+ - true, meaning that the drawer won't respond to touch gestures but it can be open by passing prop `open`
+ */
+ locked: PropTypes.bool,
+ onClose: PropTypes.func,
+ onOpen: PropTypes.func,
+ open: PropTypes.bool,
+ /* Ratio of screen width that is valid for the start of a pan open action */
+ swipeRatio: PropTypes.number,
+ width: PropTypes.number,
+ style: View.propTypes.style,
+ side: PropTypes.oneOf([ 'left', 'right' ]),
+ }
+
+ static defaultProps = {
+ side: 'left',
+ locked: false,
+ open: false,
+ swipeRatio: 0.05,
+ }
+
+ _root: any;
+
+ _tweenHandler = ratio => ({
+ main: {
+ opacity: 1,
+ },
+ mainOverlay: {
+ opacity: ratio / 2,
+ backgroundColor: 'black',
+ },
+ })
+
+ _handleClose = () => {
+ if (this.props.onClose) {
+ this.props.onClose();
+ }
+ global.requestAnimationFrame(() => {
+ if (this.props.open === false) {
+ return;
+ } else {
+ this._root.open();
+ }
+ });
+ }
+
+ _handleOpen = () => {
+ if (this.props.onOpen) {
+ this.props.onOpen();
+ }
+ global.requestAnimationFrame(() => {
+ if (this.props.open === true) {
+ return;
+ } else {
+ this._root.close();
+ }
+ });
+ }
+
+ _calculateOpenDrawerOffset = viewport => this.props.width ?
+ (viewport.width - this.props.width) :
+ (viewport.width - ((viewport.width * 80) / 100))
+
+ render(): ?React.Element {
+ const {
+ children,
+ content,
+ style,
+ side,
+ locked,
+ open,
+ swipeRatio,
+ } = this.props;
+
+ return (
+ (this._root = c)}
+ tapToClose
+ captureGestures
+ negotiatePan
+ acceptPan={!locked}
+ type='overlay'
+ tweenEasing='easeInQuad'
+ content={content}
+ open={open}
+ openDrawerOffset={this._calculateOpenDrawerOffset}
+ panOpenMask={swipeRatio}
+ onClose={this._handleClose}
+ onOpen={this._handleOpen}
+ tweenHandler={this._tweenHandler}
+ side={side}
+ styles={{ drawer: StyleSheet.flatten({ backgroundColor: white }, style) }}
+ >
+ {children}
+
+ );
+ }
+}
+
+export default Drawer;
diff --git a/src/components/Drawer/DrawerItem.js b/src/components/Drawer/DrawerItem.js
new file mode 100644
index 0000000..a8f0971
--- /dev/null
+++ b/src/components/Drawer/DrawerItem.js
@@ -0,0 +1,61 @@
+/* @flow */
+
+import color from 'color';
+import React, {
+ PropTypes,
+} from 'react';
+import { View, Text, StyleSheet } from 'react-native';
+import Icon from '.././Icon';
+import TouchableRipple from '../TouchableRipple';
+import { grey300 } from '../../styles/colors';
+import withTheme from '../../core/withTheme';
+import type { Theme } from '../../types/Theme';
+
+type Props = {
+ icon?: string;
+ label: string;
+ active?: boolean;
+ onPress?: Function;
+ theme: Theme;
+}
+
+const DrawerItem = ({ icon, label, active, onPress, theme, ...props }: Props) => {
+ const { colors } = theme;
+ const labelColor = active ? colors.primary : color(colors.text).alpha(0.87).rgbaString();
+ const iconColor = active ? colors.primary : color(colors.text).alpha(0.54).rgbaString();
+ const fontFamily = theme.fonts.medium;
+ const labelMargin = icon ? 32 : 0;
+ return (
+
+
+ { icon &&
+ }
+ {label}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ wrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingHorizontal: 16,
+ paddingVertical: 16,
+ height: 48,
+ },
+});
+
+DrawerItem.propTypes = {
+ icon: PropTypes.string,
+ label: PropTypes.string.isRequired,
+ active: PropTypes.bool,
+ onPress: PropTypes.func,
+ theme: PropTypes.object.isRequired,
+};
+
+export default withTheme(DrawerItem);
diff --git a/src/components/Drawer/DrawerSection.js b/src/components/Drawer/DrawerSection.js
new file mode 100644
index 0000000..4d84f7f
--- /dev/null
+++ b/src/components/Drawer/DrawerSection.js
@@ -0,0 +1,39 @@
+/* @flow */
+
+import color from 'color';
+import React, { PropTypes } from 'react';
+import { View, Text } from 'react-native';
+import Divider from '../Divider';
+import withTheme from '../../core/withTheme';
+import type { Theme } from '../../types/Theme';
+
+type Props = {
+ children: any;
+ label?: string;
+ theme: Theme;
+}
+
+const DrawerSection = ({ children, label, theme, ...props }: Props) => {
+ const { colors, fonts } = theme;
+ const labelColor = color(colors.text).alpha(0.54).rgbaString();
+ const fontFamily = fonts.medium;
+
+ return (
+
+ { label &&
+
+ {label}
+ }
+ {children}
+
+
+ );
+};
+
+DrawerSection.propTypes = {
+ children: PropTypes.node.isRequired,
+ label: PropTypes.string,
+ theme: PropTypes.object.isRequired,
+};
+
+export default withTheme(DrawerSection);
diff --git a/src/components/Drawer/index.js b/src/components/Drawer/index.js
new file mode 100644
index 0000000..84d04bd
--- /dev/null
+++ b/src/components/Drawer/index.js
@@ -0,0 +1,3 @@
+/* @flow */
+
+export { default as default } from './Drawer';
diff --git a/src/index.js b/src/index.js
index 9ec2313..76c5e26 100644
--- a/src/index.js
+++ b/src/index.js
@@ -20,3 +20,4 @@ export { default as Title } from './components/Typography/Title';
export { default as Text } from './components/Typography/Text';
export { default as Divider } from './components/Divider';
+export { default as Drawer } from './components/Drawer';