2018-07-06 18:56:28 -04:00
|
|
|
import React from 'react';
|
2018-08-27 10:23:21 -06:00
|
|
|
import PropTypes from 'prop-types';
|
2019-03-15 10:19:57 -04:00
|
|
|
import { css } from '@emotion/core';
|
|
|
|
import styled from '@emotion/styled';
|
2018-07-06 18:56:28 -04:00
|
|
|
import { Wrapper, Button as DropdownButton, Menu, MenuItem } from 'react-aria-menubutton';
|
2020-04-01 06:13:27 +03:00
|
|
|
import { colors, buttons, components, zIndex } from './styles';
|
2018-07-06 18:56:28 -04:00
|
|
|
import Icon from './Icon';
|
|
|
|
|
|
|
|
const StyledWrapper = styled(Wrapper)`
|
|
|
|
position: relative;
|
|
|
|
font-size: 14px;
|
|
|
|
user-select: none;
|
2018-08-07 14:46:54 -06:00
|
|
|
`;
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
const StyledDropdownButton = styled(DropdownButton)`
|
|
|
|
${buttons.button};
|
|
|
|
${buttons.default};
|
|
|
|
display: block;
|
|
|
|
padding-left: 20px;
|
|
|
|
padding-right: 40px;
|
2020-04-01 06:13:27 +03:00
|
|
|
position: relative;
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
&:after {
|
|
|
|
${components.caretDown};
|
|
|
|
content: '';
|
|
|
|
display: block;
|
|
|
|
position: absolute;
|
|
|
|
top: 16px;
|
2020-04-01 06:13:27 +03:00
|
|
|
right: 10px;
|
2018-07-06 18:56:28 -04:00
|
|
|
color: currentColor;
|
|
|
|
}
|
2018-08-07 14:46:54 -06:00
|
|
|
`;
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
const DropdownList = styled.ul`
|
2018-07-24 23:35:59 -04:00
|
|
|
${components.dropdownList};
|
2018-07-06 18:56:28 -04:00
|
|
|
margin: 0;
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
left: 0;
|
|
|
|
min-width: 100%;
|
2020-04-12 11:41:43 +02:00
|
|
|
z-index: ${zIndex.zIndex299};
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
${props => css`
|
|
|
|
width: ${props.width};
|
|
|
|
top: ${props.top};
|
|
|
|
left: ${props.position === 'left' ? 0 : 'auto'};
|
|
|
|
right: ${props.position === 'right' ? 0 : 'auto'};
|
2018-08-07 14:46:54 -06:00
|
|
|
`};
|
|
|
|
`;
|
2018-07-06 18:56:28 -04:00
|
|
|
|
2020-05-24 17:37:08 +00:00
|
|
|
const StyledMenuItem = ({ isActive, isCheckedItem = false, ...props }) => (
|
2020-04-01 06:13:27 +03:00
|
|
|
<MenuItem
|
|
|
|
css={css`
|
|
|
|
${components.dropdownItem};
|
|
|
|
&:focus,
|
|
|
|
&:active,
|
|
|
|
&:not(:focus),
|
|
|
|
&:not(:active) {
|
|
|
|
background-color: ${isActive ? colors.activeBackground : 'inherit'};
|
|
|
|
color: ${isActive ? colors.active : 'inherit'};
|
2020-05-24 17:37:08 +00:00
|
|
|
${isCheckedItem ? 'display: flex; justify-content: start' : ''};
|
2020-04-01 06:13:27 +03:00
|
|
|
}
|
|
|
|
&:hover {
|
|
|
|
color: ${colors.active};
|
|
|
|
background-color: ${colors.activeBackground};
|
|
|
|
}
|
|
|
|
`}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
);
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
const MenuItemIconContainer = styled.div`
|
|
|
|
flex: 1 0 32px;
|
|
|
|
text-align: right;
|
|
|
|
position: relative;
|
2020-04-01 06:13:27 +03:00
|
|
|
top: ${props => (props.iconSmall ? '0' : '2px')};
|
2018-08-07 14:46:54 -06:00
|
|
|
`;
|
2018-07-06 18:56:28 -04:00
|
|
|
|
|
|
|
const Dropdown = ({
|
2020-04-01 06:13:27 +03:00
|
|
|
closeOnSelection = true,
|
2018-07-06 18:56:28 -04:00
|
|
|
renderButton,
|
|
|
|
dropdownWidth = 'auto',
|
|
|
|
dropdownPosition = 'left',
|
|
|
|
dropdownTopOverlap = '0',
|
2018-07-17 11:37:17 -04:00
|
|
|
className,
|
2018-07-06 18:56:28 -04:00
|
|
|
children,
|
|
|
|
}) => {
|
|
|
|
return (
|
2020-04-01 06:13:27 +03:00
|
|
|
<StyledWrapper
|
|
|
|
closeOnSelection={closeOnSelection}
|
|
|
|
onSelection={handler => handler()}
|
|
|
|
className={className}
|
|
|
|
>
|
2018-07-06 18:56:28 -04:00
|
|
|
{renderButton()}
|
|
|
|
<Menu>
|
|
|
|
<DropdownList width={dropdownWidth} top={dropdownTopOverlap} position={dropdownPosition}>
|
|
|
|
{children}
|
|
|
|
</DropdownList>
|
|
|
|
</Menu>
|
|
|
|
</StyledWrapper>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2018-08-27 10:23:21 -06:00
|
|
|
Dropdown.propTypes = {
|
|
|
|
renderButton: PropTypes.func.isRequired,
|
|
|
|
dropdownWidth: PropTypes.string,
|
|
|
|
dropdownPosition: PropTypes.string,
|
|
|
|
dropdownTopOverlap: PropTypes.string,
|
|
|
|
className: PropTypes.string,
|
|
|
|
children: PropTypes.node,
|
|
|
|
};
|
|
|
|
|
2020-04-01 06:13:27 +03:00
|
|
|
const DropdownItem = ({ label, icon, iconDirection, iconSmall, isActive, onClick, className }) => (
|
|
|
|
<StyledMenuItem value={onClick} isActive={isActive} className={className}>
|
2018-07-06 18:56:28 -04:00
|
|
|
<span>{label}</span>
|
2018-08-07 14:46:54 -06:00
|
|
|
{icon ? (
|
2020-04-01 06:13:27 +03:00
|
|
|
<MenuItemIconContainer iconSmall={iconSmall}>
|
|
|
|
<Icon type={icon} direction={iconDirection} size={iconSmall ? 'xsmall' : 'small'} />
|
2018-08-07 14:46:54 -06:00
|
|
|
</MenuItemIconContainer>
|
|
|
|
) : null}
|
2018-07-06 18:56:28 -04:00
|
|
|
</StyledMenuItem>
|
|
|
|
);
|
|
|
|
|
2018-08-27 10:23:21 -06:00
|
|
|
DropdownItem.propTypes = {
|
|
|
|
label: PropTypes.string,
|
|
|
|
icon: PropTypes.string,
|
|
|
|
iconDirection: PropTypes.string,
|
|
|
|
onClick: PropTypes.func,
|
|
|
|
className: PropTypes.string,
|
|
|
|
};
|
|
|
|
|
2020-05-24 17:37:08 +00:00
|
|
|
const StyledDropdownCheckbox = ({ checked, id }) => (
|
|
|
|
<input
|
|
|
|
readOnly
|
|
|
|
type="checkbox"
|
|
|
|
css={css`
|
|
|
|
margin-right: 10px;
|
|
|
|
`}
|
|
|
|
checked={checked}
|
|
|
|
id={id}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
|
|
|
|
const DropdownCheckedItem = ({ label, id, checked, onClick }) => {
|
|
|
|
return (
|
|
|
|
<StyledMenuItem isCheckedItem={true} isActive={checked} onClick={onClick}>
|
|
|
|
<StyledDropdownCheckbox checked={checked} id={id} />
|
|
|
|
<span htmlFor={id}>{label}</span>
|
|
|
|
</StyledMenuItem>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
DropdownCheckedItem.propTypes = {
|
|
|
|
label: PropTypes.string.isRequired,
|
|
|
|
id: PropTypes.string.isRequired,
|
|
|
|
checked: PropTypes.bool.isRequired,
|
|
|
|
onClick: PropTypes.func.isRequired,
|
|
|
|
};
|
|
|
|
|
|
|
|
export {
|
|
|
|
Dropdown as default,
|
|
|
|
DropdownItem,
|
|
|
|
DropdownCheckedItem,
|
|
|
|
DropdownButton,
|
|
|
|
StyledDropdownButton,
|
|
|
|
};
|