web: components: Styling AdvancedSelector for People groups selector

This commit is contained in:
Alexey Safronov 2019-09-11 18:00:10 +03:00
parent aade91af35
commit 30027112f9
2 changed files with 175 additions and 27 deletions

View File

@ -12,6 +12,8 @@ import { isArrayEqual } from "../../utils/array";
import findIndex from "lodash/findIndex";
import filter from "lodash/filter";
import DropDown from "../drop-down";
import { handleAnyClick } from "../../utils/event";
import isEmpty from 'lodash/isEmpty';
/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
@ -32,16 +34,27 @@ const Container = ({
groups,
selectedGroups,
onChangeGroup,
isOpen,
isDropDown,
containerWidth,
containerHeight,
...props
}) => <div {...props} />;
/* eslint-enable react/prop-types */
/* eslint-enable no-unused-vars */
const StyledContainer = styled(Container)`
${props => (props.width ? `width: ${props.width}px;` : "")}
display: flex;
flex-direction: column;
${props => (props.containerWidth ? `width: ${props.containerWidth}px;` : "")}
${props =>
props.containerHeight
? `height: ${props.containerHeight}px;`
: ""}
.data_container {
margin: 16px;
margin: 16px 16px 0 16px;
.options_searcher {
margin-bottom: 12px;
@ -53,7 +66,7 @@ const StyledContainer = styled(Container)`
.option_select_all_checkbox {
margin-bottom: 12px;
margin-left: 8px;
/*margin-left: 8px;*/
}
.options_list {
@ -62,33 +75,36 @@ const StyledContainer = styled(Container)`
cursor: pointer;
.option_checkbox {
margin-left: 8px;
/*margin-left: 8px;*/
}
.option_link {
padding-left: 8px;
}
&:hover {
/*&:hover {
background-color: #eceef1;
}
}*/
}
}
}
.button_container {
border-top: 1px solid #eceef1;
.add_members_btn {
margin: 16px;
width: 293px;
border-top: 1px solid #eceef1;
display: flex;
.add_members_btn {
margin: 16px;
}
}
}
`;
class AdvancedSelector extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
const groups = this.convertGroups(this.props.groups);
const currentGroup = this.getCurrentGroup(groups);
@ -98,25 +114,53 @@ class AdvancedSelector extends React.Component {
groups: groups,
currentGroup: currentGroup
};
if (props.isOpen) handleAnyClick(true, this.handleClick);
}
handleClick = e => {
if (this.props.isOpen && !this.ref.current.contains(e.target)) {
this.props.onSelect && this.props.onSelect(this.state.selectedOptions);
}
};
componentWillUnmount() {
handleAnyClick(false, this.handleClick);
}
componentDidUpdate(prevProps) {
let newState = {};
if (!isArrayEqual(this.props.selectedOptions, prevProps.selectedOptions)) {
this.setState({ selectedOptions: this.props.selectedOptions });
newState = { selectedOptions: this.props.selectedOptions };
}
if (this.props.isMultiSelect !== prevProps.isMultiSelect) {
this.setState({ selectedOptions: [] });
newState = Object.assign({}, newState, {
selectedOptions: []
});
}
if (this.props.selectedAll !== prevProps.selectedAll) {
this.setState({ selectedAll: this.props.selectedAll });
newState = Object.assign({}, newState, {
selectedAll: this.props.selectedAll
});
}
if (!isArrayEqual(this.props.groups, prevProps.groups)) {
const groups = this.convertGroups(this.props.groups);
const currentGroup = this.getCurrentGroup(groups);
this.setState({ groups, currentGroup });
newState = Object.assign({}, newState, {
groups, currentGroup
});
}
if(!isEmpty(newState)) {
this.setState({ ...this.state, ...newState });
}
if (this.props.isOpen !== prevProps.isOpen) {
handleAnyClick(this.props.isOpen, this.handleClick);
}
}
@ -215,7 +259,6 @@ class AdvancedSelector extends React.Component {
const {
value,
placeholder,
maxHeight,
isDisabled,
onSearchChanged,
options,
@ -225,9 +268,19 @@ class AdvancedSelector extends React.Component {
} = this.props;
const { selectedOptions, selectedAll, currentGroup, groups } = this.state;
const containerHeight = !groups || !groups.length ? 336 : 545;
const containerWidth = !groups || !groups.length ? 325 : 690;
const listHeight = 176;
const itemHeight = 32;
return (
<StyledContainer {...this.props}>
<div className="data_container">
<StyledContainer
containerHeight={containerHeight}
containerWidth={containerWidth}
{...this.props}
>
<div className="data_container" ref={this.ref}>
<SearchInput
className="options_searcher"
isDisabled={isDisabled}
@ -264,10 +317,10 @@ class AdvancedSelector extends React.Component {
)}
<FixedSizeList
className="options_list"
height={maxHeight}
itemSize={32}
itemCount={options.length}
itemData={options}
height={listHeight}
itemSize={itemHeight}
itemCount={this.props.options.length}
itemData={this.props.options}
outerElementType={CustomScrollbarsVirtualList}
>
{this.renderRow.bind(this)}
@ -310,8 +363,7 @@ AdvancedSelector.propTypes = {
value: PropTypes.string,
placeholder: PropTypes.string,
isMultiSelect: PropTypes.bool,
mode: PropTypes.oneOf(["base", "compact"]),
width: PropTypes.number,
mode: PropTypes.oneOf(["compact", "full"]),
maxHeight: PropTypes.number,
isDisabled: PropTypes.bool,
onSearchChanged: PropTypes.func,
@ -330,9 +382,7 @@ AdvancedSelector.propTypes = {
AdvancedSelector.defaultProps = {
isMultiSelect: false,
width: 325,
maxHeight: 545,
mode: "base",
mode: "compact",
buttonLabel: "Add members",
selectAllLabel: "Select all"
};

View File

@ -0,0 +1,98 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { withKnobs, text } from "@storybook/addon-knobs/react";
import AdvancedSelector from "../advanced-selector";
import Section from "../../../.storybook/decorators/section";
import { boolean } from "@storybook/addon-knobs/dist/deprecated";
import { ArrayValue, BooleanValue } from "react-values";
import Button from "../button";
storiesOf("EXAMPLES|AdvancedSelector", module)
.addDecorator(withKnobs)
// To set a default viewport for all the stories for this component
.addParameters({ viewport: { defaultViewport: "responsive" } })
.add("people group selector", () => {
const options = [
{
key: "group-all",
label: "All groups",
total: 0
},
{
key: "group-dev",
label: "Development",
total: 0
},
{
key: "group-management",
label: "Management",
total: 0
},
{
key: "group-marketing",
label: "Marketing",
total: 0
},
{
key: "group-mobile",
label: "Mobile",
total: 0
},
{
key: "group-support",
label: "Support",
total: 0
},
{
key: "group-web",
label: "Web",
total: 0
}
];
return (
<Section>
<BooleanValue
defaultValue={true}
onChange={() => action("isOpen changed")}
>
{({ value: isOpen, toggle }) => (
<div style={{ position: "relative" }}>
<Button label="Toggle dropdown" onClick={toggle} />
<ArrayValue
defaultValue={options}
onChange={() => action("options onChange")}
>
{({ value, set }) => (
<AdvancedSelector
isDropDown={true}
isOpen={isOpen}
maxHeight={336}
width={379}
placeholder={text("placeholder", "Search")}
onSearchChanged={value => {
action("onSearchChanged")(value);
set(
options.filter(option => {
return option.label.indexOf(value) > -1;
})
);
}}
options={value}
isMultiSelect={boolean("isMultiSelect", true)}
buttonLabel={text("buttonLabel", "Add departments")}
selectAllLabel={text("selectAllLabel", "Select all")}
onSelect={selectedOptions => {
action("onSelect")(selectedOptions);
toggle();
}}
/>
)}
</ArrayValue>
</div>
)}
</BooleanValue>
</Section>
);
});