From d6f7eb7f429586898daacc0bf68b4d02d671a6ad Mon Sep 17 00:00:00 2001 From: NikolayRechkin Date: Mon, 12 Aug 2019 10:57:05 +0300 Subject: [PATCH 1/4] web: components: small fix SearchInput --- .../components/search-input/filter-button.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/web/ASC.Web.Components/src/components/search-input/filter-button.js b/web/ASC.Web.Components/src/components/search-input/filter-button.js index 2d886dd3c3..aa24c75e4c 100644 --- a/web/ASC.Web.Components/src/components/search-input/filter-button.js +++ b/web/ASC.Web.Components/src/components/search-input/filter-button.js @@ -1,20 +1,22 @@ import React from "react"; import ContextMenuButton from '../context-menu-button'; -const FilterButton = props => { - //console.log("FilterButton render"); - return ( - - ); -}; + ) + } +} export default FilterButton \ No newline at end of file From 3c4218d79dce08a171174f381470ea579bfbee3c Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Mon, 12 Aug 2019 11:19:52 +0300 Subject: [PATCH 2/4] web: Components: Reworked ComboBox component. Fixed readme and story. --- .../src/components/combobox/index.js | 198 +++++++++++------- .../stories/input/combobox/README.md | 16 +- .../input/combobox/combobox.stories.js | 119 ++++++++--- 3 files changed, 230 insertions(+), 103 deletions(-) diff --git a/web/ASC.Web.Components/src/components/combobox/index.js b/web/ASC.Web.Components/src/components/combobox/index.js index 4b072e9d6e..befc1f190f 100644 --- a/web/ASC.Web.Components/src/components/combobox/index.js +++ b/web/ASC.Web.Components/src/components/combobox/index.js @@ -1,50 +1,88 @@ import React from 'react' import PropTypes from 'prop-types' import styled from 'styled-components'; -import InputBlock from '../input-block' import DropDownItem from '../drop-down-item' import DropDown from '../drop-down' import { Icons } from '../icons' import { handleAnyClick } from '../../utils/event'; const StyledComboBox = styled.div` - * { - ${props => !props.withBorder && `border-color: transparent !important;`} - } + 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') + }; - ${state => state.isOpen && ` - .input-group-append > div { - -moz-transform: scaleY(-1); - -o-transform: scaleY(-1); - -webkit-transform: scaleY(-1); - transform: scaleY(-1); - } + position: relative; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background: #FFFFFF; + border: 1px solid #D0D5DA; + border-radius: 3px; + + ${props => props.isDisabled && ` + border-color: #ECEEF1; + background: #F8F9F9; `} - - & > div > input { - &::placeholder { - font-family: Open Sans; - font-style: normal; - font-weight: 600; - font-size: 13px; - line-height: 20px; - ${props => !props.isDisabled && `color: #333333;`} - ${props => (!props.withBorder & !props.isDisabled) && `border-bottom: 1px dotted #333333;`} - opacity: 1; - -webkit-touch-callout: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } + height: 32px; + + :hover{ + border-color: ${state => state.isOpen ? '#2DA7DB' : '#A3A9AE'}; + + ${props => props.isDisabled && ` + border-color: #ECEEF1; + `} } `; -const StyledIcon = styled.span` - width: 16px; +const StyledComboButton = styled.div` + display: flex; + align-items: center; + justify-content: center; + height: 30px; margin-left: 8px; - line-height: 14px; +`; + +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; + +margin-right: 8px; +`; + +const StyledArrowIcon = styled.div` + width: 8px; + margin-right: 8px; + margin-left: auto; + + ${state => state.isOpen && ` + transform: scale(1, -1); + margin-top: 8px; + `} `; class ComboBox extends React.PureComponent { @@ -79,7 +117,7 @@ class ComboBox extends React.PureComponent { toggle = (isOpen) => this.setState({ isOpen: isOpen }); comboBoxClick = (e) => { - if (this.props.isDisabled || !!e.target.closest('.input-group-prepend')) return; + if (this.props.isDisabled) return; this.setState({ option: this.props.option, @@ -110,7 +148,7 @@ class ComboBox extends React.PureComponent { getSelectedLabel = () => { const selectedItem = this.getSelected(); - return selectedItem ? selectedItem.label : "1-1"; + return selectedItem ? selectedItem.label : this.props.emptyOptionsPlaceholder; } componentDidUpdate(prevProps, prevState) { @@ -124,9 +162,9 @@ class ComboBox extends React.PureComponent { if (this.props.options.length !== prevProps.options.length) { //TODO: Move options from state const label = this.getSelectedLabel(); - this.setState({ + this.setState({ options: this.props.options, - boxLabel: label + boxLabel: label }); } @@ -139,52 +177,65 @@ class ComboBox extends React.PureComponent { render() { console.log("ComboBox render"); - const dropDownMaxHeightProp = this.props.dropDownMaxHeight ? { maxHeight: this.props.dropDownMaxHeight } : {} + const { dropDownMaxHeight, isDisabled, directionX, directionY, scaled, children } = this.props; + const { boxLabel, boxIcon, isOpen, options } = this.state; + + const dropDownMaxHeightProp = dropDownMaxHeight ? { maxHeight: dropDownMaxHeight } : {}; + const dropDownManualWidthProp = scaled ? { manualWidth: '100%' } : {}; + const boxIconColor = isDisabled ? '#D0D5DA' : '#333333'; + const arrowIconColor = isDisabled ? '#D0D5DA' : '#A3A9AE'; return ( - - {this.state.boxIcon && + + + {children} + + {boxIcon && - {React.createElement(Icons[this.state.boxIcon], + {React.createElement(Icons[boxIcon], { - size: "scale", - color: this.props.isDisabled ? '#D0D5DA' : '#333333', + size: 'scale', + color: boxIconColor, isfill: true }) } - } - {this.props.children} - - {this.state.options.map((option) => - - )} - - + + } + + {boxLabel} + + + {React.createElement(Icons['ExpanderDownIcon'], + { + size: 'scale', + color: arrowIconColor, + isfill: true + }) + } + + + + {options.map((option) => + + )} + ); } @@ -199,13 +250,20 @@ ComboBox.propTypes = { ]), options: PropTypes.array, onSelect: PropTypes.func, - dropDownMaxHeight: PropTypes.string + dropDownMaxHeight: PropTypes.string, + emptyOptionsPlaceholder: PropTypes.string, + + size: PropTypes.oneOf(['base', 'middle', 'big', 'huge', 'content']), + scaled: PropTypes.bool, } ComboBox.defaultProps = { isDisabled: false, withBorder: true, - dropDownMaxHeight: null + dropDownMaxHeight: null, + emptyOptionsPlaceholder: 'Select', + size: 'base', + scaled: true } export default ComboBox; \ No newline at end of file diff --git a/web/ASC.Web.Storybook/stories/input/combobox/README.md b/web/ASC.Web.Storybook/stories/input/combobox/README.md index 645ed42897..74c13b0828 100644 --- a/web/ASC.Web.Storybook/stories/input/combobox/README.md +++ b/web/ASC.Web.Storybook/stories/input/combobox/README.md @@ -40,7 +40,14 @@ const options = [ } ]; - console.log('selected', option)}/> + console.log('selected', option)} +/> ``` #### Properties @@ -49,6 +56,9 @@ const options = [ | ---------------------- | ----------------- | :------: | ---------------------------- | ------- | -------------------------------------------- | | `options` | `array` | ✅ | - | - | Combo box options | | `isDisabled` | `bool` | - | - | `false` | Indicates that component is disabled | -| `withBorder` | `bool` | - | - | `true` | Indicates that component contain border | | `selectedOption` | `string`,`number` | - | - | `0` | Index of option selected by default | -| `onSelect` | `func` | - | - | - | Will be triggered whenever an ComboBox is selected option | \ No newline at end of file +| `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 | 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 9ca2baa16f..4711630b25 100644 --- a/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js +++ b/web/ASC.Web.Storybook/stories/input/combobox/combobox.stories.js @@ -1,48 +1,107 @@ -import React from 'react' -import { storiesOf } from '@storybook/react' -import { withKnobs, boolean} from '@storybook/addon-knobs/react'; +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { withKnobs, boolean, select, number } from '@storybook/addon-knobs/react'; +import { optionsKnob as options } from '@storybook/addon-knobs'; import withReadme from 'storybook-readme/with-readme'; import Readme from './README.md'; +import { ComboBox, Icons, Button } from 'asc-web-components' import Section from '../../../.storybook/decorators/section'; -import { ComboBox } from 'asc-web-components' -import { action } from '@storybook/addon-actions'; -const options = [ - { +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) + .addDecorator(withKnobs) + .addDecorator(withReadme(Readme)) + .add('combo box', () => { + + const comboOptions = [ + { key: 1, icon: 'CatalogEmployeeIcon', label: 'Option 1' - }, - { + }, + { key: 2, icon: 'CatalogGuestIcon', label: 'Option 2', - }, - { + }, + { key: 3, label: 'Option 3' - }, - { + }, + { key: 4, label: 'Option 4' - }, - { + }, + { key: 5, icon: 'CopyIcon', label: 'Option 5' - } -]; + } + ]; -storiesOf('Components|Input', module) - .addDecorator(withKnobs) - .addDecorator(withReadme(Readme)) - .add('combo box', () => ( -
- action("Selected option")(option)} - isDisabled={boolean('isDisabled', false)} - withBorder={boolean('withBorder', true)} - /> -
- )); \ No newline at end of file + 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', + { + button: 'button', + icon: 'icon' + }, + ['icon'], + { + display: 'multi-select', + }); + + let children = []; + optionsMultiSelect.forEach(function (item, i) { + switch (item) { + case "button": + children.push(