2016-09-02 04:19:37 +08:00
|
|
|
import React, { Component, PropTypes } from 'react';
|
|
|
|
import { findDOMNode } from 'react-dom';
|
2016-08-20 05:20:17 +08:00
|
|
|
import styles from './styles';
|
2016-09-02 04:19:37 +08:00
|
|
|
import DropdownTrigger from './trigger/component';
|
|
|
|
import DropdownContent from './content/component';
|
|
|
|
|
|
|
|
const propTypes = {
|
|
|
|
children: (props, propName, componentName) => {
|
|
|
|
const children = props[propName];
|
|
|
|
|
|
|
|
if (!children || children.length < 2) {
|
|
|
|
return new Error(
|
|
|
|
'Invalid prop `' + propName + '` supplied to' +
|
|
|
|
' `' + componentName + '`. Validation failed.'
|
|
|
|
);
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
const trigger = children.find(x => x.type === DropdownTrigger);
|
|
|
|
const content = children.find(x => x.type === DropdownContent);
|
2016-08-20 05:20:17 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
if (!trigger) {
|
|
|
|
return new Error(
|
|
|
|
'Invalid prop `' + propName + '` supplied to' +
|
|
|
|
' `' + componentName + '`. Missing `DropdownTrigger`. Validation failed.'
|
|
|
|
);
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
if (!content) {
|
|
|
|
return new Error(
|
|
|
|
'Invalid prop `' + propName + '` supplied to' +
|
|
|
|
' `' + componentName + '`. Missing `DropdownContent`. Validation failed.'
|
|
|
|
);
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
2016-09-02 04:19:37 +08:00
|
|
|
},
|
|
|
|
};
|
2016-08-20 05:20:17 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
export default class Dropdown extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = { isOpen: false, };
|
|
|
|
this.handleShow = this.handleShow.bind(this);
|
|
|
|
this.handleHide = this.handleHide.bind(this);
|
|
|
|
this.handleToggle = this.handleToggle.bind(this);
|
|
|
|
this.handleWindowClick = this.handleWindowClick.bind(this);
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
handleShow() {
|
|
|
|
this.setState({ isOpen: true });
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
handleHide() {
|
|
|
|
this.setState({ isOpen: false });
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
componentDidMount () {
|
|
|
|
const { addEventListener } = window;
|
|
|
|
addEventListener('click', this.handleWindowClick, false);
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
componentWillUnmount () {
|
|
|
|
const { removeEventListener } = window;
|
|
|
|
removeEventListener('click', this.handleWindowClick, false);
|
2016-08-24 06:19:13 +08:00
|
|
|
}
|
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
handleWindowClick(event) {
|
|
|
|
const dropdownElement = findDOMNode(this);
|
|
|
|
const shouldUpdateState = event.target !== dropdownElement &&
|
|
|
|
!dropdownElement.contains(event.target) &&
|
|
|
|
this.state.isOpen;
|
2016-08-25 22:34:27 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
if (shouldUpdateState) {
|
|
|
|
this.handleHide();
|
|
|
|
}
|
|
|
|
}
|
2016-08-24 06:19:13 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
handleToggle() {
|
|
|
|
this.state.isOpen ?
|
|
|
|
this.handleHide() :
|
|
|
|
this.handleShow();
|
2016-08-20 05:20:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2016-09-02 04:19:37 +08:00
|
|
|
const { children } = this.props;
|
2016-08-24 06:19:13 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
let trigger = children.find(x => x.type === DropdownTrigger);
|
|
|
|
const content = children.find(x => x.type === DropdownContent);
|
2016-08-24 06:19:13 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
trigger = React.cloneElement(trigger, {
|
|
|
|
handleToggle: this.handleToggle,
|
|
|
|
});
|
2016-08-24 06:19:13 +08:00
|
|
|
|
2016-09-02 04:19:37 +08:00
|
|
|
return (
|
|
|
|
<div className={styles.dropdown}>
|
|
|
|
{trigger}
|
|
|
|
{this.state.isOpen ? content : null}
|
2016-08-20 05:20:17 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2016-09-02 04:19:37 +08:00
|
|
|
|
|
|
|
Dropdown.propTypes = propTypes;
|