Skip to content

Commit

Permalink
feat(navigation): Added Drawer component
Browse files Browse the repository at this point in the history
  • Loading branch information
Temzasse committed Sep 11, 2017
1 parent 3a679bd commit 0959d25
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 15 deletions.
98 changes: 98 additions & 0 deletions docs/src/components/Navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { Component } from 'react';
import {
Layout,
Gutter,
Heading,
Drawer,
Button,
ToggleSwitch,
Text,
} from 'react-components-kit';

import Properties from './common/Properties';
import CodeBlock from './common/CodeBlock';
import { drawerExample } from './codeSnippets';
import { drawerProperties } from './compProperties';

class Navigation extends Component {
state = {
drawerOpen: false,
drawerSide: 'left',
};

toggleDrawer = () => {
this.setState(prev => ({ drawerOpen: !prev.drawerOpen }));
};

toggleMenuSide = () => {
this.setState(prev => ({
drawerSide: prev.drawerSide === 'left' ? 'right' : 'left',
}));
};

render() {
const { drawerOpen, drawerSide } = this.state;

return (
<div>
<Heading>Navigation</Heading>

<Heading h2>Drawer</Heading>

<Text p>
You need to provide the menu content yourself as children
of the Drawer component.
</Text>

<Gutter vertical />

<Layout column>
<Button primary flat onClick={this.toggleDrawer}>
Open drawer
</Button>
<Gutter vertical />
<Layout align='center'>
<Text>Menu on right:</Text>
<Gutter />
<ToggleSwitch
isToggled={drawerSide === 'right'}
onToggle={this.toggleMenuSide}
/>
</Layout>
</Layout>

<Drawer
isOpen={drawerOpen}
toggleDrawer={this.toggleDrawer}
side={drawerSide}
bg='#08ffb4'
useGradient
>
<Layout column style={{ padding: 32 }}>
<Layout.Box>
Foo
</Layout.Box>
<Layout.Box>
Bar
</Layout.Box>
<Layout.Box>
Baz
</Layout.Box>
</Layout>
</Drawer>

<Gutter vertical />

<Layout>
<CodeBlock code={drawerExample} />
</Layout>

<Layout>
<Properties properties={drawerProperties} />
</Layout>
</div>
);
}
}

export default Navigation;
8 changes: 5 additions & 3 deletions docs/src/components/Sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Form from './Form';
import Utilities from './Utilities';
import Other from './Other';
import Cards from './Cards';
import Navigation from './Navigation';

const propTypes = {
something: PropTypes.any,
Expand All @@ -29,10 +30,11 @@ class Sections extends Component {
<Switch>
<Route exact path='/' component={Home} />
<Route path='/buttons' component={Buttons} />
<Route path='/typography' component={Typography} />
<Route path='/structure' component={Structure} />
<Route path='/form' component={Form} />
<Route path='/cards' component={Cards} />
<Route path='/form' component={Form} />
<Route path='/navigation' component={Navigation} />
<Route path='/structure' component={Structure} />
<Route path='/typography' component={Typography} />
<Route path='/utilities' component={Utilities} />
<Route path='/other' component={Other} />
<Route component={Home} />
Expand Down
30 changes: 18 additions & 12 deletions docs/src/components/Sidemenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ class Sidemenu extends Component {

<Gutter vertical />

<SectionTitle to='/cards'>Cards</SectionTitle>
<MenuItem to='/cards#card'>Card</MenuItem>
<MenuItem to='/cards#card-animated'>Card (animated)</MenuItem>

<Gutter vertical />


<SectionTitle to='/form'>Form</SectionTitle>
<MenuItem to='/form#textfield'>TextField</MenuItem>
<MenuItem to='/form#toggleswitch'>ToggleSwitch</MenuItem>

<Gutter vertical />

<SectionTitle to='/navigation'>Navigation</SectionTitle>
<MenuItem to='/navigation#drawer'>Drawer</MenuItem>

<Gutter vertical />

<SectionTitle to='/structure'>Structure</SectionTitle>
<MenuItem to='/structure#gutter'>Gutter</MenuItem>
<MenuItem to='/structure#divider'>Divider</MenuItem>
Expand All @@ -43,18 +61,6 @@ class Sidemenu extends Component {

<Gutter vertical />

<SectionTitle to='/form'>Form</SectionTitle>
<MenuItem to='/form#textfield'>TextField</MenuItem>
<MenuItem to='/form#toggleswitch'>ToggleSwitch</MenuItem>

<Gutter vertical />

<SectionTitle to='/cards'>Cards</SectionTitle>
<MenuItem to='/cards#card'>Card</MenuItem>
<MenuItem to='/cards#card-animated'>Card (animated)</MenuItem>

<Gutter vertical />

<SectionTitle to='/utilities'>Utilities</SectionTitle>
<MenuItem to='/utilities#badge'>Badge</MenuItem>
<MenuItem to='/utilities#circleprogress'>CircleProgress</MenuItem>
Expand Down
18 changes: 18 additions & 0 deletions docs/src/components/codeSnippets.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,21 @@ const ExampleComponent = styled.div\`
\`}
\`;
`;

export const drawerExample = `
import { Drawer } from 'react-components-kit';
const Example = () => (
<div>
<Drawer
isOpen={this.state.drawerOpen}
toggleDrawer={this.toggleDrawer}
side={this.state.drawerSide}
bg='rebeccapurple'
useGradient
>
// ... menu component goes here
</Drawer>
</div>
);
`;
37 changes: 37 additions & 0 deletions docs/src/components/compProperties.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,4 +460,41 @@ export const textFieldProperties = [
},
];

export const drawerProperties = [
{
name: 'isOpen *',
type: 'bool',
defaultVal: 'false',
description: 'Is the drawer open or not',
},
{
name: 'toggleDrawer *',
type: 'func',
description: 'Open / close the drawer',
},
{
name: 'children',
type: 'any',
description: 'Inner menu content of the drawer',
},
{
name: 'bg',
type: 'string',
defaultVal: '#fff',
description: 'background color of the drawer',
},
{
name: 'useGradient',
type: 'bool',
defaultVal: 'false',
description: 'Use a sligth gradient for the background color',
},
{
name: 'side',
type: 'string',
defaultVal: 'left',
description: 'Determines whether drawer is on the left or right side',
},
];

/* eslint-enable max-len */
124 changes: 124 additions & 0 deletions src/Drawer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import styled, { keyframes } from 'styled-components';
import color from 'color';

const ESC = 27;

class Drawer extends Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
toggleDrawer: PropTypes.func.isRequired,
side: PropTypes.oneOf(['left', 'right']),
bg: PropTypes.string,
useGradient: PropTypes.bool,
children: PropTypes.any,
};

static defaultProps = {
bg: '#fff',
side: 'right',
useGradient: false,
};

componentWillReceiveProps(nextProps) {
if (nextProps.isOpen) {
window.addEventListener('keydown', this.handleKeyDown);
} else {
window.removeEventListener('keydown', this.handleKeyDown);
}
}

handleKeyDown = ({ keyCode }) => {
if (keyCode === ESC) this.props.toggleDrawer();
}

render() {
const { children, ...rest } = this.props;

return (
<div>
<Menu {...rest}>
<Head side={rest.side}>
<CloseButton onClick={this.props.toggleDrawer}>
&times;
</CloseButton>
</Head>

{children}
</Menu>

{rest.isOpen && <Backdrop onClick={this.props.toggleDrawer} />}
</div>
);
}
}

const menuOnLeft = ({ side }) => side === 'left';
const menuOnRight = ({ side }) => side === 'right';
const getDir = ({ side }) => side === 'right' ? 1 : -1;

const fadeIn = keyframes`
from { opacity: 0; }
to { opacity: 1; }
`;

const Head = styled.div`
display: flex;
justify-content: ${props => menuOnLeft(props) ? 'flex-end' : 'flex-start'};
padding: 4px;
`;

const CloseButton = styled.button`
background: transparent;
border: 0;
font-size: 24px;
font-family: Arial, Helvetica, sans-serif;
opacity: 0.7;
transition: all 0.2s ease;
&:hover {
transform: scale(1.2);
opacity: 1;
}
`;

const Backdrop = styled.div`
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
animation: ${fadeIn} 0.4s;
z-index: 99;
`;

const Menu = styled.div`
position: fixed;
top: 0;
bottom: 0;
${props => menuOnRight(props) && 'right: 0;'}
${props => menuOnLeft(props) && 'left: 0;'}
width: 360px;
z-index: 100;
display: flex;
flex-direction: column;
box-shadow: 0px 0px 12px rgba(0,0,0,0.5);
opacity: ${props => props.isOpen ? 1 : 0};
transform: translateX(${props => props.isOpen ? 0 : getDir(props) * 360}px);
transition: transform 0.4s cubic-bezier(0.2, 0.71, 0.14, 0.91);
background: ${props => props.bg};
background: ${props => props.useGradient && `linear-gradient(
to bottom,
${props.bg} 0%,
${color(props.bg).darken(0.2).hsl().string()} 100%
)`};
@media (max-width: 400px) {
width: 300px;
transform: translateX(${props => props.isOpen ? 0 : getDir(props) * 300}px);
}
`;

export default Drawer;
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export { default as withRipple } from './withRipple';
export { default as Table } from './Table';
export { default as TextField } from './TextField';
export { default as OutsideReactor } from './OutsideReactor';
export { default as Drawer } from './Drawer';

0 comments on commit 0959d25

Please sign in to comment.