From 3061afdafb83ad90f9b9da1f22f29525961378d5 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 31 Oct 2018 14:14:12 -0700 Subject: feat: add more asestMetaDatas --- .../instant/src/data/asset_data_network_mapping.ts | 44 ++++++++++++++++++ packages/instant/src/data/asset_meta_data_map.ts | 54 ++++++++++++++++++++++ 2 files changed, 98 insertions(+) (limited to 'packages') diff --git a/packages/instant/src/data/asset_data_network_mapping.ts b/packages/instant/src/data/asset_data_network_mapping.ts index e8ccbf011..45bfc2a02 100644 --- a/packages/instant/src/data/asset_data_network_mapping.ts +++ b/packages/instant/src/data/asset_data_network_mapping.ts @@ -8,8 +8,52 @@ interface AssetDataByNetwork { } export const assetDataNetworkMapping: AssetDataByNetwork[] = [ + // ZRX { [Network.Mainnet]: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', [Network.Kovan]: '0xf47261b00000000000000000000000002002d3812f58e35f0ea1ffbf80a75a38c32175fa', }, + // SPANK + { + [Network.Mainnet]: '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18', + [Network.Kovan]: '0xf47261b00000000000000000000000007c9eee8448f3a7d1193389652d863b27e543272d', + }, + // OMG + { + [Network.Mainnet]: '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18', + [Network.Kovan]: '0xf47261b000000000000000000000000046096d8ec059dbaae2950b30e01634ff0dc652ec', + }, + // MKR + { + [Network.Mainnet]: '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2', + [Network.Kovan]: '0xf47261b00000000000000000000000000xbf5e8e38659562fda594fbb3ec5a3576d02a9e0a', + }, + // BAT + { + [Network.Mainnet]: '0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef', + [Network.Kovan]: '0xf47261b0000000000000000000000000c87faa7a58f0adf306bad9e7d892fb045a20e5af', + }, + // SNT + { + [Network.Mainnet]: '0xf47261b0000000000000000000000000744d70fdbe2ba4cf95131626614a1763df805b9e', + [Network.Kovan]: '0xf47261b00000000000000000000000009cfe76a718ea75e3e8ce4fc7ad0fef84be70919b', + }, + // MANA + { + [Network.Mainnet]: '0xf47261b00000000000000000000000000f5d2fb29fb7d3cfee444a200298f468908cc942', + [Network.Kovan]: '0xf47261b0000000000000000000000000c64edfc78321673435fbeebdaaa7f9d755963542', + }, + // GNT + { + [Network.Mainnet]: '0xf47261b0000000000000000000000000a74476443119A942dE498590Fe1f2454d7D4aC0d', + [Network.Kovan]: '0xf47261b00000000000000000000000006986fa3646f408905ecb1876bfd355d25039ee3a', + }, + // SUB + { + [Network.Mainnet]: '0xf47261b000000000000000000000000012480e24eb5bec1a9d4369cab6a80cad3c0a377a', + }, + // Dentacoin + { + [Network.Mainnet]: '0xf47261b000000000000000000000000008d32b0da63e2C3bcF8019c9c5d849d7a9d791e6', + }, ]; diff --git a/packages/instant/src/data/asset_meta_data_map.ts b/packages/instant/src/data/asset_meta_data_map.ts index 3a820a0c4..d77298d78 100644 --- a/packages/instant/src/data/asset_meta_data_map.ts +++ b/packages/instant/src/data/asset_meta_data_map.ts @@ -11,4 +11,58 @@ export const assetMetaDataMap: ObjectMap = { primaryColor: 'rgb(54, 50, 60)', symbol: 'zrx', }, + '0xf47261b000000000000000000000000042d6622dece394b54999fbd73d108123806f6a18': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#ec3e6c', + symbol: 'spank', + }, + '0xf47261b0000000000000000000000000d26114cd6EE289AccF82350c8d8487fedB8A0C07': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#2e61ea', + symbol: 'omg', + }, + '0xf47261b00000000000000000000000009f8f72aa9304c8b593d555f12ef6589cc3a579a2': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: 'white', + symbol: 'mkr', + }, + '0xf47261b00000000000000000000000000d8775f648430679a709e98d2b0cb6250d2887ef': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#9c326c', + symbol: 'bat', + }, + '0xf47261b0000000000000000000000000744d70fdbe2ba4cf95131626614a1763df805b9e': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#5663b0', + symbol: 'snt', + }, + '0xf47261b00000000000000000000000000f5d2fb29fb7d3cfee444a200298f468908cc942': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#f08839', + symbol: 'mana', + }, + '0xf47261b0000000000000000000000000a74476443119A942dE498590Fe1f2454d7D4aC0d': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#263469', + symbol: 'gnt', + }, + '0xf47261b000000000000000000000000012480e24eb5bec1a9d4369cab6a80cad3c0a377a': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#de5445', + symbol: 'sub', + }, + '0xf47261b000000000000000000000000008d32b0da63e2C3bcF8019c9c5d849d7a9d791e6': { + assetProxyId: AssetProxyId.ERC20, + decimals: 18, + primaryColor: '#000', + symbol: 'dentacoin', + }, }; -- cgit v1.2.3 From 76f88a0a62fb4bedd63cdce07276d3fc05651831 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 31 Oct 2018 15:33:20 -0700 Subject: feat: expose new `getAvailableAssetDatasAsync` API BREAKING CHANGE: the `OrderProvider` now requires a new method `getAvailableMakerAssetDatasAsync` and the `StandardRelayerAPIOrderProvider` requires the network id at init. --- packages/asset-buyer/src/asset_buyer.ts | 12 +++++++- packages/asset-buyer/src/constants.ts | 2 +- .../src/order_providers/basic_order_provider.ts | 9 ++++++ .../standard_relayer_api_order_provider.ts | 35 ++++++++++++++++++---- packages/asset-buyer/src/types.ts | 5 ++-- packages/asset-buyer/src/utils/assert.ts | 1 - 6 files changed, 54 insertions(+), 10 deletions(-) (limited to 'packages') diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts index 34e2d9639..2bc80ac12 100644 --- a/packages/asset-buyer/src/asset_buyer.ts +++ b/packages/asset-buyer/src/asset_buyer.ts @@ -77,7 +77,8 @@ export class AssetBuyer { ): AssetBuyer { assert.isWeb3Provider('provider', provider); assert.isWebUri('sraApiUrl', sraApiUrl); - const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl); + const networkId = options.networkId || constants.DEFAULT_ASSET_BUYER_OPTS.networkId; + const orderProvider = new StandardRelayerAPIOrderProvider(sraApiUrl, networkId); const assetBuyer = new AssetBuyer(provider, orderProvider, options); return assetBuyer; } @@ -240,6 +241,15 @@ export class AssetBuyer { } } } + /** + * Get the asset data of all assets that are purchaseable with ether token (wETH) in the order provider passed in at init. + * + * @return An array of asset data strings that can be purchased using wETH. + */ + public async getAvailableAssetDatasAsync(): Promise { + const etherTokenAssetData = this._getEtherTokenAssetDataOrThrow(); + return this.orderProvider.getAvailableMakerAssetDatasAsync(etherTokenAssetData); + } /** * Grab orders from the map, if there is a miss or it is time to refresh, fetch and process the orders */ diff --git a/packages/asset-buyer/src/constants.ts b/packages/asset-buyer/src/constants.ts index c912253bd..b2f025bdb 100644 --- a/packages/asset-buyer/src/constants.ts +++ b/packages/asset-buyer/src/constants.ts @@ -36,6 +36,6 @@ export const constants = { DEFAULT_ASSET_BUYER_OPTS, DEFAULT_BUY_QUOTE_EXECUTION_OPTS, DEFAULT_BUY_QUOTE_REQUEST_OPTS, - MAX_PER_PAGE: 10000, + MAX_PER_PAGE: 1000, EMPTY_ORDERS_AND_FILLABLE_AMOUNTS, }; diff --git a/packages/asset-buyer/src/order_providers/basic_order_provider.ts b/packages/asset-buyer/src/order_providers/basic_order_provider.ts index 68406f19b..76685f27a 100644 --- a/packages/asset-buyer/src/order_providers/basic_order_provider.ts +++ b/packages/asset-buyer/src/order_providers/basic_order_provider.ts @@ -29,4 +29,13 @@ export class BasicOrderProvider implements OrderProvider { }); return { orders }; } + /** + * Given a taker asset data string, return all availabled paired maker asset data strings. + * @param takerAssetData A string representing the taker asset data. + * @return An array of asset data strings that can be purchased using takerAssetData. + */ + public async getAvailableMakerAssetDatasAsync(takerAssetData: string): Promise { + const ordersWithTakerAssetData = _.filter(this.orders, { takerAssetData }); + return _.map(ordersWithTakerAssetData, order => order.makerAssetData); + } } diff --git a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts index 41fd1fb30..c6adcfc4a 100644 --- a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts +++ b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts @@ -1,7 +1,8 @@ import { HttpClient } from '@0x/connect'; -import { APIOrder, OrderbookResponse } from '@0x/types'; +import { APIOrder, AssetPairsResponse, OrderbookResponse } from '@0x/types'; import * as _ from 'lodash'; +import { constants } from '../constants'; import { AssetBuyerError, OrderProvider, @@ -14,6 +15,7 @@ import { orderUtils } from '../utils/order_utils'; export class StandardRelayerAPIOrderProvider implements OrderProvider { public readonly apiUrl: string; + public readonly networkId: number; private readonly _sraClient: HttpClient; /** * Given an array of APIOrder objects from a standard relayer api, return an array @@ -44,12 +46,15 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider { } /** * Instantiates a new StandardRelayerAPIOrderProvider instance - * @param apiUrl The standard relayer API base HTTP url you would like to source orders from. + * @param apiUrl The standard relayer API base HTTP url you would like to source orders from. + * @param networkId The ethereum network id. * @return An instance of StandardRelayerAPIOrderProvider */ - constructor(apiUrl: string) { + constructor(apiUrl: string, networkId: number) { assert.isWebUri('apiUrl', apiUrl); + assert.isNumber('networkId', networkId); this.apiUrl = apiUrl; + this.networkId = networkId; this._sraClient = new HttpClient(apiUrl); } /** @@ -59,9 +64,9 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider { */ public async getOrdersAsync(orderProviderRequest: OrderProviderRequest): Promise { assert.isValidOrderProviderRequest('orderProviderRequest', orderProviderRequest); - const { makerAssetData, takerAssetData, networkId } = orderProviderRequest; + const { makerAssetData, takerAssetData } = orderProviderRequest; const orderbookRequest = { baseAssetData: makerAssetData, quoteAssetData: takerAssetData }; - const requestOpts = { networkId }; + const requestOpts = { networkId: this.networkId }; let orderbook: OrderbookResponse; try { orderbook = await this._sraClient.getOrderbookAsync(orderbookRequest, requestOpts); @@ -76,4 +81,24 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider { orders, }; } + /** + * Given a taker asset data string, return all availabled paired maker asset data strings. + * @param takerAssetData A string representing the taker asset data. + * @return An array of asset data strings that can be purchased using takerAssetData. + */ + public async getAvailableMakerAssetDatasAsync(takerAssetData: string): Promise { + const requestOpts = { networkId: this.networkId, perPage: constants.MAX_PER_PAGE }; + const assetPairsRequest = { assetDataA: takerAssetData }; + const fullRequest = { + ...requestOpts, + ...assetPairsRequest, + }; + let response: AssetPairsResponse; + try { + response = await this._sraClient.getAssetPairsAsync(fullRequest); + } catch (err) { + throw new Error(AssetBuyerError.StandardRelayerApiError); + } + return _.map(response.records, item => item.assetDataB.assetData); + } } diff --git a/packages/asset-buyer/src/types.ts b/packages/asset-buyer/src/types.ts index f15e7e934..3f1e6ff21 100644 --- a/packages/asset-buyer/src/types.ts +++ b/packages/asset-buyer/src/types.ts @@ -9,7 +9,6 @@ import { BigNumber } from '@0x/utils'; export interface OrderProviderRequest { makerAssetData: string; takerAssetData: string; - networkId: number; } /** @@ -27,10 +26,12 @@ export interface SignedOrderWithRemainingFillableMakerAssetAmount extends Signed remainingFillableMakerAssetAmount?: BigNumber; } /** - * Given an OrderProviderRequest, get an OrderProviderResponse. + * gerOrdersAsync: Given an OrderProviderRequest, get an OrderProviderResponse. + * getAvailableMakerAssetDatasAsync: Given a taker asset data string, return all availabled paired maker asset data strings. */ export interface OrderProvider { getOrdersAsync: (orderProviderRequest: OrderProviderRequest) => Promise; + getAvailableMakerAssetDatasAsync: (takerAssetData: string) => Promise; } /** diff --git a/packages/asset-buyer/src/utils/assert.ts b/packages/asset-buyer/src/utils/assert.ts index e8cb7f763..e5bfd2d81 100644 --- a/packages/asset-buyer/src/utils/assert.ts +++ b/packages/asset-buyer/src/utils/assert.ts @@ -29,7 +29,6 @@ export const assert = { isValidOrderProviderRequest(variableName: string, orderFetcherRequest: OrderProviderRequest): void { sharedAssert.isHexString(`${variableName}.makerAssetData`, orderFetcherRequest.makerAssetData); sharedAssert.isHexString(`${variableName}.takerAssetData`, orderFetcherRequest.takerAssetData); - sharedAssert.isNumber(`${variableName}.networkId`, orderFetcherRequest.networkId); }, areValidProvidedOrders(variableName: string, orders: SignedOrder[]): void { if (orders.length === 0) { -- cgit v1.2.3 From 8c336925601127c759ad4cfbca119368a2edfd56 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 31 Oct 2018 15:58:21 -0700 Subject: chore: add to changelog --- packages/asset-buyer/CHANGELOG.json | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'packages') diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 5d6604ea9..c572ba4cf 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -5,6 +5,11 @@ { "note": "`getAssetBuyerForProvidedOrders` factory function now takes 3 args instead of 4", "pr": 1187 + }, + { + "note": + "the `OrderProvider` now requires a new method `getAvailableMakerAssetDatasAsync` and the `StandardRelayerAPIOrderProvider` requires the network id at init.", + "pr": 1203 } ] }, -- cgit v1.2.3 From c2645b26b457c66b3adcb98a5c089eba3e72f458 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Wed, 31 Oct 2018 15:09:12 -0700 Subject: feat(instant): add interactive overlay presentation to umd bundle --- packages/instant/public/index.html | 1 + packages/instant/src/components/ui/button.tsx | 20 +++- packages/instant/src/components/ui/icon.tsx | 8 ++ packages/instant/src/components/ui/index.ts | 5 +- packages/instant/src/components/ui/overlay.tsx | 49 +++++++++ .../instant/src/components/zero_ex_instant.tsx | 115 ++------------------- .../src/components/zero_ex_instant_overlay.tsx | 21 ++++ .../src/components/zero_ex_instant_provider.tsx | 108 +++++++++++++++++++ packages/instant/src/constants.ts | 1 + packages/instant/src/index.ts | 1 + packages/instant/src/index.umd.ts | 39 +++++-- packages/instant/src/style/theme.ts | 3 + 12 files changed, 251 insertions(+), 120 deletions(-) create mode 100644 packages/instant/src/components/ui/overlay.tsx create mode 100644 packages/instant/src/components/zero_ex_instant_overlay.tsx create mode 100644 packages/instant/src/components/zero_ex_instant_provider.tsx (limited to 'packages') diff --git a/packages/instant/public/index.html b/packages/instant/public/index.html index 62532dad9..7580ab132 100644 --- a/packages/instant/public/index.html +++ b/packages/instant/public/index.html @@ -74,6 +74,7 @@ const renderOptionsDefaults = { liquiditySource: 'https://api.radarrelay.com/0x/v2/', assetData: '0xf47261b0000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498', + onClose: () => { console.log('0x Instant Closed') } } const liquiditySourceOverride = queryParams.getQueryParamValue('liquiditySource'); const renderOptionsOverrides = { diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index 5274d835b..0051482e7 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -3,6 +3,11 @@ import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; +export enum ButtonHoverStyle { + Darken = 0, + Opacity, +} + export interface ButtonProps { backgroundColor?: ColorOption; borderColor?: ColorOption; @@ -12,6 +17,7 @@ export interface ButtonProps { isDisabled?: boolean; onClick?: (event: React.MouseEvent) => void; className?: string; + hoverStyle?: ButtonHoverStyle; } const PlainButton: React.StatelessComponent = ({ children, isDisabled, onClick, type, className }) => ( @@ -32,30 +38,38 @@ export const Button = styled(PlainButton)` 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')}; + opacity: ${props => (props.hoverStyle === ButtonHoverStyle.Opacity ? 0.7 : 1)}; &:hover { background-color: ${props => - !props.isDisabled + shouldDarken(props) ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) : ''} !important; + opacity: 1; } &:active { background-color: ${props => - !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; + shouldDarken(props) ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; + opacity: 1; } &:disabled { - opacity: 0.5; + opacity: ${props => (props.hoverStyle === ButtonHoverStyle.Darken ? 0.5 : 0.2)}; } &:focus { background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; } `; +const shouldDarken = (props: ButtonProps) => { + return !props.isDisabled && props.hoverStyle === ButtonHoverStyle.Darken; +}; + Button.defaultProps = { backgroundColor: ColorOption.primaryColor, borderColor: ColorOption.primaryColor, width: 'auto', isDisabled: false, padding: '1em 2.2em', + hoverStyle: ButtonHoverStyle.Darken, }; Button.displayName = 'Button'; diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index 61b382760..a05017ba1 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -13,11 +13,19 @@ interface IconInfo { strokeLinejoin?: 'miter' | 'round' | 'bevel' | 'inherit'; } interface IconInfoMapping { + closeX: IconInfo; failed: IconInfo; success: IconInfo; chevron: IconInfo; } const ICONS: IconInfoMapping = { + closeX: { + viewBox: '0 0 11 11', + fillRule: 'evenodd', + clipRule: 'evenodd', + path: + 'M10.45 10.449C10.7539 10.1453 10.7539 9.65282 10.45 9.34909L6.60068 5.49999L10.45 1.65093C10.7538 1.3472 10.7538 0.854765 10.45 0.551038C10.1462 0.24731 9.65378 0.24731 9.34995 0.551038L5.50058 4.40006L1.65024 0.549939C1.34641 0.246212 0.853973 0.246212 0.550262 0.549939C0.246429 0.853667 0.246429 1.34611 0.550262 1.64983L4.40073 5.49995L0.55014 9.35019C0.246307 9.65392 0.246307 10.1464 0.55014 10.4501C0.853851 10.7538 1.34628 10.7538 1.65012 10.4501L5.5007 6.59987L9.35007 10.449C9.6539 10.7527 10.1463 10.7527 10.45 10.449Z', + }, failed: { viewBox: '0 0 34 34', fillRule: 'evenodd', diff --git a/packages/instant/src/components/ui/index.ts b/packages/instant/src/components/ui/index.ts index 28f76c262..c60b9640e 100644 --- a/packages/instant/src/components/ui/index.ts +++ b/packages/instant/src/components/ui/index.ts @@ -1,7 +1,8 @@ -export { Text, Title } from './text'; -export { Button, ButtonProps } from './button'; +export { Text, TextProps, Title } from './text'; +export { Button, ButtonProps, ButtonHoverStyle } from './button'; export { Flex, FlexProps } from './flex'; export { Container, ContainerProps } from './container'; export { Input, InputProps } from './input'; export { Icon, IconProps } from './icon'; export { Spinner, SpinnerProps } from './spinner'; +export { Overlay, OverlayProps } from './overlay'; diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx new file mode 100644 index 000000000..94fa10fc5 --- /dev/null +++ b/packages/instant/src/components/ui/overlay.tsx @@ -0,0 +1,49 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { ColorOption, overlayBlack, styled } from '../../style/theme'; +import { util } from '../../util/util'; + +import { Button, ButtonHoverStyle } from './button'; +import { Container } from './container'; +import { Flex } from './flex'; +import { Icon } from './icon'; + +export interface OverlayProps { + className?: string; + onClose?: () => void; + zIndex?: number; +} + +const PlainOverlay: React.StatelessComponent = ({ children, className, onClose }) => ( + + + + +
{children}
+
+); +export const Overlay = styled(PlainOverlay)` + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: ${props => props.zIndex} + background-color: ${overlayBlack}; +`; + +Overlay.defaultProps = { + onClose: util.boundNoop, + zIndex: 100, +}; + +Overlay.displayName = 'Overlay'; diff --git a/packages/instant/src/components/zero_ex_instant.tsx b/packages/instant/src/components/zero_ex_instant.tsx index d54dfc153..907c42e7a 100644 --- a/packages/instant/src/components/zero_ex_instant.tsx +++ b/packages/instant/src/components/zero_ex_instant.tsx @@ -1,111 +1,14 @@ -import { AssetBuyer } from '@0x/asset-buyer'; -import { ObjectMap, SignedOrder } from '@0x/types'; -import * as _ from 'lodash'; import * as React from 'react'; -import { Provider } from 'react-redux'; - -import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; -import { asyncData } from '../redux/async_data'; -import { INITIAL_STATE, State } from '../redux/reducer'; -import { store, Store } from '../redux/store'; -import { fonts } from '../style/fonts'; -import { AssetMetaData, Network } from '../types'; -import { assetUtils } from '../util/asset'; -import { BigNumberInput } from '../util/big_number_input'; -import { errorFlasher } from '../util/error_flasher'; -import { gasPriceEstimator } from '../util/gas_price_estimator'; -import { getProvider } from '../util/provider'; -import { web3Wrapper } from '../util/web3_wrapper'; import { ZeroExInstantContainer } from './zero_ex_instant_container'; +import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider'; -fonts.include(); - -export type ZeroExInstantProps = ZeroExInstantRequiredProps & Partial; - -export interface ZeroExInstantRequiredProps { - // TODO: Change API when we allow the selection of different assetDatas - assetData: string; - liquiditySource: string | SignedOrder[]; -} - -export interface ZeroExInstantOptionalProps { - defaultAssetBuyAmount?: number; - additionalAssetMetaDataMap: ObjectMap; - networkId: Network; -} - -export class ZeroExInstant extends React.Component { - private readonly _store: Store; - private static _mergeInitialStateWithProps(props: ZeroExInstantProps, state: State = INITIAL_STATE): State { - const networkId = props.networkId || state.network; - // TODO: Provider needs to not be hard-coded to injected web3. - const provider = getProvider(); - const assetBuyerOptions = { - networkId, - }; - let assetBuyer; - if (_.isString(props.liquiditySource)) { - assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl( - provider, - props.liquiditySource, - assetBuyerOptions, - ); - } else { - assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.liquiditySource, assetBuyerOptions); - } - const completeAssetMetaDataMap = { - ...props.additionalAssetMetaDataMap, - ...state.assetMetaDataMap, - }; - const storeStateFromProps: State = { - ...state, - assetBuyer, - network: networkId, - selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, networkId), - selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount) - ? state.selectedAssetAmount - : new BigNumberInput(props.defaultAssetBuyAmount), - assetMetaDataMap: completeAssetMetaDataMap, - }; - return storeStateFromProps; - } - constructor(props: ZeroExInstantProps) { - super(props); - const initialAppState = ZeroExInstant._mergeInitialStateWithProps(this.props, INITIAL_STATE); - this._store = store.create(initialAppState); - } - - public componentDidMount(): void { - // tslint:disable-next-line:no-floating-promises - asyncData.fetchAndDispatchToStore(this._store); - - // warm up the gas price estimator cache just in case we can't - // grab the gas price estimate when submitting the transaction - // tslint:disable-next-line:no-floating-promises - gasPriceEstimator.getFastAmountInWeiAsync(); - - // tslint:disable-next-line:no-floating-promises - this._flashErrorIfWrongNetwork(); - } - - public render(): React.ReactNode { - return ( - - - - - - ); - } +export type ZeroExInstantProps = ZeroExInstantProviderProps; - private readonly _flashErrorIfWrongNetwork = async (): Promise => { - const msToShowError = 30000; // 30 seconds - const network = this._store.getState().network; - const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); - if (network !== networkOfProvider) { - const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; - errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); - } - }; -} +export const ZeroExInstant: React.StatelessComponent = props => { + return ( + + + + ); +}; diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx new file mode 100644 index 000000000..8f872f896 --- /dev/null +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { Overlay } from './ui'; +import { ZeroExInstantContainer } from './zero_ex_instant_container'; +import { ZeroExInstantProvider, ZeroExInstantProviderProps } from './zero_ex_instant_provider'; + +export interface ZeroExInstantOverlayProps extends ZeroExInstantProviderProps { + onClose?: () => void; + zIndex?: number; +} + +export const ZeroExInstantOverlay: React.StatelessComponent = props => { + const { onClose, zIndex, ...rest } = props; + return ( + + + + + + ); +}; diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx new file mode 100644 index 000000000..8c1025723 --- /dev/null +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -0,0 +1,108 @@ +import { AssetBuyer } from '@0x/asset-buyer'; +import { ObjectMap, SignedOrder } from '@0x/types'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { Provider } from 'react-redux'; + +import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; +import { asyncData } from '../redux/async_data'; +import { INITIAL_STATE, State } from '../redux/reducer'; +import { store, Store } from '../redux/store'; +import { fonts } from '../style/fonts'; +import { AssetMetaData, Network } from '../types'; +import { assetUtils } from '../util/asset'; +import { BigNumberInput } from '../util/big_number_input'; +import { errorFlasher } from '../util/error_flasher'; +import { gasPriceEstimator } from '../util/gas_price_estimator'; +import { getProvider } from '../util/provider'; +import { web3Wrapper } from '../util/web3_wrapper'; + +fonts.include(); + +export type ZeroExInstantProviderProps = ZeroExInstantProviderRequiredProps & + Partial; + +export interface ZeroExInstantProviderRequiredProps { + // TODO: Change API when we allow the selection of different assetDatas + assetData: string; + liquiditySource: string | SignedOrder[]; +} + +export interface ZeroExInstantProviderOptionalProps { + defaultAssetBuyAmount?: number; + additionalAssetMetaDataMap: ObjectMap; + networkId: Network; +} + +export class ZeroExInstantProvider extends React.Component { + private readonly _store: Store; + private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State { + const networkId = props.networkId || state.network; + // TODO: Provider needs to not be hard-coded to injected web3. + const provider = getProvider(); + const assetBuyerOptions = { + networkId, + }; + let assetBuyer; + if (_.isString(props.liquiditySource)) { + assetBuyer = AssetBuyer.getAssetBuyerForStandardRelayerAPIUrl( + provider, + props.liquiditySource, + assetBuyerOptions, + ); + } else { + assetBuyer = AssetBuyer.getAssetBuyerForProvidedOrders(provider, props.liquiditySource, assetBuyerOptions); + } + const completeAssetMetaDataMap = { + ...props.additionalAssetMetaDataMap, + ...state.assetMetaDataMap, + }; + const storeStateFromProps: State = { + ...state, + assetBuyer, + network: networkId, + selectedAsset: assetUtils.createAssetFromAssetData(props.assetData, completeAssetMetaDataMap, networkId), + selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount) + ? state.selectedAssetAmount + : new BigNumberInput(props.defaultAssetBuyAmount), + assetMetaDataMap: completeAssetMetaDataMap, + }; + return storeStateFromProps; + } + constructor(props: ZeroExInstantProviderProps) { + super(props); + const initialAppState = ZeroExInstantProvider._mergeInitialStateWithProps(this.props, INITIAL_STATE); + this._store = store.create(initialAppState); + } + + public componentDidMount(): void { + // tslint:disable-next-line:no-floating-promises + asyncData.fetchAndDispatchToStore(this._store); + + // warm up the gas price estimator cache just in case we can't + // grab the gas price estimate when submitting the transaction + // tslint:disable-next-line:no-floating-promises + gasPriceEstimator.getFastAmountInWeiAsync(); + + // tslint:disable-next-line:no-floating-promises + this._flashErrorIfWrongNetwork(); + } + + public render(): React.ReactNode { + return ( + + {this.props.children} + + ); + } + + private readonly _flashErrorIfWrongNetwork = async (): Promise => { + const msToShowError = 30000; // 30 seconds + const network = this._store.getState().network; + const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); + if (network !== networkOfProvider) { + const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; + errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); + } + }; +} diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 424f35ecb..3e830ba00 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -2,6 +2,7 @@ import { BigNumber } from '@0x/utils'; export const BIG_NUMBER_ZERO = new BigNumber(0); export const ETH_DECIMALS = 18; export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer'; +export const INJECTED_DIV_ID = 'zeroExInstant'; export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed'; export const GWEI_IN_WEI = new BigNumber(1000000000); export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); diff --git a/packages/instant/src/index.ts b/packages/instant/src/index.ts index 54059cdad..6e611dae8 100644 --- a/packages/instant/src/index.ts +++ b/packages/instant/src/index.ts @@ -1 +1,2 @@ export { ZeroExInstant, ZeroExInstantProps } from './components/zero_ex_instant'; +export { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './components/zero_ex_instant_overlay'; diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts index dabd45cae..b12e65485 100644 --- a/packages/instant/src/index.umd.ts +++ b/packages/instant/src/index.umd.ts @@ -2,21 +2,42 @@ import * as _ from 'lodash'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR } from './constants'; -import { ZeroExInstant, ZeroExInstantProps } from './index'; +import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_ID } from './constants'; +import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; -export const render = (props: ZeroExInstantProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { - assert.isHexString('assetData', props.assetData); - assert.isValidLiquiditySource('liquiditySource', props.liquiditySource); +export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { + assert.isHexString('props.assetData', props.assetData); + assert.isValidLiquiditySource('props.liquiditySource', props.liquiditySource); if (!_.isUndefined(props.additionalAssetMetaDataMap)) { - assert.isValidAssetMetaDataMap('additionalAssetMetaDataMap', props.additionalAssetMetaDataMap); + assert.isValidAssetMetaDataMap('props.additionalAssetMetaDataMap', props.additionalAssetMetaDataMap); } if (!_.isUndefined(props.defaultAssetBuyAmount)) { - assert.isNumber('defaultAssetBuyAmount', props.defaultAssetBuyAmount); + assert.isNumber('props.defaultAssetBuyAmount', props.defaultAssetBuyAmount); } if (!_.isUndefined(props.networkId)) { - assert.isNumber('networkId', props.networkId); + assert.isNumber('props.networkId', props.networkId); } - ReactDOM.render(React.createElement(ZeroExInstant, props), document.querySelector(selector)); + if (!_.isUndefined(props.onClose)) { + assert.isFunction('props.onClose', props.onClose); + } + if (!_.isUndefined(props.zIndex)) { + assert.isNumber('props.zIndex', props.zIndex); + } + const appendToIfExists = document.querySelector(selector); + assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); + const appendTo = appendToIfExists as Element; + const injectedDiv = document.createElement('div'); + injectedDiv.setAttribute('id', INJECTED_DIV_ID); + appendTo.appendChild(injectedDiv); + const instantOverlayProps = { + ...props, + onClose: () => { + appendTo.removeChild(injectedDiv); + if (!_.isUndefined(props.onClose)) { + props.onClose(); + } + }, + }; + ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); }; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index 6575ff9f4..c7cb0bebe 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -14,6 +14,7 @@ export enum ColorOption { white = 'white', lightOrange = 'lightOrange', darkOrange = 'darkOrange', + clear = 'clear', } export const theme: Theme = { @@ -26,8 +27,10 @@ export const theme: Theme = { white: 'white', lightOrange: '#F9F2ED', darkOrange: '#F2994C', + clear: 'rgba(0, 0, 0, 0.0)', }; export const transparentWhite = 'rgba(255,255,255,0.3)'; +export const overlayBlack = 'rgba(0, 0, 0, 0.6)'; export { styled, css, keyframes, ThemeProvider }; -- cgit v1.2.3 From c50c4a4669d881000bb74de9a33684319ff740b9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 1 Nov 2018 15:11:03 -0700 Subject: fix: make maxPerPage for the SRA getAvailableMakerAssetDatasAsync call a local var --- packages/asset-buyer/src/constants.ts | 1 - .../src/order_providers/standard_relayer_api_order_provider.ts | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'packages') diff --git a/packages/asset-buyer/src/constants.ts b/packages/asset-buyer/src/constants.ts index b2f025bdb..cc415102c 100644 --- a/packages/asset-buyer/src/constants.ts +++ b/packages/asset-buyer/src/constants.ts @@ -36,6 +36,5 @@ export const constants = { DEFAULT_ASSET_BUYER_OPTS, DEFAULT_BUY_QUOTE_EXECUTION_OPTS, DEFAULT_BUY_QUOTE_REQUEST_OPTS, - MAX_PER_PAGE: 1000, EMPTY_ORDERS_AND_FILLABLE_AMOUNTS, }; diff --git a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts index c6adcfc4a..be1fc55d6 100644 --- a/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts +++ b/packages/asset-buyer/src/order_providers/standard_relayer_api_order_provider.ts @@ -2,7 +2,6 @@ import { HttpClient } from '@0x/connect'; import { APIOrder, AssetPairsResponse, OrderbookResponse } from '@0x/types'; import * as _ from 'lodash'; -import { constants } from '../constants'; import { AssetBuyerError, OrderProvider, @@ -87,7 +86,9 @@ export class StandardRelayerAPIOrderProvider implements OrderProvider { * @return An array of asset data strings that can be purchased using takerAssetData. */ public async getAvailableMakerAssetDatasAsync(takerAssetData: string): Promise { - const requestOpts = { networkId: this.networkId, perPage: constants.MAX_PER_PAGE }; + // Return a maximum of 1000 asset datas + const maxPerPage = 1000; + const requestOpts = { networkId: this.networkId, perPage: maxPerPage }; const assetPairsRequest = { assetDataA: takerAssetData }; const fullRequest = { ...requestOpts, -- cgit v1.2.3 From d16499da4e0611438df7bfe226bce940beca6918 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Thu, 1 Nov 2018 15:23:42 -0700 Subject: Remove alternate hover styling from button and move into icon component --- packages/instant/src/components/ui/button.tsx | 20 ++------ packages/instant/src/components/ui/icon.tsx | 69 ++++++++++++++++++-------- packages/instant/src/components/ui/index.ts | 2 +- packages/instant/src/components/ui/overlay.tsx | 15 +----- packages/instant/src/style/theme.ts | 2 - 5 files changed, 54 insertions(+), 54 deletions(-) (limited to 'packages') diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx index 0051482e7..5274d835b 100644 --- a/packages/instant/src/components/ui/button.tsx +++ b/packages/instant/src/components/ui/button.tsx @@ -3,11 +3,6 @@ import * as React from 'react'; import { ColorOption, styled } from '../../style/theme'; -export enum ButtonHoverStyle { - Darken = 0, - Opacity, -} - export interface ButtonProps { backgroundColor?: ColorOption; borderColor?: ColorOption; @@ -17,7 +12,6 @@ export interface ButtonProps { isDisabled?: boolean; onClick?: (event: React.MouseEvent) => void; className?: string; - hoverStyle?: ButtonHoverStyle; } const PlainButton: React.StatelessComponent = ({ children, isDisabled, onClick, type, className }) => ( @@ -38,38 +32,30 @@ export const Button = styled(PlainButton)` 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')}; - opacity: ${props => (props.hoverStyle === ButtonHoverStyle.Opacity ? 0.7 : 1)}; &:hover { background-color: ${props => - shouldDarken(props) + !props.isDisabled ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white']) : ''} !important; - opacity: 1; } &:active { background-color: ${props => - shouldDarken(props) ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; - opacity: 1; + !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''}; } &:disabled { - opacity: ${props => (props.hoverStyle === ButtonHoverStyle.Darken ? 0.5 : 0.2)}; + opacity: 0.5; } &:focus { background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])}; } `; -const shouldDarken = (props: ButtonProps) => { - return !props.isDisabled && props.hoverStyle === ButtonHoverStyle.Darken; -}; - Button.defaultProps = { backgroundColor: ColorOption.primaryColor, borderColor: ColorOption.primaryColor, width: 'auto', isDisabled: false, padding: '1em 2.2em', - hoverStyle: ButtonHoverStyle.Darken, }; Button.displayName = 'Button'; diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx index a05017ba1..f12059cff 100644 --- a/packages/instant/src/components/ui/icon.tsx +++ b/packages/instant/src/components/ui/icon.tsx @@ -1,5 +1,8 @@ +import * as _ from 'lodash'; import * as React from 'react'; +import { styled } from '../../style/theme'; + type svgRule = 'evenodd' | 'nonzero' | 'inherit'; interface IconInfo { viewBox: string; @@ -52,33 +55,57 @@ const ICONS: IconInfoMapping = { }; export interface IconProps { + className?: string; width: number; height?: number; color?: string; icon: keyof IconInfoMapping; + onClick?: (event: React.MouseEvent) => void; + padding?: string; } -export const Icon: React.SFC = props => { +const PlainIcon: React.SFC = props => { const iconInfo = ICONS[props.icon]; - return ( - - - +
+ + + +
); }; + +export const Icon = styled(PlainIcon)` + cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')}; + transition: opacity 0.5s ease; + padding: ${props => props.padding}; + opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)}; + &:hover { + opacity: 1; + } + &:active { + opacity: 1; + } +`; + +Icon.defaultProps = { + color: 'white', + padding: '0em 0em', +}; + +Icon.displayName = 'Icon'; diff --git a/packages/instant/src/components/ui/index.ts b/packages/instant/src/components/ui/index.ts index c60b9640e..0efabdb85 100644 --- a/packages/instant/src/components/ui/index.ts +++ b/packages/instant/src/components/ui/index.ts @@ -1,5 +1,5 @@ export { Text, TextProps, Title } from './text'; -export { Button, ButtonProps, ButtonHoverStyle } from './button'; +export { Button, ButtonProps } from './button'; export { Flex, FlexProps } from './flex'; export { Container, ContainerProps } from './container'; export { Input, InputProps } from './input'; diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx index 94fa10fc5..c5258b031 100644 --- a/packages/instant/src/components/ui/overlay.tsx +++ b/packages/instant/src/components/ui/overlay.tsx @@ -1,10 +1,8 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { ColorOption, overlayBlack, styled } from '../../style/theme'; -import { util } from '../../util/util'; +import { overlayBlack, styled } from '../../style/theme'; -import { Button, ButtonHoverStyle } from './button'; import { Container } from './container'; import { Flex } from './flex'; import { Icon } from './icon'; @@ -18,15 +16,7 @@ export interface OverlayProps { const PlainOverlay: React.StatelessComponent = ({ children, className, onClose }) => ( - +
{children}
@@ -42,7 +32,6 @@ export const Overlay = styled(PlainOverlay)` `; Overlay.defaultProps = { - onClose: util.boundNoop, zIndex: 100, }; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index c7cb0bebe..e81694620 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -14,7 +14,6 @@ export enum ColorOption { white = 'white', lightOrange = 'lightOrange', darkOrange = 'darkOrange', - clear = 'clear', } export const theme: Theme = { @@ -27,7 +26,6 @@ export const theme: Theme = { white: 'white', lightOrange: '#F9F2ED', darkOrange: '#F2994C', - clear: 'rgba(0, 0, 0, 0.0)', }; export const transparentWhite = 'rgba(255,255,255,0.3)'; -- cgit v1.2.3