web: Components: Fixed ComboBox component, added usage ComboButton sub-component. Fixed README and story.

This commit is contained in:
Ilya Oleshko 2019-09-18 14:45:29 +03:00
parent 097f78d290
commit c4209faddb
3 changed files with 109 additions and 151 deletions

View File

@ -54,7 +54,7 @@ const advancedOptions = (
directionX="right" directionX="right"
> >
<Icons.NavLogoIcon size="medium" key="comboIcon" /> <Icons.NavLogoIcon size="medium" key="comboIcon" />
</ComboBox>; </ComboBox>
``` ```
#### Usage #### Usage
@ -101,3 +101,52 @@ const options = [
| `scaled` | `bool` | - | - | `true` | Indicates that component is scaled by parent | | `scaled` | `bool` | - | - | `true` | Indicates that component is scaled by parent |
| `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default | | `size` | `oneOf` | - | `base`, `middle`, `big`, `huge`, `content` | `base` | Select component width, one of default |
| `advancedOptions` | `element` | - | - | - | If you need display options not basic options | | `advancedOptions` | `element` | - | - | - | If you need display options not basic options |
## ComboButton
#### Description
> This description is for reference only, the component described below is not exported.
To create designs using combobox logic, there is a child component ComboButton.
This is an independent element that responds to changes in parameters and serves only to demonstrate set values.
```js
<ComboButton
noBorder={false}
isDisabled={false}
selectedOption={
{
key: 0,
label: 'Select'
}
}
withOptions={false}
optionsLength={0}
withAdvancedOptions={true}
innerContainer={
<>Demo container</>
}
innerContainerClassName='optionalBlock'
isOpen={false}
size='content'
scaled={false}
/>
```
#### Properties
| Props | Type | Required | Values | Default | Description |
| ------------------------- | -------- | :------: | -------------------------------- | ---------------- | -------------------------------------------------------- |
| `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled |
| `noBorder` | `bool` | - | - | `false` | Indicates that component is displayed without borders |
| `selectedOption` | `object` | - | - | - | Selected option |
| `withOptions` | `bool` | - | - | `true` | Lets you style as ComboBox with options |
| `optionsLength` | `number` | - | - | - | Lets you style as ComboBox with options |
| `withAdvancedOptions` | `bool` | - | - | `false` | Lets you style as a ComboBox with advanced options |
| `innerContainer` | `node` | - | - | - | Allows displaying third-party element inside ComboButton |
| `innerContainerClassName` | `string` | - | - | `innerContainer` | Required to access third-party container |
| `isOpen` | `bool` | - | - | `false` | Lets you style as ComboBox arrow |
| `scaled` | `bool` | - | - | `false` | Indicates that component is scaled by parent |
| `size` | `oneOf` | - | `base`, `...`, `huge`, `content` | `content` | Select component width, one of default |
| `onClick` | `func` | - | - | - | Will be triggered whenever an ComboButton is clicked |

View File

@ -146,7 +146,6 @@ storiesOf('Components|Input', module)
> >
<Icons.NavLogoIcon size="medium" key='comboIcon' /> <Icons.NavLogoIcon size="medium" key='comboIcon' />
</ComboBox> </ComboBox>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -3,12 +3,11 @@ import PropTypes from 'prop-types'
import styled from 'styled-components'; import styled from 'styled-components';
import DropDownItem from '../drop-down-item' import DropDownItem from '../drop-down-item'
import DropDown from '../drop-down' import DropDown from '../drop-down'
import { Icons } from '../icons'
import { handleAnyClick } from '../../utils/event'; import { handleAnyClick } from '../../utils/event';
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
import ComboButton from './sub-components/combo-button'
const StyledComboBox = styled.div` const StyledComboBox = styled.div`
color: ${props => props.isDisabled ? '#D0D5DA' : '#333333'};
width: ${props => width: ${props =>
(props.scaled && '100%') || (props.scaled && '100%') ||
(props.size === 'base' && '173px') || (props.size === 'base' && '173px') ||
@ -19,92 +18,6 @@ const StyledComboBox = styled.div`
}; };
position: relative; position: relative;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: #FFFFFF;
${props => !props.noBorder && `
border: 1px solid #D0D5DA;
border-radius: 3px;
`}
${props => props.isDisabled && !props.noBorder && `
border-color: #ECEEF1;
background: #F8F9F9;
`}
${props => !props.noBorder && `
height: 32px;
`}
:hover{
border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE' };
cursor: ${props => (props.isDisabled || !props.options.length ) ? (props.advancedOptions) ? 'pointer' : 'default' : 'pointer'};
${props => props.isDisabled && `
border-color: #ECEEF1;
`}
}
`;
const StyledComboButton = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: ${props => props.noBorder ? `18px` : `30px`};
margin-left: 8px;
`;
const StyledIcon = styled.div`
width: 16px;
margin-right: 8px;
margin-top: -2px;
`;
const StyledOptionalItem = styled.div`
margin-right: 8px;
`;
const StyledLabel = styled.div`
font-family: Open Sans;
font-style: normal;
font-weight: 600;
font-size: 13px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 8px;
${props => props.noBorder && `
line-height: 11px;
border-bottom: 1px dashed transparent;
:hover{
border-bottom: 1px dashed;
}
`};
`;
const StyledArrowIcon = styled.div`
display: flex;
align-self: start;
width: ${props => props.needDisplay ? '8px' : '0px'};
flex: 0 0 ${props => props.needDisplay ? '8px' : '0px'};
margin-top: ${props => props.noBorder ? `5px` : `12px`};
margin-right: ${props => props.needDisplay ? '8px' : '0px'};
margin-left: ${props => props.needDisplay ? 'auto' : '0px'};
${props => props.isOpen && `
transform: scale(1, -1);
`}
`; `;
class ComboBox extends React.Component { class ComboBox extends React.Component {
@ -137,11 +50,11 @@ class ComboBox extends React.Component {
}; };
optionClick = (option) => { optionClick = (option) => {
this.toggle(!this.state.isOpen);
this.setState({ this.setState({
isOpen: !this.state.isOpen, isOpen: !this.state.isOpen,
selectedOption: option selectedOption: option
}); });
this.props.onSelect && this.props.onSelect(option); this.props.onSelect && this.props.onSelect(option);
}; };
@ -149,7 +62,7 @@ class ComboBox extends React.Component {
handleAnyClick(false, this.handleClick); handleAnyClick(false, this.handleClick);
} }
shouldComponentUpdate(nextProps,nextState) { shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState); return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
} }
@ -170,62 +83,57 @@ class ComboBox extends React.Component {
render() { render() {
//console.log("ComboBox render"); //console.log("ComboBox render");
const { const {
dropDownMaxHeight, dropDownMaxHeight,
isDisabled, directionX,
directionX, directionY,
directionY, scaled,
scaled, size,
children, options,
options, advancedOptions,
noBorder, isDisabled,
advancedOptions children,
} = this.props; noBorder } = this.props;
const { isOpen, selectedOption } = this.state; const { isOpen, selectedOption } = this.state;
const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight } : {}; const dropDownMaxHeightProp = dropDownMaxHeight
const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {}; ? { maxHeight: dropDownMaxHeight }
const boxIconColor = isDisabled ? '#D0D5DA' : '#333333'; : {};
const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE'; const dropDownManualWidthProp = scaled
? { manualWidth: '100%' }
: {};
const optionsLength = options.length
? options.length
: 0;
const advancedOptionsLength = advancedOptions
&& advancedOptions.props.children.length
? advancedOptions.props.children.length
: 0;
return ( return (
<StyledComboBox ref={this.ref} <StyledComboBox
{...this.props} ref={this.ref}
{...this.state} isDisabled={isDisabled}
scaled={scaled}
size={size}
data={selectedOption} data={selectedOption}
onClick={this.comboBoxClick} onClick={this.comboBoxClick}
onSelect={this.stopAction} {...this.props}
> >
<StyledComboButton noBorder={noBorder}> <ComboButton
{children && noBorder={noBorder}
<StyledOptionalItem className='optionalBlock'> isDisabled={isDisabled}
{children} selectedOption={selectedOption}
</StyledOptionalItem> withOptions={optionsLength > 0}
} optionsLength={optionsLength}
{selectedOption && selectedOption.icon && withAdvancedOptions={advancedOptionsLength > 0}
<StyledIcon> innerContainer={children}
{React.createElement(Icons[selectedOption.icon], innerContainerClassName='optionalBlock'
{ isOpen={isOpen}
size: 'scale', size={size}
color: boxIconColor, scaled={scaled}
isfill: true />
})
}
</StyledIcon>
}
<StyledLabel noBorder={noBorder}>
{selectedOption.label}
</StyledLabel>
<StyledArrowIcon needDisplay={options.length > 0 || advancedOptions !== undefined} noBorder={noBorder} isOpen={isOpen}>
{(options.length > 0 || advancedOptions !== undefined) &&
React.createElement(Icons['ExpanderDownIcon'],
{
size: 'scale',
color: arrowIconColor,
isfill: true
})
}
</StyledArrowIcon>
</StyledComboButton>
<DropDown <DropDown
directionX={directionX} directionX={directionX}
directionY={directionY} directionY={directionY}
@ -234,15 +142,17 @@ class ComboBox extends React.Component {
{...dropDownMaxHeightProp} {...dropDownMaxHeightProp}
{...dropDownManualWidthProp} {...dropDownManualWidthProp}
> >
{advancedOptions {advancedOptions
? advancedOptions ? advancedOptions
: options.map((option) => : options.map((option) =>
<DropDownItem {...option} <DropDownItem {...option}
key={option.key} key={option.key}
disabled={option.disabled || (option.label === selectedOption.label)} disabled={
onClick={this.optionClick.bind(this, option)} option.disabled
/> || (option.label === selectedOption.label)}
)} onClick={this.optionClick.bind(this, option)}
/>
)}
</DropDown> </DropDown>
</StyledComboBox> </StyledComboBox>
); );