New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Menu doesnt stay open on click #330
Changes from 10 commits
0dddb87
ee5955e
06eb6e1
9957e8a
2d559c0
4e05ef0
e572591
554378d
ab03349
88cdeea
bf71f4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,27 +14,55 @@ import React, { PropTypes } from 'react'; | |
* | ||
* A menu style button to use within the Toolbar. | ||
*/ | ||
export function ToolbarMenu({ title, label, children }) { | ||
return ( | ||
<a | ||
className="toolbar-menu toolbar-button" | ||
onMouseDown={preventDefault} | ||
title={title}> | ||
{label} | ||
<svg width="14" height="8"> | ||
<path fill="#666" d="M 5 1.5 L 14 1.5 L 9.5 7 z" /> | ||
</svg> | ||
<ul className="toolbar-menu-items"> | ||
{children} | ||
</ul> | ||
</a> | ||
); | ||
} | ||
export class ToolbarMenu extends React.Component { | ||
static propTypes = { | ||
title: PropTypes.string, | ||
label: PropTypes.string, | ||
} | ||
|
||
ToolbarMenu.propTypes = { | ||
title: PropTypes.string, | ||
label: PropTypes.string, | ||
}; | ||
constructor(props) { | ||
super(props); | ||
this.state = { visible: false }; | ||
} | ||
|
||
componentWillUnmount() { | ||
document.removeEventListener('click', this.handleClick.bind(this)); | ||
} | ||
|
||
render() { | ||
const visible = this.state.visible; | ||
return ( | ||
<a | ||
className="toolbar-menu toolbar-button" | ||
onClick={this.handleOpen.bind(this)} | ||
onMouseDown={preventDefault} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Non-blocking feedback.) I think we should either just kill the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah forgot to put this in, let me do another commit really quick |
||
ref={node => {this._node = node;}} | ||
title={this.props.title}> | ||
{this.props.label} | ||
<svg width="14" height="8"> | ||
<path fill="#666" d="M 5 1.5 L 14 1.5 L 9.5 7 z" /> | ||
</svg> | ||
<ul className={'toolbar-menu-items' + (visible ? ' open' : '')}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could use the |
||
{this.props.children} | ||
</ul> | ||
</a> | ||
); | ||
} | ||
|
||
handleClick(e) { | ||
if (this._node !== e.target) { | ||
preventDefault(e); | ||
this.setState({ visible: false }); | ||
document.removeEventListener('click', this.handleClick.bind(this)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't forget to also remove it, if present, in |
||
} | ||
} | ||
|
||
handleOpen = e => { | ||
preventDefault(e); | ||
this.setState({ visible: true }); | ||
document.addEventListener('click', this.handleClick.bind(this)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For hygiene, we should make sure we remove this event listener on unmount or close. The currently implementation will re-bind repeatedly. |
||
}; | ||
} | ||
|
||
export function ToolbarMenuItem({ onSelect, title, label }) { | ||
return ( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,42 +14,74 @@ import React, { PropTypes } from 'react'; | |
* | ||
* A select-option style button to use within the Toolbar. | ||
* | ||
* Note that, like React's <select>, this component is stateless and expects you | ||
* to re-render with a new selected={} condition on the child options. | ||
*/ | ||
export function ToolbarSelect({ onSelect, title, children }) { | ||
let selectedChild; | ||
const optionChildren = React.Children.map(children, (child, i) => { | ||
if (!selectedChild || child.props.selected) { | ||
selectedChild = child; | ||
} | ||
const onChildSelect = | ||
|
||
export class ToolbarSelect extends React.Component { | ||
static propTypes = { | ||
title: PropTypes.string, | ||
label: PropTypes.string, | ||
onSelect: PropTypes.func | ||
} | ||
|
||
constructor(props) { | ||
super(props); | ||
this.state = { visible: false }; | ||
} | ||
|
||
componentWillUnmount() { | ||
document.removeEventListener('click', this.handleClick.bind(this)); | ||
} | ||
|
||
render() { | ||
let selectedChild; | ||
const visible = this.state.visible; | ||
const optionChildren = React.Children.map(this.props.children, | ||
(child, i) => { | ||
if (!selectedChild || child.props.selected) { | ||
selectedChild = child; | ||
} | ||
const onChildSelect = | ||
child.props.onSelect || | ||
onSelect && onSelect.bind(null, child.props.value, i); | ||
return <ToolbarSelectOption {...child.props} onSelect={onChildSelect} />; | ||
}); | ||
this.props.onSelect && this.props.onSelect.bind(null, | ||
child.props.value, | ||
i | ||
); | ||
return <ToolbarSelectOption {...child.props} onSelect={onChildSelect} />; | ||
}); | ||
return ( | ||
<a | ||
className="toolbar-select toolbar-button" | ||
onClick={this.handleOpen.bind(this)} | ||
onMouseDown={preventDefault} | ||
ref={node => {this._node = node;}} | ||
title={this.props.title}> | ||
{selectedChild.props.label} | ||
<svg width="13" height="10"> | ||
<path fill="#666" d="M 5 5 L 13 5 L 9 1 z" /> | ||
<path fill="#666" d="M 5 6 L 13 6 L 9 10 z" /> | ||
</svg> | ||
<ul className={'toolbar-select-options' + (visible ? ' open' : '')}> | ||
{optionChildren} | ||
</ul> | ||
</a> | ||
); | ||
} | ||
|
||
return ( | ||
<a | ||
className="toolbar-select toolbar-button" | ||
onMouseDown={preventDefault} | ||
title={title}> | ||
{selectedChild.props.label} | ||
<svg width="13" height="10"> | ||
<path fill="#666" d="M 5 5 L 13 5 L 9 1 z" /> | ||
<path fill="#666" d="M 5 6 L 13 6 L 9 10 z" /> | ||
</svg> | ||
<ul className="toolbar-select-options"> | ||
{optionChildren} | ||
</ul> | ||
</a> | ||
); | ||
} | ||
handleClick(e) { | ||
if (this._node !== e.target) { | ||
preventDefault(e); | ||
this.setState({ visible: false }); | ||
document.removeEventListener('click', this.handleClick.bind(this)); | ||
} | ||
} | ||
|
||
ToolbarSelect.propTypes = { | ||
onSelect: PropTypes.func, | ||
title: PropTypes.string, | ||
}; | ||
handleOpen = e => { | ||
preventDefault(e); | ||
this.setState({ visible: true }); | ||
document.addEventListener('click', this.handleClick.bind(this)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue with unmount here. Should always have a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whoops! |
||
}; | ||
|
||
} | ||
|
||
export function ToolbarSelectOption({ onSelect, label, selected }) { | ||
return ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure that any of these
removeEventListener
calls will do what you want, because when you callbind
you get a new function that is not===
, which means that you won't remove anything here. (I could be wrong about that, but that's what I think will happen.)I think the way to do this is as follows:
And then call those methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, makes sense. Yeah I was afraid of that but I wasn't really sure. Implemented _subscribe and _release and tested that everything works.