diff --git a/web/ASC.Web.Components/src/components/combobox/index.js b/web/ASC.Web.Components/src/components/combobox/index.js index 6d50896513..cd6222cf2d 100644 --- a/web/ASC.Web.Components/src/components/combobox/index.js +++ b/web/ASC.Web.Components/src/components/combobox/index.js @@ -26,15 +26,20 @@ const StyledComboBox = styled.div` user-select: none; background: #FFFFFF; - border: 1px solid #D0D5DA; - border-radius: 3px; - ${props => props.isDisabled && ` + ${props => !props.noBorder && ` + border: 1px solid #D0D5DA; + border-radius: 3px; + `} + + ${props => props.isDisabled && !props.noBorder && ` border-color: #ECEEF1; background: #F8F9F9; `} - height: 32px; + ${props => !props.noBorder && ` + height: 32px; + `} :hover{ border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE'}; @@ -49,7 +54,9 @@ const StyledComboButton = styled.div` display: flex; align-items: center; justify-content: center; - height: 30px; + + height: ${props => props.noBorder ? `18px` : `30px`}; + margin-left: 8px; `; @@ -72,16 +79,26 @@ font-size: 13px; white-space: nowrap; margin-right: 8px; + +${props => props.noBorder && ` + line-height: none; + + :hover{ + border-bottom: 1px dashed; + } +`}; `; const StyledArrowIcon = styled.div` +display: flex; +align-self: start; width: 8px; + margin-top: ${props => props.noBorder ? `5px` : `12px`}; margin-right: 8px; margin-left: auto; - ${state => state.isOpen && ` + ${props => props.isOpen && ` transform: scale(1, -1); - margin-top: 8px; `} `; @@ -91,26 +108,19 @@ class ComboBox extends React.PureComponent { this.ref = React.createRef(); - const selectedItem = this.getSelected(); - this.state = { isOpen: props.opened, - boxLabel: selectedItem && selectedItem.label, - boxIcon: selectedItem && selectedItem.icon, - options: props.options + selectedOption: props.selectedOption }; - this.handleClick = this.handleClick.bind(this); - this.stopAction = this.stopAction.bind(this); - this.toggle = this.toggle.bind(this); - this.comboBoxClick = this.comboBoxClick.bind(this); - this.optionClick = this.optionClick.bind(this); - if (props.opened) handleAnyClick(true, this.handleClick); } - handleClick = (e) => this.state.isOpen && !this.ref.current.contains(e.target) && this.toggle(false); + handleClick = (e) => + this.state.isOpen + && !this.ref.current.contains(e.target) + && this.toggle(false); stopAction = (e) => e.preventDefault(); @@ -118,69 +128,43 @@ class ComboBox extends React.PureComponent { comboBoxClick = (e) => { if (this.props.isDisabled || e.target.closest('.optionalBlock')) return; - - this.setState({ - option: this.props.option, - isOpen: !this.state.isOpen - }); + this.toggle(!this.state.isOpen); }; optionClick = (option) => { - this.setState({ - boxLabel: option.label, - boxIcon: option.icon, - isOpen: !this.state.isOpen + this.toggle(!this.state.isOpen); + this.setState({ + isOpen: !this.state.isOpen, + selectedOption: option }); this.props.onSelect && this.props.onSelect(option); }; componentWillUnmount() { handleAnyClick(false, this.handleClick); - } - - getSelected = () => { - const selectedItem = this.props.options.find(x => x.key === this.props.selectedOption) - || this.props.options[0]; - - return selectedItem; - } - - getSelectedLabel = () => { - const selectedItem = this.getSelected(); - - return selectedItem ? selectedItem.label : this.props.emptyOptionsPlaceholder; - } + }; componentDidUpdate(prevProps, prevState) { if (this.props.opened !== prevProps.opened) { - this.toggle(this.props.opened); + handleAnyClick(this.props.opened, this.handleClick); } if (this.state.isOpen !== prevState.isOpen) { handleAnyClick(this.state.isOpen, this.handleClick); } - if (this.props.options.length !== prevProps.options.length) { //TODO: Move options from state - const label = this.getSelectedLabel(); - this.setState({ - options: this.props.options, - boxLabel: label - }); - } - if (this.props.selectedOption !== prevProps.selectedOption) { - const label = this.getSelectedLabel(); - this.setState({ boxLabel: label }); + this.setState({selectedOption: this.props.selectedOption}); } - } + }; render() { - //console.log("ComboBox render"); + console.log("ComboBox render"); - const { dropDownMaxHeight, isDisabled, directionX, directionY, scaled, children } = this.props; - const { boxLabel, boxIcon, isOpen, options } = this.state; + const { dropDownMaxHeight, isDisabled, directionX, directionY, scaled, children, options, noBorder } = this.props; + const { isOpen, selectedOption } = this.state; - const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight} : {}; + const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight } : {}; const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {}; const boxIconColor = isDisabled ? '#D0D5DA' : '#333333'; const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE'; @@ -189,17 +173,17 @@ class ComboBox extends React.PureComponent { - + {children} - {boxIcon && + {selectedOption && selectedOption.icon && - {React.createElement(Icons[boxIcon], + {React.createElement(Icons[selectedOption.icon], { size: 'scale', color: boxIconColor, @@ -208,10 +192,10 @@ class ComboBox extends React.PureComponent { } } - - {boxLabel} + + {selectedOption.label} - + {React.createElement(Icons['ExpanderDownIcon'], { size: 'scale', @@ -231,7 +215,7 @@ class ComboBox extends React.PureComponent { > {options.map((option) => )} @@ -242,25 +226,20 @@ class ComboBox extends React.PureComponent { }; ComboBox.propTypes = { + noBorder: PropTypes.bool, isDisabled: PropTypes.bool, - withBorder: PropTypes.bool, - selectedOption: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.number - ]), + selectedOption: PropTypes.object, options: PropTypes.array, onSelect: PropTypes.func, dropDownMaxHeight: PropTypes.number, - emptyOptionsPlaceholder: PropTypes.string, size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']), scaled: PropTypes.bool, } ComboBox.defaultProps = { + noBorder: false, isDisabled: false, - withBorder: true, - emptyOptionsPlaceholder: 'Select', size: 'base', scaled: true } diff --git a/web/ASC.Web.Storybook/stories/input/combobox/README.md b/web/ASC.Web.Storybook/stories/input/combobox/README.md index 74c13b0828..ad65341bfd 100644 --- a/web/ASC.Web.Storybook/stories/input/combobox/README.md +++ b/web/ASC.Web.Storybook/stories/input/combobox/README.md @@ -37,13 +37,25 @@ const options = [ key: 5, icon: 'CopyIcon', label: 'Option 5' + }, + { + key: 6, + label: 'Option 6' + }, + { + key: 7, + label: 'Option 7' } ]; console.log('selected', option)} @@ -56,9 +68,9 @@ const options = [ | ---------------------- | ----------------- | :------: | ---------------------------- | ------- | -------------------------------------------- | | `options` | `array` | ✅ | - | - | Combo box options | | `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled | -| `selectedOption` | `string`,`number` | - | - | `0` | Index of option selected by default | +| `noBorder` | `bool` | - | - | `false` | Indicates that component is displayed without borders | +| `selectedOption` | `object` | - | - | - | Selected option | | `onSelect` | `func` | - | - | - | Will be triggered whenever an ComboBox is selected option | | `dropDownMaxHeight` | `string` | - | - | - | Height of Dropdown | | `scaled` | `bool` | - | - | `true` | Indicates that component is scaled by parent | -| `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default | -| `emptyOptionsPlaceholder`| `string` | - | - | `Select`| Label displayed in absence of options | +| `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default | \ No newline at end of file diff --git a/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js b/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js index d15457878b..093dcdff3b 100644 --- a/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js +++ b/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js @@ -11,17 +11,6 @@ import Section from '../../../.storybook/decorators/section'; const iconNames = Object.keys(Icons); const sizeOptions = ['base', 'middle', 'big', 'huge', 'content']; -const appendOptions = (comboOptions, optionsCount) => { - let newOptions = comboOptions; - for (let i = 0; i <= optionsCount; i++) { - newOptions.push({ - key: (i + 6), - label: 'Option ' + (i + 6) - }) - } - return newOptions; -}; - iconNames.push("NONE"); storiesOf('Components|Input', module) @@ -52,26 +41,25 @@ storiesOf('Components|Input', module) key: 5, icon: 'CopyIcon', label: 'Option 5' + }, + { + key: 6, + label: 'Option 6' + }, + { + key: 7, + label: 'Option 7' } ]; - const optionsCount = number('Add options', 1, - { - range: true, - min: 1, - max: 100, - step: 1 - } - ); - const needScrollDropDown = boolean('Need scroll dropdown', false); const dropDownMaxHeight = needScrollDropDown && number('dropDownMaxHeight', 200); - const optionsMultiSelect = options('Children', + const optionsMultiSelect = options('children', { button: 'button', icon: 'icon' }, - ['icon'], + [], { display: 'multi-select', }); @@ -80,10 +68,10 @@ storiesOf('Components|Input', module) optionsMultiSelect.forEach(function (item, i) { switch (item) { case "button": - children.push(