Skip to content

Commit 0277719

Browse files
committed
Merge pull request react-toolbox#313 from patrick-jones/sidenav-283
Make drawer compliant with material design guidelines.
2 parents 48e5c48 + 6e586a9 commit 0277719

File tree

15 files changed

+981
-0
lines changed

15 files changed

+981
-0
lines changed

components/_globals.scss

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,31 @@ $z-index-high: 100 !default;
5353
$z-index-normal: 1 !default;
5454
$z-index-low: -100 !default;
5555
$z-index-lower: -200 !default;
56+
57+
58+
//-- Breakpoints
59+
// height of app bar
60+
// https://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
61+
$standard-increment-mobile: (5.6 * $unit) !default;
62+
$standard-increment-desktop: (6.4 * $unit) !default;
63+
64+
// https://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-baseline-grids
65+
$baseline-grid: (0.8 * $unit) !default;
66+
$layout-gutter-width-sm: ($baseline-grid * 2) !default;
67+
$layout-gutter-width: ($baseline-grid * 3) !default;
68+
69+
70+
// https://www.google.com/design/spec/layout/responsive-ui.html#responsive-ui-breakpoints
71+
// 4 columns
72+
$layout-breakpoint-xxs: 480px !default;
73+
// 8 columns
74+
$layout-breakpoint-xs: 600px !default;
75+
// 12 columns
76+
$layout-breakpoint-sm-tablet: 720px !default;
77+
$layout-breakpoint-sm: 840px !default;
78+
$layout-breakpoint-md: 960px !default;
79+
$layout-breakpoint-lg-tablet: 1024px !default;
80+
$layout-breakpoint-lg: 1280px !default;
81+
$layout-breakpoint-xl: 1440px !default;
82+
$layout-breakpoint-xxl: 1600px !default;
83+
$layout-breakpoint-xxxl: 1920px !default;

components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export Dropdown from './dropdown';
1313
export FontIcon from './font_icon';
1414
export Form from './form';
1515
export Input from './input';
16+
export { Layout, NavDrawer, Panel, Sidebar } from './layout';
1617
export Link from './link';
1718
export List from './list/List';
1819
export ListItem from './list/ListItem';

components/layout/Layout.jsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import ClassNames from 'classnames';
3+
import style from './style';
4+
5+
6+
const Layout = (props) => {
7+
const className = ClassNames(style.root, props.className);
8+
9+
return (
10+
<div data-react-toolbox='layout' className={className}>
11+
{props.children}
12+
</div>
13+
);
14+
};
15+
16+
const ALLOWED = [
17+
'Panel',
18+
'NavDrawer|Panel',
19+
'NavDrawer|Panel|Sidebar',
20+
'Panel|Sidebar'
21+
];
22+
23+
function getChildName (child) {
24+
if (child.type) {
25+
return child.type.name || child.type;
26+
}
27+
if (!child.constructor || !child.constructor.name) {
28+
return 'UNKNOWN';
29+
}
30+
return child.constructor.name;
31+
}
32+
33+
Layout.propTypes = {
34+
children (props, propName, componentName) {
35+
// Accept only [NavDrawer]Pane[Sidebar]
36+
const children = props[propName];
37+
if (React.Children.count(children) > 3) {
38+
return new Error(
39+
'`' + componentName + '` ' +
40+
'should have a Pane for a child, optionally preceded and/or followed by a Drawer.'
41+
);
42+
}
43+
44+
const names = React.Children.map(children, getChildName).join('|');
45+
46+
if (!(~ALLOWED.indexOf(names))) {
47+
return new Error(
48+
'`' + componentName + '` ' +
49+
'should have a Panel for a child, optionally preceded by a NavDrawer and/or followed by a Sidebar.'
50+
);
51+
}
52+
},
53+
className: React.PropTypes.string
54+
};
55+
56+
Layout.defaultProps = {
57+
className: ''
58+
};
59+
60+
export default Layout;

components/layout/NavDrawer.jsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import ClassNames from 'classnames';
3+
import style from './style';
4+
5+
const NavDrawer = (props) => {
6+
7+
const rootClasses = ClassNames([style.navDrawer], {
8+
[style['permanent-' + props.permanentAt]]: props.permanentAt,
9+
[style.wide]: (props.width === 'wide'),
10+
[style.active]: props.active,
11+
[style.pinned]: props.pinned
12+
}, props.className);
13+
14+
const drawerClasses = ClassNames(style.drawerContent, {
15+
[style.scrollY]: props.scrollY
16+
});
17+
18+
return (
19+
<div data-react-toolbox='nav-drawer' className={rootClasses} onClick={props.onOverlayClick}>
20+
<div data-react-toolbox='nav-drawer-scrim' className={style.scrim}>
21+
<aside data-react-toolbox='nav-drawer-content' className={drawerClasses}>
22+
{props.children}
23+
</aside>
24+
</div>
25+
</div>
26+
);
27+
};
28+
29+
NavDrawer.propTypes = {
30+
active: React.PropTypes.bool,
31+
children: React.PropTypes.any,
32+
className: React.PropTypes.string,
33+
onOverlayClick: React.PropTypes.func,
34+
permanentAt: React.PropTypes.oneOf(['sm', 'md', 'lg', 'xl', 'xxl', 'xxxl']),
35+
pinned: React.PropTypes.bool,
36+
scrollY: React.PropTypes.bool,
37+
width: React.PropTypes.oneOf(['normal', 'wide'])
38+
};
39+
40+
NavDrawer.defaultProps = {
41+
active: false,
42+
className: '',
43+
scrollY: false,
44+
width: 'normal'
45+
};
46+
47+
export default NavDrawer;

components/layout/Panel.jsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import ClassNames from 'classnames';
3+
import style from './style';
4+
5+
const Panel = (props) => {
6+
const className = ClassNames(style.panel, {
7+
[style.scrollY]: props.scrollY
8+
}, props.className);
9+
10+
return (
11+
<div data-react-toolbox='panel' className={className}>
12+
{props.children}
13+
</div>
14+
);
15+
};
16+
17+
Panel.propTypes = {
18+
children: React.PropTypes.any,
19+
className: React.PropTypes.string,
20+
scrollY: React.PropTypes.bool
21+
};
22+
23+
Panel.defaultProps = {
24+
className: '',
25+
scrollY: false
26+
};
27+
28+
export default Panel;

components/layout/Sidebar.jsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from 'react';
2+
import ClassNames from 'classnames';
3+
import style from './style';
4+
5+
const Sidebar = (props) => {
6+
const wrapperClasses = ClassNames(style.sidebar, style[`width-${props.width}`], {
7+
[style.pinned]: props.pinned
8+
}, props.className);
9+
10+
const innerClasses = ClassNames(style.sidebarContent, {
11+
[style.scrollY]: props.scrollY
12+
});
13+
14+
return (
15+
<div data-react-toolbox='sidebar' className={wrapperClasses}>
16+
<aside data-react-toolbox='sidebar-content' className={innerClasses}>
17+
{props.children}
18+
</aside>
19+
</div>
20+
);
21+
};
22+
23+
Sidebar.propTypes = {
24+
children: React.PropTypes.any,
25+
className: React.PropTypes.string,
26+
pinned: React.PropTypes.bool,
27+
scrollY: React.PropTypes.bool,
28+
width: React.PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 33, 50, 66, 75, 100])
29+
};
30+
31+
Sidebar.defaultProps = {
32+
className: '',
33+
pinned: false,
34+
scrollY: false,
35+
width: 5
36+
};
37+
38+
export default Sidebar;

components/layout/_config.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
$drawer-background-color: $palette-grey-50 !default;
2+
$drawer-border-color: $palette-grey-300 !default;
3+
$drawer-text-color: $palette-grey-800 !default;
4+
5+
$drawer-overlay-color: $color-black !default;
6+
$drawer-overlay-opacity: .6 !default;
7+
8+
9+
// from: https://www.google.com/design/spec/layout/structure.html#structure-side-nav
10+
$navigation-drawer-desktop-width: 5 * $standard-increment-desktop !default;
11+
$navigation-drawer-max-desktop-width: 40 * $unit !default;
12+
// Mobile:
13+
// Width = Screen width − 56 dp
14+
// Maximum width: 320dp
15+
$navigation-drawer-mobile-width: 5 * $standard-increment-mobile !default;
16+
// sass doesn't like use of variable here: calc(100% - $standard-increment-mobile);
17+
$navigation-drawer-max-mobile-width: calc(100% - 5.6rem) !default;

components/layout/_mixins.scss

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
@mixin open() {
3+
transition-delay: $animation-delay;
4+
& > .scrim {
5+
& > .drawerContent {
6+
pointer-events: all;
7+
transition-delay: $animation-delay;
8+
transform: translateX(0);
9+
}
10+
}
11+
}
12+
13+
@mixin permanent() {
14+
@include open();
15+
16+
width: $navigation-drawer-desktop-width;
17+
max-width: $navigation-drawer-desktop-width;
18+
19+
&.wide {
20+
width: $navigation-drawer-max-desktop-width;
21+
max-width: $navigation-drawer-max-desktop-width;
22+
}
23+
24+
&.active {
25+
& > .scrim {
26+
width: 0;
27+
background-color: rgba($drawer-overlay-color, 0);
28+
}
29+
}
30+
}

components/layout/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { default as Layout } from './Layout.jsx';
2+
export { default as Panel } from './Panel.jsx';
3+
export { default as NavDrawer } from './NavDrawer.jsx';
4+
export { default as Sidebar } from './Sidebar.jsx';

0 commit comments

Comments
 (0)