2019-07-18 08:00:54 +00:00
|
|
|
import React from 'react'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import styled from 'styled-components';
|
|
|
|
import DropDownItem from '../drop-down-item'
|
|
|
|
import DropDown from '../drop-down'
|
2019-08-08 11:14:25 +00:00
|
|
|
import { Icons } from '../icons'
|
2019-08-02 07:35:54 +00:00
|
|
|
import { handleAnyClick } from '../../utils/event';
|
2019-09-12 12:21:58 +00:00
|
|
|
import isEqual from 'lodash/isEqual';
|
2019-07-18 08:00:54 +00:00
|
|
|
|
|
|
|
const StyledComboBox = styled.div`
|
2019-08-12 08:19:52 +00:00
|
|
|
color: ${props => props.isDisabled ? '#D0D5DA' : '#333333'};
|
|
|
|
width: ${props =>
|
|
|
|
(props.scaled && '100%') ||
|
|
|
|
(props.size === 'base' && '173px') ||
|
|
|
|
(props.size === 'middle' && '300px') ||
|
|
|
|
(props.size === 'big' && '350px') ||
|
|
|
|
(props.size === 'huge' && '500px') ||
|
|
|
|
(props.size === 'content' && 'fit-content')
|
|
|
|
};
|
2019-08-08 11:14:25 +00:00
|
|
|
|
2019-08-12 08:19:52 +00:00
|
|
|
position: relative;
|
|
|
|
|
|
|
|
-webkit-touch-callout: none;
|
|
|
|
-webkit-user-select: none;
|
|
|
|
-moz-user-select: none;
|
|
|
|
-ms-user-select: none;
|
|
|
|
user-select: none;
|
|
|
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
2019-08-14 12:53:05 +00:00
|
|
|
${props => !props.noBorder && `
|
|
|
|
border: 1px solid #D0D5DA;
|
|
|
|
border-radius: 3px;
|
|
|
|
`}
|
|
|
|
|
|
|
|
${props => props.isDisabled && !props.noBorder && `
|
2019-08-12 08:19:52 +00:00
|
|
|
border-color: #ECEEF1;
|
|
|
|
background: #F8F9F9;
|
|
|
|
`}
|
|
|
|
|
2019-08-14 12:53:05 +00:00
|
|
|
${props => !props.noBorder && `
|
|
|
|
height: 32px;
|
|
|
|
`}
|
2019-08-12 08:19:52 +00:00
|
|
|
|
|
|
|
:hover{
|
2019-08-16 06:54:23 +00:00
|
|
|
border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE' };
|
2019-08-30 13:44:04 +00:00
|
|
|
cursor: ${props => (props.isDisabled || !props.options.length ) ? (props.advancedOptions) ? 'pointer' : 'default' : 'pointer'};
|
2019-08-12 08:19:52 +00:00
|
|
|
|
|
|
|
${props => props.isDisabled && `
|
|
|
|
border-color: #ECEEF1;
|
2019-08-16 06:54:23 +00:00
|
|
|
`}
|
2019-08-08 11:14:25 +00:00
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2019-08-12 08:19:52 +00:00
|
|
|
const StyledComboButton = styled.div`
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
2019-08-14 12:53:05 +00:00
|
|
|
|
|
|
|
height: ${props => props.noBorder ? `18px` : `30px`};
|
2019-08-08 11:14:25 +00:00
|
|
|
margin-left: 8px;
|
2019-08-12 08:19:52 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
const StyledIcon = styled.div`
|
|
|
|
width: 16px;
|
|
|
|
margin-right: 8px;
|
|
|
|
margin-top: -2px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const StyledOptionalItem = styled.div`
|
2019-08-30 13:44:04 +00:00
|
|
|
margin-right: 8px;
|
2019-08-12 08:19:52 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
const StyledLabel = styled.div`
|
2019-08-21 09:25:36 +00:00
|
|
|
font-family: Open Sans;
|
|
|
|
font-style: normal;
|
|
|
|
font-weight: 600;
|
|
|
|
font-size: 13px;
|
2019-08-12 08:19:52 +00:00
|
|
|
|
2019-08-21 09:25:36 +00:00
|
|
|
white-space: nowrap;
|
|
|
|
overflow: hidden;
|
|
|
|
text-overflow: ellipsis;
|
2019-08-12 08:19:52 +00:00
|
|
|
|
2019-08-21 09:25:36 +00:00
|
|
|
margin-right: 8px;
|
2019-08-14 12:53:05 +00:00
|
|
|
|
2019-08-21 09:25:36 +00:00
|
|
|
${props => props.noBorder && `
|
|
|
|
line-height: 11px;
|
|
|
|
border-bottom: 1px dashed transparent;
|
2019-08-14 12:53:05 +00:00
|
|
|
|
2019-08-21 09:25:36 +00:00
|
|
|
:hover{
|
|
|
|
border-bottom: 1px dashed;
|
|
|
|
}
|
|
|
|
`};
|
2019-08-12 08:19:52 +00:00
|
|
|
`;
|
|
|
|
|
|
|
|
const StyledArrowIcon = styled.div`
|
2019-08-21 09:25:36 +00:00
|
|
|
display: flex;
|
|
|
|
align-self: start;
|
2019-09-05 13:07:18 +00:00
|
|
|
width: ${props => props.needDisplay ? '8px' : '0px'};
|
|
|
|
flex: 0 0 ${props => props.needDisplay ? '8px' : '0px'};
|
2019-08-14 12:53:05 +00:00
|
|
|
margin-top: ${props => props.noBorder ? `5px` : `12px`};
|
2019-08-30 13:44:04 +00:00
|
|
|
margin-right: ${props => props.needDisplay ? '8px' : '0px'};
|
|
|
|
margin-left: ${props => props.needDisplay ? 'auto' : '0px'};
|
2019-08-12 08:19:52 +00:00
|
|
|
|
2019-08-14 12:53:05 +00:00
|
|
|
${props => props.isOpen && `
|
2019-08-12 08:19:52 +00:00
|
|
|
transform: scale(1, -1);
|
|
|
|
`}
|
2019-07-18 08:00:54 +00:00
|
|
|
`;
|
|
|
|
|
2019-09-12 12:21:58 +00:00
|
|
|
class ComboBox extends React.Component {
|
2019-07-30 13:49:33 +00:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2019-07-18 08:00:54 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
this.ref = React.createRef();
|
2019-07-26 09:02:08 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
this.state = {
|
|
|
|
isOpen: props.opened,
|
2019-08-14 12:53:05 +00:00
|
|
|
selectedOption: props.selectedOption
|
2019-07-30 13:49:33 +00:00
|
|
|
};
|
2019-07-24 17:43:18 +00:00
|
|
|
|
2019-08-06 07:39:33 +00:00
|
|
|
if (props.opened)
|
2019-08-02 07:35:54 +00:00
|
|
|
handleAnyClick(true, this.handleClick);
|
2019-07-30 13:49:33 +00:00
|
|
|
}
|
2019-07-18 08:00:54 +00:00
|
|
|
|
2019-08-14 12:53:05 +00:00
|
|
|
handleClick = (e) =>
|
|
|
|
this.state.isOpen
|
|
|
|
&& !this.ref.current.contains(e.target)
|
|
|
|
&& this.toggle(false);
|
2019-08-05 12:45:12 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
stopAction = (e) => e.preventDefault();
|
2019-08-05 12:45:12 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
toggle = (isOpen) => this.setState({ isOpen: isOpen });
|
2019-08-05 12:45:12 +00:00
|
|
|
|
|
|
|
comboBoxClick = (e) => {
|
2019-08-30 13:44:04 +00:00
|
|
|
if (this.props.isDisabled || e.target.closest('.optionalBlock')) return;
|
2019-08-14 12:53:05 +00:00
|
|
|
this.toggle(!this.state.isOpen);
|
2019-07-30 13:49:33 +00:00
|
|
|
};
|
2019-08-05 12:45:12 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
optionClick = (option) => {
|
2019-08-14 12:53:05 +00:00
|
|
|
this.toggle(!this.state.isOpen);
|
2019-08-16 06:54:23 +00:00
|
|
|
this.setState({
|
2019-08-14 12:53:05 +00:00
|
|
|
isOpen: !this.state.isOpen,
|
|
|
|
selectedOption: option
|
2019-07-31 18:42:23 +00:00
|
|
|
});
|
2019-07-30 13:49:33 +00:00
|
|
|
this.props.onSelect && this.props.onSelect(option);
|
|
|
|
};
|
2019-07-18 08:00:54 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
componentWillUnmount() {
|
2019-08-02 07:35:54 +00:00
|
|
|
handleAnyClick(false, this.handleClick);
|
2019-09-09 13:32:04 +00:00
|
|
|
}
|
2019-08-09 09:19:07 +00:00
|
|
|
|
2019-09-12 12:21:58 +00:00
|
|
|
shouldComponentUpdate(nextProps,nextState) {
|
|
|
|
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
|
|
|
}
|
|
|
|
|
2019-08-02 07:35:54 +00:00
|
|
|
componentDidUpdate(prevProps, prevState) {
|
2019-07-30 13:49:33 +00:00
|
|
|
if (this.props.opened !== prevProps.opened) {
|
2019-08-14 12:53:05 +00:00
|
|
|
handleAnyClick(this.props.opened, this.handleClick);
|
2019-07-18 08:00:54 +00:00
|
|
|
}
|
2019-08-02 07:35:54 +00:00
|
|
|
|
2019-08-06 07:39:33 +00:00
|
|
|
if (this.state.isOpen !== prevState.isOpen) {
|
2019-08-02 07:35:54 +00:00
|
|
|
handleAnyClick(this.state.isOpen, this.handleClick);
|
|
|
|
}
|
2019-08-05 15:12:25 +00:00
|
|
|
|
2019-08-06 07:39:33 +00:00
|
|
|
if (this.props.selectedOption !== prevProps.selectedOption) {
|
2019-08-16 06:54:23 +00:00
|
|
|
this.setState({ selectedOption: this.props.selectedOption });
|
2019-08-05 15:12:25 +00:00
|
|
|
}
|
2019-09-09 13:32:04 +00:00
|
|
|
}
|
2019-07-18 08:00:54 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
render() {
|
2019-08-28 12:53:38 +00:00
|
|
|
//console.log("ComboBox render");
|
2019-09-02 11:15:24 +00:00
|
|
|
const {
|
|
|
|
dropDownMaxHeight,
|
|
|
|
isDisabled,
|
|
|
|
directionX,
|
|
|
|
directionY,
|
|
|
|
scaled,
|
|
|
|
children,
|
|
|
|
options,
|
|
|
|
noBorder,
|
|
|
|
advancedOptions
|
|
|
|
} = this.props;
|
2019-08-14 12:53:05 +00:00
|
|
|
const { isOpen, selectedOption } = this.state;
|
2019-08-12 08:19:52 +00:00
|
|
|
|
2019-08-14 12:53:05 +00:00
|
|
|
const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight } : {};
|
2019-08-12 08:19:52 +00:00
|
|
|
const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {};
|
|
|
|
const boxIconColor = isDisabled ? '#D0D5DA' : '#333333';
|
|
|
|
const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE';
|
2019-08-30 13:44:04 +00:00
|
|
|
|
2019-07-30 13:49:33 +00:00
|
|
|
return (
|
2019-08-08 11:14:25 +00:00
|
|
|
<StyledComboBox ref={this.ref}
|
|
|
|
{...this.props}
|
|
|
|
{...this.state}
|
2019-08-14 12:53:05 +00:00
|
|
|
data={selectedOption}
|
2019-08-08 11:14:25 +00:00
|
|
|
onClick={this.comboBoxClick}
|
|
|
|
onSelect={this.stopAction}
|
|
|
|
>
|
2019-08-14 12:53:05 +00:00
|
|
|
<StyledComboButton noBorder={noBorder}>
|
2019-08-30 13:44:04 +00:00
|
|
|
{children &&
|
|
|
|
<StyledOptionalItem className='optionalBlock'>
|
|
|
|
{children}
|
|
|
|
</StyledOptionalItem>
|
|
|
|
}
|
2019-08-14 12:53:05 +00:00
|
|
|
{selectedOption && selectedOption.icon &&
|
2019-08-08 11:14:25 +00:00
|
|
|
<StyledIcon>
|
2019-08-14 12:53:05 +00:00
|
|
|
{React.createElement(Icons[selectedOption.icon],
|
2019-08-08 11:14:25 +00:00
|
|
|
{
|
2019-08-12 08:19:52 +00:00
|
|
|
size: 'scale',
|
|
|
|
color: boxIconColor,
|
2019-08-08 11:14:25 +00:00
|
|
|
isfill: true
|
|
|
|
})
|
|
|
|
}
|
2019-08-12 08:19:52 +00:00
|
|
|
</StyledIcon>
|
|
|
|
}
|
2019-08-14 12:53:05 +00:00
|
|
|
<StyledLabel noBorder={noBorder}>
|
|
|
|
{selectedOption.label}
|
2019-08-12 08:19:52 +00:00
|
|
|
</StyledLabel>
|
2019-08-30 13:44:04 +00:00
|
|
|
<StyledArrowIcon needDisplay={options.length > 0 || advancedOptions !== undefined} noBorder={noBorder} isOpen={isOpen}>
|
2019-09-02 11:15:24 +00:00
|
|
|
{(options.length > 0 || advancedOptions !== undefined) &&
|
2019-08-16 06:54:23 +00:00
|
|
|
React.createElement(Icons['ExpanderDownIcon'],
|
|
|
|
{
|
|
|
|
size: 'scale',
|
|
|
|
color: arrowIconColor,
|
|
|
|
isfill: true
|
|
|
|
})
|
2019-08-12 08:19:52 +00:00
|
|
|
}
|
|
|
|
</StyledArrowIcon>
|
|
|
|
</StyledComboButton>
|
|
|
|
<DropDown
|
|
|
|
directionX={directionX}
|
|
|
|
directionY={directionY}
|
|
|
|
manualY='102%'
|
|
|
|
isOpen={isOpen}
|
|
|
|
{...dropDownMaxHeightProp}
|
|
|
|
{...dropDownManualWidthProp}
|
|
|
|
>
|
2019-09-02 11:15:24 +00:00
|
|
|
{advancedOptions
|
|
|
|
? advancedOptions
|
|
|
|
: options.map((option) =>
|
2019-08-12 08:19:52 +00:00
|
|
|
<DropDownItem {...option}
|
2019-09-09 13:32:04 +00:00
|
|
|
key={option.key}
|
2019-08-29 12:54:19 +00:00
|
|
|
disabled={option.disabled || (option.label === selectedOption.label)}
|
2019-08-12 08:19:52 +00:00
|
|
|
onClick={this.optionClick.bind(this, option)}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</DropDown>
|
2019-07-30 13:49:33 +00:00
|
|
|
</StyledComboBox>
|
|
|
|
);
|
|
|
|
}
|
2019-09-09 13:32:04 +00:00
|
|
|
}
|
2019-07-18 08:00:54 +00:00
|
|
|
|
|
|
|
ComboBox.propTypes = {
|
2019-08-14 12:53:05 +00:00
|
|
|
noBorder: PropTypes.bool,
|
2019-07-30 13:49:33 +00:00
|
|
|
isDisabled: PropTypes.bool,
|
2019-08-15 14:06:03 +00:00
|
|
|
selectedOption: PropTypes.object.isRequired,
|
2019-08-30 13:44:04 +00:00
|
|
|
|
2019-08-15 14:06:03 +00:00
|
|
|
options: PropTypes.array.isRequired,
|
2019-08-30 13:44:04 +00:00
|
|
|
advancedOptions: PropTypes.element,
|
2019-09-09 13:32:04 +00:00
|
|
|
children: PropTypes.any,
|
|
|
|
opened: PropTypes.bool,
|
2019-08-30 13:44:04 +00:00
|
|
|
|
2019-08-09 07:57:12 +00:00
|
|
|
onSelect: PropTypes.func,
|
2019-08-13 11:12:26 +00:00
|
|
|
dropDownMaxHeight: PropTypes.number,
|
2019-08-12 08:19:52 +00:00
|
|
|
size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']),
|
2019-09-09 13:32:04 +00:00
|
|
|
directionX: PropTypes.oneOf(['left', 'right']),
|
|
|
|
directionY: PropTypes.oneOf(['bottom', 'top']),
|
2019-08-30 13:44:04 +00:00
|
|
|
scaled: PropTypes.bool
|
2019-07-18 08:00:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ComboBox.defaultProps = {
|
2019-08-14 12:53:05 +00:00
|
|
|
noBorder: false,
|
2019-07-30 13:49:33 +00:00
|
|
|
isDisabled: false,
|
2019-08-12 08:19:52 +00:00
|
|
|
size: 'base',
|
|
|
|
scaled: true
|
2019-07-18 08:00:54 +00:00
|
|
|
}
|
2019-07-26 09:02:08 +00:00
|
|
|
|
2019-07-18 08:00:54 +00:00
|
|
|
export default ComboBox;
|