Web: Components: Added onSelect callback at GroupButtonsMenu and isSelect property at GroupButton component. Fixed stories of GroupButtonsMenu component.

This commit is contained in:
Ilya Oleshko 2019-07-30 14:17:19 +03:00
parent 9dc1a7f196
commit 826586ec15
4 changed files with 348 additions and 284 deletions

View File

@ -4,6 +4,7 @@ import PropTypes from "prop-types";
import { Icons } from "../icons";
import DropDown from "../drop-down";
import DropDownItem from "../drop-down-item";
import Checkbox from "../checkbox";
const textColor = "#333333",
disabledTextColor = "#A3A9AE";
@ -82,6 +83,15 @@ const Separator = styled.div`
margin-top: 16px;
`;
const StyledCheckbox = styled.div`
display: inline-block;
margin: auto 0 auto 16px;
& > * {
margin: 0px;
}
`;
class GroupButton extends React.PureComponent {
constructor(props) {
super(props);
@ -89,7 +99,8 @@ class GroupButton extends React.PureComponent {
this.ref = React.createRef();
this.state = {
isOpen: props.opened
isOpen: props.opened,
selected: props.selected
};
this.handleClick = this.handleClick.bind(this);
@ -122,41 +133,46 @@ class GroupButton extends React.PureComponent {
render() {
//console.log("GroupButton render");
const { label, isDropdown, disabled, isSeparator } = this.props;
const { label, isDropdown, disabled, isSeparator, isSelect, onSelect, checked, isIndeterminate, onChange, children, selected } = this.props;
const color = disabled ? disabledTextColor : textColor;
return (
<StyledGroupButton ref={this.ref}>
{isDropdown ? (
<>
<StyledDropdownToggle
{...this.props}
{isDropdown
? <>
{isSelect &&
<StyledCheckbox>
<Checkbox
isChecked={checked}
isIndeterminate={isIndeterminate}
onChange={(e) => {
onChange && onChange(e.target.checked);
this.setState({ selected: selected });
}} />
</StyledCheckbox>
}
<StyledDropdownToggle {...this.props}
onClick={() => {
disabled ? false : this.toggle(!this.state.isOpen);
}}
>
{label}
<Caret
size="small"
color={disabled ? disabledTextColor : textColor}
/>
{!isSelect ? label : this.state.selected}
<Caret size="small" color={color} />
</StyledDropdownToggle>
<DropDown isOpen={this.state.isOpen}>
{
React.Children.map(this.props.children, (child) =>
<DropDownItem
{...child.props}
onClick={() => {
child.props.onClick && child.props.onClick();
this.toggle(!this.state.isOpen);
}}
/>
)
}
{React.Children.map(children, (child) => {
return <DropDownItem {...child.props} onClick={() => {
child.props.onClick && child.props.onClick();
onSelect && onSelect(child);
this.setState({ selected: child.props.label });
this.toggle(!this.state.isOpen);
}} />;
})}
</DropDown>
</>
) : (
<StyledDropdownToggle {...this.props}>{label}</StyledDropdownToggle>
)}
: <StyledDropdownToggle {...this.props}>{label}</StyledDropdownToggle>
}
{isSeparator && <Separator />}
</StyledGroupButton>
);
@ -173,7 +189,9 @@ GroupButton.propTypes = {
isSeparator: PropTypes.bool,
tabIndex: PropTypes.number,
onClick: PropTypes.func,
fontWeight: PropTypes.string
fontWeight: PropTypes.string,
onSelect: PropTypes.func,
isSelect: PropTypes.bool
};
GroupButton.defaultProps = {
@ -185,7 +203,8 @@ GroupButton.defaultProps = {
isDropdown: false,
isSeparator: false,
tabIndex: -1,
fontWeight: "600"
fontWeight: "600",
isSelect: false
};
export default GroupButton;

View File

@ -1,9 +1,8 @@
import React from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import GroupButton from '../group-button'
import DropDownItem from '../drop-down-item'
import Checkbox from '../checkbox'
import React from 'react';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import GroupButton from '../group-button';
import DropDownItem from '../drop-down-item';
const StyledGroupButtonsMenu = styled.div`
position: sticky;
@ -48,137 +47,125 @@ const CloseButton = styled.div`
}
`;
const StyledCheckbox = styled.div`
display: inline-block;
margin-left: 16px;
vertical-align: middle;
& > * {
margin: 0px;
}
`;
class GroupButtonsMenu extends React.PureComponent {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
priorityItems: props.menuItems,
moreItems: [],
visible: true
}
this.fullMenuArray = this.props.menuItems;
this.checkBox = this.props.checkBox;
this.updateMenu = this.updateMenu.bind(this);
this.howManyItemsInMenuArray = this.howManyItemsInMenuArray.bind(this);
this.state = {
priorityItems: props.menuItems,
moreItems: [],
visible: true
}
componentDidMount() {
this.widthsArray = Array.from(document.getElementById("groupMenu").children).map(item => item.getBoundingClientRect().width);
this.fullMenuArray = this.props.menuItems;
this.checkBox = this.props.checkBox;
window.addEventListener('resize', _.throttle(this.updateMenu), 100);
this.updateMenu();
this.updateMenu = this.updateMenu.bind(this);
this.howManyItemsInMenuArray = this.howManyItemsInMenuArray.bind(this);
}
componentDidMount() {
this.widthsArray = Array.from(document.getElementById("groupMenu").children).map(item => item.getBoundingClientRect().width);
window.addEventListener('resize', _.throttle(this.updateMenu), 300);
this.updateMenu();
}
componentDidUpdate(prevProps) {
if (this.props.visible !== prevProps.visible) {
this.setState({ visible: this.props.visible });
}
};
componentDidUpdate(prevProps) {
if (this.props.visible !== prevProps.visible) {
this.setState({ visible: this.props.visible });
}
howManyItemsInMenuArray = (array, outerWidth, initialWidth) => {
let total = (initialWidth + 80);
for (let i = 0, len = array.length; i < len; i++) {
if (total + array[i] > outerWidth) {
return i < 1 ? 1 : i;
} else {
total += array[i];
}
}
};
updateMenu = () => {
const moreMenuElement = document.getElementById("moreMenu");
const outerWidth = document.getElementById("groupMenuOuter").getBoundingClientRect().width;
const moreMenuWidth = moreMenuElement ? moreMenuElement.getBoundingClientRect().width : 0;
const arrayAmount = this.howManyItemsInMenuArray(this.widthsArray, outerWidth, moreMenuWidth);
const navItemsCopy = this.fullMenuArray;
const priorityItems = navItemsCopy.slice(0, arrayAmount);
this.setState({
priorityItems: priorityItems,
moreItems: priorityItems.length !== navItemsCopy.length ? navItemsCopy.slice(arrayAmount, navItemsCopy.length) : []
});
};
componentWillUnmount() {
window.removeEventListener('resize', this.updateMenu());
}
render() {
//console.log("GroupButtonsMenu render");
const closeMenu = (e) => {
this.setState({ visible: false });
this.props.onClose && this.props.onClose(e);
};
howManyItemsInMenuArray = (array, outerWidth, initialWidth, minimumNumberInNav) => {
let total = (initialWidth + 180);
for (let i = 0; i < array.length; i++) {
if (total + array[i] > outerWidth) {
return i < minimumNumberInNav ? minimumNumberInNav : i;
} else {
total += array[i];
}
return (
<StyledGroupButtonsMenu id="groupMenuOuter" visible={this.state.visible} {...this.state}>
<div id="groupMenu" style={{ display: 'inline-block' }}>
{this.state.priorityItems.map((item, i) =>
<GroupButton key={`navItem-${i}`}
label={item.label}
isDropdown={item.isDropdown}
isSeparator={item.isSeparator}
isSelect={item.isSelect}
onSelect={item.onSelect}
fontWeight={item.fontWeight}
onClick={(e) => {
item.onClick(e);
closeMenu(e);
}}
{...this.props}>
{item.children}
</GroupButton>
)}
</div>
{this.state.moreItems.length > 0 &&
<GroupButton id="moreMenu" isDropdown label={this.props.moreLabel}>
{this.state.moreItems.map((item, i) =>
<DropDownItem
key={`moreNavItem-${i}`}
label={item.label}
onClick={(e) => {
item.onClick(e);
closeMenu(e);
}}
/>
)}
</GroupButton>
}
};
updateMenu = () => {
this.outerWidth = document.getElementById("groupMenuOuter") ? document.getElementById("groupMenuOuter").getBoundingClientRect().width : 0;
this.moreMenu = document.getElementById("moreMenu") ? document.getElementById("moreMenu").getBoundingClientRect().width : 0;
const arrayAmount = this.howManyItemsInMenuArray(this.widthsArray, this.outerWidth, this.moreMenu, 1);
const navItemsCopy = this.fullMenuArray;
const priorityItems = navItemsCopy.slice(0, arrayAmount);
this.setState({
priorityItems: priorityItems,
moreItems: priorityItems.length !== navItemsCopy.length ? navItemsCopy.slice(arrayAmount, navItemsCopy.length) : []
});
};
componentWillUnmount() {
window.removeEventListener('resize', this.updateMenu());
}
render() {
console.log("GroupButtonsMenu render");
const closeMenu = (e) => {
this.setState({ visible: false });
this.props.onClose && this.props.onClose(e);
};
return (
<StyledGroupButtonsMenu id="groupMenuOuter" visible={this.state.visible} {...this.state}>
{this.props.hasOwnProperty("checked") &&
<StyledCheckbox>
<Checkbox isChecked={this.props.checked} isIndeterminate={this.props.isIndeterminate} onChange={(e) => {
this.props.onChange && this.props.onChange(e.target.checked);
}} />
</StyledCheckbox>
}
<div id="groupMenu" style={{ display: 'inline-block' }}>
{this.state.priorityItems.map((item, i) =>
<GroupButton key={`navItem-${i}`}
label={item.label}
isDropdown={item.isDropdown}
isSeparator={item.isSeparator}
fontWeight={item.fontWeight}
onClick={(e) => {
item.onClick(e);
closeMenu(e);
}}>
{item.children}
</GroupButton>
)}
</div>
{this.state.moreItems.length > 0 &&
<GroupButton id="moreMenu" isDropdown label={this.props.moreLabel}>
{this.state.moreItems.map((item, i) =>
<DropDownItem
key={`moreNavItem-${i}`}
label={item.label}
onClick={(e) => {
item.onClick(e);
closeMenu(e);
}}
/>
)}
</GroupButton>
}
<CloseButton title={this.props.closeTitle} onClick={closeMenu} />
</StyledGroupButtonsMenu>
);
}
<CloseButton title={this.props.closeTitle} onClick={closeMenu} />
</StyledGroupButtonsMenu>
);
}
}
GroupButtonsMenu.propTypes = {
onClick: PropTypes.func,
onClose: PropTypes.func,
onChange: PropTypes.func,
menuItems: PropTypes.array,
checked: PropTypes.bool,
visible: PropTypes.bool,
moreLabel: PropTypes.string,
closeTitle: PropTypes.string
onClick: PropTypes.func,
onClose: PropTypes.func,
onChange: PropTypes.func,
onSelect: PropTypes.func,
menuItems: PropTypes.array,
checked: PropTypes.bool,
selected: PropTypes.string,
visible: PropTypes.bool,
moreLabel: PropTypes.string,
closeTitle: PropTypes.string
}
export default GroupButtonsMenu;

View File

@ -11,69 +11,126 @@ const GroupButtonsMenuContainer = styled.div`
height: 2000px;
`;
const createItems = (label, dropDownLabel, menuItemLabel, count) => {
var items =[
{
label: label,
isDropdown: true,
isSeparator: true,
fontWeight: 'bold',
children: [
<DropDownItem key='1' label={dropDownLabel}/>,
<DropDownItem key='2' label={dropDownLabel}/>,
<DropDownItem key='3' label={dropDownLabel}/>
]
}
];
for (var i=0; i<count; i++){
items.push({label:menuItemLabel, onClick: () => console.log('Click action')});
}
return items;
}
const groupItems = [
{
label: 'Select',
isDropdown: true,
isSeparator: true,
isSelect: true,
fontWeight: 'bold',
children: [
<DropDownItem key='aaa' label='aaa' />,
<DropDownItem key='bbb' label='bbb' />,
<DropDownItem key='ccc' label='ccc' />,
],
onSelect: (a) => console.log(a)
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
},
{
label: 'Menu item',
onClick: () => console.log('Menu item action')
}
];
storiesOf('Components|GroupButtonsMenu', module)
.addDecorator(withReadme(Readme))
.addDecorator(withKnobs)
.add('base', () => {
const elements = 10;
const selectLabel = 'Select';
const dropLabel = 'Dropdown item';
const menuItemLabel = 'Menu item';
const menuItems = createItems(selectLabel, dropLabel, menuItemLabel, elements);
return (
<BooleanValue>
{({ value: visible, toggle }) => (
<>
<Button
label="Show menu"
onClick={(e) => {
toggle(visible);
}}
/>
<GroupButtonsMenuContainer>
<BooleanValue>
{({ value: checked, toggle }) => (
<GroupButtonsMenu
checked={checked}
menuItems={menuItems}
visible={visible}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
onClose={() => console.log('Close action')}
onChange={(e) => toggle(checked)}
/>
)}
</BooleanValue>
</GroupButtonsMenuContainer>
</>
.addDecorator(withReadme(Readme))
.addDecorator(withKnobs)
.add('base', () => {
return (
<BooleanValue>
{({ value: visible, toggle }) => (
<>
<Button
label="Show menu"
onClick={(e) => {
toggle(visible);
}}
/>
<GroupButtonsMenuContainer>
<BooleanValue>
{({ value: checked, toggle }) => (
<GroupButtonsMenu
checked={checked}
menuItems={groupItems}
visible={visible}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
onClose={() => console.log('Close action')}
onChange={(e) => toggle(checked)}
selected={groupItems[0].label}
/>
)}
</BooleanValue>
);
});
</BooleanValue>
</GroupButtonsMenuContainer>
</>
)}
</BooleanValue>
);
});

View File

@ -1,6 +1,6 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { withKnobs, text} from '@storybook/addon-knobs/react';
import { withKnobs, text } from '@storybook/addon-knobs/react';
import { BooleanValue } from 'react-values'
import styled from '@emotion/styled';
import { GroupButtonsMenu, DropDownItem, Button } from 'asc-web-components'
@ -10,77 +10,78 @@ const GroupButtonsMenuContainer = styled.div`
`;
const peopleItems = [
{
label: 'Select',
isDropdown: true,
isSeparator: true,
fontWeight: 'bold',
children: [
<DropDownItem key='active' label='Active'/>,
<DropDownItem key='disabled' label='Disabled'/>,
<DropDownItem key='invited' label='Invited'/>
]
},
{
label: 'Make employee',
onClick: () => console.log('Make employee action')
},
{
label: 'Make guest',
onClick: () => console.log('Make guest action')
},
{
label: 'Set active',
onClick: () => console.log('Set active action')
},
{
label: 'Set disabled',
onClick: () => console.log('Set disabled action')
},
{
label: 'Invite again',
onClick: () => console.log('Invite again action')
},
{
label: 'Send e-mail',
onClick: () => console.log('Send e-mail action')
},
{
label: 'Delete',
onClick: () => console.log('Delete action')
}
{
label: 'Select',
isDropdown: true,
isSeparator: true,
isSelect: true,
fontWeight: 'bold',
children: [
<DropDownItem key='active' label='Active' />,
<DropDownItem key='disabled' label='Disabled' />,
<DropDownItem key='invited' label='Invited' />
],
onSelect: (a) => console.log(a)
},
{
label: 'Make employee',
onClick: () => console.log('Make employee action')
},
{
label: 'Make guest',
onClick: () => console.log('Make guest action')
},
{
label: 'Set active',
onClick: () => console.log('Set active action')
},
{
label: 'Set disabled',
onClick: () => console.log('Set disabled action')
},
{
label: 'Invite again',
onClick: () => console.log('Invite again action')
},
{
label: 'Send e-mail',
onClick: () => console.log('Send e-mail action')
},
{
label: 'Delete',
onClick: () => console.log('Delete action')
}
];
storiesOf('EXAMPLES|GroupButtonsMenu', module)
.addDecorator(withKnobs)
.add('people', () => (
<BooleanValue>
{({ value: visible, toggle }) => (
<>
<Button
label="Show menu"
onClick={(e) => {
toggle(visible);
}}
.addDecorator(withKnobs)
.add('people', () => (
<BooleanValue>
{({ value: visible, toggle }) => (
<>
<Button
label="Show menu"
onClick={(e) => {
toggle(visible);
}}
/>
<GroupButtonsMenuContainer>
<BooleanValue>
{({ value: checked, toggle }) => (
<GroupButtonsMenu
checked={checked}
menuItems={peopleItems}
visible={visible}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
onClose={() => console.log('Close action')}
onChange={(e) => toggle(checked)}
selected={peopleItems[0].label}
/>
<GroupButtonsMenuContainer>
<BooleanValue>
{({ value: checked, toggle }) => (
<GroupButtonsMenu
checked={checked}
menuItems={peopleItems}
visible={visible}
moreLabel={text('moreLabel', 'More')}
closeTitle={text('closeTitle', 'Close')}
onClose={() => console.log('Close action')}
onChange={(e) => toggle(checked)}
/>
)}
</BooleanValue>
</GroupButtonsMenuContainer>
</>
)}
)}
</BooleanValue>
</GroupButtonsMenuContainer>
</>
)}
</BooleanValue>
));
));