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

Make drawer items extendable and support non-item contents in the drawer #251

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ import {
StackNavigation,
DrawerNavigation,
DrawerNavigationItem,
DrawerNavigationChild,
} from '@exponent/ex-navigation';

// Treat the DrawerNavigationLayout route like any other route -- you may want to set
Expand Down Expand Up @@ -554,6 +555,10 @@ class DrawerNavigationLayout extends React.Component {
/>
</DrawerNavigationItem>

<DrawerNavigationChild>
<Text style={styles.headingText}>Meta</Text>
</DrawerNavigationChild>

<DrawerNavigationItem
id='about'
selectedStyle={styles.selectedItemStyle}
Expand Down Expand Up @@ -590,6 +595,10 @@ const styles = StyleSheet.create({
height: 20
},

headingText: {
fontWeight: 'bold'
},

selectedItemStyle: {
backgroundColor: 'blue'
},
Expand Down
119 changes: 78 additions & 41 deletions example/components/DrawerNavigationExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,75 +9,106 @@ import {
StackNavigation,
DrawerNavigation,
DrawerNavigationItem,
DrawerNavigationChild,
} from '@exponent/ex-navigation';
import { Ionicons } from '@exponent/vector-icons';
import { Router } from '../main';

export default class DrawerNavigationExample extends Component {
class Heading extends DrawerNavigationChild {
renderDrawerItem() {
return (
<Text style={styles.headingText}>{this.props.title}</Text>
);
}
}

_renderHeader = () => {
class DrawerItem extends DrawerNavigationItem {
renderIcon = (isSelected: bool) => {
let extraStyle = {marginTop: 2};
if (this.props.icon === 'md-alert') {
extraStyle = {...extraStyle, marginLeft: -3};
}
return (
<View style={{height: 180, width: 300}}>
<Image source={require('../assets/sparkles.jpg')} style={styles.header} />
</View>
<Ionicons
style={[styles.icon, isSelected ? styles.selectedText : null, extraStyle]}
name={this.props.icon}
size={24}
/>
);
};

_renderTitle = (text: string, isSelected: bool) => {
renderTitle = (isSelected: bool) => {
return (
<Text style={[styles.buttonTitleText, isSelected ? styles.selectedText : null]}>
{text}
{this.props.title}
</Text>
);
};

_renderIcon = (name: string, isSelected: bool) => {
let extraStyle = {marginTop: 2};
if (name === 'md-alert') {
extraStyle = {...extraStyle, marginLeft: -3};
}
get selectedItemStyle() {
return styles.selectedItemStyle;
}

get children() {
let { defaultRouteConfig } = this.props;

return (
<Ionicons
style={[styles.icon, isSelected ? styles.selectedText : null, extraStyle]}
name={name}
size={24}
<StackNavigation
id="root"
defaultRouteConfig={defaultRouteConfig}
initialRoute={Router.getRoute('home')}
/>
);
}
}

export default class DrawerNavigationExample extends Component {
renderHeader = () => {
return (
<View style={{height: 180, width: 300}}>
<Image source={require('../assets/sparkles.jpg')} style={styles.header} />
</View>
);
};

render() {
return (
<DrawerNavigation
drawerPosition="right"
renderHeader={this._renderHeader}
renderHeader={this.renderHeader}
drawerWidth={300}
initialItem="home">
<DrawerNavigationItem
<DrawerItem
id="home"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('Examples', isSelected)}
renderIcon={isSelected => this._renderIcon('md-apps', isSelected)}>
<StackNavigation
id="root"
defaultRouteConfig={{
navigationBar: {
backgroundColor: '#0084FF',
tintColor: '#fff',
},
}}
initialRoute={Router.getRoute('home')}
/>
</DrawerNavigationItem>
<DrawerNavigationItem
icon="md-apps"
title="Examples"
defaultRouteConfig={{
navigationBar: {
backgroundColor: '#0084FF',
tintColor: '#fff',
},
}}
stack={{
id: 'root',
initialRoute: Router.getRoute('home'),
}}
/>
<Heading title="Meta" />
<DrawerItem
id="another"
selectedStyle={styles.selectedItemStyle}
renderTitle={isSelected => this._renderTitle('About', isSelected)}
renderIcon={isSelected => this._renderIcon('md-alert', isSelected)}>
<StackNavigation
id="about"
initialRoute={Router.getRoute('about')}
/>
</DrawerNavigationItem>
icon="md-alert"
title="About"
defaultRouteConfig={{
navigationBar: {
backgroundColor: '#0084FF',
tintColor: '#fff',
},
}}
stack={{
id: 'root',
initialRoute: Router.getRoute('about'),
}}
/>
</DrawerNavigation>
);
}
Expand All @@ -90,6 +121,12 @@ const styles = StyleSheet.create({
width: null,
resizeMode: 'cover',
},
headingText: {
paddingVertical: 10,
paddingHorizontal: 15,
color: '#777',
fontWeight: 'bold',
},
buttonTitleText: {
color: '#222',
fontWeight: 'bold',
Expand Down
1 change: 1 addition & 0 deletions src/ExNavigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { default as SlidingTabNavigationItem } from './sliding-tab/ExNavigationS

export { default as DrawerNavigation } from './drawer/ExNavigationDrawer';
export { default as DrawerNavigationItem } from './drawer/ExNavigationDrawerItem';
export { default as DrawerNavigationChild } from './drawer/ExNavigationDrawerChild';

export { default as NavigationBar } from './ExNavigationBar';

Expand Down
71 changes: 17 additions & 54 deletions src/drawer/ExNavigationDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
} from 'react-native';
import DrawerLayout from 'react-native-drawer-layout';
import PureComponent from '../utils/PureComponent';
import StaticContainer from 'react-static-container';

import invariant from 'invariant';
import _ from 'lodash';
Expand All @@ -22,6 +21,7 @@ import { createNavigatorComponent } from '../ExNavigationComponents';

import ExNavigationDrawerLayout from './ExNavigationDrawerLayout';
import ExNavigationDrawerItem from './ExNavigationDrawerItem';
import ExNavigationDrawerChild from './ExNavigationDrawerChild';
import type ExNavigationContext from '../ExNavigationContext';

export class ExNavigationDrawerContext extends ExNavigatorContext {
Expand Down Expand Up @@ -77,7 +77,7 @@ type Props = {
type State = {
id: string,
navigatorUID: string,
drawerItems: Array<ExNavigationDrawerItem>,
drawerItems: Array<React.Element<any>>,
parentNavigatorUID: string,
renderedItemKeys: Array<string>,
};
Expand Down Expand Up @@ -147,6 +147,7 @@ class ExNavigationDrawer extends PureComponent<any, Props, State> {
drawerPosition: this.props.drawerPosition,
width: this.props.drawerWidth,
renderNavigationView: this.props.renderNavigationView,
setActiveItem: this.setActiveItem,
style: [
this.props.drawerStyle,
],
Expand All @@ -163,7 +164,7 @@ class ExNavigationDrawer extends PureComponent<any, Props, State> {

renderContent = () => {
const items = this.state.renderedItemKeys.map(key => {
return this.state.drawerItems.find(i => i.id === key);
return this.state.drawerItems.find(i => i.props.id === key);
});

return (
Expand All @@ -173,26 +174,16 @@ class ExNavigationDrawer extends PureComponent<any, Props, State> {
);
};

renderItemContent(drawerItem: Object) {
if (!drawerItem.element) {
return null;
}

renderItemContent(drawerItem: React.Element<any>) {
const navState = this._getNavigationState();
const selectedChild = navState.routes[navState.index];
const isSelected = drawerItem.id === selectedChild.key;
const isSelected = drawerItem.props.id === selectedChild.key;

return (
<View
key={drawerItem.id}
removeClippedSubviews={!isSelected}
style={[styles.itemContentInner, {opacity: isSelected ? 1 : 0}]}
pointerEvents={isSelected ? 'auto' : 'none'}>
<StaticContainer shouldUpdate={isSelected}>
{drawerItem.element}
</StaticContainer>
</View>
);
return React.cloneElement(drawerItem, {
key: drawerItem.props.id,
isSelected,
renderTo: 'content',
});
}

componentWillMount() {
Expand Down Expand Up @@ -265,46 +256,25 @@ class ExNavigationDrawer extends PureComponent<any, Props, State> {
}

invariant(
child.type === ExNavigationDrawerItem,
'All children of DrawerNavigation must be DrawerNavigationItems.',
child.type.prototype === ExNavigationDrawerChild.prototype ||
child.type instanceof Object && ExNavigationDrawerChild.prototype.isPrototypeOf(child.type.prototype),
'All children of DrawerNavigation must be DrawerNavigationChild descendant components.'
);

const drawerItemProps = child.props;

let drawerItem = {
..._.omit(drawerItemProps, ['children']),
};

if (Children.count(drawerItemProps.children) > 0) {
drawerItem.element = Children.only(drawerItemProps.children);
}

const drawerItemOnPress = () => {
this._setActiveItem(drawerItemProps.id, index);
};

if (typeof drawerItemProps.onPress === 'function') {
drawerItem.onPress = drawerItem.onPress.bind(this, drawerItemOnPress);
} else {
drawerItem.onPress = drawerItemOnPress;
}

drawerItem.onLongPress = drawerItemProps.onLongPress;

return drawerItem;
return child;
});

this.setState({
drawerItems,
});
}

_setActiveItem(id, index) {
setActiveItem = (id) => {
this._getNavigatorContext().jumpToItem(id);
if (typeof this.props.onPress === 'function') {
this.props.onPress(id);
}
}
};

toggleDrawer = () => {
this._drawerLayout && this._drawerLayout.toggle();
Expand Down Expand Up @@ -346,11 +316,4 @@ const styles = StyleSheet.create({
itemContentOuter: {
flex: 1,
},
itemContentInner: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
});
Loading