zepio/app/components/dropdown.js

137 lines
3.0 KiB
JavaScript
Raw Normal View History

2018-12-10 12:51:22 -08:00
// @flow
2019-02-04 20:41:45 -08:00
2018-12-10 12:51:22 -08:00
import React, { type Node, Component } from 'react';
import styled from 'styled-components';
/* eslint-disable import/no-extraneous-dependencies */
// $FlowFixMe
import { darken } from 'polished';
import Popover from 'react-popover';
import ClickOutside from 'react-click-outside';
import { TextComponent } from './text';
2019-01-29 07:36:13 -08:00
import { truncateAddress } from '../utils/truncate-address';
2018-12-10 12:51:22 -08:00
/* eslint-disable max-len */
const MenuWrapper = styled.div`
background-image: ${props => `linear-gradient(to right, ${darken(0.05, props.theme.colors.activeItem)}, ${
2019-01-29 07:36:13 -08:00
props.theme.colors.activeItem
})`};
border-radius: ${props => props.theme.boxBorderRadius};
2018-12-10 12:51:22 -08:00
margin-left: -10px;
max-width: 400px;
overflow: hidden;
2018-12-10 12:51:22 -08:00
`;
const MenuItem = styled.button`
outline: none;
background-color: transparent;
border: none;
border-bottom-style: solid;
border-bottom-color: ${props => props.theme.colors.text};
2018-12-10 12:51:22 -08:00
border-bottom-width: 1px;
padding: 15px;
2018-12-10 12:51:22 -08:00
cursor: pointer;
font-weight: 700;
overflow: hidden;
2018-12-10 12:51:22 -08:00
width: 100%;
2018-12-10 16:52:45 -08:00
text-align: left;
2018-12-10 12:51:22 -08:00
&:hover {
opacity: 1;
2018-12-10 12:51:22 -08:00
}
2018-12-10 16:52:45 -08:00
&:disabled {
cursor: default;
&:hover {
opacity: 1;
}
}
&:last-child {
border-bottom: none;
}
2018-12-10 12:51:22 -08:00
`;
const OptionItem = styled(MenuItem)`
&:hover {
2019-01-29 07:36:13 -08:00
background-color: #f9d114;
}
`;
const Option = styled(TextComponent)`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
2018-12-10 12:51:22 -08:00
const PopoverWithStyle = styled(Popover)`
& > .Popover-tip {
fill: ${props => props.theme.colors.activeItem};
2018-12-10 12:51:22 -08:00
}
`;
type Props = {
2018-12-10 13:23:04 -08:00
renderTrigger: (toggleVisibility: () => void, isOpen: boolean) => Node,
2018-12-10 12:51:22 -08:00
options: Array<{ label: string, onClick: () => void }>,
2018-12-10 16:52:45 -08:00
label?: string | null,
truncate?: boolean,
2018-12-10 12:51:22 -08:00
};
type State = {
isOpen: boolean,
};
2018-12-10 13:23:04 -08:00
export class DropdownComponent extends Component<Props, State> {
2018-12-10 12:51:22 -08:00
state = {
isOpen: false,
};
2018-12-10 16:52:45 -08:00
static defaultProps = {
label: null,
truncate: false,
2018-12-10 16:52:45 -08:00
};
2018-12-10 12:51:22 -08:00
render() {
const { isOpen } = this.state;
const {
label, options, truncate, renderTrigger,
} = this.props;
const body = [
<ClickOutside onClickOutside={() => this.setState(() => ({ isOpen: false }))}>
<MenuWrapper>
{label && (
<MenuItem disabled isGroupLabel>
<TextComponent value={label} isBold />
</MenuItem>
)}
{options.map(({ label: optionLabel, onClick }) => (
<OptionItem onClick={onClick} key={optionLabel} data-testid='DropdownOption'>
<Option value={truncate ? truncateAddress(optionLabel) : optionLabel} />
</OptionItem>
))}
</MenuWrapper>
</ClickOutside>,
];
2018-12-10 12:51:22 -08:00
return (
<PopoverWithStyle
isOpen={isOpen}
2018-12-10 12:51:22 -08:00
preferPlace='below'
enterExitTransitionDurationMs={0}
2018-12-10 16:52:45 -08:00
tipSize={7}
body={body}
2018-12-10 12:51:22 -08:00
>
{renderTrigger(
() => this.setState(state => ({
isOpen: !state.isOpen,
})),
isOpen,
)}
2018-12-10 12:51:22 -08:00
</PopoverWithStyle>
);
}
}