diff --git a/.gitignore b/.gitignore index e3b86d0..4caa8a0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ coverage examples/bundle.js examples/style.css npm-debug.log +yarn.lock diff --git a/src/Dropdown/DialogWrapper.js b/src/Dropdown/DialogWrapper.js new file mode 100644 index 0000000..94ab3e5 --- /dev/null +++ b/src/Dropdown/DialogWrapper.js @@ -0,0 +1,28 @@ +import React, { Component, PropTypes } from 'react'; +/* + * We must make another component so that this.closePortal + * gets passed down and handed to children + */ +export default class DialogWrapper extends Component { + static propTypes = { + closePortal: PropTypes.func, + children: PropTypes.any, + target: PropTypes.any.isRequired + } + + componentDidMount() { + this.dialogDom.showModal(this.props.target) + } + + render() { + const { closePortal, children } = this.props + return( + this.dialogDom = c}> + { React.cloneElement( + children, + {closePortal: closePortal} + )} + + ); + } +} diff --git a/src/Dropdown/Dropdown.css b/src/Dropdown/Dropdown.css index f6b21bd..deb4be8 100644 --- a/src/Dropdown/Dropdown.css +++ b/src/Dropdown/Dropdown.css @@ -14,3 +14,13 @@ .mdl-dropdown *, .mdl-dropdown *:before, .mdl-dropdown *:after { box-sizing: inherit; } + +.portal__dialog { + border: 0 none; + margin: 0; + padding: 0; +} + +.portal__dialog::backdrop { + background: transparent; +} diff --git a/src/Dropdown/Dropdown.js b/src/Dropdown/Dropdown.js index ea1f6b4..0973097 100644 --- a/src/Dropdown/Dropdown.js +++ b/src/Dropdown/Dropdown.js @@ -5,6 +5,7 @@ import Portal from 'react-portal' import Tether from 'tether' import './Dropdown.css' +import DialogWrapper from './DialogWrapper'; const POS = { t: 'top', @@ -63,9 +64,10 @@ export default class Dropdown extends Component { useTargetMinHeight, viewportPadding: pad, } = this.props + const mdlParent = findDOMNode(this.dialogDom); // append class name - portalNode.classList.add('mdl-dropdown') + mdlParent.classList.add('mdl-dropdown') // window is our boundary const { innerWidth, innerHeight } = window @@ -74,7 +76,7 @@ export default class Dropdown extends Component { const targetNode = this.props.targetNode || findDOMNode(this) // get bounding rects - const portal = portalNode.getBoundingClientRect() + const portal = portalNode.getBoundingClientRect() // TOOD: Test const target = targetNode.getBoundingClientRect() // parse position @@ -167,7 +169,7 @@ export default class Dropdown extends Component { // tether this.tether = new Tether({ - element: portalNode, + element: mdlParent, target: targetNode, attachment: `${ay} ${ax}`, targetAttachment: `${ty} ${tx}`, @@ -179,7 +181,7 @@ export default class Dropdown extends Component { }) // fade in - this.applyStyles(portalNode, { opacity: 1 }) + this.applyStyles(mdlParent, { opacity: 1 }) // force reposition if (portal.height > maxHeight) { @@ -213,9 +215,13 @@ export default class Dropdown extends Component { onOpen={this.onOpen} beforeClose={this.beforeClose} > - {children} + this.dialogDom = c} + > + {children} + ) } - } diff --git a/stories/Menu.story.js b/stories/Menu.story.js index 7112c6f..7e3595c 100644 --- a/stories/Menu.story.js +++ b/stories/Menu.story.js @@ -5,6 +5,8 @@ import faker from 'faker' import { Card, Button, IconButton } from 'react-mdl' import { Menu, MenuItem } from '../src' +import DialogHelper from './helpers/DialogHelper' +import StatefulMenu from './helpers/StatefulMenu' const bigMenuItems = [...Array(35).keys()].map(i => Menu Item {i} @@ -22,6 +24,16 @@ storiesOf('Menu', module) console.log('select three')}>Three )) + .add('default with icon', () => ( +
+

Menu with Icon

+

Useful for a button-style dropdown.

+ +
+ )) .add('position', () => { const styles = { center: { @@ -231,3 +243,19 @@ storiesOf('Menu', module) ) }) + .add('opens within dialog', () => { + return ( +
+ + } align={'tr br'}> + console.log('select one')}>One + console.log('select two')}>Two + console.log('select three')}>Three + I + Am + Free + + +
+ ) + }) diff --git a/stories/helpers/DialogHelper.js b/stories/helpers/DialogHelper.js new file mode 100644 index 0000000..fc29b05 --- /dev/null +++ b/stories/helpers/DialogHelper.js @@ -0,0 +1,55 @@ +import React, { Component, PropTypes } from 'react' +import { Button, Dialog, DialogTitle, DialogActions, DialogContent } from 'react-mdl' + + +export default class DialogHelper extends Component { + + constructor(props) { + super(props); + this.state = { + dialogOpen: props.dialogOpen + } + } + + static propTypes = { + dialogOpen: PropTypes.bool, + children: PropTypes.object + } + + static defaultProps = { + dialogOpen: false, + children: [] + } + + handelCloseDialog = () => { + this.setState({ + dialogOpen: false + }); + } + + handleOpenDialog = () => { + this.setState({ + dialogOpen: true + }); + } + + render() { + const { children } = this.props; + const { dialogOpen } = this.state; + return( +
+ + + How does it render within a Dialog? + + { children } + + + + + +
+ ); + } + +} diff --git a/stories/helpers/StatefulMenu.js b/stories/helpers/StatefulMenu.js new file mode 100644 index 0000000..b187a17 --- /dev/null +++ b/stories/helpers/StatefulMenu.js @@ -0,0 +1,40 @@ +import React, { Component, PropTypes } from 'react'; +import { Button, Icon } from 'react-mdl' +import { Menu, MenuItem } from '../../src' + +export default class StatefulMenu extends Component { + + constructor(props) { + super(props); + this.state = { value: null } + } + + static propTypes = { + options: PropTypes.arrayOf(React.PropTypes.string).isRequired, + value: PropTypes.string + } + + static defaultProps = { + value: null + } + + onChange = (value) => { + this.setState({ value }) + console.log(`select ${value}`) + } + + render() { + const { value, options } = this.props; + const val = this.state.value ? this.state.value : value ? value : options[0]; + return ( + {val} } + align={'tl bl'} + > + { options.map((option) => ( + this.onChange(option) }>{option} + ))} + + ) + } +}