From c0d8ceca82a91a3a6c222e71ecb58f2cd95da62e Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 20:30:45 -0800 Subject: feat: implement basic dropdown component --- .../src/components/erc20_asset_amount_input.tsx | 2 +- packages/instant/src/components/payment_method.tsx | 31 +++++ packages/instant/src/components/ui/dropdown.tsx | 127 +++++++++++++++++++++ packages/instant/src/components/ui/icon.tsx | 9 +- .../src/components/zero_ex_instant_container.tsx | 5 +- packages/instant/src/style/z_index.ts | 3 +- 6 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 packages/instant/src/components/payment_method.tsx create mode 100644 packages/instant/src/components/ui/dropdown.tsx diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index f21c21b87..520ac33d5 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component - + ); }; diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx new file mode 100644 index 000000000..125b54bad --- /dev/null +++ b/packages/instant/src/components/payment_method.tsx @@ -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 { + public render(): React.ReactNode { + return ( + + + + Payment Method + + + + + ); + } +} diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx new file mode 100644 index 000000000..2bc552ab4 --- /dev/null +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -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 { + 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 ( + + + + + {value} + + + + {label} + + {hasItems && ( + + + + )} + + + + {isOpen && ( + + {_.map(items, (item, index) => ( + + ))} + + )} + + ); + } + 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 = ({ text, onClick, isLast }) => ( + + {text} + +); diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index 94ea26900..707aee24f 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -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) => void; padding?: string; @@ -75,6 +74,7 @@ export interface IconProps { const PlainIcon: React.StatelessComponent = 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 (
= 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 = 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)}; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 851dfa2db..0543a8e4e 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -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 + diff --git a/packages/instant/src/style/z_index.ts b/packages/instant/src/style/z_index.ts index 727a5189d..95e6cd912 100644 --- a/packages/instant/src/style/z_index.ts +++ b/packages/instant/src/style/z_index.ts @@ -1,5 +1,6 @@ export const zIndex = { errorPopup: 1, mainContainer: 2, - panel: 3, + dropdownItems: 3, + panel: 4, }; -- cgit v1.2.3 From 4181a040b5d5ca2335556948585278133ec63bd1 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 20:53:25 -0800 Subject: feat: refactor out overlay component and use it to implement click-outside --- packages/instant/src/components/ui/dropdown.tsx | 98 ++++++++++++---------- packages/instant/src/components/ui/overlay.tsx | 28 +++---- .../src/components/zero_ex_instant_overlay.tsx | 21 ++++- packages/instant/src/style/theme.ts | 1 + packages/instant/src/style/z_index.ts | 9 +- 5 files changed, 89 insertions(+), 68 deletions(-) diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index 2bc552ab4..c69e89c0e 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -1,12 +1,13 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { ColorOption } from '../../style/theme'; +import { ColorOption, completelyTransparent } from '../../style/theme'; import { zIndex } from '../../style/z_index'; import { Container } from './container'; import { Flex } from './flex'; import { Icon } from './icon'; +import { Overlay } from './overlay'; import { Text } from './text'; export interface DropdownItemConfig { @@ -27,12 +28,12 @@ export interface DropdownState { export class Dropdown extends React.Component { public static defaultProps = { items: [ - { - text: 'Item 1', - }, - { - text: 'Item 2', - }, + // { + // text: 'Item 1', + // }, + // { + // text: 'Item 2', + // }, ], }; public state: DropdownState = { @@ -44,48 +45,57 @@ export class Dropdown extends React.Component { const hasItems = !_.isEmpty(items); const borderRadius = isOpen ? '4px 4px 0px 0px' : '4px'; return ( - - - - - {value} - - - - {label} - - {hasItems && ( - - - - )} - - - + {isOpen && ( - + )} + + - {_.map(items, (item, index) => ( - - ))} + + + {value} + + + + {label} + + {hasItems && ( + + + + )} + + - )} - + {isOpen && ( + + {_.map(items, (item, index) => ( + + ))} + + )} + + ); } private readonly _handleDropdownClick = (): void => { diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index f1706c874..64090a6b3 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -1,38 +1,30 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { ColorOption, overlayBlack, styled } from '../../style/theme'; - -import { Container } from './container'; -import { Flex } from './flex'; -import { Icon } from './icon'; +import { overlayBlack, styled } from '../../style/theme'; +import { zIndex } from '../../style/z_index'; export interface OverlayProps { - className?: string; - onClose?: () => void; zIndex?: number; + backgroundColor?: string; } -const PlainOverlay: React.StatelessComponent = ({ children, className, onClose }) => ( - - - - -
{children}
- -); -export const Overlay = styled(PlainOverlay)` +export const Overlay = + styled.div < + OverlayProps > + ` position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: ${props => props.zIndex} - background-color: ${overlayBlack}; + background-color: ${props => props.backgroundColor}; `; Overlay.defaultProps = { - zIndex: 100, + zIndex: zIndex.overlayDefault, + backgroundColor: overlayBlack, }; Overlay.displayName = 'Overlay'; diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 3461600e1..d2b41d27f 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,5 +1,10 @@ import * as React from 'react'; +import { ColorOption, overlayBlack, styled } from '../style/theme'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Icon } from './ui/icon'; import { Overlay } from './ui/overlay'; import { ZeroExInstantContainer } from './zero_ex_instant_container'; import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider'; @@ -13,8 +18,20 @@ export const ZeroExInstantOverlay: React.StatelessComponent - - + + + + + + + ); diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index d10c9b72c..7917164a1 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -32,5 +32,6 @@ export const theme: Theme = { export const transparentWhite = 'rgba(255,255,255,0.3)'; export const overlayBlack = 'rgba(0, 0, 0, 0.6)'; +export const completelyTransparent = 'rga(0, 0, 0, 0)'; export { styled, css, keyframes, withTheme, ThemeProvider }; diff --git a/packages/instant/src/style/z_index.ts b/packages/instant/src/style/z_index.ts index 95e6cd912..0eedcaf29 100644 --- a/packages/instant/src/style/z_index.ts +++ b/packages/instant/src/style/z_index.ts @@ -1,6 +1,7 @@ export const zIndex = { - errorPopup: 1, - mainContainer: 2, - dropdownItems: 3, - panel: 4, + errorPopup: 10, + mainContainer: 20, + dropdownItems: 30, + panel: 40, + overlayDefault: 100, }; -- cgit v1.2.3 From 94d1e427c142fe5cad7a211d38dd9a3235d15df9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 20:57:57 -0800 Subject: fix: height of token selector overflow div --- packages/instant/src/components/erc20_token_selector.tsx | 2 +- packages/instant/src/components/ui/dropdown.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 41b0b44b0..365995905 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -35,7 +35,7 @@ export class ERC20TokenSelector extends React.Component value={this.state.searchQuery} onChange={this._handleSearchInputChange} /> - + {_.map(tokens, token => { if (!this._isTokenQueryMatch(token)) { return null; diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index c69e89c0e..bfedc0f5a 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -28,12 +28,12 @@ export interface DropdownState { export class Dropdown extends React.Component { public static defaultProps = { items: [ - // { - // text: 'Item 1', - // }, - // { - // text: 'Item 2', - // }, + { + text: 'Item 1', + }, + { + text: 'Item 2', + }, ], }; public state: DropdownState = { -- cgit v1.2.3 From f7642c06f0d5662c955ec36e1549d63445a74056 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 21:05:07 -0800 Subject: chore: remove unused props --- packages/instant/src/components/ui/dropdown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index bfedc0f5a..ae4731b6f 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -65,11 +65,11 @@ export class Dropdown extends React.Component { borderBottom="1px solid" > - + {value} - + {label} {hasItems && ( -- cgit v1.2.3 From ecb92a44bc5a4b433f2a673fc77199c7b8a6dc18 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 21:38:54 -0800 Subject: feat: create PaymentMethodDropdown --- .../src/components/erc20_token_selector.tsx | 2 +- packages/instant/src/components/payment_method.tsx | 4 +- .../src/components/payment_method_dropdown.tsx | 33 ++++++++++++ packages/instant/src/components/ui/button.tsx | 62 +++++++++++++--------- packages/instant/src/components/ui/dropdown.tsx | 21 +++----- packages/instant/src/components/ui/overlay.tsx | 1 - .../src/components/zero_ex_instant_container.tsx | 1 - .../src/components/zero_ex_instant_overlay.tsx | 2 +- packages/instant/src/util/format.ts | 3 ++ 9 files changed, 86 insertions(+), 43 deletions(-) create mode 100644 packages/instant/src/components/payment_method_dropdown.tsx diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index 365995905..c10b1492e 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -35,7 +35,7 @@ export class ERC20TokenSelector extends React.Component value={this.state.searchQuery} onChange={this._handleSearchInputChange} /> - + {_.map(tokens, token => { if (!this._isTokenQueryMatch(token)) { return null; diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 125b54bad..4d3daff62 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -3,8 +3,8 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; +import { PaymentMethodDropdown } from './payment_method_dropdown'; import { Container } from './ui/container'; -import { Dropdown } from './ui/dropdown'; import { Text } from './ui/text'; export interface PaymentMethodProps {} @@ -24,7 +24,7 @@ export class PaymentMethod extends React.Component { Payment Method - + ); } diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx new file mode 100644 index 000000000..09d21e384 --- /dev/null +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -0,0 +1,33 @@ +import { BigNumber } from '@0x/utils'; +import * as React from 'react'; + +import { format } from '../util/format'; + +import { Dropdown, DropdownItemConfig } from './ui/dropdown'; + +export interface PaymentMethodDropdownProps { + selectedEthAddress: string; + addressEthBaseAmount: BigNumber; +} + +export class PaymentMethodDropdown extends React.Component { + public static defaultProps = { + selectedEthAddress: '0xa1b2c3d4e5f6g7h8j9k10', + addressEthBaseAmount: new BigNumber(10500000000000000000), + }; + public render(): React.ReactNode { + const { selectedEthAddress, addressEthBaseAmount } = this.props; + const value = format.ethAddress(selectedEthAddress); + const label = format.ethBaseAmount(addressEthBaseAmount) as string; + return ; + } + private readonly _getDropdownItemConfigs = (): DropdownItemConfig[] => { + const viewOnEtherscan = { + text: 'View on Etherscan', + }; + const copyAddressToClipboard = { + text: 'Copy address to clipboard', + }; + return [viewOnEtherscan, copyAddressToClipboard]; + }; +} diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index 5274d835b..61a0f23a8 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -6,6 +6,8 @@ import { ColorOption, styled } from '../../style/theme'; export interface ButtonProps { backgroundColor?: ColorOption; borderColor?: ColorOption; + fontColor?: ColorOption; + fontSize?: string; width?: string; padding?: string; type?: string; @@ -24,38 +26,50 @@ const darkenOnHoverAmount = 0.1; const darkenOnActiveAmount = 0.2; const saturateOnFocusAmount = 0.2; export const Button = styled(PlainButton)` - cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; - transition: background-color, opacity 0.5s ease; - padding: ${props => props.padding}; - border-radius: 3px; - outline: none; - width: ${props => props.width}; - background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; - border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')}; - &:hover { - background-color: ${props => - !props.isDisabled - ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) - : ''} !important; - } - &:active { - background-color: ${props => - !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; - } - &:disabled { - opacity: 0.5; - } - &:focus { - background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; + && { + all: initial; + box-sizing: border-box; + font-size: ${props => props.fontSize}; + font-family: 'Inter UI', sans-serif; + font-weight: 600; + color: ${props => props.fontColor && props.theme[props.fontColor]}; + cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; + transition: background-color, opacity 0.5s ease; + padding: ${props => props.padding}; + border-radius: 3px; + text-align: center; + outline: none; + width: ${props => props.width}; + background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; + border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')}; + &:hover { + background-color: ${props => + !props.isDisabled + ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) + : ''} !important; + } + &:active { + background-color: ${props => + !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; + } + &:disabled { + opacity: 0.5; + } + &:focus { + background-color: ${props => + saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; + } } `; Button.defaultProps = { backgroundColor: ColorOption.primaryColor, borderColor: ColorOption.primaryColor, + fontColor: ColorOption.white, width: 'auto', isDisabled: false, - padding: '1em 2.2em', + padding: '.6em 1.2em', + fontSize: '15px', }; Button.displayName = 'Button'; diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index ae4731b6f..d51060c05 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -17,7 +17,7 @@ export interface DropdownItemConfig { export interface DropdownProps { value: string; - label: string; + label?: string; items: DropdownItemConfig[]; } @@ -27,14 +27,7 @@ export interface DropdownState { export class Dropdown extends React.Component { public static defaultProps = { - items: [ - { - text: 'Item 1', - }, - { - text: 'Item 2', - }, - ], + items: [], }; public state: DropdownState = { isOpen: false, @@ -57,7 +50,7 @@ export class Dropdown extends React.Component { { {value} - - {label} - + {label && ( + + {label} + + )} {hasItems && ( diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index 64090a6b3..7c941d294 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -1,5 +1,4 @@ import * as _ from 'lodash'; -import * as React from 'react'; import { overlayBlack, styled } from '../../style/theme'; import { zIndex } from '../../style/z_index'; diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 0543a8e4e..7a33c9203 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -6,7 +6,6 @@ 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 { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index d2b41d27f..734747b57 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { ColorOption, overlayBlack, styled } from '../style/theme'; +import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index 4a48dec9d..44661d697 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -50,4 +50,7 @@ export const format = { } return `$${ethUnitAmount.mul(ethUsdPrice).toFixed(decimalPlaces)}`; }, + ethAddress: (address: string): string => { + return `0x${address.slice(2, 7)}…${address.slice(-5)}`; + }, }; -- cgit v1.2.3 From 1151371e57643662b14c0c940ec558e74a6d1120 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 21:54:26 -0800 Subject: feat: add MetaMask sign, refactor Circle --- .../src/components/erc20_token_selector.tsx | 2 +- packages/instant/src/components/payment_method.tsx | 30 +++++++++++++++------- packages/instant/src/components/ui/circle.tsx | 19 ++++++++------ packages/instant/src/style/theme.ts | 4 +++ 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx index c10b1492e..d3043438e 100644 --- a/packages/instant/src/components/erc20_token_selector.tsx +++ b/packages/instant/src/components/erc20_token_selector.tsx @@ -85,7 +85,7 @@ class TokenSelectorRow extends React.Component { - + {displaySymbol} diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx index 4d3daff62..70ad1f96e 100644 --- a/packages/instant/src/components/payment_method.tsx +++ b/packages/instant/src/components/payment_method.tsx @@ -4,7 +4,9 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { PaymentMethodDropdown } from './payment_method_dropdown'; +import { Circle } from './ui/circle'; import { Container } from './ui/container'; +import { Flex } from './ui/flex'; import { Text } from './ui/text'; export interface PaymentMethodProps {} @@ -14,15 +16,25 @@ export class PaymentMethod extends React.Component { return ( - - Payment Method - + + + Payment Method + + + + + + MetaMask + + + + diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx index eec2777d2..cb121992f 100644 --- a/packages/instant/src/components/ui/circle.tsx +++ b/packages/instant/src/components/ui/circle.tsx @@ -1,22 +1,25 @@ -import { styled } from '../../style/theme'; +import { ColorOption, styled, Theme, withTheme } from '../../style/theme'; export interface CircleProps { diameter: number; - fillColor?: string; + rawColor?: string; + color?: ColorOption; + theme: Theme; } -export const Circle = +export const Circle = withTheme( styled.div < - CircleProps > - ` + CircleProps > + ` width: ${props => props.diameter}px; height: ${props => props.diameter}px; - background-color: ${props => props.fillColor}; + background-color: ${props => (props.rawColor ? props.rawColor : props.theme[props.color || ColorOption.white])}; border-radius: 50%; -`; +`, +); Circle.displayName = 'Circle'; Circle.defaultProps = { - fillColor: 'white', + color: ColorOption.white, }; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index 7917164a1..0bd8ce4e0 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -15,6 +15,8 @@ export enum ColorOption { white = 'white', lightOrange = 'lightOrange', darkOrange = 'darkOrange', + green = 'green', + red = 'red', } export const theme: Theme = { @@ -28,6 +30,8 @@ export const theme: Theme = { white: 'white', lightOrange: '#F9F2ED', darkOrange: '#F2994C', + green: '#3CB34F', + red: '#D00000', }; export const transparentWhite = 'rgba(255,255,255,0.3)'; -- cgit v1.2.3 From d7742029c7ff991e60352cddeb52c2cdc1589a57 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 22:08:40 -0800 Subject: feat: implement copy-to-clipboard --- packages/instant/package.json | 1 + .../instant/src/components/payment_method_dropdown.tsx | 16 ++++++++++++++++ packages/instant/src/util/etherscan.ts | 7 +++++++ yarn.lock | 6 ++++++ 4 files changed, 30 insertions(+) diff --git a/packages/instant/package.json b/packages/instant/package.json index f90990649..2af4a799c 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -53,6 +53,7 @@ "@0x/typescript-typings": "^3.0.3", "@0x/utils": "^2.0.3", "@0x/web3-wrapper": "^3.1.0", + "copy-to-clipboard": "^3.0.8", "ethereum-types": "^1.1.1", "lodash": "^4.17.10", "polished": "^2.2.0", diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index 09d21e384..d1586f2c7 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -1,6 +1,9 @@ import { BigNumber } from '@0x/utils'; +import copy from 'copy-to-clipboard'; import * as React from 'react'; +import { Network } from '../types'; +import { etherscanUtil } from '../util/etherscan'; import { format } from '../util/format'; import { Dropdown, DropdownItemConfig } from './ui/dropdown'; @@ -8,12 +11,14 @@ import { Dropdown, DropdownItemConfig } from './ui/dropdown'; export interface PaymentMethodDropdownProps { selectedEthAddress: string; addressEthBaseAmount: BigNumber; + network: Network; } export class PaymentMethodDropdown extends React.Component { public static defaultProps = { selectedEthAddress: '0xa1b2c3d4e5f6g7h8j9k10', addressEthBaseAmount: new BigNumber(10500000000000000000), + network: Network.Mainnet, }; public render(): React.ReactNode { const { selectedEthAddress, addressEthBaseAmount } = this.props; @@ -24,10 +29,21 @@ export class PaymentMethodDropdown extends React.Component { const viewOnEtherscan = { text: 'View on Etherscan', + onClick: this._handleEtherscanClick, }; const copyAddressToClipboard = { text: 'Copy address to clipboard', + onClick: this._handleCopyToClipboardClick, }; return [viewOnEtherscan, copyAddressToClipboard]; }; + private readonly _handleEtherscanClick = (): void => { + const { selectedEthAddress, network } = this.props; + const etherscanUrl = etherscanUtil.getEtherScanEthAddressIfExists(selectedEthAddress, network); + window.open(etherscanUrl, '_blank'); + }; + private readonly _handleCopyToClipboardClick = (): void => { + const { selectedEthAddress } = this.props; + copy(selectedEthAddress); + }; } diff --git a/packages/instant/src/util/etherscan.ts b/packages/instant/src/util/etherscan.ts index cfc2578a3..4d62c4d9f 100644 --- a/packages/instant/src/util/etherscan.ts +++ b/packages/instant/src/util/etherscan.ts @@ -21,4 +21,11 @@ export const etherscanUtil = { } return `https://${prefix}etherscan.io/tx/${txHash}`; }, + getEtherScanEthAddressIfExists: (ethAddress: string, networkId: number) => { + const prefix = etherscanPrefix(networkId); + if (_.isUndefined(prefix)) { + return; + } + return `https://${prefix}etherscan.io/address/${ethAddress}`; + }, }; diff --git a/yarn.lock b/yarn.lock index 81e55020a..3cd04e13e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4407,6 +4407,12 @@ copy-to-clipboard@^3: dependencies: toggle-selection "^1.0.3" +copy-to-clipboard@^3.0.8: + version "3.0.8" + resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.0.8.tgz#f4e82f4a8830dce4666b7eb8ded0c9bcc313aba9" + dependencies: + toggle-selection "^1.0.3" + copyfiles@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.0.0.tgz#bbd78bb78e8fd6db5c67adf54249317b24560f2a" -- cgit v1.2.3 From 8b0928617346ae5066d2ea8185af625de5b5f577 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 22:17:27 -0800 Subject: fix: restore button to previous state --- packages/instant/src/components/ui/button.tsx | 62 +++++++++++---------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index 61a0f23a8..5274d835b 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -6,8 +6,6 @@ import { ColorOption, styled } from '../../style/theme'; export interface ButtonProps { backgroundColor?: ColorOption; borderColor?: ColorOption; - fontColor?: ColorOption; - fontSize?: string; width?: string; padding?: string; type?: string; @@ -26,50 +24,38 @@ const darkenOnHoverAmount = 0.1; const darkenOnActiveAmount = 0.2; const saturateOnFocusAmount = 0.2; export const Button = styled(PlainButton)` - && { - all: initial; - box-sizing: border-box; - font-size: ${props => props.fontSize}; - font-family: 'Inter UI', sans-serif; - font-weight: 600; - color: ${props => props.fontColor && props.theme[props.fontColor]}; - cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; - transition: background-color, opacity 0.5s ease; - padding: ${props => props.padding}; - border-radius: 3px; - text-align: center; - outline: none; - width: ${props => props.width}; - background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; - border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')}; - &:hover { - background-color: ${props => - !props.isDisabled - ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) - : ''} !important; - } - &:active { - background-color: ${props => - !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; - } - &:disabled { - opacity: 0.5; - } - &:focus { - background-color: ${props => - saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; - } + cursor: ${props => (props.isDisabled ? 'default' : 'pointer')}; + transition: background-color, opacity 0.5s ease; + padding: ${props => props.padding}; + border-radius: 3px; + outline: none; + width: ${props => props.width}; + background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; + border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')}; + &:hover { + background-color: ${props => + !props.isDisabled + ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) + : ''} !important; + } + &:active { + background-color: ${props => + !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; + } + &:disabled { + opacity: 0.5; + } + &:focus { + background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; } `; Button.defaultProps = { backgroundColor: ColorOption.primaryColor, borderColor: ColorOption.primaryColor, - fontColor: ColorOption.white, width: 'auto', isDisabled: false, - padding: '.6em 1.2em', - fontSize: '15px', + padding: '1em 2.2em', }; Button.displayName = 'Button'; -- cgit v1.2.3 From 88eb642aa543673bde52c1d14fc1f3e92d8b2137 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 7 Nov 2018 22:21:51 -0800 Subject: chore: cleanup --- packages/instant/src/components/ui/dropdown.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/components/ui/dropdown.tsx b/packages/instant/src/components/ui/dropdown.tsx index d51060c05..dc413d690 100644 --- a/packages/instant/src/components/ui/dropdown.tsx +++ b/packages/instant/src/components/ui/dropdown.tsx @@ -55,7 +55,6 @@ export class Dropdown extends React.Component { border="1px solid" borderColor={ColorOption.feintGrey} padding="0.8em" - borderBottom="1px solid" > @@ -127,6 +126,8 @@ export const DropdownItem: React.StatelessComponent = ({ text width="100%" borderColor={ColorOption.feintGrey} > - {text} + + {text} + ); -- cgit v1.2.3 From d0c009adff53d94414cf51028eff490e0452a3c9 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 7 Nov 2018 18:02:24 -0800 Subject: feat(instant): fetch account address at startup and drive account state changes --- packages/instant/src/components/buy_button.tsx | 21 ++++++---------- .../src/components/buy_order_state_buttons.tsx | 2 ++ .../src/components/zero_ex_instant_provider.tsx | 4 +-- packages/instant/src/constants.ts | 14 ++++++++++- .../selected_asset_buy_order_state_buttons.ts | 6 ++++- packages/instant/src/redux/actions.ts | 8 ++++++ packages/instant/src/redux/async_data.ts | 21 ++++++++++++++++ packages/instant/src/redux/reducer.ts | 29 +++++++++++++++++++++- .../instant/src/util/provider_state_factory.ts | 8 +----- 9 files changed, 88 insertions(+), 25 deletions(-) diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 515cd18e9..f24bb57ee 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -16,6 +16,7 @@ import { Button } from './ui/button'; import { Text } from './ui/text'; export interface BuyButtonProps { + accountAddress?: string; buyQuote?: BuyQuote; assetBuyer: AssetBuyer; affiliateInfo?: AffiliateInfo; @@ -34,7 +35,8 @@ export class BuyButton extends React.Component { onBuyFailure: util.boundNoop, }; public render(): React.ReactNode { - const shouldDisableButton = _.isUndefined(this.props.buyQuote); + const { buyQuote, accountAddress } = this.props; + const shouldDisableButton = _.isUndefined(buyQuote) || _.isUndefined(accountAddress); return (