diff --git a/dist/index.js b/dist/index.js index d8920f6..b4d4fe5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); @@ -50,6 +52,7 @@ var Dropdown = function (_Component) { _this.mounted = true; _this.handleDocumentClick = _this.handleDocumentClick.bind(_this); _this.handleKeyPressEvent = _this.handleKeyPressEvent.bind(_this); + _this.isItSelected = _this.isItSelected.bind(_this); return _this; } @@ -61,7 +64,9 @@ var Dropdown = function (_Component) { } else if (!newProps.value && newProps.placeholder) { this.setState({ selected: { label: newProps.placeholder, value: '' } }); } else if (!newProps.value) { - this.setState({ selected: { label: DEFAULT_PLACEHOLDER_STRING, value: '' } }); + this.setState({ + selected: { label: DEFAULT_PLACEHOLDER_STRING, value: '' } + }); } } }, { @@ -84,7 +89,9 @@ var Dropdown = function (_Component) { value: function handleDocumentClick(event) { if (this.mounted) { if (!_reactDom2.default.findDOMNode(this).contains(event.target)) { - this.setState({ isOpen: false }); + this.setState(function () { + return { isOpen: false }; + }); } } } @@ -92,7 +99,9 @@ var Dropdown = function (_Component) { key: 'handleKeyPressEvent', value: function handleKeyPressEvent(e) { if (e.keyCode === 27) { - this.setState({ isOpen: false }); + this.setState(function () { + return { isOpen: false }; + }); } } }, { @@ -105,21 +114,24 @@ var Dropdown = function (_Component) { }, { key: 'handleMouseDown', value: function handleMouseDown(event) { + var _this2 = this; if (event.type === 'mousedown' && event.button !== 0) return; event.stopPropagation(); event.preventDefault(); if (!this.props.disabled) { - this.setState({ - isOpen: !this.state.isOpen + this.setState(function () { + return { isOpen: !_this2.state.isOpen }; }); } } }, { key: 'handleDropdownFocus', value: function handleDropdownFocus() { - this.setState({ isOpen: true }); + this.setState(function () { + return { isOpen: true }; + }); } }, { key: 'handleDropdownBlur', @@ -135,7 +147,9 @@ var Dropdown = function (_Component) { } } } - this.setState({ isOpen: stayOpen }); + this.setState(function () { + return { isOpen: stayOpen }; + }); } }, { key: 'handleDropdownKeyDown', @@ -166,28 +180,45 @@ var Dropdown = function (_Component) { }, { key: 'setValue', value: function setValue(value, label) { + var _this3 = this; + var newState = { + isOpen: false, selected: { value: value, label: label - }, - isOpen: false + } }; this.fireChangeEvent(newState); this.dropdownButton.focus(); - this.setState(newState); + // there seems to be a race condition in IE11 for closing the menu in render, so setTimeout :( + setTimeout(function () { + _this3.setState(function () { + return newState; + }); + }, 20); + } + }, { + key: 'isItSelected', + value: function isItSelected(option) { + var isSelected = false; + if ((typeof option === 'undefined' ? 'undefined' : _typeof(option)) === 'object') { + isSelected = option.value === this.state.selected.value || option.label === this.state.selected; + } else { + isSelected = option === this.state.selected.value || option === this.state.selected; + } + return isSelected; } }, { key: 'renderOption', value: function renderOption(option) { var _classNames, - _this2 = this; + _this4 = this; - var optionClass = (0, _classnames2.default)((_classNames = {}, _defineProperty(_classNames, this.props.baseClassName + '-option', true), _defineProperty(_classNames, 'is-selected', option === this.state.selected), _classNames)); + var optionClass = (0, _classnames2.default)((_classNames = {}, _defineProperty(_classNames, this.props.baseClassName + '-option', true), _defineProperty(_classNames, 'is-selected', this.isItSelected(option)), _classNames)); var value = option.value || option.label || option; var label = option.label || option.value || option; - return _react2.default.createElement( 'div', { @@ -196,16 +227,16 @@ var Dropdown = function (_Component) { key: value, className: optionClass, onMouseDown: function onMouseDown() { - return _this2.setValue(value, label); + return _this4.setValue(value, label); }, onClick: function onClick() { - return _this2.setValue(value, label); + return _this4.setValue(value, label); }, onKeyDown: function onKeyDown(e) { - return _this2.handleOptionKeyDown(e, value, label); + return _this4.handleOptionKeyDown(e, value, label); }, onBlur: function onBlur(e) { - return _this2.handleDropdownBlur(e); + return _this4.handleDropdownBlur(e); } }, label @@ -214,7 +245,7 @@ var Dropdown = function (_Component) { }, { key: 'buildMenu', value: function buildMenu() { - var _this3 = this; + var _this5 = this; var _props = this.props, options = _props.options, @@ -228,7 +259,7 @@ var Dropdown = function (_Component) { option.name ); var _options = option.items.map(function (item) { - return _this3.renderOption(item); + return _this5.renderOption(item); }); return _react2.default.createElement( @@ -238,7 +269,7 @@ var Dropdown = function (_Component) { _options ); } else { - return _this3.renderOption(option); + return _this5.renderOption(option); } }); @@ -251,7 +282,7 @@ var Dropdown = function (_Component) { }, { key: 'render', value: function render() { - var _this4 = this, + var _this6 = this, _classNames2; var baseClassName = this.props.baseClassName; @@ -263,16 +294,16 @@ var Dropdown = function (_Component) { { className: baseClassName + '-placeholder' }, placeHolderValue ); - var menu = this.state.isOpen ? _react2.default.createElement( + var menu = _react2.default.createElement( 'div', { ref: function ref(el) { - _this4.dropdownMenu = el; + _this6.dropdownMenu = el; }, className: baseClassName + '-menu' }, this.buildMenu() - ) : null; + ); var dropdownClass = (0, _classnames2.default)((_classNames2 = {}, _defineProperty(_classNames2, baseClassName + '-root', true), _defineProperty(_classNames2, 'is-open', this.state.isOpen), _classNames2)); @@ -285,29 +316,29 @@ var Dropdown = function (_Component) { tabIndex: this.props.tabIndex || '0', role: 'menu', ref: function ref(el) { - _this4.dropdownButton = el; + _this6.dropdownButton = el; }, onFocus: function onFocus() { - return _this4.handleDropdownFocus(); + return _this6.handleDropdownFocus(); }, onBlur: function onBlur(e) { - return _this4.handleDropdownBlur(e); + return _this6.handleDropdownBlur(e); }, className: baseClassName + '-control ' + disabledClass, onMouseDown: function onMouseDown(e) { - return _this4.handleMouseDown(e); + return _this6.handleMouseDown(e); }, onTouchEnd: function onTouchEnd(e) { - return _this4.handleMouseDown(e); + return _this6.handleMouseDown(e); }, onKeyDown: function onKeyDown(e) { - return _this4.handleDropdownKeyDown(e); + return _this6.handleDropdownKeyDown(e); } }, value, _react2.default.createElement('span', { className: baseClassName + '-arrow' }) ), - menu + this.state.isOpen && menu ); } }]); diff --git a/index.js b/index.js index 29eddb6..ead0089 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ import classNames from 'classnames'; const DEFAULT_PLACEHOLDER_STRING = 'Select...'; class Dropdown extends Component { - constructor (props) { + constructor(props) { super(props); this.state = { selected: props.value || { @@ -19,129 +19,150 @@ class Dropdown extends Component { this.mounted = true; this.handleDocumentClick = this.handleDocumentClick.bind(this); this.handleKeyPressEvent = this.handleKeyPressEvent.bind(this); + this.isItSelected = this.isItSelected.bind(this); } - componentWillReceiveProps (newProps) { + componentWillReceiveProps(newProps) { if (newProps.value && newProps.value !== this.state.selected) { - this.setState({selected: newProps.value}); + this.setState({ selected: newProps.value }); } else if (!newProps.value && newProps.placeholder) { - this.setState({selected: { label: newProps.placeholder, value: '' }}); - } else if (!newProps.value){ - this.setState({selected: { label: DEFAULT_PLACEHOLDER_STRING, value: '' }}); + this.setState({ selected: { label: newProps.placeholder, value: '' } }); + } else if (!newProps.value) { + this.setState({ + selected: { label: DEFAULT_PLACEHOLDER_STRING, value: '' } + }); } } - componentDidMount () { + componentDidMount() { document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('touchend', this.handleDocumentClick, false); document.addEventListener('keydown', this.handleKeyPressEvent, false); } - componentWillUnmount () { + componentWillUnmount() { this.mounted = false; document.removeEventListener('click', this.handleDocumentClick, false); document.removeEventListener('touchend', this.handleDocumentClick, false); document.removeEventListener('keydown', this.handleKeyPressEvent, false); } - handleDocumentClick (event) { + handleDocumentClick(event) { if (this.mounted) { if (!ReactDOM.findDOMNode(this).contains(event.target)) { - this.setState({ isOpen: false }); + this.setState(() => ({ isOpen: false })); } } } - handleKeyPressEvent(e){ - if(e.keyCode === 27){ - this.setState({ isOpen: false }); + handleKeyPressEvent(e) { + if (e.keyCode === 27) { + this.setState(() => ({ isOpen: false })); } } - fireChangeEvent (newState) { + fireChangeEvent(newState) { if (newState.selected !== this.state.selected && this.props.onChange) { this.props.onChange(newState.selected); } } - handleMouseDown (event) { - + handleMouseDown(event) { if (event.type === 'mousedown' && event.button !== 0) return; event.stopPropagation(); event.preventDefault(); if (!this.props.disabled) { - this.setState({ - isOpen: !this.state.isOpen - }); + this.setState(() => ({ isOpen: !this.state.isOpen })); } } - handleDropdownFocus(){ - this.setState({ isOpen: true }); + handleDropdownFocus() { + this.setState(() => ({ isOpen: true })); } - handleDropdownBlur(e){ + handleDropdownBlur(e) { let stayOpen = false; - if(e.relatedTarget === this.dropdownButton){ + if (e.relatedTarget === this.dropdownButton) { stayOpen = true; - } else if(this.dropdownMenu){ - const options = this.dropdownMenu.getElementsByClassName(`${this.props.baseClassName}-option`); - for(var i=0; i ({ isOpen: stayOpen })); } - handleDropdownKeyDown(e){ - if(e.keyCode == 40){ + handleDropdownKeyDown(e) { + if (e.keyCode == 40) { e.preventDefault(); - const options = this.dropdownMenu.getElementsByClassName(`${this.props.baseClassName}-option`); + const options = this.dropdownMenu.getElementsByClassName( + `${this.props.baseClassName}-option` + ); options.length && options[0].focus(); } } - handleOptionKeyDown(e, value, label){ - if(e.keyCode == 32 || e.keyCode == 13){ + handleOptionKeyDown(e, value, label) { + if (e.keyCode == 32 || e.keyCode == 13) { e.preventDefault(); this.setValue(value, label); - } else if(e.keyCode == 38 || e.keyCode == 40){ + } else if (e.keyCode == 38 || e.keyCode == 40) { e.preventDefault(); - const options = this.dropdownMenu.getElementsByClassName(`${this.props.baseClassName}-option`); - for(var i=0; i 0 && options[i-1].focus(); - e.keyCode == 40 && i < options.length - 1 && options[i+1].focus(); + const options = this.dropdownMenu.getElementsByClassName( + `${this.props.baseClassName}-option` + ); + for (var i = 0; i < options.length; i++) { + if (options[i] === e.target) { + e.keyCode == 38 && i > 0 && options[i - 1].focus(); + e.keyCode == 40 && i < options.length - 1 && options[i + 1].focus(); } } } } - setValue (value, label) { + setValue(value, label) { let newState = { + isOpen: false, selected: { value, label - }, - isOpen: false + } }; this.fireChangeEvent(newState); this.dropdownButton.focus(); - this.setState(newState); + // there seems to be a race condition in IE11 for closing the menu in render, so setTimeout :( + setTimeout(() => { + this.setState(() => newState); + }, 20); + } + + isItSelected(option) { + let isSelected = false; + if (typeof option === 'object') { + isSelected = + option.value === this.state.selected.value || + option.label === this.state.selected; + } else { + isSelected = + option === this.state.selected.value || option === this.state.selected; + } + return isSelected; } - renderOption (option) { + renderOption(option) { let optionClass = classNames({ [`${this.props.baseClassName}-option`]: true, - 'is-selected': option === this.state.selected, + 'is-selected': this.isItSelected(option) }); let value = option.value || option.label || option; let label = option.label || option.value || option; - return (
{ + let ops = options.map(option => { if (option.type === 'group') { - let groupTitle = (
{option.name}
); - let _options = option.items.map((item) => this.renderOption(item)); + let groupTitle = ( +
{option.name}
+ ); + let _options = option.items.map(item => this.renderOption(item)); return (
@@ -176,22 +199,33 @@ class Dropdown extends Component { } }); - return ops.length ? ops :
No options found
; + return ops.length ? ( + ops + ) : ( +
No options found
+ ); } - render () { + render() { const { baseClassName } = this.props; const disabledClass = this.props.disabled ? 'Dropdown-disabled' : ''; - const placeHolderValue = typeof this.state.selected === 'string' ? this.state.selected : this.state.selected.label; - let value = (
{placeHolderValue}
); - let menu = this.state.isOpen ? ( -
{ this.dropdownMenu = el; }} - className={`${baseClassName}-menu`} - > - {this.buildMenu()} -
- ) : null; + const placeHolderValue = + typeof this.state.selected === 'string' + ? this.state.selected + : this.state.selected.label; + let value = ( +
{placeHolderValue}
+ ); + let menu = ( +
{ + this.dropdownMenu = el; + }} + className={`${baseClassName}-menu`} + > + {this.buildMenu()} +
+ ); let dropdownClass = classNames({ [`${baseClassName}-root`]: true, @@ -203,7 +237,9 @@ class Dropdown extends Component {
{ this.dropdownButton = el; }} + ref={el => { + this.dropdownButton = el; + }} onFocus={() => this.handleDropdownFocus()} onBlur={e => this.handleDropdownBlur(e)} className={`${baseClassName}-control ${disabledClass}`} @@ -214,11 +250,10 @@ class Dropdown extends Component { {value}
- {menu} + {this.state.isOpen && menu}
); } - } Dropdown.defaultProps = { baseClassName: 'Dropdown' };