aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-12-19 00:59:15 +0800
committerFabio Berger <me@fabioberger.com>2018-12-19 00:59:15 +0800
commit622b9f662e74d571da745047ede097c7a392d09e (patch)
tree68a9517882b04a3d428f6996e0790ceb82e89be4 /packages/instant/src/components
parente295eeb8938468b1527d5d81f212766cef40bc81 (diff)
parent67df5a433d68a2af1a3a03a8bf431629a534dc97 (diff)
downloaddexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar.gz
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar.bz2
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar.lz
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar.xz
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.tar.zst
dexon-sol-tools-622b9f662e74d571da745047ede097c7a392d09e.zip
Merge branch 'development' into features/orderwatcher_ws
* development: (107 commits) Fix OrderWatcher title to fix sidebar top Fix version picker so it doesn't overflow onto two lines Fix bug in pull_missing_blocks with incorrect start block (#1438) Pull approval events for ZRX and DAI (#1430) fix semicolon and apply prettier Fix dex order quote/base asset assigning (#1432) Apply prettier Publish Updated CHANGELOGS Rename contracts CHANGELOGs to DEPLOYs Move Forwarder CHANGELOG entries to extensions CHANGELOG Make contracts packages not private Publish Updated CHANGELOGS Show @ price in light grey Updated CHANGELOGS typeof -> isString add special case to scrape OHLCV for eth/usd (#1428) run linter simplify scaling input logic ...
Diffstat (limited to 'packages/instant/src/components')
-rw-r--r--packages/instant/src/components/erc20_token_selector.tsx13
-rw-r--r--packages/instant/src/components/instant_heading.tsx34
-rw-r--r--packages/instant/src/components/order_details.tsx265
-rw-r--r--packages/instant/src/components/payment_method.tsx11
-rw-r--r--packages/instant/src/components/scaling_amount_input.tsx1
-rw-r--r--packages/instant/src/components/scaling_input.tsx93
-rw-r--r--packages/instant/src/components/section_header.tsx20
-rw-r--r--packages/instant/src/components/ui/input.tsx6
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx2
9 files changed, 286 insertions, 159 deletions
diff --git a/packages/instant/src/components/erc20_token_selector.tsx b/packages/instant/src/components/erc20_token_selector.tsx
index f7d5a4fe4..cb8a8c797 100644
--- a/packages/instant/src/components/erc20_token_selector.tsx
+++ b/packages/instant/src/components/erc20_token_selector.tsx
@@ -7,7 +7,6 @@ import { analytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { SearchInput } from './search_input';
-
import { Circle } from './ui/circle';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
@@ -123,10 +122,20 @@ interface TokenSelectorRowIconProps {
token: ERC20Asset;
}
+const getTokenIcon = (symbol: string): React.StatelessComponent | undefined => {
+ try {
+ return require(`../assets/icons/${symbol}.svg`) as React.StatelessComponent;
+ } catch (e) {
+ // Can't find icon
+ return undefined;
+ }
+};
+
const TokenSelectorRowIcon: React.StatelessComponent<TokenSelectorRowIconProps> = props => {
const { token } = props;
const iconUrlIfExists = token.metaData.iconUrl;
- const TokenIcon = require(`../assets/icons/${token.metaData.symbol}.svg`);
+
+ const TokenIcon = getTokenIcon(token.metaData.symbol);
const displaySymbol = assetUtils.bestNameForAsset(token);
if (!_.isUndefined(iconUrlIfExists)) {
return <img src={iconUrlIfExists} />;
diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx
index 117f9dd5f..5b1f9592d 100644
--- a/packages/instant/src/components/instant_heading.tsx
+++ b/packages/instant/src/components/instant_heading.tsx
@@ -61,12 +61,19 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
}
private _renderAmountsSection(): React.ReactNode {
- return (
- <Container>
- <Container marginBottom="5px">{this._renderPlaceholderOrAmount(this._renderEthAmount)}</Container>
- <Container opacity={0.7}>{this._renderPlaceholderOrAmount(this._renderDollarAmount)}</Container>
- </Container>
- );
+ if (
+ _.isUndefined(this.props.totalEthBaseUnitAmount) &&
+ this.props.quoteRequestState !== AsyncProcessState.Pending
+ ) {
+ return null;
+ } else {
+ return (
+ <Container>
+ <Container marginBottom="5px">{this._renderPlaceholderOrAmount(this._renderEthAmount)}</Container>
+ <Container opacity={0.7}>{this._renderPlaceholderOrAmount(this._renderDollarAmount)}</Container>
+ </Container>
+ );
+ }
}
private _renderIcon(): React.ReactNode {
@@ -106,20 +113,23 @@ export class InstantHeading extends React.Component<InstantHeadingProps, {}> {
}
private readonly _renderEthAmount = (): React.ReactNode => {
+ const ethAmount = format.ethBaseUnitAmount(
+ this.props.totalEthBaseUnitAmount,
+ 4,
+ <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />,
+ );
+
+ const fontSize = _.isString(ethAmount) && ethAmount.length >= 13 ? '14px' : '16px';
return (
<Text
- fontSize="16px"
+ fontSize={fontSize}
textAlign="right"
width="100%"
fontColor={ColorOption.white}
fontWeight={500}
noWrap={true}
>
- {format.ethBaseUnitAmount(
- this.props.totalEthBaseUnitAmount,
- 4,
- <AmountPlaceholder isPulsating={false} color={PLACEHOLDER_COLOR} />,
- )}
+ {ethAmount}
</Text>
);
};
diff --git a/packages/instant/src/components/order_details.tsx b/packages/instant/src/components/order_details.tsx
index a8e0e2513..9c10ef9e6 100644
--- a/packages/instant/src/components/order_details.tsx
+++ b/packages/instant/src/components/order_details.tsx
@@ -4,124 +4,227 @@ import * as _ from 'lodash';
import * as React from 'react';
import { oc } from 'ts-optchain';
-import { BIG_NUMBER_ZERO } from '../constants';
+import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
import { ColorOption } from '../style/theme';
+import { BaseCurrency } from '../types';
import { format } from '../util/format';
import { AmountPlaceholder } from './amount_placeholder';
+import { SectionHeader } from './section_header';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
-import { Text } from './ui/text';
+import { Text, TextProps } from './ui/text';
export interface OrderDetailsProps {
buyQuoteInfo?: BuyQuoteInfo;
selectedAssetUnitAmount?: BigNumber;
ethUsdPrice?: BigNumber;
isLoading: boolean;
+ assetName?: string;
+ baseCurrency: BaseCurrency;
+ onBaseCurrencySwitchEth: () => void;
+ onBaseCurrencySwitchUsd: () => void;
}
export class OrderDetails extends React.Component<OrderDetailsProps> {
public render(): React.ReactNode {
- const { buyQuoteInfo, ethUsdPrice, selectedAssetUnitAmount } = this.props;
- const buyQuoteAccessor = oc(buyQuoteInfo);
- const assetEthBaseUnitAmount = buyQuoteAccessor.assetEthAmount();
- const feeEthBaseUnitAmount = buyQuoteAccessor.feeEthAmount();
- const totalEthBaseUnitAmount = buyQuoteAccessor.totalEthAmount();
- const pricePerTokenEth =
- !_.isUndefined(assetEthBaseUnitAmount) &&
- !_.isUndefined(selectedAssetUnitAmount) &&
- !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO)
- ? assetEthBaseUnitAmount.div(selectedAssetUnitAmount).ceil()
- : undefined;
+ const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
return (
<Container width="100%" flexGrow={1} padding="20px 20px 0px 20px">
- <Container marginBottom="10px">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.primaryColor}
- fontWeight={600}
- textTransform="uppercase"
- fontSize="14px"
- >
- Order Details
- </Text>
- </Container>
- <EthAmountRow
- rowLabel="Token Price"
- ethAmount={pricePerTokenEth}
- ethUsdPrice={ethUsdPrice}
- isLoading={this.props.isLoading}
+ <Container marginBottom="10px">{this._renderHeader()}</Container>
+ {shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()}
+ </Container>
+ );
+ }
+
+ private _renderRows(): React.ReactNode {
+ const { buyQuoteInfo } = this.props;
+ return (
+ <React.Fragment>
+ <OrderDetailsRow
+ labelText={this._assetAmountLabel()}
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.assetEthAmount)}
/>
- <EthAmountRow
- rowLabel="Fee"
- ethAmount={feeEthBaseUnitAmount}
- ethUsdPrice={ethUsdPrice}
- isLoading={this.props.isLoading}
+ <OrderDetailsRow
+ labelText="Fee"
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.feeEthAmount)}
/>
- <EthAmountRow
- rowLabel="Total Cost"
- ethAmount={totalEthBaseUnitAmount}
- ethUsdPrice={ethUsdPrice}
- shouldEmphasize={true}
- isLoading={this.props.isLoading}
+ <OrderDetailsRow
+ labelText="Total Cost"
+ isLabelBold={true}
+ primaryValue={this._displayAmountOrPlaceholder(buyQuoteInfo && buyQuoteInfo.totalEthAmount)}
+ isPrimaryValueBold={true}
+ secondaryValue={this._totalCostSecondaryValue()}
/>
- </Container>
+ </React.Fragment>
);
}
-}
-export interface EthAmountRowProps {
- rowLabel: string;
- ethAmount?: BigNumber;
- isEthAmountInBaseUnits?: boolean;
- ethUsdPrice?: BigNumber;
- shouldEmphasize?: boolean;
- isLoading: boolean;
+ private _renderErrorFetchingUsdPrice(): React.ReactNode {
+ return (
+ <Text>
+ There was an error fetching the USD price.
+ <Text
+ onClick={this.props.onBaseCurrencySwitchEth}
+ fontWeight={700}
+ fontColor={ColorOption.primaryColor}
+ >
+ Click here
+ </Text>
+ {' to view ETH prices'}
+ </Text>
+ );
+ }
+
+ private _hadErrorFetchingUsdPrice(): boolean {
+ return this.props.ethUsdPrice ? this.props.ethUsdPrice.equals(BIG_NUMBER_ZERO) : false;
+ }
+
+ private _totalCostSecondaryValue(): React.ReactNode {
+ const secondaryCurrency = this.props.baseCurrency === BaseCurrency.USD ? BaseCurrency.ETH : BaseCurrency.USD;
+
+ const canDisplayCurrency =
+ secondaryCurrency === BaseCurrency.ETH ||
+ (secondaryCurrency === BaseCurrency.USD && this.props.ethUsdPrice && !this._hadErrorFetchingUsdPrice());
+
+ if (this.props.buyQuoteInfo && canDisplayCurrency) {
+ return this._displayAmount(secondaryCurrency, this.props.buyQuoteInfo.totalEthAmount);
+ } else {
+ return undefined;
+ }
+ }
+
+ private _displayAmountOrPlaceholder(weiAmount?: BigNumber): React.ReactNode {
+ const { baseCurrency, isLoading } = this.props;
+
+ if (_.isUndefined(weiAmount)) {
+ return (
+ <Container opacity={0.5}>
+ <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} />
+ </Container>
+ );
+ }
+
+ return this._displayAmount(baseCurrency, weiAmount);
+ }
+
+ private _displayAmount(currency: BaseCurrency, weiAmount: BigNumber): React.ReactNode {
+ switch (currency) {
+ case BaseCurrency.USD:
+ return format.ethBaseUnitAmountInUsd(weiAmount, this.props.ethUsdPrice, 2, '');
+ case BaseCurrency.ETH:
+ return format.ethBaseUnitAmount(weiAmount, 4, '');
+ }
+ }
+
+ private _assetAmountLabel(): React.ReactNode {
+ const { assetName, baseCurrency } = this.props;
+ const numTokens = this.props.selectedAssetUnitAmount;
+
+ // Display as 0 if we have a selected asset
+ const displayNumTokens =
+ assetName && assetName !== DEFAULT_UNKOWN_ASSET_NAME && _.isUndefined(numTokens)
+ ? new BigNumber(0)
+ : numTokens;
+ if (!_.isUndefined(displayNumTokens)) {
+ let numTokensWithSymbol: React.ReactNode = displayNumTokens.toString();
+ if (assetName) {
+ numTokensWithSymbol += ` ${assetName}`;
+ }
+ const pricePerTokenWei = this._pricePerTokenWei();
+ if (pricePerTokenWei) {
+ const atPriceDisplay = (
+ <Text fontColor={ColorOption.lightGrey}>
+ @ {this._displayAmount(baseCurrency, pricePerTokenWei)}
+ </Text>
+ );
+ numTokensWithSymbol = (
+ <React.Fragment>
+ {numTokensWithSymbol} {atPriceDisplay}
+ </React.Fragment>
+ );
+ }
+ return numTokensWithSymbol;
+ }
+ return 'Token Amount';
+ }
+
+ private _pricePerTokenWei(): BigNumber | undefined {
+ const buyQuoteAccessor = oc(this.props.buyQuoteInfo);
+ const assetTotalInWei = buyQuoteAccessor.assetEthAmount();
+ const selectedAssetUnitAmount = this.props.selectedAssetUnitAmount;
+ return !_.isUndefined(assetTotalInWei) &&
+ !_.isUndefined(selectedAssetUnitAmount) &&
+ !selectedAssetUnitAmount.eq(BIG_NUMBER_ZERO)
+ ? assetTotalInWei.div(selectedAssetUnitAmount).ceil()
+ : undefined;
+ }
+
+ private _baseCurrencyChoice(choice: BaseCurrency): React.ReactNode {
+ const onClick =
+ choice === BaseCurrency.ETH ? this.props.onBaseCurrencySwitchEth : this.props.onBaseCurrencySwitchUsd;
+ const isSelected = this.props.baseCurrency === choice;
+
+ const textStyle: TextProps = { onClick, fontSize: '12px' };
+ if (isSelected) {
+ textStyle.fontColor = ColorOption.primaryColor;
+ textStyle.fontWeight = 700;
+ } else {
+ textStyle.fontColor = ColorOption.lightGrey;
+ }
+ return <Text {...textStyle}>{choice}</Text>;
+ }
+
+ private _renderHeader(): React.ReactNode {
+ return (
+ <Flex justify="space-between">
+ <SectionHeader>Order Details</SectionHeader>
+ <Container>
+ {this._baseCurrencyChoice(BaseCurrency.ETH)}
+ <Container marginLeft="5px" marginRight="5px" display="inline">
+ <Text fontSize="12px" fontColor={ColorOption.feintGrey}>
+ /
+ </Text>
+ </Container>
+ {this._baseCurrencyChoice(BaseCurrency.USD)}
+ </Container>
+ </Flex>
+ );
+ }
}
-export class EthAmountRow extends React.Component<EthAmountRowProps> {
- public static defaultProps = {
- shouldEmphasize: false,
- isEthAmountInBaseUnits: true,
- };
+export interface OrderDetailsRowProps {
+ labelText: React.ReactNode;
+ isLabelBold?: boolean;
+ isPrimaryValueBold?: boolean;
+ primaryValue: React.ReactNode;
+ secondaryValue?: React.ReactNode;
+}
+export class OrderDetailsRow extends React.Component<OrderDetailsRowProps, {}> {
public render(): React.ReactNode {
- const { rowLabel, ethAmount, isEthAmountInBaseUnits, shouldEmphasize, isLoading } = this.props;
-
- const fontWeight = shouldEmphasize ? 700 : 400;
- const ethFormatter = isEthAmountInBaseUnits ? format.ethBaseUnitAmount : format.ethUnitAmount;
return (
<Container padding="10px 0px" borderTop="1px dashed" borderColor={ColorOption.feintGrey}>
<Flex justify="space-between">
- <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {rowLabel}
+ <Text fontWeight={this.props.isLabelBold ? 700 : 400} fontColor={ColorOption.grey}>
+ {this.props.labelText}
</Text>
- <Container>
- {this._renderUsdSection()}
- <Text fontWeight={fontWeight} fontColor={ColorOption.grey}>
- {ethFormatter(
- ethAmount,
- 4,
- <Container opacity={0.5}>
- <AmountPlaceholder color={ColorOption.lightGrey} isPulsating={isLoading} />
- </Container>,
- )}
- </Text>
- </Container>
+ <Container>{this._renderValues()}</Container>
</Flex>
</Container>
);
}
- private _renderUsdSection(): React.ReactNode {
- const usdFormatter = this.props.isEthAmountInBaseUnits
- ? format.ethBaseUnitAmountInUsd
- : format.ethUnitAmountInUsd;
- const shouldHideUsdPriceSection = _.isUndefined(this.props.ethUsdPrice) || _.isUndefined(this.props.ethAmount);
- return shouldHideUsdPriceSection ? null : (
+
+ private _renderValues(): React.ReactNode {
+ const secondaryValueNode: React.ReactNode = this.props.secondaryValue && (
<Container marginRight="3px" display="inline-block">
- <Text fontColor={ColorOption.lightGrey}>
- ({usdFormatter(this.props.ethAmount, this.props.ethUsdPrice)})
- </Text>
+ <Text fontColor={ColorOption.lightGrey}>({this.props.secondaryValue})</Text>
</Container>
);
+ return (
+ <React.Fragment>
+ {secondaryValueNode}
+ <Text fontWeight={this.props.isPrimaryValueBold ? 700 : 400}>{this.props.primaryValue}</Text>
+ </React.Fragment>
+ );
}
}
diff --git a/packages/instant/src/components/payment_method.tsx b/packages/instant/src/components/payment_method.tsx
index 7c93f1d1c..abadf4bd6 100644
--- a/packages/instant/src/components/payment_method.tsx
+++ b/packages/instant/src/components/payment_method.tsx
@@ -8,6 +8,7 @@ import { envUtil } from '../util/env';
import { CoinbaseWalletLogo } from './coinbase_wallet_logo';
import { MetaMaskLogo } from './meta_mask_logo';
import { PaymentMethodDropdown } from './payment_method_dropdown';
+import { SectionHeader } from './section_header';
import { Circle } from './ui/circle';
import { Container } from './ui/container';
import { Flex } from './ui/flex';
@@ -29,15 +30,7 @@ export class PaymentMethod extends React.Component<PaymentMethodProps> {
<Container width="100%" height="120px" padding="20px 20px 0px 20px">
<Container marginBottom="12px">
<Flex justify="space-between">
- <Text
- letterSpacing="1px"
- fontColor={ColorOption.primaryColor}
- fontWeight={600}
- textTransform="uppercase"
- fontSize="14px"
- >
- {this._renderTitleText()}
- </Text>
+ <SectionHeader>{this._renderTitleText()}</SectionHeader>
{this._renderTitleLabel()}
</Flex>
</Container>
diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx
index 86aca5a65..4feb0502d 100644
--- a/packages/instant/src/components/scaling_amount_input.tsx
+++ b/packages/instant/src/components/scaling_amount_input.tsx
@@ -58,6 +58,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps,
const { textLengthThreshold, fontColor, maxFontSizePx, onFontSizeChange } = this.props;
return (
<ScalingInput
+ type="number"
maxFontSizePx={maxFontSizePx}
textLengthThreshold={textLengthThreshold}
onFontSizeChange={onFontSizeChange}
diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 791692257..00aea37da 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -1,3 +1,4 @@
+import { ObjectMap } from '@0x/types';
import * as _ from 'lodash';
import * as React from 'react';
@@ -13,10 +14,15 @@ export enum ScalingInputPhase {
export interface ScalingSettings {
percentageToReduceFontSizePerCharacter: number;
- constantPxToIncreaseWidthPerCharacter: number;
+ // 1ch = the width of the 0 chararacter.
+ // Allow to customize 'char' length for different characters.
+ characterWidthOverrides: ObjectMap<number>;
+ // How much room to leave to the right of the scaling input.
+ additionalInputSpaceInCh: number;
}
export interface ScalingInputProps {
+ type?: string;
textLengthThreshold: number;
maxFontSizePx: number;
value: string;
@@ -31,32 +37,29 @@ export interface ScalingInputProps {
hasAutofocus: boolean;
}
-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,
+ percentageToReduceFontSizePerCharacter: 0.1,
+ characterWidthOverrides: {
+ '1': 0.7,
+ '.': 0.4,
+ },
+ additionalInputSpaceInCh: 0.4,
};
-export class ScalingInput extends React.Component<ScalingInputProps, ScalingInputState> {
+export class ScalingInput extends React.Component<ScalingInputProps> {
public static defaultProps = {
onChange: util.boundNoop,
onFontSizeChange: util.boundNoop,
- maxLength: 7,
+ maxLength: 9,
scalingSettings: defaultScalingSettings,
isDisabled: false,
hasAutofocus: false,
};
- public state: ScalingInputState = {
- inputWidthPxAtPhaseChange: undefined,
- };
private readonly _inputRef = React.createRef<HTMLInputElement>();
public static getPhase(textLengthThreshold: number, value: string): ScalingInputPhase {
if (value.length <= textLengthThreshold) {
@@ -93,36 +96,15 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
scalingSettings.percentageToReduceFontSizePerCharacter,
);
}
- public getSnapshotBeforeUpdate(): ScalingInputSnapshot {
- return {
- inputWidthPx: this._getInputWidthInPx(),
- };
- }
public componentDidMount(): void {
// Trigger an initial notification of the calculated fontSize.
const currentPhase = ScalingInput.getPhaseFromProps(this.props);
const currentFontSize = ScalingInput.calculateFontSizeFromProps(this.props, currentPhase);
this.props.onFontSizeChange(currentFontSize);
}
- public componentDidUpdate(
- prevProps: ScalingInputProps,
- prevState: ScalingInputState,
- snapshot: ScalingInputSnapshot,
- ): void {
+ public componentDidUpdate(prevProps: ScalingInputProps): 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.
@@ -131,13 +113,14 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
}
}
public render(): React.ReactNode {
- const { hasAutofocus, isDisabled, fontColor, onChange, placeholder, value, maxLength } = this.props;
+ const { type, hasAutofocus, isDisabled, fontColor, placeholder, value, maxLength } = this.props;
const phase = ScalingInput.getPhaseFromProps(this.props);
return (
<Input
+ type={type}
ref={this._inputRef as any}
fontColor={fontColor}
- onChange={onChange}
+ onChange={this._handleChange}
value={value}
placeholder={placeholder}
fontSize={`${this._calculateFontSize(phase)}px`}
@@ -149,32 +132,34 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
);
}
private readonly _calculateWidth = (phase: ScalingInputPhase): string => {
- const { value, textLengthThreshold, scalingSettings } = this.props;
+ const { value, 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`;
+ const lengthInCh = _.reduce(
+ value.split(''),
+ (sum, char) => {
+ const widthOverride = scalingSettings.characterWidthOverrides[char];
+ if (!_.isUndefined(widthOverride)) {
+ // tslint is confused
+ // tslint:disable-next-line:restrict-plus-operands
+ return sum + widthOverride;
}
- return `${textLengthThreshold}ch`;
- }
+ return sum + 1;
+ },
+ scalingSettings.additionalInputSpaceInCh,
+ );
+ return `${lengthInCh}ch`;
};
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;
+ private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
+ const value = event.target.value;
+ const { maxLength } = this.props;
+ if (!_.isUndefined(value) && !_.isUndefined(maxLength) && value.length > maxLength) {
+ return;
}
- return ref.getBoundingClientRect().width;
+ this.props.onChange(event);
};
}
diff --git a/packages/instant/src/components/section_header.tsx b/packages/instant/src/components/section_header.tsx
new file mode 100644
index 000000000..d0974ebdc
--- /dev/null
+++ b/packages/instant/src/components/section_header.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react';
+
+import { ColorOption } from '../style/theme';
+
+import { Text } from './ui/text';
+
+export interface SectionHeaderProps {}
+export const SectionHeader: React.StatelessComponent<SectionHeaderProps> = props => {
+ return (
+ <Text
+ letterSpacing="1px"
+ fontColor={ColorOption.primaryColor}
+ fontWeight={600}
+ textTransform="uppercase"
+ fontSize="12px"
+ >
+ {props.children}
+ </Text>
+ );
+};
diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx
index 62c70f9e1..53c43ea0b 100644
--- a/packages/instant/src/components/ui/input.tsx
+++ b/packages/instant/src/components/ui/input.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import { ColorOption, styled } from '../../style/theme';
-export interface InputProps {
+export interface InputProps extends React.HTMLAttributes<HTMLInputElement> {
tabIndex?: number;
className?: string;
value?: string;
@@ -32,6 +32,10 @@ export const Input =
color: ${props => props.theme[props.fontColor || 'white']} !important;
opacity: 0.5 !important;
}
+ &::-webkit-outer-spin-button, &::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+ }
}
`;
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 7ae27de23..2de327cd7 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -38,6 +38,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
props.orderSource,
networkId,
props.provider,
+ props.walletDisplayName,
);
// merge the additional additionalAssetMetaDataMap with our default map
const completeAssetMetaDataMap = {
@@ -121,6 +122,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
window,
state.selectedAsset,
this.props.affiliateInfo,
+ state.baseCurrency,
),
);
analytics.trackInstantOpened();