Merge pull request #1175 from 0xProject/feature/instant/input-fees-rounding
[instant] Create a ScalingInput component and use it in the amount input and upgrade to styled-components v4
This commit is contained in:
commit
4c5b26db18
@ -58,7 +58,7 @@
|
|||||||
"react-redux": "^5.0.7",
|
"react-redux": "^5.0.7",
|
||||||
"redux": "^4.0.0",
|
"redux": "^4.0.0",
|
||||||
"redux-devtools-extension": "^2.13.5",
|
"redux-devtools-extension": "^2.13.5",
|
||||||
"styled-components": "^3.4.9",
|
"styled-components": "^4.0.2",
|
||||||
"ts-optchain": "^0.1.1"
|
"ts-optchain": "^0.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -73,6 +73,7 @@
|
|||||||
"@types/react-dom": "^16.0.8",
|
"@types/react-dom": "^16.0.8",
|
||||||
"@types/react-redux": "^6.0.9",
|
"@types/react-redux": "^6.0.9",
|
||||||
"@types/redux": "^3.6.0",
|
"@types/redux": "^3.6.0",
|
||||||
|
"@types/styled-components": "^4.0.1",
|
||||||
"awesome-typescript-loader": "^5.2.1",
|
"awesome-typescript-loader": "^5.2.1",
|
||||||
"enzyme": "^3.6.0",
|
"enzyme": "^3.6.0",
|
||||||
"enzyme-adapter-react-16": "^1.5.0",
|
"enzyme-adapter-react-16": "^1.5.0",
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { ColorOption } from '../style/theme';
|
|
||||||
import { util } from '../util/util';
|
|
||||||
|
|
||||||
import { Container, Input } from './ui';
|
|
||||||
|
|
||||||
export interface AmountInputProps {
|
|
||||||
fontColor?: ColorOption;
|
|
||||||
fontSize?: string;
|
|
||||||
value?: BigNumber;
|
|
||||||
onChange: (value?: BigNumber) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AmountInput extends React.Component<AmountInputProps> {
|
|
||||||
public static defaultProps = {
|
|
||||||
onChange: util.boundNoop,
|
|
||||||
};
|
|
||||||
public render(): React.ReactNode {
|
|
||||||
const { fontColor, fontSize, value } = this.props;
|
|
||||||
return (
|
|
||||||
<Container borderBottom="1px solid rgba(255,255,255,0.3)" display="inline-block">
|
|
||||||
<Input
|
|
||||||
fontColor={fontColor}
|
|
||||||
fontSize={fontSize}
|
|
||||||
onChange={this._handleChange}
|
|
||||||
value={!_.isUndefined(value) ? value.toString() : ''}
|
|
||||||
placeholder="0.00"
|
|
||||||
width="2.2em"
|
|
||||||
/>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const value = event.target.value;
|
|
||||||
let bigNumberValue;
|
|
||||||
if (!_.isEmpty(value)) {
|
|
||||||
try {
|
|
||||||
bigNumberValue = new BigNumber(event.target.value);
|
|
||||||
} catch {
|
|
||||||
// We don't want to allow values that can't be a BigNumber, so don't even call onChange.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.props.onChange(bigNumberValue);
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { Keyframes } from 'styled-components';
|
||||||
|
|
||||||
import { keyframes, styled } from '../../style/theme';
|
import { css, keyframes, styled } from '../../style/theme';
|
||||||
|
|
||||||
const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes`
|
const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes`
|
||||||
from {
|
from {
|
||||||
@ -15,7 +16,7 @@ const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export interface SlideAnimationProps {
|
export interface SlideAnimationProps {
|
||||||
keyframes: string;
|
keyframes: Keyframes;
|
||||||
animationType: string;
|
animationType: string;
|
||||||
animationDirection?: string;
|
animationDirection?: string;
|
||||||
}
|
}
|
||||||
@ -24,7 +25,10 @@ export const SlideAnimation =
|
|||||||
styled.div <
|
styled.div <
|
||||||
SlideAnimationProps >
|
SlideAnimationProps >
|
||||||
`
|
`
|
||||||
animation-name: ${props => props.keyframes};
|
animation-name: ${props =>
|
||||||
|
css`
|
||||||
|
${props.keyframes};
|
||||||
|
`};
|
||||||
animation-duration: 0.3s;
|
animation-duration: 0.3s;
|
||||||
animation-timing-function: ${props => props.animationType};
|
animation-timing-function: ${props => props.animationType};
|
||||||
animation-delay: 0s;
|
animation-delay: 0s;
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
|
||||||
import * as _ from 'lodash';
|
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { ColorOption } from '../style/theme';
|
|
||||||
import { ERC20Asset } from '../types';
|
|
||||||
import { assetUtils } from '../util/asset';
|
|
||||||
import { util } from '../util/util';
|
|
||||||
|
|
||||||
import { AmountInput, AmountInputProps } from './amount_input';
|
|
||||||
import { Container, Text } from './ui';
|
|
||||||
|
|
||||||
// Asset amounts only apply to ERC20 assets
|
|
||||||
export interface AssetAmountInputProps extends AmountInputProps {
|
|
||||||
asset?: ERC20Asset;
|
|
||||||
onChange: (value?: BigNumber, asset?: ERC20Asset) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AssetAmountInput extends React.Component<AssetAmountInputProps> {
|
|
||||||
public static defaultProps = {
|
|
||||||
onChange: util.boundNoop,
|
|
||||||
};
|
|
||||||
public render(): React.ReactNode {
|
|
||||||
const { asset, onChange, ...rest } = this.props;
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<AmountInput {...rest} onChange={this._handleChange} />
|
|
||||||
<Container display="inline-block" marginLeft="10px">
|
|
||||||
<Text fontSize={rest.fontSize} fontColor={ColorOption.white} textTransform="uppercase">
|
|
||||||
{assetUtils.bestNameForAsset(asset)}
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
private readonly _handleChange = (value?: BigNumber): void => {
|
|
||||||
this.props.onChange(value, this.props.asset);
|
|
||||||
};
|
|
||||||
}
|
|
84
packages/instant/src/components/erc20_asset_amount_input.tsx
Normal file
84
packages/instant/src/components/erc20_asset_amount_input.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ColorOption, transparentWhite } from '../style/theme';
|
||||||
|
import { ERC20Asset } from '../types';
|
||||||
|
import { assetUtils } from '../util/asset';
|
||||||
|
import { BigNumberInput } from '../util/big_number_input';
|
||||||
|
import { util } from '../util/util';
|
||||||
|
|
||||||
|
import { ScalingAmountInput } from './scaling_amount_input';
|
||||||
|
import { Container, Text } from './ui';
|
||||||
|
|
||||||
|
// Asset amounts only apply to ERC20 assets
|
||||||
|
export interface ERC20AssetAmountInputProps {
|
||||||
|
asset?: ERC20Asset;
|
||||||
|
value?: BigNumberInput;
|
||||||
|
onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void;
|
||||||
|
startingFontSizePx: number;
|
||||||
|
fontColor?: ColorOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ERC20AssetAmountInputState {
|
||||||
|
currentFontSizePx: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInputProps, ERC20AssetAmountInputState> {
|
||||||
|
public static defaultProps = {
|
||||||
|
onChange: util.boundNoop,
|
||||||
|
};
|
||||||
|
constructor(props: ERC20AssetAmountInputProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
currentFontSizePx: props.startingFontSizePx,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
const { asset, onChange, ...rest } = this.props;
|
||||||
|
return (
|
||||||
|
<Container whiteSpace="nowrap">
|
||||||
|
<Container borderBottom={`1px solid ${transparentWhite}`} display="inline-block">
|
||||||
|
<ScalingAmountInput
|
||||||
|
{...rest}
|
||||||
|
textLengthThreshold={this._textLengthThresholdForAsset(asset)}
|
||||||
|
maxFontSizePx={this.props.startingFontSizePx}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
onFontSizeChange={this._handleFontSizeChange}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
<Container display="inline-flex" marginLeft="10px" title={assetUtils.bestNameForAsset(asset)}>
|
||||||
|
<Text
|
||||||
|
fontSize={`${this.state.currentFontSizePx}px`}
|
||||||
|
fontColor={ColorOption.white}
|
||||||
|
textTransform="uppercase"
|
||||||
|
>
|
||||||
|
{assetUtils.formattedSymbolForAsset(asset)}
|
||||||
|
</Text>
|
||||||
|
</Container>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private readonly _handleChange = (value?: BigNumberInput): void => {
|
||||||
|
this.props.onChange(value, this.props.asset);
|
||||||
|
};
|
||||||
|
private readonly _handleFontSizeChange = (fontSizePx: number): void => {
|
||||||
|
this.setState({
|
||||||
|
currentFontSizePx: fontSizePx,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// For assets with symbols of different length,
|
||||||
|
// start scaling the input at different character lengths
|
||||||
|
private readonly _textLengthThresholdForAsset = (asset?: ERC20Asset): number => {
|
||||||
|
if (_.isUndefined(asset)) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
const symbol = asset.metaData.symbol;
|
||||||
|
if (symbol.length <= 3) {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if (symbol.length === 5) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
};
|
||||||
|
}
|
@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { SelectedAssetAmountInput } from '../containers/selected_asset_amount_input';
|
import { SelectedERC20AssetAmountInput } from '../containers/selected_erc20_asset_amount_input';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { AsyncProcessState, OrderProcessState, OrderState } from '../types';
|
import { AsyncProcessState, OrderProcessState, OrderState } from '../types';
|
||||||
import { format } from '../util/format';
|
import { format } from '../util/format';
|
||||||
@ -48,7 +48,9 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
|
|||||||
</Text>
|
</Text>
|
||||||
</Container>
|
</Container>
|
||||||
<Flex direction="row" justify="space-between">
|
<Flex direction="row" justify="space-between">
|
||||||
<SelectedAssetAmountInput fontSize="45px" />
|
<Flex height="60px">
|
||||||
|
<SelectedERC20AssetAmountInput startingFontSizePx={38} />
|
||||||
|
</Flex>
|
||||||
<Flex direction="column" justify="space-between">
|
<Flex direction="column" justify="space-between">
|
||||||
{iconOrAmounts}
|
{iconOrAmounts}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
52
packages/instant/src/components/scaling_amount_input.tsx
Normal file
52
packages/instant/src/components/scaling_amount_input.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ColorOption } from '../style/theme';
|
||||||
|
import { BigNumberInput } from '../util/big_number_input';
|
||||||
|
import { util } from '../util/util';
|
||||||
|
|
||||||
|
import { ScalingInput } from './scaling_input';
|
||||||
|
|
||||||
|
export interface ScalingAmountInputProps {
|
||||||
|
maxFontSizePx: number;
|
||||||
|
textLengthThreshold: number;
|
||||||
|
fontColor?: ColorOption;
|
||||||
|
value?: BigNumberInput;
|
||||||
|
onChange: (value?: BigNumberInput) => void;
|
||||||
|
onFontSizeChange: (fontSizePx: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> {
|
||||||
|
public static defaultProps = {
|
||||||
|
onChange: util.boundNoop,
|
||||||
|
onFontSizeChange: util.boundNoop,
|
||||||
|
};
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
const { textLengthThreshold, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props;
|
||||||
|
return (
|
||||||
|
<ScalingInput
|
||||||
|
maxFontSizePx={maxFontSizePx}
|
||||||
|
textLengthThreshold={textLengthThreshold}
|
||||||
|
onFontSizeChange={onFontSizeChange}
|
||||||
|
fontColor={fontColor}
|
||||||
|
onChange={this._handleChange}
|
||||||
|
value={!_.isUndefined(value) ? value.toDisplayString() : ''}
|
||||||
|
placeholder="0.00"
|
||||||
|
emptyInputWidthCh={3.5}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
const value = event.target.value;
|
||||||
|
let bigNumberValue;
|
||||||
|
if (!_.isEmpty(value)) {
|
||||||
|
try {
|
||||||
|
bigNumberValue = new BigNumberInput(value);
|
||||||
|
} catch {
|
||||||
|
// We don't want to allow values that can't be a BigNumber, so don't even call onChange.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.props.onChange(bigNumberValue);
|
||||||
|
};
|
||||||
|
}
|
170
packages/instant/src/components/scaling_input.tsx
Normal file
170
packages/instant/src/components/scaling_input.tsx
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import { ColorOption } from '../style/theme';
|
||||||
|
import { util } from '../util/util';
|
||||||
|
|
||||||
|
import { Input } from './ui';
|
||||||
|
|
||||||
|
export enum ScalingInputPhase {
|
||||||
|
FixedFontSize,
|
||||||
|
ScalingFontSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScalingSettings {
|
||||||
|
percentageToReduceFontSizePerCharacter: number;
|
||||||
|
constantPxToIncreaseWidthPerCharacter: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScalingInputProps {
|
||||||
|
textLengthThreshold: number;
|
||||||
|
maxFontSizePx: number;
|
||||||
|
value: string;
|
||||||
|
emptyInputWidthCh: number;
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
onFontSizeChange: (fontSizePx: number) => void;
|
||||||
|
fontColor?: ColorOption;
|
||||||
|
placeholder?: string;
|
||||||
|
maxLength?: number;
|
||||||
|
scalingSettings: ScalingSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScalingInputState {
|
||||||
|
inputWidthPxAtPhaseChange?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScalingInputSnapshot {
|
||||||
|
inputWidthPx: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are magic numbers that were determined experimentally.
|
||||||
|
const defaultScalingSettings: ScalingSettings = {
|
||||||
|
percentageToReduceFontSizePerCharacter: 0.125,
|
||||||
|
constantPxToIncreaseWidthPerCharacter: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ScalingInput extends React.Component<ScalingInputProps, ScalingInputState> {
|
||||||
|
public static defaultProps = {
|
||||||
|
onChange: util.boundNoop,
|
||||||
|
onFontSizeChange: util.boundNoop,
|
||||||
|
maxLength: 7,
|
||||||
|
scalingSettings: defaultScalingSettings,
|
||||||
|
};
|
||||||
|
public state: ScalingInputState = {
|
||||||
|
inputWidthPxAtPhaseChange: undefined,
|
||||||
|
};
|
||||||
|
private readonly _inputRef = React.createRef<HTMLInputElement>();
|
||||||
|
public static getPhase(textLengthThreshold: number, value: string): ScalingInputPhase {
|
||||||
|
if (value.length <= textLengthThreshold) {
|
||||||
|
return ScalingInputPhase.FixedFontSize;
|
||||||
|
}
|
||||||
|
return ScalingInputPhase.ScalingFontSize;
|
||||||
|
}
|
||||||
|
public static getPhaseFromProps(props: ScalingInputProps): ScalingInputPhase {
|
||||||
|
const { value, textLengthThreshold } = props;
|
||||||
|
return ScalingInput.getPhase(textLengthThreshold, value);
|
||||||
|
}
|
||||||
|
public static calculateFontSize(
|
||||||
|
textLengthThreshold: number,
|
||||||
|
maxFontSizePx: number,
|
||||||
|
phase: ScalingInputPhase,
|
||||||
|
value: string,
|
||||||
|
percentageToReduceFontSizePerCharacter: number,
|
||||||
|
): number {
|
||||||
|
if (phase !== ScalingInputPhase.ScalingFontSize) {
|
||||||
|
return maxFontSizePx;
|
||||||
|
}
|
||||||
|
const charactersOverMax = value.length - textLengthThreshold;
|
||||||
|
const scalingFactor = (1 - percentageToReduceFontSizePerCharacter) ** charactersOverMax;
|
||||||
|
const fontSize = scalingFactor * maxFontSizePx;
|
||||||
|
return fontSize;
|
||||||
|
}
|
||||||
|
public static calculateFontSizeFromProps(props: ScalingInputProps, phase: ScalingInputPhase): number {
|
||||||
|
const { textLengthThreshold, value, maxFontSizePx, scalingSettings } = props;
|
||||||
|
return ScalingInput.calculateFontSize(
|
||||||
|
textLengthThreshold,
|
||||||
|
maxFontSizePx,
|
||||||
|
phase,
|
||||||
|
value,
|
||||||
|
scalingSettings.percentageToReduceFontSizePerCharacter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public getSnapshotBeforeUpdate(): ScalingInputSnapshot {
|
||||||
|
return {
|
||||||
|
inputWidthPx: this._getInputWidthInPx(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public componentDidUpdate(
|
||||||
|
prevProps: ScalingInputProps,
|
||||||
|
prevState: ScalingInputState,
|
||||||
|
snapshot: ScalingInputSnapshot,
|
||||||
|
): void {
|
||||||
|
const prevPhase = ScalingInput.getPhaseFromProps(prevProps);
|
||||||
|
const curPhase = ScalingInput.getPhaseFromProps(this.props);
|
||||||
|
// if we went from fixed to scaling, save the width from the transition
|
||||||
|
if (prevPhase !== ScalingInputPhase.ScalingFontSize && curPhase === ScalingInputPhase.ScalingFontSize) {
|
||||||
|
this.setState({
|
||||||
|
inputWidthPxAtPhaseChange: snapshot.inputWidthPx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// if we went from scaling to fixed, revert back to scaling using `ch`
|
||||||
|
if (prevPhase === ScalingInputPhase.ScalingFontSize && curPhase !== ScalingInputPhase.ScalingFontSize) {
|
||||||
|
this.setState({
|
||||||
|
inputWidthPxAtPhaseChange: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const prevFontSize = ScalingInput.calculateFontSizeFromProps(prevProps, prevPhase);
|
||||||
|
const curFontSize = ScalingInput.calculateFontSizeFromProps(this.props, curPhase);
|
||||||
|
// If font size has changed, notify.
|
||||||
|
if (prevFontSize !== curFontSize) {
|
||||||
|
this.props.onFontSizeChange(curFontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public render(): React.ReactNode {
|
||||||
|
const { fontColor, onChange, placeholder, value, maxLength } = this.props;
|
||||||
|
const phase = ScalingInput.getPhaseFromProps(this.props);
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
ref={this._inputRef as any}
|
||||||
|
fontColor={fontColor}
|
||||||
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
placeholder={placeholder}
|
||||||
|
fontSize={`${this._calculateFontSize(phase)}px`}
|
||||||
|
width={this._calculateWidth(phase)}
|
||||||
|
maxLength={maxLength}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private readonly _calculateWidth = (phase: ScalingInputPhase): string => {
|
||||||
|
const { value, textLengthThreshold, scalingSettings } = this.props;
|
||||||
|
if (_.isEmpty(value)) {
|
||||||
|
return `${this.props.emptyInputWidthCh}ch`;
|
||||||
|
}
|
||||||
|
switch (phase) {
|
||||||
|
case ScalingInputPhase.FixedFontSize:
|
||||||
|
return `${value.length}ch`;
|
||||||
|
case ScalingInputPhase.ScalingFontSize:
|
||||||
|
const { inputWidthPxAtPhaseChange } = this.state;
|
||||||
|
if (!_.isUndefined(inputWidthPxAtPhaseChange)) {
|
||||||
|
const charactersOverMax = value.length - textLengthThreshold;
|
||||||
|
const scalingAmount = scalingSettings.constantPxToIncreaseWidthPerCharacter * charactersOverMax;
|
||||||
|
const width = inputWidthPxAtPhaseChange + scalingAmount;
|
||||||
|
return `${width}px`;
|
||||||
|
}
|
||||||
|
return `${textLengthThreshold}ch`;
|
||||||
|
default:
|
||||||
|
return '1ch';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private readonly _calculateFontSize = (phase: ScalingInputPhase): number => {
|
||||||
|
return ScalingInput.calculateFontSizeFromProps(this.props, phase);
|
||||||
|
};
|
||||||
|
private readonly _getInputWidthInPx = (): number => {
|
||||||
|
const ref = this._inputRef.current;
|
||||||
|
if (!ref) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ref.getBoundingClientRect().width;
|
||||||
|
};
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { ColorOption, styled } from '../../style/theme';
|
import { ColorOption, styled } from '../../style/theme';
|
||||||
import { cssRuleIfExists } from '../../style/util';
|
import { cssRuleIfExists } from '../../style/util';
|
||||||
|
|
||||||
@ -11,6 +9,7 @@ export interface ContainerProps {
|
|||||||
bottom?: string;
|
bottom?: string;
|
||||||
left?: string;
|
left?: string;
|
||||||
width?: string;
|
width?: string;
|
||||||
|
height?: string;
|
||||||
maxWidth?: string;
|
maxWidth?: string;
|
||||||
margin?: string;
|
margin?: string;
|
||||||
marginTop?: string;
|
marginTop?: string;
|
||||||
@ -27,14 +26,14 @@ export interface ContainerProps {
|
|||||||
backgroundColor?: ColorOption;
|
backgroundColor?: ColorOption;
|
||||||
hasBoxShadow?: boolean;
|
hasBoxShadow?: boolean;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
|
whiteSpace?: string;
|
||||||
opacity?: number;
|
opacity?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlainContainer: React.StatelessComponent<ContainerProps> = ({ children, className }) => (
|
export const Container =
|
||||||
<div className={className}>{children}</div>
|
styled.div <
|
||||||
);
|
ContainerProps >
|
||||||
|
`
|
||||||
export const Container = styled(PlainContainer)`
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
${props => cssRuleIfExists(props, 'display')}
|
${props => cssRuleIfExists(props, 'display')}
|
||||||
${props => cssRuleIfExists(props, 'position')}
|
${props => cssRuleIfExists(props, 'position')}
|
||||||
@ -43,6 +42,7 @@ export const Container = styled(PlainContainer)`
|
|||||||
${props => cssRuleIfExists(props, 'bottom')}
|
${props => cssRuleIfExists(props, 'bottom')}
|
||||||
${props => cssRuleIfExists(props, 'left')}
|
${props => cssRuleIfExists(props, 'left')}
|
||||||
${props => cssRuleIfExists(props, 'width')}
|
${props => cssRuleIfExists(props, 'width')}
|
||||||
|
${props => cssRuleIfExists(props, 'height')}
|
||||||
${props => cssRuleIfExists(props, 'max-width')}
|
${props => cssRuleIfExists(props, 'max-width')}
|
||||||
${props => cssRuleIfExists(props, 'margin')}
|
${props => cssRuleIfExists(props, 'margin')}
|
||||||
${props => cssRuleIfExists(props, 'margin-top')}
|
${props => cssRuleIfExists(props, 'margin-top')}
|
||||||
@ -55,6 +55,7 @@ export const Container = styled(PlainContainer)`
|
|||||||
${props => cssRuleIfExists(props, 'border-top')}
|
${props => cssRuleIfExists(props, 'border-top')}
|
||||||
${props => cssRuleIfExists(props, 'border-bottom')}
|
${props => cssRuleIfExists(props, 'border-bottom')}
|
||||||
${props => cssRuleIfExists(props, 'z-index')}
|
${props => cssRuleIfExists(props, 'z-index')}
|
||||||
|
${props => cssRuleIfExists(props, 'white-space')}
|
||||||
${props => cssRuleIfExists(props, 'opacity')}
|
${props => cssRuleIfExists(props, 'opacity')}
|
||||||
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
||||||
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { ColorOption, styled } from '../../style/theme';
|
import { ColorOption, styled } from '../../style/theme';
|
||||||
import { cssRuleIfExists } from '../../style/util';
|
import { cssRuleIfExists } from '../../style/util';
|
||||||
|
|
||||||
@ -9,21 +7,22 @@ export interface FlexProps {
|
|||||||
justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
||||||
align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
|
||||||
width?: string;
|
width?: string;
|
||||||
|
height?: string;
|
||||||
backgroundColor?: ColorOption;
|
backgroundColor?: ColorOption;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlainFlex: React.StatelessComponent<FlexProps> = ({ children, className }) => (
|
export const Flex =
|
||||||
<div className={className}>{children}</div>
|
styled.div <
|
||||||
);
|
FlexProps >
|
||||||
|
`
|
||||||
export const Flex = styled(PlainFlex)`
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: ${props => props.direction};
|
flex-direction: ${props => props.direction};
|
||||||
flex-wrap: ${props => props.flexWrap};
|
flex-wrap: ${props => props.flexWrap};
|
||||||
justify-content: ${props => props.justify};
|
justify-content: ${props => props.justify};
|
||||||
align-items: ${props => props.align};
|
align-items: ${props => props.align};
|
||||||
${props => cssRuleIfExists(props, 'width')}
|
${props => cssRuleIfExists(props, 'width')}
|
||||||
|
${props => cssRuleIfExists(props, 'height')}
|
||||||
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -12,11 +12,10 @@ export interface InputProps {
|
|||||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlainInput: React.StatelessComponent<InputProps> = ({ value, className, placeholder, onChange }) => (
|
export const Input =
|
||||||
<input className={className} value={value} onChange={onChange} placeholder={placeholder} />
|
styled.input <
|
||||||
);
|
InputProps >
|
||||||
|
`
|
||||||
export const Input = styled(PlainInput)`
|
|
||||||
font-size: ${props => props.fontSize};
|
font-size: ${props => props.fontSize};
|
||||||
width: ${props => props.width};
|
width: ${props => props.width};
|
||||||
padding: 0.1em 0em;
|
padding: 0.1em 0em;
|
||||||
|
@ -23,14 +23,11 @@ export interface TextProps {
|
|||||||
display?: string;
|
display?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PlainText: React.StatelessComponent<TextProps> = ({ children, className, onClick }) => (
|
|
||||||
<div className={className} onClick={onClick}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const darkenOnHoverAmount = 0.3;
|
const darkenOnHoverAmount = 0.3;
|
||||||
export const Text = styled(PlainText)`
|
export const Text =
|
||||||
|
styled.div <
|
||||||
|
TextProps >
|
||||||
|
`
|
||||||
font-family: ${props => props.fontFamily};
|
font-family: ${props => props.fontFamily};
|
||||||
font-style: ${props => props.fontStyle};
|
font-style: ${props => props.fontStyle};
|
||||||
font-weight: ${props => props.fontWeight};
|
font-weight: ${props => props.fontWeight};
|
||||||
|
@ -11,34 +11,35 @@ import { Action, actions } from '../redux/actions';
|
|||||||
import { State } from '../redux/reducer';
|
import { State } from '../redux/reducer';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { ERC20Asset, OrderProcessState } from '../types';
|
import { ERC20Asset, OrderProcessState } from '../types';
|
||||||
|
import { BigNumberInput } from '../util/big_number_input';
|
||||||
import { errorUtil } from '../util/error';
|
import { errorUtil } from '../util/error';
|
||||||
|
|
||||||
import { AssetAmountInput } from '../components/asset_amount_input';
|
import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
|
||||||
|
|
||||||
export interface SelectedAssetAmountInputProps {
|
export interface SelectedERC20AssetAmountInputProps {
|
||||||
fontColor?: ColorOption;
|
fontColor?: ColorOption;
|
||||||
fontSize?: string;
|
startingFontSizePx: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectedState {
|
interface ConnectedState {
|
||||||
assetBuyer?: AssetBuyer;
|
assetBuyer?: AssetBuyer;
|
||||||
value?: BigNumber;
|
value?: BigNumberInput;
|
||||||
asset?: ERC20Asset;
|
asset?: ERC20Asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectedDispatch {
|
interface ConnectedDispatch {
|
||||||
updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumber, asset?: ERC20Asset) => void;
|
updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumberInput, asset?: ERC20Asset) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectedProps {
|
interface ConnectedProps {
|
||||||
value?: BigNumber;
|
value?: BigNumberInput;
|
||||||
asset?: ERC20Asset;
|
asset?: ERC20Asset;
|
||||||
onChange: (value?: BigNumber, asset?: ERC20Asset) => void;
|
onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type FinalProps = ConnectedProps & SelectedAssetAmountInputProps;
|
type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps;
|
||||||
|
|
||||||
const mapStateToProps = (state: State, _ownProps: SelectedAssetAmountInputProps): ConnectedState => {
|
const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => {
|
||||||
const selectedAsset = state.selectedAsset;
|
const selectedAsset = state.selectedAsset;
|
||||||
if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) {
|
if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) {
|
||||||
return {
|
return {
|
||||||
@ -82,7 +83,7 @@ const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trai
|
|||||||
|
|
||||||
const mapDispatchToProps = (
|
const mapDispatchToProps = (
|
||||||
dispatch: Dispatch<Action>,
|
dispatch: Dispatch<Action>,
|
||||||
_ownProps: SelectedAssetAmountInputProps,
|
_ownProps: SelectedERC20AssetAmountInputProps,
|
||||||
): ConnectedDispatch => ({
|
): ConnectedDispatch => ({
|
||||||
updateBuyQuote: (assetBuyer, value, asset) => {
|
updateBuyQuote: (assetBuyer, value, asset) => {
|
||||||
// Update the input
|
// Update the input
|
||||||
@ -104,7 +105,7 @@ const mapDispatchToProps = (
|
|||||||
const mergeProps = (
|
const mergeProps = (
|
||||||
connectedState: ConnectedState,
|
connectedState: ConnectedState,
|
||||||
connectedDispatch: ConnectedDispatch,
|
connectedDispatch: ConnectedDispatch,
|
||||||
ownProps: SelectedAssetAmountInputProps,
|
ownProps: SelectedERC20AssetAmountInputProps,
|
||||||
): FinalProps => {
|
): FinalProps => {
|
||||||
return {
|
return {
|
||||||
...ownProps,
|
...ownProps,
|
||||||
@ -116,8 +117,8 @@ const mergeProps = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectedAssetAmountInput: React.ComponentClass<SelectedAssetAmountInputProps> = connect(
|
export const SelectedERC20AssetAmountInput: React.ComponentClass<SelectedERC20AssetAmountInputProps> = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps,
|
mapDispatchToProps,
|
||||||
mergeProps,
|
mergeProps,
|
||||||
)(AssetAmountInput);
|
)(ERC20AssetAmountInput);
|
@ -2,6 +2,8 @@ import { BuyQuote } from '@0x/asset-buyer';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { BigNumberInput } from '../util/big_number_input';
|
||||||
|
|
||||||
import { ActionsUnion, OrderState } from '../types';
|
import { ActionsUnion, OrderState } from '../types';
|
||||||
|
|
||||||
export interface PlainAction<T extends string> {
|
export interface PlainAction<T extends string> {
|
||||||
@ -36,7 +38,8 @@ export enum ActionTypes {
|
|||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price),
|
updateEthUsdPrice: (price?: BigNumber) => createAction(ActionTypes.UPDATE_ETH_USD_PRICE, price),
|
||||||
updateSelectedAssetAmount: (amount?: BigNumber) => createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount),
|
updateSelectedAssetAmount: (amount?: BigNumberInput) =>
|
||||||
|
createAction(ActionTypes.UPDATE_SELECTED_ASSET_AMOUNT, amount),
|
||||||
updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState),
|
updateBuyOrderState: (orderState: OrderState) => createAction(ActionTypes.UPDATE_BUY_ORDER_STATE, orderState),
|
||||||
updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote),
|
updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote),
|
||||||
updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData),
|
updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData),
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
OrderState,
|
OrderState,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { assetUtils } from '../util/asset';
|
import { assetUtils } from '../util/asset';
|
||||||
|
import { BigNumberInput } from '../util/big_number_input';
|
||||||
|
|
||||||
import { Action, ActionTypes } from './actions';
|
import { Action, ActionTypes } from './actions';
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ export interface State {
|
|||||||
assetBuyer?: AssetBuyer;
|
assetBuyer?: AssetBuyer;
|
||||||
assetMetaDataMap: ObjectMap<AssetMetaData>;
|
assetMetaDataMap: ObjectMap<AssetMetaData>;
|
||||||
selectedAsset?: Asset;
|
selectedAsset?: Asset;
|
||||||
selectedAssetAmount?: BigNumber;
|
selectedAssetAmount?: BigNumberInput;
|
||||||
buyOrderState: OrderState;
|
buyOrderState: OrderState;
|
||||||
ethUsdPrice?: BigNumber;
|
ethUsdPrice?: BigNumber;
|
||||||
latestBuyQuote?: BuyQuote;
|
latestBuyQuote?: BuyQuote;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { injectGlobal } from './theme';
|
|
||||||
|
|
||||||
export const fonts = {
|
export const fonts = {
|
||||||
include: () => {
|
include: () => {
|
||||||
// Inject the inter-ui font into the page
|
// Inject the inter-ui font into the page
|
||||||
return injectGlobal`
|
const appendTo = document.head || document.getElementsByTagName('head')[0] || document.body;
|
||||||
@import url('https://rsms.me/inter/inter-ui.css');
|
const style = document.createElement('style');
|
||||||
`;
|
style.type = 'text/css';
|
||||||
|
style.appendChild(document.createTextNode(`@import url('https://rsms.me/inter/inter-ui.css')`));
|
||||||
|
appendTo.appendChild(style);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as styledComponents from 'styled-components';
|
import * as styledComponents from 'styled-components';
|
||||||
|
|
||||||
const { default: styled, css, injectGlobal, keyframes, ThemeProvider } = styledComponents;
|
const { default: styled, css, keyframes, ThemeProvider } = styledComponents;
|
||||||
|
|
||||||
export type Theme = { [key in ColorOption]: string };
|
export type Theme = { [key in ColorOption]: string };
|
||||||
|
|
||||||
@ -28,4 +28,6 @@ export const theme: Theme = {
|
|||||||
darkOrange: '#F2994C',
|
darkOrange: '#F2994C',
|
||||||
};
|
};
|
||||||
|
|
||||||
export { styled, css, injectGlobal, keyframes, ThemeProvider };
|
export const transparentWhite = 'rgba(255,255,255,0.3)';
|
||||||
|
|
||||||
|
export { styled, css, keyframes, ThemeProvider };
|
||||||
|
@ -2,7 +2,7 @@ import { AssetProxyId, ObjectMap } from '@0x/types';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { assetDataNetworkMapping } from '../data/asset_data_network_mapping';
|
import { assetDataNetworkMapping } from '../data/asset_data_network_mapping';
|
||||||
import { Asset, AssetMetaData, Network, ZeroExInstantError } from '../types';
|
import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types';
|
||||||
|
|
||||||
export const assetUtils = {
|
export const assetUtils = {
|
||||||
createAssetFromAssetData: (
|
createAssetFromAssetData: (
|
||||||
@ -43,6 +43,16 @@ export const assetUtils = {
|
|||||||
return defaultName;
|
return defaultName;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
formattedSymbolForAsset: (asset?: ERC20Asset, defaultName: string = '???'): string => {
|
||||||
|
if (_.isUndefined(asset)) {
|
||||||
|
return defaultName;
|
||||||
|
}
|
||||||
|
const symbol = asset.metaData.symbol;
|
||||||
|
if (symbol.length <= 5) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
return `${symbol.slice(0, 3)}…`;
|
||||||
|
},
|
||||||
getAssociatedAssetDataIfExists: (assetData: string, network: Network): string | undefined => {
|
getAssociatedAssetDataIfExists: (assetData: string, network: Network): string | undefined => {
|
||||||
const assetDataGroupIfExists = _.find(assetDataNetworkMapping, value => value[network] === assetData);
|
const assetDataGroupIfExists = _.find(assetDataNetworkMapping, value => value[network] === assetData);
|
||||||
if (_.isUndefined(assetDataGroupIfExists)) {
|
if (_.isUndefined(assetDataGroupIfExists)) {
|
||||||
|
29
packages/instant/src/util/big_number_input.ts
Normal file
29
packages/instant/src/util/big_number_input.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BigNumber extension that is more flexible about decimal strings.
|
||||||
|
* Such as allowing:
|
||||||
|
* new BigNumberInput('0.') => 0
|
||||||
|
* new BigNumberInput('1.') => 1
|
||||||
|
* new BigNumberInput('1..') => still throws
|
||||||
|
*/
|
||||||
|
export class BigNumberInput extends BigNumber {
|
||||||
|
private readonly _isEndingWithDecimal: boolean;
|
||||||
|
constructor(bigNumberString: string) {
|
||||||
|
const hasDecimalPeriod = _.endsWith(bigNumberString, '.');
|
||||||
|
let internalString = bigNumberString;
|
||||||
|
if (hasDecimalPeriod) {
|
||||||
|
internalString = bigNumberString.slice(0, -1);
|
||||||
|
}
|
||||||
|
super(internalString);
|
||||||
|
this._isEndingWithDecimal = hasDecimalPeriod;
|
||||||
|
}
|
||||||
|
public toDisplayString(): string {
|
||||||
|
const internalString = super.toString();
|
||||||
|
if (this._isEndingWithDecimal) {
|
||||||
|
return `${internalString}.`;
|
||||||
|
}
|
||||||
|
return internalString;
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ export const format = {
|
|||||||
if (_.isUndefined(ethUnitAmount)) {
|
if (_.isUndefined(ethUnitAmount)) {
|
||||||
return defaultText;
|
return defaultText;
|
||||||
}
|
}
|
||||||
const roundedAmount = ethUnitAmount.round(decimalPlaces);
|
const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces);
|
||||||
return `${roundedAmount} ETH`;
|
return `${roundedAmount} ETH`;
|
||||||
},
|
},
|
||||||
ethBaseAmountInUsd: (
|
ethBaseAmountInUsd: (
|
||||||
|
@ -20,8 +20,8 @@ describe('format', () => {
|
|||||||
it('converts .432414 ETH in base units to the string `.4324 ETH`', () => {
|
it('converts .432414 ETH in base units to the string `.4324 ETH`', () => {
|
||||||
expect(format.ethBaseAmount(DECIMAL_ETH_IN_BASE_UNITS)).toBe('0.4324 ETH');
|
expect(format.ethBaseAmount(DECIMAL_ETH_IN_BASE_UNITS)).toBe('0.4324 ETH');
|
||||||
});
|
});
|
||||||
it('converts 5.3014059295032 ETH in base units to the string `5.3014 ETH`', () => {
|
it('converts 5.3014059295032 ETH in base units to the string `5.301 ETH`', () => {
|
||||||
expect(format.ethBaseAmount(IRRATIONAL_ETH_IN_BASE_UNITS)).toBe('5.3014 ETH');
|
expect(format.ethBaseAmount(IRRATIONAL_ETH_IN_BASE_UNITS)).toBe('5.301 ETH');
|
||||||
});
|
});
|
||||||
it('returns defaultText param when ethBaseAmount is not defined', () => {
|
it('returns defaultText param when ethBaseAmount is not defined', () => {
|
||||||
const defaultText = 'defaultText';
|
const defaultText = 'defaultText';
|
||||||
@ -38,8 +38,8 @@ describe('format', () => {
|
|||||||
it('converts BigNumer(.432414) to the string `.4324 ETH`', () => {
|
it('converts BigNumer(.432414) to the string `.4324 ETH`', () => {
|
||||||
expect(format.ethUnitAmount(BIG_NUMBER_DECIMAL)).toBe('0.4324 ETH');
|
expect(format.ethUnitAmount(BIG_NUMBER_DECIMAL)).toBe('0.4324 ETH');
|
||||||
});
|
});
|
||||||
it('converts BigNumber(5.3014059295032) to the string `5.3014 ETH`', () => {
|
it('converts BigNumber(5.3014059295032) to the string `5.301 ETH`', () => {
|
||||||
expect(format.ethUnitAmount(BIG_NUMBER_IRRATIONAL)).toBe('5.3014 ETH');
|
expect(format.ethUnitAmount(BIG_NUMBER_IRRATIONAL)).toBe('5.301 ETH');
|
||||||
});
|
});
|
||||||
it('returns defaultText param when ethUnitAmount is not defined', () => {
|
it('returns defaultText param when ethUnitAmount is not defined', () => {
|
||||||
const defaultText = 'defaultText';
|
const defaultText = 'defaultText';
|
||||||
|
67
yarn.lock
67
yarn.lock
@ -484,6 +484,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight" "^7.0.0"
|
"@babel/highlight" "^7.0.0"
|
||||||
|
|
||||||
|
"@babel/helper-annotate-as-pure@^7.0.0":
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.0.0"
|
||||||
|
|
||||||
"@babel/highlight@^7.0.0":
|
"@babel/highlight@^7.0.0":
|
||||||
version "7.0.0"
|
version "7.0.0"
|
||||||
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
|
resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
|
||||||
@ -504,6 +510,24 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.12.0"
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
|
"@babel/types@^7.0.0":
|
||||||
|
version "7.1.3"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d"
|
||||||
|
dependencies:
|
||||||
|
esutils "^2.0.2"
|
||||||
|
lodash "^4.17.10"
|
||||||
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
|
"@emotion/is-prop-valid@^0.6.8":
|
||||||
|
version "0.6.8"
|
||||||
|
resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz#68ad02831da41213a2089d2cab4e8ac8b30cbd85"
|
||||||
|
dependencies:
|
||||||
|
"@emotion/memoize" "^0.6.6"
|
||||||
|
|
||||||
|
"@emotion/memoize@^0.6.6":
|
||||||
|
version "0.6.6"
|
||||||
|
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b"
|
||||||
|
|
||||||
"@ledgerhq/hw-app-eth@^4.3.0":
|
"@ledgerhq/hw-app-eth@^4.3.0":
|
||||||
version "4.7.3"
|
version "4.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.7.3.tgz#d352e19658ae296532e522c53c8ec2a1a77b64e5"
|
resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.7.3.tgz#d352e19658ae296532e522c53c8ec2a1a77b64e5"
|
||||||
@ -1579,6 +1603,13 @@
|
|||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
|
"@types/styled-components@^4.0.1":
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.npmjs.org/@types/styled-components/-/styled-components-4.0.1.tgz#5eb9a5474dbde3becab2bcc8f04e0b8e8dcf8c06"
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/tmp@^0.0.33":
|
"@types/tmp@^0.0.33":
|
||||||
version "0.0.33"
|
version "0.0.33"
|
||||||
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d"
|
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d"
|
||||||
@ -2532,6 +2563,13 @@ babel-plugin-jest-hoist@^23.2.0:
|
|||||||
version "23.2.0"
|
version "23.2.0"
|
||||||
resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167"
|
resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167"
|
||||||
|
|
||||||
|
"babel-plugin-styled-components@>= 1":
|
||||||
|
version "1.8.0"
|
||||||
|
resolved "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.8.0.tgz#9dd054c8e86825203449a852a5746f29f2dab857"
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-annotate-as-pure" "^7.0.0"
|
||||||
|
lodash "^4.17.10"
|
||||||
|
|
||||||
babel-plugin-syntax-async-functions@^6.8.0:
|
babel-plugin-syntax-async-functions@^6.8.0:
|
||||||
version "6.13.0"
|
version "6.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
|
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
|
||||||
@ -4581,6 +4619,14 @@ css-to-react-native@^2.0.3:
|
|||||||
fbjs "^0.8.5"
|
fbjs "^0.8.5"
|
||||||
postcss-value-parser "^3.3.0"
|
postcss-value-parser "^3.3.0"
|
||||||
|
|
||||||
|
css-to-react-native@^2.2.2:
|
||||||
|
version "2.2.2"
|
||||||
|
resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-2.2.2.tgz#c077d0f7bf3e6c915a539e7325821c9dd01f9965"
|
||||||
|
dependencies:
|
||||||
|
css-color-keywords "^1.0.0"
|
||||||
|
fbjs "^0.8.5"
|
||||||
|
postcss-value-parser "^3.3.0"
|
||||||
|
|
||||||
css-vendor@^0.3.8:
|
css-vendor@^0.3.8:
|
||||||
version "0.3.8"
|
version "0.3.8"
|
||||||
resolved "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa"
|
resolved "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa"
|
||||||
@ -6705,7 +6751,7 @@ ganache-core@0xProject/ganache-core#monorepo-dep:
|
|||||||
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
|
||||||
ethereumjs-util "^5.2.0"
|
ethereumjs-util "^5.2.0"
|
||||||
ethereumjs-vm "2.3.5"
|
ethereumjs-vm "2.3.5"
|
||||||
ethereumjs-wallet "0.6.0"
|
ethereumjs-wallet "~0.6.0"
|
||||||
fake-merkle-patricia-tree "~1.0.1"
|
fake-merkle-patricia-tree "~1.0.1"
|
||||||
heap "~0.2.6"
|
heap "~0.2.6"
|
||||||
js-scrypt "^0.2.0"
|
js-scrypt "^0.2.0"
|
||||||
@ -14394,19 +14440,18 @@ styled-components@^3.3.3:
|
|||||||
stylis-rule-sheet "^0.0.10"
|
stylis-rule-sheet "^0.0.10"
|
||||||
supports-color "^3.2.3"
|
supports-color "^3.2.3"
|
||||||
|
|
||||||
styled-components@^3.4.9:
|
styled-components@^4.0.2:
|
||||||
version "3.4.10"
|
version "4.0.2"
|
||||||
resolved "https://registry.npmjs.org/styled-components/-/styled-components-3.4.10.tgz#9a654c50ea2b516c36ade57ddcfa296bf85c96e1"
|
resolved "https://registry.npmjs.org/styled-components/-/styled-components-4.0.2.tgz#7d4409ada019cdd34c25ba68c4577ea95dbcf0c5"
|
||||||
dependencies:
|
dependencies:
|
||||||
buffer "^5.0.3"
|
"@emotion/is-prop-valid" "^0.6.8"
|
||||||
css-to-react-native "^2.0.3"
|
babel-plugin-styled-components ">= 1"
|
||||||
fbjs "^0.8.16"
|
css-to-react-native "^2.2.2"
|
||||||
hoist-non-react-statics "^2.5.0"
|
memoize-one "^4.0.0"
|
||||||
prop-types "^15.5.4"
|
prop-types "^15.5.4"
|
||||||
react-is "^16.3.1"
|
react-is "^16.3.1"
|
||||||
stylis "^3.5.0"
|
stylis "^3.5.0"
|
||||||
stylis-rule-sheet "^0.0.10"
|
stylis-rule-sheet "^0.0.10"
|
||||||
supports-color "^3.2.3"
|
|
||||||
|
|
||||||
stylis-rule-sheet@^0.0.10:
|
stylis-rule-sheet@^0.0.10:
|
||||||
version "0.0.10"
|
version "0.0.10"
|
||||||
@ -14849,6 +14894,10 @@ to-fast-properties@^1.0.3:
|
|||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
|
||||||
|
|
||||||
|
to-fast-properties@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||||
|
|
||||||
to-no-case@^1.0.0:
|
to-no-case@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
|
resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user