From 5a5d2daa4341208e54ae0d048c3f9e423464a92a Mon Sep 17 00:00:00 2001 From: Alex Kovalevych Date: Tue, 24 May 2016 16:10:09 +0300 Subject: [PATCH] add property to show all multi options in the menu --- src/Option.js | 11 ++++++++++- src/Select.js | 46 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/Option.js b/src/Option.js index b024f64d..6b8e4215 100644 --- a/src/Option.js +++ b/src/Option.js @@ -12,8 +12,14 @@ const Option = React.createClass({ onSelect: React.PropTypes.func, // method to handle click on option element onUnfocus: React.PropTypes.func, // method to handle mouseLeave on option element option: React.PropTypes.object.isRequired, // object that is base for that option + showCheckedIcon: React.PropTypes.bool // show/hide cheched icon (used for multuple options select) }, - blockEvent (event) { + getInitialState: function() { + return { + isChecked: this.props.isSelected + }; + }, + blockEvent (event) { event.preventDefault(); event.stopPropagation(); if ((event.target.tagName !== 'A') || !('href' in event.target)) { @@ -30,6 +36,9 @@ const Option = React.createClass({ event.preventDefault(); event.stopPropagation(); this.props.onSelect(this.props.option, event); + this.setState({ + isChecked: !this.state.isChecked + }); }, handleMouseEnter (event) { diff --git a/src/Select.js b/src/Select.js index 91933e46..466f6f1b 100644 --- a/src/Select.js +++ b/src/Select.js @@ -95,7 +95,8 @@ const Select = React.createClass({ resetValue: React.PropTypes.any, // value to use when you clear the control scrollMenuIntoView: React.PropTypes.bool, // boolean to enable the viewport to shift so that the full menu fully visible when engaged searchable: React.PropTypes.bool, // whether to enable searching feature or not - simpleValue: React.PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false + showAllOptions: React.PropTypes.bool, // always show all options for multiple dropdown + simpleValue: React.PropTypes.bool, // pass the value to onChange as a simple value (legacy pre 1.0 mode), defaults to false, style: React.PropTypes.object, // optional style to apply to the control tabIndex: React.PropTypes.string, // optional tab index of the control tabSelectsValue: React.PropTypes.bool, // whether to treat tabbing out while focused to be value selection @@ -143,6 +144,7 @@ const Select = React.createClass({ resetValue: null, scrollMenuIntoView: true, searchable: true, + showAllOptions: false, simpleValue: false, tabSelectsValue: true, valueComponent: Value, @@ -202,19 +204,19 @@ const Select = React.createClass({ componentDidUpdate (prevProps, prevState) { // focus to the selected option - if (this.refs.menu && this.refs.focused && this.state.isOpen && !this.hasScrolledToOption) { + let multiScrollDisable = this.props.multi && this.props.showAllOptions; + if (this.refs.menu && this.refs.focused && this.state.isOpen && !this.hasScrolledToOption && !multiScrollDisable) { let focusedOptionNode = ReactDOM.findDOMNode(this.refs.focused); - let focusedOptionParent = focusedOptionNode.parentElement; + let focusedOptionParent = focusedOptionNode.parentElement; let menuNode = ReactDOM.findDOMNode(this.refs.menu); - menuNode.scrollTop = focusedOptionParent.className === 'Select-menu' ? - focusedOptionNode.offsetTop : + menuNode.scrollTop = focusedOptionParent.className === 'Select-menu' ? focusedOptionNode.offsetTop : focusedOptionParent.offsetTop; this.hasScrolledToOption = true; } else if (!this.state.isOpen) { this.hasScrolledToOption = false; } - if (this._scrollToFocusedOptionOnUpdate && this.refs.focused && this.refs.menu) { + if (this._scrollToFocusedOptionOnUpdate && this.refs.focused && this.refs.menu && !multiScrollDisable) { this._scrollToFocusedOptionOnUpdate = false; var focusedDOM = ReactDOM.findDOMNode(this.refs.focused); var menuDOM = ReactDOM.findDOMNode(this.refs.menu); @@ -224,7 +226,7 @@ const Select = React.createClass({ menuDOM.scrollTop = (focusedDOM.offsetTop + focusedDOM.clientHeight - menuDOM.offsetHeight); } } - if (this.props.scrollMenuIntoView && this.refs.menuContainer) { + if (this.props.scrollMenuIntoView && this.refs.menuContainer && !multiScrollDisable) { var menuContainerRect = this.refs.menuContainer.getBoundingClientRect(); if (window.innerHeight < menuContainerRect.bottom + this.props.menuBuffer) { window.scrollBy(0, menuContainerRect.bottom + this.props.menuBuffer - window.innerHeight); @@ -451,7 +453,7 @@ const Select = React.createClass({ }, handleMenuScroll (event) { - if (!this.props.onMenuScrollToBottom) return; + if (!this.props.onMenuScrollToBottom || (this.props.multi && this.props.showAllOptions)) return; let { target } = event; if (target.scrollHeight > target.offsetHeight && !(target.scrollHeight - target.offsetHeight - target.scrollTop)) { this.props.onMenuScrollToBottom(); @@ -517,7 +519,16 @@ const Select = React.createClass({ selectValue (value) { this.hasScrolledToOption = false; if (this.props.multi) { - this.addValue(value); + if (this.props.showAllOptions) { + let values = this.getValueArray(this.props.value); + if (values.indexOf(value) > -1) { + this.removeValue(value); + } else { + this.addValue(value); + } + } else { + this.addValue(value); + } this.setState({ inputValue: '', }); @@ -861,6 +872,7 @@ const Select = React.createClass({ option={option} isSelected={isSelected} ref={optionRef} + showCheckedIcon={this.props.multi && this.props.showAllOptions} > {renderLabel(option)} @@ -934,8 +946,13 @@ const Select = React.createClass({ }, render () { - let valueArray = this.getValueArray(this.props.value); - let options = this.filterOptions(this.props.options || [], this.props.multi ? valueArray : null); + let valueArray = this.getValueArray(this.props.value); + let excludeOptions = this.props.multi ? valueArray : null; + if (this.props.multi && this.props.showAllOptions) { + excludeOptions = null; + } + + let options = this.filterOptions(this.props.options || [], excludeOptions); this._visibleOptions = this.flattenOptions(options); let isOpen = typeof this.props.isOpen === 'boolean' ? this.props.isOpen : this.state.isOpen; if (this.props.multi && !options.length && valueArray.length && !this.state.inputValue) isOpen = false; @@ -952,6 +969,11 @@ const Select = React.createClass({ 'has-value': valueArray.length, }); + let outerValueArray = !this.props.multi ? valueArray : null; + if (this.props.multi && this.props.showAllOptions) { + outerValueArray = valueArray; + } + return (
{this.renderHiddenField(valueArray)} @@ -969,7 +991,7 @@ const Select = React.createClass({ {this.renderClear()} {this.renderArrow()}
- {isOpen ? this.renderOuter(options, !this.props.multi ? valueArray : null, focusedOption) : null} + {isOpen ? this.renderOuter(options, outerValueArray, focusedOption) : null} ); }