aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components
diff options
context:
space:
mode:
authorBrandon Millman <brandon.millman@gmail.com>2018-11-01 06:09:12 +0800
committerBrandon Millman <brandon.millman@gmail.com>2018-11-02 05:15:30 +0800
commitc2645b26b457c66b3adcb98a5c089eba3e72f458 (patch)
tree5f0a56af898e896fe1040628a4f175bec975ca30 /packages/instant/src/components
parent0955feb0234bc90b7dcf5ad3a308570c9fa5d490 (diff)
downloaddexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar.gz
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar.bz2
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar.lz
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar.xz
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.tar.zst
dexon-sol-tools-c2645b26b457c66b3adcb98a5c089eba3e72f458.zip
feat(instant): add interactive overlay presentation to umd bundle
Diffstat (limited to 'packages/instant/src/components')
-rw-r--r--packages/instant/src/components/ui/button.tsx20
-rw-r--r--packages/instant/src/components/ui/icon.tsx8
-rw-r--r--packages/instant/src/components/ui/index.ts5
-rw-r--r--packages/instant/src/components/ui/overlay.tsx49
-rw-r--r--packages/instant/src/components/zero_ex_instant.tsx115
-rw-r--r--packages/instant/src/components/zero_ex_instant_overlay.tsx21
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx108
7 files changed, 215 insertions, 111 deletions
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<HTMLElement>) => void;
className?: string;
+ hoverStyle?: ButtonHoverStyle;
}
const PlainButton: React.StatelessComponent<ButtonProps> = ({ 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<OverlayProps> = ({ children, className, onClose }) => (
+ <Flex height="100vh" className={className}>
+ <Container position="absolute" top="0px" right="0px">
+ <Button
+ backgroundColor={ColorOption.clear}
+ borderColor={ColorOption.clear}
+ padding="2em 2em"
+ onClick={onClose}
+ hoverStyle={ButtonHoverStyle.Opacity}
+ >
+ <Icon height={18} width={18} color="white" icon="closeX" />
+ </Button>
+ </Container>
+ <div>{children}</div>
+ </Flex>
+);
+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<ZeroExInstantOptionalProps>;
-
-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<AssetMetaData>;
- networkId: Network;
-}
-
-export class ZeroExInstant extends React.Component<ZeroExInstantProps> {
- 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 (
- <Provider store={this._store}>
- <SelectedAssetThemeProvider>
- <ZeroExInstantContainer />
- </SelectedAssetThemeProvider>
- </Provider>
- );
- }
+export type ZeroExInstantProps = ZeroExInstantProviderProps;
- private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
- 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<ZeroExInstantProps> = props => {
+ return (
+ <ZeroExInstantProvider {...props}>
+ <ZeroExInstantContainer />
+ </ZeroExInstantProvider>
+ );
+};
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<ZeroExInstantOverlayProps> = props => {
+ const { onClose, zIndex, ...rest } = props;
+ return (
+ <ZeroExInstantProvider {...rest}>
+ <Overlay onClose={onClose} zIndex={zIndex}>
+ <ZeroExInstantContainer />
+ </Overlay>
+ </ZeroExInstantProvider>
+ );
+};
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<ZeroExInstantProviderOptionalProps>;
+
+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<AssetMetaData>;
+ networkId: Network;
+}
+
+export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
+ 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 (
+ <Provider store={this._store}>
+ <SelectedAssetThemeProvider>{this.props.children}</SelectedAssetThemeProvider>
+ </Provider>
+ );
+ }
+
+ private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => {
+ 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);
+ }
+ };
+}