Skip to content

Commit

Permalink
feat(Dialog): add new Dialog component (#8)
Browse files Browse the repository at this point in the history
* feat(Dialog): create new component

* docs: update list example to use List component

* feat(Dialog): no need for onClose event, there is already full controll from buttons

* feat(Dialog) export dialog in main index
  • Loading branch information
cayasso authored and kradio3 committed Mar 21, 2017
1 parent a3c3816 commit 250cad6
Show file tree
Hide file tree
Showing 15 changed files with 364 additions and 10 deletions.
3 changes: 3 additions & 0 deletions docs/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ linkPrefix = "/react-mdc-web"
[[components]]
name = "Checkbox"
path = "/components/checkbox/"
[[components]]
name = "Dialog"
path = "/components/dialog/"
[[components]]
name = "Drawer"
path = "/components/drawer/"
Expand Down
6 changes: 6 additions & 0 deletions docs/css/mdc.dialog.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 11 additions & 10 deletions docs/pages/_template.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { colors, activeColors } from 'utils/colors'

import typography from 'utils/typography'
import { config } from 'config'
import {
import {
Drawer,
DrawerSpacer,
Navigation,
Expand All @@ -21,6 +21,7 @@ import Content from 'components/Content';
// Import styles.
import '../../node_modules/material-components-web/dist/material-components-web.css';
import 'prismjs/themes/prism-okaidia.css'
import 'css/mdc.dialog.min.css'
import 'css/main.css'

const { rhythm, adjustFontSizeTo } = typography
Expand All @@ -34,12 +35,12 @@ module.exports = React.createClass({
render () {
const isIntroductionActive = this.props.location.pathname===prefixLink('/');
const isThemingActive = this.props.location.pathname===prefixLink('/theming/');
const componentLinks = config.components.map(({name, path}) => {
const componentLinks = config.components.map(({name, path}) => {
const isActive = this.props.location.pathname===prefixLink(path);
return (
<Link
<Link
key={name}
to={prefixLink(path)}
to={prefixLink(path)}
selected={ isActive }
>
{name}
Expand Down Expand Up @@ -69,20 +70,20 @@ module.exports = React.createClass({
</a>
</Toolbar>
<Content>
<Drawer
permanent
<Drawer
permanent
style={{height: 'inherit', minHeight: '100%'}}
>
<ListGroup>
<Navigation>
<Link
to={prefixLink('/')}
<Link
to={prefixLink('/')}
selected={ isIntroductionActive }
>
{'Introduction'}
</Link>
<Link
to={prefixLink('/theming/')}
<Link
to={prefixLink('/theming/')}
selected={ isThemingActive }
>
{'Theming'}
Expand Down
56 changes: 56 additions & 0 deletions docs/pages/components/dialog/Scrollable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, {PropTypes} from 'react'
import Dialog from '../../../../src/Dialog/Dialog'
import DialogBody from '../../../../src/Dialog/DialogBody'
import DialogTitle from '../../../../src/Dialog/DialogTitle'
import DialogHeader from '../../../../src/Dialog/DialogHeader'
import DialogFooter from '../../../../src/Dialog/DialogFooter'
import Button from '../../../../src/Button/Button'
import List from '../../../../src/List/List'
import ListItem from '../../../../src/List/ListItem'

class Standard extends React.PureComponent {

constructor(props){
super(props);
this.state={isOpen: false};
}

render () {
return (
<div>
<Button
primary
raised
onClick={()=> { this.setState({isOpen: !this.state.isOpen}) }}
>
Show dialog
</Button>
<Dialog open={this.state.isOpen}>
<DialogHeader>
<DialogTitle>Choose a Ringtone</DialogTitle>
</DialogHeader>
<DialogBody scrollable>
<List>
<ListItem>None</ListItem>
<ListItem>Callisto</ListItem>
<ListItem>Ganymede</ListItem>
<ListItem>Luna</ListItem>
<ListItem>Marimba</ListItem>
<ListItem>Schwifty</ListItem>
<ListItem>Callisto</ListItem>
<ListItem>Ganymede</ListItem>
<ListItem>Luna</ListItem>
<ListItem>Marimba</ListItem>
<ListItem>Schwifty</ListItem>
</List>
</DialogBody>
<DialogFooter>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Cancel</Button>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Accept</Button>
</DialogFooter>
</Dialog>
</div>
)
}
}
export default Standard;
42 changes: 42 additions & 0 deletions docs/pages/components/dialog/Standard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, {PropTypes} from 'react'
import Dialog from '../../../../src/Dialog/Dialog'
import DialogBody from '../../../../src/Dialog/DialogBody'
import DialogTitle from '../../../../src/Dialog/DialogTitle'
import DialogHeader from '../../../../src/Dialog/DialogHeader'
import DialogFooter from '../../../../src/Dialog/DialogFooter'
import Button from '../../../../src/Button/Button'

class Standard extends React.PureComponent {

constructor(props){
super(props);
this.state={isOpen: false};
}

render () {
return (
<div>
<Button
primary
raised
onClick={()=> { this.setState({isOpen: !this.state.isOpen}) }}
>
Show dialog
</Button>
<Dialog open={this.state.isOpen}>
<DialogHeader>
<DialogTitle>Use Google's location service?</DialogTitle>
</DialogHeader>
<DialogBody>
Let Google help apps determine location.
</DialogBody>
<DialogFooter>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Decline</Button>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Accept</Button>
</DialogFooter>
</Dialog>
</div>
)
}
}
export default Standard;
28 changes: 28 additions & 0 deletions docs/pages/components/dialog/_template.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, {PropTypes} from 'react'
import ReactDOM from 'react-dom'
import Standard from './Standard'
import Scrollable from './Scrollable'

class Template extends React.PureComponent {

static propTypes = {
children: PropTypes.node,
}

componentDidMount() {
const standard = document.getElementById("simple");
ReactDOM.render(<Standard/>, standard);

const scrollable = document.getElementById("scrollable");
ReactDOM.render(<Scrollable/>, scrollable);
}

render () {
return (
<div>
{this.props.children}
</div>
)
}
}
export default Template;
66 changes: 66 additions & 0 deletions docs/pages/components/dialog/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: "Dialog"
---

### Simple dialog
```react-snippet
simple
```
```jsx
<Button
primary
raised
onClick={()=> { this.setState({isOpen: !this.state.isOpen}) }}
>
Show dialog
</Button>
<Dialog open={this.state.isOpen}>
<DialogHeader>
<DialogTitle>Use Google's location service?</DialogTitle>
</DialogHeader>
<DialogBody>
Let Google help apps determine location.
</DialogBody>
<DialogFooter>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Decline</Button>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Accept</Button>
</DialogFooter>
</Drawer>
```
### Scrollable dialog
```react-snippet
scrollable
```
```jsx
<Button
primary
raised
onClick={()=> { this.setState({isOpen: !this.state.isOpen}) }}
>
Show scrollable dialog
</Button>
<Dialog open={this.state.isOpen}>
<DialogHeader>
<DialogTitle>Choose a Ringtone</DialogTitle>
</DialogHeader>
<DialogBody scrollable>
<List>
<ListItem>None</ListItem>
<ListItem>Callisto</ListItem>
<ListItem>Ganymede</ListItem>
<ListItem>Luna</ListItem>
<ListItem>Marimba</ListItem>
<ListItem>Schwifty</ListItem>
<ListItem>Callisto</ListItem>
<ListItem>Ganymede</ListItem>
<ListItem>Luna</ListItem>
<ListItem>Marimba</ListItem>
<ListItem>Schwifty</ListItem>
</List>
</DialogBody>
<DialogFooter>
<Button compact onClick={()=> { this.setState({isOpen: false}) }}>Cancel</Button>
<Button compact onClick={()=> { this.setState({isOpen: false}) }} >Accept</Button>
</DialogFooter>
</Drawer>
```
37 changes: 37 additions & 0 deletions src/Dialog/Dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import { ROOT, OPEN, SURFACE, BACKDROP, SCROLL_LOCK } from './constants';

class Dialog extends Component {

static propTypes = {
className: PropTypes.string,
children: PropTypes.node,
open: PropTypes.bool,
}

componentWillReceiveProps(nextProps) {
if (nextProps.open) document.body.classList.add(SCROLL_LOCK);
else document.body.classList.remove(SCROLL_LOCK);
}

render() {
const { className, children, open, ...otherProps } = this.props;

return (
<div
className={classnames(ROOT, {
[OPEN]: open,
}, className)}
{...otherProps}
>
<div className={SURFACE}>
{children}
</div>
<div className={BACKDROP} />
</div>
);
}
}

export default Dialog;
22 changes: 22 additions & 0 deletions src/Dialog/DialogBody.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { PropTypes } from 'react';
import classnames from 'classnames';
import { BODY, SCROLLABLE } from './constants';

const propTypes = {
className: PropTypes.string,
children: PropTypes.node,
scrollable: PropTypes.bool,
};

const DialogBody = ({ className, children, scrollable, ...otherProps }) => (
<section
className={classnames(BODY, {
[SCROLLABLE]: scrollable,
}, className)}
{...otherProps}
>
{children}
</section>
);
DialogBody.propTypes = propTypes;
export default DialogBody;
31 changes: 31 additions & 0 deletions src/Dialog/DialogFooter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { PropTypes } from 'react';
import classnames from 'classnames';
import { FOOTER, FOOTER_BUTTON, FOOTER_BUTTON_CANCEL, FOOTER_BUTTON_ACCEPT } from './constants';

const propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};

const DialogFooter = ({ className, children }) => {
const last = children.length - 1;
const actions = React.Children.map(children, (action, index) => {
const isLastAction = last === index;
const actionClasses = action.props.className;
const classes = classnames(actionClasses, 'mdc-button', FOOTER_BUTTON, {
[FOOTER_BUTTON_CANCEL]: !isLastAction,
[FOOTER_BUTTON_ACCEPT]: isLastAction,
});
return React.cloneElement(action, { key: index, className: classes });
});

return (
<footer
className={classnames(FOOTER, className)}
>
{actions}
</footer>
);
};
DialogFooter.propTypes = propTypes;
export default DialogFooter;
18 changes: 18 additions & 0 deletions src/Dialog/DialogHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { PropTypes } from 'react';
import classnames from 'classnames';
import { HEADER } from './constants';

const propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};

const DialogHeader = ({ className, children }) => (
<header
className={classnames(HEADER, className)}
>
{children}
</header>
);
DialogHeader.propTypes = propTypes;
export default DialogHeader;
Loading

0 comments on commit 250cad6

Please sign in to comment.