Skip to content

Commit 32a1637

Browse files
authored
Merge pull request #16 from Zetoff/feature/improving-drawers-api
better support for Drawers
2 parents 746146a + f9ec90e commit 32a1637

File tree

10 files changed

+250
-140
lines changed

10 files changed

+250
-140
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
#WIP
22

3+
#If you see me REMEMBER ME to add tests please
4+
5+
## Roadmap
6+
- [] Add tests
7+
- [] Add better support for two rows AppBars
8+
- [] Example web
9+
10+
311
material-ui-layout

src/components/AppBar/AppBar.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @flow weak
22

3+
// TODO Is this component required anymore?
4+
35
import React from 'react';
46
import PropTypes from 'prop-types';
57
import { withStyles } from 'material-ui/styles';
@@ -14,12 +16,13 @@ class AppBar extends React.PureComponent {
1416
children: PropTypes.element,
1517
position: PropTypes.string,
1618
color: PropTypes.string,
19+
className: PropTypes.string,
1720
};
1821

1922
render() {
20-
const { children, position, classes, color, ...other } = this.props;
23+
const { children, position, classes, color, className, ...other } = this.props;
2124
return (
22-
<MaterialUIAppBar position={position} color={color}>
25+
<MaterialUIAppBar position={position} color={color} className={className}>
2326
{React.cloneElement(children, { ...other })}
2427
</MaterialUIAppBar>
2528
);

src/components/Layout/Layout.jsx

Lines changed: 145 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ import PropTypes from 'prop-types';
33
import { withStyles } from 'material-ui/styles';
44
import classNames from 'classnames';
55
import Drawer from 'material-ui/Drawer';
6+
import compose from 'recompose/compose';
7+
import withWidth, { isWidthDown } from 'material-ui/utils/withWidth';
68
import controllable from 'react-controllables';
79

810
import styles from './styles';
911

1012
import AppBar from '../AppBar';
1113
import Footer from '../Footer';
1214

13-
// TODO create Layout Library
15+
// FIXME remove once material-ui drawer style is fixed
16+
const isDocked = type => type === 'permanent' || type === 'persistent';
1417

1518
class Layout extends React.PureComponent {
1619
static propTypes = {
@@ -19,73 +22,184 @@ class Layout extends React.PureComponent {
1922
children: PropTypes.element.isRequired,
2023
appBarPosition: PropTypes.string,
2124
stickyFooter: PropTypes.bool,
22-
footerContent: PropTypes.element,
2325
appBarContent: PropTypes.element,
24-
drawerOpen: PropTypes.bool.isRequired,
25-
onDrawerOpenChange: PropTypes.func,
26-
drawerContent: PropTypes.element,
2726
appBarProps: PropTypes.shape({}),
28-
drawerProps: PropTypes.shape({}),
27+
footerContent: PropTypes.element,
2928
footerProps: PropTypes.shape({}),
29+
leftDrawerOpen: PropTypes.bool.isRequired,
30+
onLeftDrawerOpenChange: PropTypes.func,
31+
leftDrawerContent: PropTypes.element,
32+
leftDrawerType: PropTypes.string,
33+
leftDrawerUnder: PropTypes.bool,
34+
leftDrawerProps: PropTypes.shape({}),
35+
rightDrawerOpen: PropTypes.bool.isRequired,
36+
onRightDrawerOpenChange: PropTypes.func,
37+
rightDrawerContent: PropTypes.element,
38+
rightDrawerType: PropTypes.string,
39+
rightDrawerUnder: PropTypes.bool,
40+
rightDrawerProps: PropTypes.shape({}),
41+
width: PropTypes.string,
3042
};
3143

3244
static defaultProps = {
3345
title: '',
34-
appBarPosition: 'default',
46+
appBarPosition: 'fixed',
3547
stickyFooter: false,
36-
drawerOpen: false,
48+
leftDrawerOpen: false,
49+
leftDrawerUnder: false,
3750
};
3851

39-
handleDrawerClose = () => {
40-
if (!this.props.onDrawerOpenChange) return;
52+
handleLeftDrawerClose = () => {
53+
if (!this.props.onLeftDrawerOpenChange) return;
4154

42-
this.props.onDrawerOpenChange(false);
55+
this.props.onLeftDrawerOpenChange(false);
4356
};
4457

45-
toggleDrawer = () => {
46-
if (!this.props.onDrawerOpenChange) return;
58+
toggleLeftDrawer = () => {
59+
if (!this.props.onLeftDrawerOpenChange) return;
4760

48-
this.props.onDrawerOpenChange(!this.props.drawerOpen);
61+
this.props.onLeftDrawerOpenChange(!this.props.leftDrawerOpen);
62+
};
63+
64+
handleRightDrawerClose = () => {
65+
if (!this.props.onRightDrawerOpenChange) return;
66+
67+
this.props.onRightDrawerOpenChange(false);
68+
};
69+
70+
toggleRightDrawer = () => {
71+
if (!this.props.onRightDrawerOpenChange) return;
72+
73+
this.props.onRightDrawerOpenChange(!this.props.rightDrawerOpen);
4974
};
5075

5176
render() {
5277
const {
5378
classes: defaultClasses,
5479
overrideClasses,
5580
children,
56-
appBarPosition,
57-
stickyFooter,
58-
footerContent,
5981
appBarContent,
60-
drawerContent,
61-
drawerOpen,
82+
appBarPosition,
6283
appBarProps,
63-
drawerProps,
84+
leftDrawerContent,
85+
leftDrawerOpen,
86+
leftDrawerType,
87+
leftDrawerUnder,
88+
leftDrawerProps,
89+
rightDrawerContent,
90+
rightDrawerOpen,
91+
rightDrawerType,
92+
rightDrawerUnder,
93+
rightDrawerProps,
94+
footerContent,
95+
stickyFooter,
6496
footerProps,
97+
width,
6598
} = this.props;
6699

100+
// TODO change the way to overrideClasses
101+
// use classes insted of overrideClasses as material-ui
67102
const classes = { ...defaultClasses, ...overrideClasses };
68103

69-
const mainClassnames = classNames(
70-
classes.main,
71-
{ [`${classes.mainFixedAppBar}`]: appBarPosition === 'fixed' },
72-
{ [`${classes.mainStickyFooter}`]: stickyFooter },
73-
);
104+
const smallScreen = isWidthDown('xs', width);
105+
106+
const mainLeftShift =
107+
!smallScreen &&
108+
(leftDrawerType === 'permanent' ||
109+
(leftDrawerOpen && leftDrawerType === 'persistent'));
110+
111+
const mainRightShift =
112+
!smallScreen &&
113+
(rightDrawerType === 'permanent' ||
114+
(rightDrawerOpen && rightDrawerType === 'persistent'));
115+
116+
const mainClassnames = classNames(classes.main, {
117+
[`${classes.mainFixedAppBar}`]: appBarPosition === 'fixed',
118+
[`${classes.mainStickyFooter}`]: stickyFooter,
119+
[`${classes.mainShift}`]: mainLeftShift || mainRightShift,
120+
[`${classes.mainLeftShift}`]: mainLeftShift,
121+
[`${classes.mainRightShift}`]: mainRightShift,
122+
[`${classes.mainLeftRightShift}`]: mainLeftShift && mainRightShift,
123+
});
124+
125+
const appBarLeftShift =
126+
!smallScreen &&
127+
(!leftDrawerUnder &&
128+
((leftDrawerOpen && leftDrawerType === 'persistent') ||
129+
leftDrawerType === 'permanent'));
130+
131+
const appBarRightShift =
132+
!smallScreen &&
133+
(!rightDrawerUnder &&
134+
((rightDrawerOpen && rightDrawerType === 'persistent') ||
135+
rightDrawerType === 'permanent'));
136+
137+
const appBarClassnames = classNames(classes.appBar, {
138+
[`${classes.appBarShift}`]: appBarLeftShift || appBarRightShift,
139+
[`${classes.appBarLeftShift}`]: appBarLeftShift,
140+
[`${classes.appBarRightShift}`]: appBarRightShift,
141+
[`${classes.appBarLeftRightShift}`]: appBarLeftShift && appBarRightShift,
142+
});
143+
144+
const leftDrawerPaperClassnames = classNames(classes.drawerPaper, {
145+
[`${classes.drawerPaperUnder}`]: !smallScreen && leftDrawerUnder,
146+
});
147+
console.log(isDocked(rightDrawerType));
148+
const rightDrawerPaperClassnames = classNames(classes.drawerPaper, {
149+
[`${classes.drawerPaperUnder}`]: !smallScreen && rightDrawerUnder,
150+
[`${classes.rightDrawerDockedFix}`]: isDocked(rightDrawerType), // FIXME remove once material-ui drawer style is fixed
151+
});
152+
74153
return (
75154
<div className={classes.layout}>
76-
<AppBar {...appBarProps} position={appBarPosition} onIconClick={this.toggleDrawer}>
155+
<AppBar
156+
position={appBarPosition}
157+
toggleLeftDrawer={this.toggleLeftDrawer}
158+
toggleRightDrawer={this.toggleRightDrawer}
159+
className={appBarClassnames}
160+
{...appBarProps}
161+
>
77162
{appBarContent}
78163
</AppBar>
79-
{drawerContent ? (
80-
<Drawer {...drawerProps} open={drawerOpen} onRequestClose={this.handleDrawerClose}>
81-
{drawerContent}
164+
{leftDrawerContent ? (
165+
<Drawer
166+
open={leftDrawerOpen}
167+
onRequestClose={this.handleLeftDrawerClose}
168+
type={!smallScreen && leftDrawerType}
169+
classes={{ paper: leftDrawerPaperClassnames }}
170+
{...leftDrawerProps}
171+
>
172+
{!smallScreen && leftDrawerUnder ? (
173+
<div className={classes.drawerHeader} />
174+
) : null}
175+
{leftDrawerContent}
176+
</Drawer>
177+
) : null}
178+
{rightDrawerContent ? (
179+
<Drawer
180+
anchor="right"
181+
open={rightDrawerOpen}
182+
onRequestClose={this.handleRightDrawerClose}
183+
type={!smallScreen && rightDrawerType}
184+
classes={{ paper: rightDrawerPaperClassnames }}
185+
{...rightDrawerProps}
186+
>
187+
{!smallScreen && rightDrawerUnder ? (
188+
<div className={classes.drawerHeader} />
189+
) : null}
190+
{rightDrawerContent}
82191
</Drawer>
83192
) : null}
84193
<main className={mainClassnames}>{children}</main>
85-
{footerContent ? <Footer {...footerProps}>{footerContent}</Footer> : null}
194+
{footerContent ? (
195+
<Footer {...footerProps}>{footerContent}</Footer>
196+
) : null}
86197
</div>
87198
);
88199
}
89200
}
90201

91-
export default controllable(withStyles(styles)(Layout), ['drawerOpen']);
202+
export default controllable(compose(withStyles(styles), withWidth())(Layout), [
203+
'leftDrawerOpen',
204+
'rightDrawerOpen',
205+
]);

src/components/Layout/styles.js

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,87 @@
1-
const styles = {
1+
// TODO curry drawerWidth?
2+
const drawerWidth = 240;
3+
4+
const styles = theme => ({
25
layout: {
36
display: 'flex',
47
minHeight: '100vh',
58
flexDirection: 'column',
69
},
10+
appBar: {
11+
transition: theme.transitions.create(['margin', 'width'], {
12+
easing: theme.transitions.easing.sharp,
13+
duration: theme.transitions.duration.leavingScreen,
14+
}),
15+
},
16+
appBarShift: {
17+
transition: theme.transitions.create(['margin', 'width'], {
18+
easing: theme.transitions.easing.easeOut,
19+
duration: theme.transitions.duration.enteringScreen,
20+
}),
21+
},
22+
appBarLeftShift: {
23+
marginLeft: drawerWidth,
24+
width: `calc(100% - ${drawerWidth}px)`,
25+
},
26+
appBarRightShift: {
27+
marginRight: drawerWidth,
28+
width: `calc(100% - ${drawerWidth}px)`,
29+
},
30+
appBarLeftRightShift: {
31+
marginLeft: drawerWidth,
32+
marginRight: drawerWidth,
33+
width: `calc(100% - ${drawerWidth * 2}px)`,
34+
},
735
main: {
836
paddingTop: '0px',
937
display: 'flex',
38+
transition: theme.transitions.create(['margin'], {
39+
easing: theme.transitions.easing.sharp,
40+
duration: theme.transitions.duration.leavingScreen,
41+
}),
42+
backgroundColor: 'red',
1043
},
1144
mainFixedAppBar: {
12-
marginTop: '64px',
45+
marginTop: 56,
46+
},
47+
[theme.breakpoints.up('sm')]: {
48+
mainFixedAppBar: {
49+
marginTop: 64,
50+
},
1351
},
1452
mainStickyFooter: {
1553
flex: 1,
1654
},
17-
'@media (max-width: 599px)': {
18-
mainFixedAppBar: {
19-
marginTop: '56px',
20-
},
55+
mainShift: {
56+
transition: theme.transitions.create(['margin'], {
57+
easing: theme.transitions.easing.easeOut,
58+
duration: theme.transitions.duration.enteringScreen,
59+
}),
60+
},
61+
mainLeftShift: {
62+
marginLeft: drawerWidth,
63+
width: `calc(100% - ${drawerWidth}px)`,
64+
},
65+
mainRightShift: {
66+
marginRight: drawerWidth,
67+
width: `calc(100% - ${drawerWidth}px)`,
68+
},
69+
mainLeftRightShift: {
70+
marginRight: drawerWidth,
71+
marginLeft: drawerWidth,
72+
width: `calc(100% - ${drawerWidth * 2}px)`,
73+
},
74+
drawerPaper: {
75+
width: drawerWidth,
76+
},
77+
drawerPaperUnder: {
78+
zIndex: '1000',
79+
},
80+
drawerHeader: theme.mixins.toolbar,
81+
rightDrawerDockedFix: {
82+
borderLeft: `1px solid ${theme.palette.text.divider}`,
83+
borderRight: 'none',
2184
},
22-
};
85+
});
2386

2487
export default styles;

0 commit comments

Comments
 (0)