feat: implement basic dropdown component
This commit is contained in:
@@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput
|
||||
}
|
||||
return (
|
||||
<Container marginLeft="5px">
|
||||
<Icon icon="chevron" width={12} onClick={this._handleSelectAssetClick} />
|
||||
<Icon icon="chevron" width={12} stroke={ColorOption.white} onClick={this._handleSelectAssetClick} />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
31
packages/instant/src/components/payment_method.tsx
Normal file
31
packages/instant/src/components/payment_method.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ColorOption } from '../style/theme';
|
||||
|
||||
import { Container } from './ui/container';
|
||||
import { Dropdown } from './ui/dropdown';
|
||||
import { Text } from './ui/text';
|
||||
|
||||
export interface PaymentMethodProps {}
|
||||
|
||||
export class PaymentMethod extends React.Component<PaymentMethodProps> {
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<Container padding="20px" width="100%">
|
||||
<Container marginBottom="10px">
|
||||
<Text
|
||||
letterSpacing="1px"
|
||||
fontColor={ColorOption.primaryColor}
|
||||
fontWeight={600}
|
||||
textTransform="uppercase"
|
||||
fontSize="14px"
|
||||
>
|
||||
Payment Method
|
||||
</Text>
|
||||
</Container>
|
||||
<Dropdown value="0x00000000000000" label="25.33 ETH" />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
127
packages/instant/src/components/ui/dropdown.tsx
Normal file
127
packages/instant/src/components/ui/dropdown.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ColorOption } from '../../style/theme';
|
||||
import { zIndex } from '../../style/z_index';
|
||||
|
||||
import { Container } from './container';
|
||||
import { Flex } from './flex';
|
||||
import { Icon } from './icon';
|
||||
import { Text } from './text';
|
||||
|
||||
export interface DropdownItemConfig {
|
||||
text: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export interface DropdownProps {
|
||||
value: string;
|
||||
label: string;
|
||||
items: DropdownItemConfig[];
|
||||
}
|
||||
|
||||
export interface DropdownState {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export class Dropdown extends React.Component<DropdownProps, DropdownState> {
|
||||
public static defaultProps = {
|
||||
items: [
|
||||
{
|
||||
text: 'Item 1',
|
||||
},
|
||||
{
|
||||
text: 'Item 2',
|
||||
},
|
||||
],
|
||||
};
|
||||
public state: DropdownState = {
|
||||
isOpen: false,
|
||||
};
|
||||
public render(): React.ReactNode {
|
||||
const { value, label, items } = this.props;
|
||||
const { isOpen } = this.state;
|
||||
const hasItems = !_.isEmpty(items);
|
||||
const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px';
|
||||
return (
|
||||
<Container position="relative">
|
||||
<Container
|
||||
cursor={hasItems ? 'pointer' : undefined}
|
||||
onClick={this._handleDropdownClick}
|
||||
hasBoxShadow={true}
|
||||
borderRadius={borderRadius}
|
||||
border="1px solid"
|
||||
borderColor={ColorOption.feintGrey}
|
||||
padding="0.8em"
|
||||
borderBottom="1px solid"
|
||||
>
|
||||
<Flex justify="space-between">
|
||||
<Text fontSize="16px" lineHeight="19px" fontColor={ColorOption.darkGrey}>
|
||||
{value}
|
||||
</Text>
|
||||
<Container>
|
||||
<Text fontSize="16px" lineHeight="17px" fontColor={ColorOption.lightGrey}>
|
||||
{label}
|
||||
</Text>
|
||||
{hasItems && (
|
||||
<Container marginLeft="5px" display="inline-block" position="relative" bottom="2px">
|
||||
<Icon padding="3px" icon="chevron" width={12} stroke={ColorOption.grey} />
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
</Flex>
|
||||
</Container>
|
||||
{isOpen && (
|
||||
<Container
|
||||
width="100%"
|
||||
position="absolute"
|
||||
onClick={this._closeDropdown}
|
||||
backgroundColor={ColorOption.white}
|
||||
hasBoxShadow={true}
|
||||
zIndex={zIndex.dropdownItems}
|
||||
>
|
||||
{_.map(items, (item, index) => (
|
||||
<DropdownItem key={item.text} {...item} isLast={index === items.length - 1} />
|
||||
))}
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
private readonly _handleDropdownClick = (): void => {
|
||||
if (_.isEmpty(this.props.items)) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen,
|
||||
});
|
||||
};
|
||||
private readonly _closeDropdown = (): void => {
|
||||
this.setState({
|
||||
isOpen: false,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export interface DropdownItemProps extends DropdownItemConfig {
|
||||
text: string;
|
||||
onClick?: () => void;
|
||||
isLast: boolean;
|
||||
}
|
||||
|
||||
export const DropdownItem: React.StatelessComponent<DropdownItemProps> = ({ text, onClick, isLast }) => (
|
||||
<Container
|
||||
onClick={onClick}
|
||||
cursor="pointer"
|
||||
darkenOnHover={true}
|
||||
backgroundColor={ColorOption.white}
|
||||
padding="0.8em"
|
||||
borderTop="0"
|
||||
border="1px solid"
|
||||
borderRadius={isLast ? '0px 0px 4px 4px' : undefined}
|
||||
width="100%"
|
||||
borderColor={ColorOption.feintGrey}
|
||||
>
|
||||
<Text>{text}</Text>
|
||||
</Container>
|
||||
);
|
||||
@@ -9,7 +9,6 @@ interface IconInfo {
|
||||
path: string;
|
||||
fillRule?: svgRule;
|
||||
clipRule?: svgRule;
|
||||
stroke?: string;
|
||||
strokeOpacity?: number;
|
||||
strokeWidth?: number;
|
||||
strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
|
||||
@@ -47,7 +46,6 @@ const ICONS: IconInfoMapping = {
|
||||
chevron: {
|
||||
viewBox: '0 0 12 7',
|
||||
path: 'M11 1L6 6L1 1',
|
||||
stroke: 'white',
|
||||
strokeOpacity: 0.5,
|
||||
strokeWidth: 1.5,
|
||||
strokeLinecap: 'round',
|
||||
@@ -67,6 +65,7 @@ export interface IconProps {
|
||||
width: number;
|
||||
height?: number;
|
||||
color?: ColorOption;
|
||||
stroke?: ColorOption;
|
||||
icon: keyof IconInfoMapping;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
padding?: string;
|
||||
@@ -75,6 +74,7 @@ export interface IconProps {
|
||||
const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
||||
const iconInfo = ICONS[props.icon];
|
||||
const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color];
|
||||
const strokeValue = _.isUndefined(props.stroke) ? undefined : props.theme[props.stroke];
|
||||
return (
|
||||
<div onClick={props.onClick} className={props.className}>
|
||||
<svg
|
||||
@@ -89,7 +89,7 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
||||
fill={colorValue}
|
||||
fillRule={iconInfo.fillRule || 'nonzero'}
|
||||
clipRule={iconInfo.clipRule || 'nonzero'}
|
||||
stroke={iconInfo.stroke}
|
||||
stroke={strokeValue}
|
||||
strokeOpacity={iconInfo.strokeOpacity}
|
||||
strokeWidth={iconInfo.strokeWidth}
|
||||
strokeLinecap={iconInfo.strokeLinecap}
|
||||
@@ -101,7 +101,8 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
||||
};
|
||||
|
||||
export const Icon = withTheme(styled(PlainIcon)`
|
||||
cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')};
|
||||
display: inline-block;
|
||||
${props => (!_.isUndefined(props.onClick) ? 'cursor: pointer' : '')};
|
||||
transition: opacity 0.5s ease;
|
||||
padding: ${props => props.padding};
|
||||
opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
|
||||
|
||||
@@ -3,15 +3,15 @@ import * as React from 'react';
|
||||
import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector';
|
||||
import { LatestBuyQuoteOrderDetails } from '../containers/latest_buy_quote_order_details';
|
||||
import { LatestError } from '../containers/latest_error';
|
||||
import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress';
|
||||
import { SelectedAssetBuyOrderStateButtons } from '../containers/selected_asset_buy_order_state_buttons';
|
||||
import { SelectedAssetInstantHeading } from '../containers/selected_asset_instant_heading';
|
||||
|
||||
import { SelectedAssetBuyOrderProgress } from '../containers/selected_asset_buy_order_progress';
|
||||
|
||||
import { ColorOption } from '../style/theme';
|
||||
import { zIndex } from '../style/z_index';
|
||||
|
||||
import { SlideAnimationState } from './animations/slide_animation';
|
||||
import { PaymentMethod } from './payment_method';
|
||||
import { SlidingPanel } from './sliding_panel';
|
||||
import { Container } from './ui/container';
|
||||
import { Flex } from './ui/flex';
|
||||
@@ -41,6 +41,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain
|
||||
>
|
||||
<Flex direction="column" justify="flex-start">
|
||||
<SelectedAssetInstantHeading onSelectAssetClick={this._handleSymbolClick} />
|
||||
<PaymentMethod />
|
||||
<SelectedAssetBuyOrderProgress />
|
||||
<LatestBuyQuoteOrderDetails />
|
||||
<Container padding="20px" width="100%">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const zIndex = {
|
||||
errorPopup: 1,
|
||||
mainContainer: 2,
|
||||
panel: 3,
|
||||
dropdownItems: 3,
|
||||
panel: 4,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user