From 43ad2fe23bec01b077f5c55a23736fdcb24781a3 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 19 Oct 2018 13:34:42 -0700 Subject: feat: upgrade to styled-components v4 --- packages/instant/package.json | 5 +- .../src/components/animations/slide_animations.tsx | 10 +++- packages/instant/src/style/fonts.ts | 10 ++-- packages/instant/src/style/theme.ts | 4 +- yarn.lock | 65 +++++++++++++++++++--- 5 files changed, 74 insertions(+), 20 deletions(-) diff --git a/packages/instant/package.json b/packages/instant/package.json index 1a6e9d2e9..be85b5062 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -58,12 +58,12 @@ "react-redux": "^5.0.7", "redux": "^4.0.0", "redux-devtools-extension": "^2.13.5", - "styled-components": "^3.4.9", + "styled-components": "^4.0.2", "ts-optchain": "^0.1.1" }, "devDependencies": { - "@static/discharge": "^1.2.2", "@0x/tslint-config": "^1.0.9", + "@static/discharge": "^1.2.2", "@types/enzyme": "^3.1.14", "@types/enzyme-adapter-react-16": "^1.0.3", "@types/jest": "^23.3.5", @@ -73,6 +73,7 @@ "@types/react-dom": "^16.0.8", "@types/react-redux": "^6.0.9", "@types/redux": "^3.6.0", + "@types/styled-components": "^4.0.1", "awesome-typescript-loader": "^5.2.1", "enzyme": "^3.6.0", "enzyme-adapter-react-16": "^1.5.0", diff --git a/packages/instant/src/components/animations/slide_animations.tsx b/packages/instant/src/components/animations/slide_animations.tsx index 1f10a2ed6..84280372b 100644 --- a/packages/instant/src/components/animations/slide_animations.tsx +++ b/packages/instant/src/components/animations/slide_animations.tsx @@ -1,6 +1,7 @@ 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` from { @@ -15,7 +16,7 @@ const slideKeyframeGenerator = (fromY: string, toY: string) => keyframes` `; export interface SlideAnimationProps { - keyframes: string; + keyframes: Keyframes; animationType: string; animationDirection?: string; } @@ -24,7 +25,10 @@ export const SlideAnimation = styled.div < SlideAnimationProps > ` - animation-name: ${props => props.keyframes}; + animation-name: ${props => + css` + ${props.keyframes}; + `}; animation-duration: 0.3s; animation-timing-function: ${props => props.animationType}; animation-delay: 0s; diff --git a/packages/instant/src/style/fonts.ts b/packages/instant/src/style/fonts.ts index 975a30a61..f305fd612 100644 --- a/packages/instant/src/style/fonts.ts +++ b/packages/instant/src/style/fonts.ts @@ -1,10 +1,10 @@ -import { injectGlobal } from './theme'; - export const fonts = { include: () => { // Inject the inter-ui font into the page - return injectGlobal` - @import url('https://rsms.me/inter/inter-ui.css'); - `; + const head = document.head || document.getElementsByTagName('head')[0]; + const style = document.createElement('style'); + style.type = 'text/css'; + style.appendChild(document.createTextNode(`@import url('https://rsms.me/inter/inter-ui.css')`)); + head.appendChild(style); }, }; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index d26c816c1..be527a12c 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -1,6 +1,6 @@ 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 }; @@ -28,4 +28,4 @@ export const theme: Theme = { darkOrange: '#F2994C', }; -export { styled, css, injectGlobal, keyframes, ThemeProvider }; +export { styled, css, keyframes, ThemeProvider }; diff --git a/yarn.lock b/yarn.lock index f0064bff1..aeddefa31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -484,6 +484,12 @@ dependencies: "@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": version "7.0.0" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -504,6 +510,24 @@ dependencies: 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": version "4.7.3" resolved "https://registry.yarnpkg.com/@ledgerhq/hw-app-eth/-/hw-app-eth-4.7.3.tgz#d352e19658ae296532e522c53c8ec2a1a77b64e5" @@ -1579,6 +1603,13 @@ "@types/node" "*" "@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": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" @@ -2536,6 +2567,13 @@ babel-plugin-jest-hoist@^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" +"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: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -4593,6 +4631,14 @@ css-to-react-native@^2.0.3: fbjs "^0.8.5" 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: version "0.3.8" resolved "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa" @@ -14427,19 +14473,18 @@ styled-components@^3.3.3: stylis-rule-sheet "^0.0.10" supports-color "^3.2.3" -styled-components@^3.4.9: - version "3.4.10" - resolved "https://registry.npmjs.org/styled-components/-/styled-components-3.4.10.tgz#9a654c50ea2b516c36ade57ddcfa296bf85c96e1" +styled-components@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/styled-components/-/styled-components-4.0.2.tgz#7d4409ada019cdd34c25ba68c4577ea95dbcf0c5" dependencies: - buffer "^5.0.3" - css-to-react-native "^2.0.3" - fbjs "^0.8.16" - hoist-non-react-statics "^2.5.0" + "@emotion/is-prop-valid" "^0.6.8" + babel-plugin-styled-components ">= 1" + css-to-react-native "^2.2.2" + memoize-one "^4.0.0" prop-types "^15.5.4" react-is "^16.3.1" stylis "^3.5.0" stylis-rule-sheet "^0.0.10" - supports-color "^3.2.3" stylis-rule-sheet@^0.0.10: version "0.0.10" @@ -14882,6 +14927,10 @@ to-fast-properties@^1.0.3: version "1.0.3" 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: version "1.0.2" resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" -- cgit v1.2.3 From d5105b5c9f74a4f52e4952b845a37692bb824fd4 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 19 Oct 2018 13:45:12 -0700 Subject: feat: user better syntax for defining ui components --- packages/instant/src/components/ui/container.tsx | 6 +----- packages/instant/src/components/ui/flex.tsx | 2 +- packages/instant/src/components/ui/input.tsx | 6 +----- packages/instant/src/components/ui/text.tsx | 8 +------- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 02b16e39f..b7e17d807 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -29,11 +29,7 @@ export interface ContainerProps { zIndex?: number; } -const PlainContainer: React.StatelessComponent = ({ children, className }) => ( -
{children}
-); - -export const Container = styled(PlainContainer)` +export const Container = styled('div')` box-sizing: border-box; ${props => cssRuleIfExists(props, 'display')} ${props => cssRuleIfExists(props, 'position')} diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx index 327e91926..f2013f60f 100644 --- a/packages/instant/src/components/ui/flex.tsx +++ b/packages/instant/src/components/ui/flex.tsx @@ -17,7 +17,7 @@ const PlainFlex: React.StatelessComponent = ({ children, className })
{children}
); -export const Flex = styled(PlainFlex)` +export const Flex = styled('div')` display: flex; flex-direction: ${props => props.direction}; flex-wrap: ${props => props.flexWrap}; diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index f8c6b6ef6..9db7d1c4c 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -12,11 +12,7 @@ export interface InputProps { onChange?: (event: React.ChangeEvent) => void; } -const PlainInput: React.StatelessComponent = ({ value, className, placeholder, onChange }) => ( - -); - -export const Input = styled(PlainInput)` +export const Input = styled('input')` font-size: ${props => props.fontSize}; width: ${props => props.width}; padding: 0.1em 0em; diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index 9fb8ea26f..d23b0034d 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -23,14 +23,8 @@ export interface TextProps { display?: string; } -const PlainText: React.StatelessComponent = ({ children, className, onClick }) => ( -
- {children} -
-); - const darkenOnHoverAmount = 0.3; -export const Text = styled(PlainText)` +export const Text = styled('div')` font-family: ${props => props.fontFamily}; font-style: ${props => props.fontStyle}; font-weight: ${props => props.fontWeight}; -- cgit v1.2.3 From f06541ec94c2f3b8d1924da376178a5fc3f442e6 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 19 Oct 2018 13:46:31 -0700 Subject: fix: animation component typing --- packages/instant/src/components/animations/slide_animations.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/instant/src/components/animations/slide_animations.tsx b/packages/instant/src/components/animations/slide_animations.tsx index 84280372b..7c8666861 100644 --- a/packages/instant/src/components/animations/slide_animations.tsx +++ b/packages/instant/src/components/animations/slide_animations.tsx @@ -21,10 +21,7 @@ export interface SlideAnimationProps { animationDirection?: string; } -export const SlideAnimation = - styled.div < - SlideAnimationProps > - ` +export const SlideAnimation = styled('div')` animation-name: ${props => css` ${props.keyframes}; -- cgit v1.2.3 From 6510454337dd5add86522c0eb5621a3f55ac062d Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 19 Oct 2018 14:58:12 -0700 Subject: feat: add scaling input component --- packages/instant/src/components/amount_input.tsx | 10 +-- packages/instant/src/components/scaling_input.tsx | 82 +++++++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 packages/instant/src/components/scaling_input.tsx diff --git a/packages/instant/src/components/amount_input.tsx b/packages/instant/src/components/amount_input.tsx index c89fb05ad..f6f562be8 100644 --- a/packages/instant/src/components/amount_input.tsx +++ b/packages/instant/src/components/amount_input.tsx @@ -5,7 +5,8 @@ import * as React from 'react'; import { ColorOption } from '../style/theme'; import { util } from '../util/util'; -import { Container, Input } from './ui'; +import { ScalingInput } from './scaling_input'; +import { Container, Text } from './ui'; export interface AmountInputProps { fontColor?: ColorOption; @@ -22,13 +23,14 @@ export class AmountInput extends React.Component { const { fontColor, fontSize, value } = this.props; return ( - ); diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx new file mode 100644 index 000000000..ea0a925d2 --- /dev/null +++ b/packages/instant/src/components/scaling_input.tsx @@ -0,0 +1,82 @@ +import { BigNumber } from '@0x/utils'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +import { ColorOption } from '../style/theme'; +import { util } from '../util/util'; + +import { Container, Input } from './ui'; + +export enum ScalingInputPhase { + Start, + Scaling, + End, +} + +export interface ScalingInputProps { + startWidthCh: number; + endWidthCh: number; + startFontSizePx: number; + value?: string; + onChange?: (event: React.ChangeEvent) => void; + fontColor?: ColorOption; + placeholder?: string; +} +// Magic value obtained via trial-and-error +const scalingRateToMaintainSameWidth = 0.1; +export class ScalingInput extends React.Component { + public static defaultProps = { + onChange: util.boundNoop, + }; + public render(): React.ReactNode { + const { fontColor, onChange, placeholder, value } = this.props; + const phase = this._getPhase(); + return ( + + ); + } + private readonly _calculateFontSize = (phase: ScalingInputPhase): string => { + const { value, endWidthCh, startFontSizePx } = this.props; + if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { + return `${startFontSizePx}px`; + } + const charactersOverMax = value.length - endWidthCh; + const pixelsToReduceFontSizeBy = charactersOverMax * 2; + const newFontSizePx = startFontSizePx - pixelsToReduceFontSizeBy; + return `${newFontSizePx}px`; + }; + private readonly _calculateWidth = (phase: ScalingInputPhase): string => { + const { value, startWidthCh, endWidthCh } = this.props; + if (_.isUndefined(value)) { + return `${startWidthCh}ch`; + } + switch (phase) { + case ScalingInputPhase.Start: + return `${startWidthCh}ch`; + case ScalingInputPhase.Scaling: + return `${value.length}ch`; + case ScalingInputPhase.End: + return `${endWidthCh}ch`; + default: + return `${startWidthCh}ch`; + } + }; + private readonly _getPhase = (): ScalingInputPhase => { + const { value, startWidthCh, endWidthCh } = this.props; + if (_.isUndefined(value) || value.length <= this.props.startWidthCh) { + return ScalingInputPhase.Start; + } + if (value.length > startWidthCh && value.length <= endWidthCh) { + return ScalingInputPhase.Scaling; + } + return ScalingInputPhase.End; + }; +} -- cgit v1.2.3 From 77a4d7e2b76a1808c37ed9f0a97cbd3b34a0ebe9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 10:50:25 -0700 Subject: feat: have basic scaling amount input working --- packages/instant/src/components/amount_input.tsx | 51 ----------- .../instant/src/components/asset_amount_input.tsx | 41 +++++++-- .../instant/src/components/instant_heading.tsx | 2 +- .../src/components/scaling_amount_input.tsx | 52 +++++++++++ packages/instant/src/components/scaling_input.tsx | 101 +++++++++++++++------ .../src/containers/selected_asset_amount_input.ts | 2 +- 6 files changed, 164 insertions(+), 85 deletions(-) delete mode 100644 packages/instant/src/components/amount_input.tsx create mode 100644 packages/instant/src/components/scaling_amount_input.tsx diff --git a/packages/instant/src/components/amount_input.tsx b/packages/instant/src/components/amount_input.tsx deleted file mode 100644 index f6f562be8..000000000 --- a/packages/instant/src/components/amount_input.tsx +++ /dev/null @@ -1,51 +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 { ScalingInput } from './scaling_input'; -import { Container, Text } from './ui'; - -export interface AmountInputProps { - fontColor?: ColorOption; - fontSize?: string; - value?: BigNumber; - onChange: (value?: BigNumber) => void; -} - -export class AmountInput extends React.Component { - public static defaultProps = { - onChange: util.boundNoop, - }; - public render(): React.ReactNode { - const { fontColor, fontSize, value } = this.props; - return ( - - - - ); - } - private readonly _handleChange = (event: React.ChangeEvent): 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); - }; -} diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index c03ef1cf3..0b22c889c 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -7,33 +7,62 @@ import { ERC20Asset } from '../types'; import { assetUtils } from '../util/asset'; import { util } from '../util/util'; -import { AmountInput, AmountInputProps } from './amount_input'; +import { ScalingAmountInput } from './scaling_amount_input'; import { Container, Text } from './ui'; // Asset amounts only apply to ERC20 assets -export interface AssetAmountInputProps extends AmountInputProps { +export interface AssetAmountInputProps { asset?: ERC20Asset; onChange: (value?: BigNumber, asset?: ERC20Asset) => void; + startingFontSizePx: number; + fontColor?: ColorOption; } -export class AssetAmountInput extends React.Component { +export interface AssetAmountInputState { + currentFontSizePx: number; +} + +export class AssetAmountInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, }; + constructor(props: AssetAmountInputProps) { + super(props); + this.state = { + currentFontSizePx: props.startingFontSizePx, + }; + } public render(): React.ReactNode { const { asset, onChange, ...rest } = this.props; return ( - + + + - + {assetUtils.bestNameForAsset(asset)} ); } - private readonly _handleChange = (value?: BigNumber): void => { + private readonly _handleChange = (value?: BigNumber, fontSize?: number): void => { this.props.onChange(value, this.props.asset); + if (!_.isUndefined(fontSize)) { + this.setState({ + currentFontSizePx: fontSize, + }); + } }; } diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index a36d35a93..defe3b8b1 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -69,7 +69,7 @@ export const InstantHeading: React.StatelessComponent = pro - + diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx new file mode 100644 index 000000000..a0b7b74af --- /dev/null +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -0,0 +1,52 @@ +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 { ScalingInput } from './scaling_input'; +import { Container, Text } from './ui'; + +export interface ScalingAmountInputProps { + fontSizePx: number; + startWidthCh: number; + endWidthCh: number; + fontColor?: ColorOption; + value?: BigNumber; + onChange: (value?: BigNumber, fontSize?: number) => void; +} + +export class ScalingAmountInput extends React.Component { + public static defaultProps = { + onChange: util.boundNoop, + onFontSizeChange: util.boundNoop, + }; + public render(): React.ReactNode { + const { startWidthCh, endWidthCh, fontColor, fontSizePx, value } = this.props; + return ( + + ); + } + private readonly _handleChange = (event: React.ChangeEvent, fontSize?: number): 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, fontSize); + }; +} diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index ea0a925d2..a2c4ba342 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -17,47 +17,79 @@ export enum ScalingInputPhase { export interface ScalingInputProps { startWidthCh: number; endWidthCh: number; - startFontSizePx: number; + fontSizePx: number; value?: string; - onChange?: (event: React.ChangeEvent) => void; + onChange: (event: React.ChangeEvent, fontSize: number) => void; fontColor?: ColorOption; placeholder?: string; } -// Magic value obtained via trial-and-error -const scalingRateToMaintainSameWidth = 0.1; + +export interface ScalingInputProps { + fixedWidthInPxIfExists?: number; +} + export class ScalingInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, + onFontSizeChange: util.boundNoop, }; + public state = { + fixedWidthInPxIfExists: undefined, + }; + private _inputRef = React.createRef(); + public static getPhase(startWidthCh: number, endWidthCh: number, value?: string): ScalingInputPhase { + if (_.isUndefined(value) || value.length <= startWidthCh) { + return ScalingInputPhase.Start; + } + if (value.length > startWidthCh && value.length <= endWidthCh) { + return ScalingInputPhase.Scaling; + } + return ScalingInputPhase.End; + } + public static getPhaseFromProps(props: ScalingInputProps): ScalingInputPhase { + const { value, startWidthCh, endWidthCh } = props; + return ScalingInput.getPhase(startWidthCh, endWidthCh, value); + } + public componentDidUpdate(prevProps: ScalingInputProps): void { + const prevPhase = ScalingInput.getPhaseFromProps(prevProps); + const curPhase = ScalingInput.getPhaseFromProps(this.props); + // if we went from anything else to end, fix to the current width as it shouldn't change as we grow + if (prevPhase !== ScalingInputPhase.End && curPhase === ScalingInputPhase.End) { + this.setState({ + fixedWidthInPxIfExists: this._getInputWidthInPx(), + }); + } + // if we end from end to to anything else, un-fix the width + if (prevPhase === ScalingInputPhase.End && curPhase !== ScalingInputPhase.End) { + this.setState({ + fixedWidthInPxIfExists: undefined, + }); + } + } public render(): React.ReactNode { const { fontColor, onChange, placeholder, value } = this.props; - const phase = this._getPhase(); + const phase = ScalingInput.getPhaseFromProps(this.props); return ( ); } - private readonly _calculateFontSize = (phase: ScalingInputPhase): string => { - const { value, endWidthCh, startFontSizePx } = this.props; - if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { - return `${startFontSizePx}px`; - } - const charactersOverMax = value.length - endWidthCh; - const pixelsToReduceFontSizeBy = charactersOverMax * 2; - const newFontSizePx = startFontSizePx - pixelsToReduceFontSizeBy; - return `${newFontSizePx}px`; - }; - private readonly _calculateWidth = (phase: ScalingInputPhase): string => { + private readonly _calculateWidth = (): string => { + const phase = ScalingInput.getPhaseFromProps(this.props); const { value, startWidthCh, endWidthCh } = this.props; if (_.isUndefined(value)) { return `${startWidthCh}ch`; } + if (!_.isUndefined(this.state.fixedWidthInPxIfExists)) { + return `${this.state.fixedWidthInPxIfExists}px`; + } switch (phase) { case ScalingInputPhase.Start: return `${startWidthCh}ch`; @@ -69,14 +101,31 @@ export class ScalingInput extends React.Component { return `${startWidthCh}ch`; } }; - private readonly _getPhase = (): ScalingInputPhase => { - const { value, startWidthCh, endWidthCh } = this.props; - if (_.isUndefined(value) || value.length <= this.props.startWidthCh) { - return ScalingInputPhase.Start; + private readonly _getInputWidthInPx = (): number => { + const ref = this._inputRef.current; + if (!ref) { + return 0; } - if (value.length > startWidthCh && value.length <= endWidthCh) { - return ScalingInputPhase.Scaling; + return (ref as any).getBoundingClientRect().width; + }; + private readonly _calculateNextFontSize = ( + currentFontSizePx: number, + value: string, + startWidthCh: number, + endWidthCh: number, + ): number => { + const phase = ScalingInput.getPhase(startWidthCh, endWidthCh, value); + if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { + return currentFontSizePx; } - return ScalingInputPhase.End; + const charactersOverMax = value.length - endWidthCh; + const pixelsToReduceFontSizeBy = charactersOverMax * 5; + const fontSize = currentFontSizePx - pixelsToReduceFontSizeBy; + return fontSize; + }; + private readonly _handleChange = (event: React.ChangeEvent) => { + const value = event.target.value; + const { fontSizePx, startWidthCh, endWidthCh } = this.props; + this.props.onChange(event, this._calculateNextFontSize(fontSizePx, value, startWidthCh, endWidthCh)); }; } diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts index 6cd39b855..1b5f3cd22 100644 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ b/packages/instant/src/containers/selected_asset_amount_input.ts @@ -17,7 +17,7 @@ import { AssetAmountInput } from '../components/asset_amount_input'; export interface SelectedAssetAmountInputProps { fontColor?: ColorOption; - fontSize?: string; + startingFontSizePx: number; } interface ConnectedState { -- cgit v1.2.3 From 921492e8186697e477c27d76bd7eb58ce2454765 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 16:45:48 -0700 Subject: feature: reduce font size by a percentage instead of a constant --- .../instant/src/components/asset_amount_input.tsx | 15 ++--- .../src/components/scaling_amount_input.tsx | 8 ++- packages/instant/src/components/scaling_input.tsx | 73 +++++++++++++--------- 3 files changed, 57 insertions(+), 39 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index 0b22c889c..beb21a4cf 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -41,8 +41,9 @@ export class AssetAmountInput extends React.Component @@ -57,12 +58,12 @@ export class AssetAmountInput extends React.Component ); } - private readonly _handleChange = (value?: BigNumber, fontSize?: number): void => { + private readonly _handleChange = (value?: BigNumber): void => { this.props.onChange(value, this.props.asset); - if (!_.isUndefined(fontSize)) { - this.setState({ - currentFontSizePx: fontSize, - }); - } + }; + private readonly _handleFontSizeChange = (fontSizePx: number): void => { + this.setState({ + currentFontSizePx: fontSizePx, + }); }; } diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index a0b7b74af..83375af00 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -9,12 +9,13 @@ import { ScalingInput } from './scaling_input'; import { Container, Text } from './ui'; export interface ScalingAmountInputProps { - fontSizePx: number; + maxFontSizePx: number; startWidthCh: number; endWidthCh: number; fontColor?: ColorOption; value?: BigNumber; onChange: (value?: BigNumber, fontSize?: number) => void; + onFontSizeChange: (fontSizePx: number) => void; } export class ScalingAmountInput extends React.Component { @@ -23,12 +24,13 @@ export class ScalingAmountInput extends React.Component onFontSizeChange: util.boundNoop, }; public render(): React.ReactNode { - const { startWidthCh, endWidthCh, fontColor, fontSizePx, value } = this.props; + const { startWidthCh, endWidthCh, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; return ( , fontSize: number) => void; + onChange: (event: React.ChangeEvent) => void; + onFontSizeChange: (fontSizePx: number) => void; fontColor?: ColorOption; placeholder?: string; + maxLength?: number; } -export interface ScalingInputProps { +export interface ScalingInputState { fixedWidthInPxIfExists?: number; } -export class ScalingInput extends React.Component { +export interface ScalingInputSnapshot { + inputWidthPx: number; +} +// This is a magic number that was determined experimentally. +const percentageToReduceByPerCharacter = 0.15; +export class ScalingInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, + maxLength: 10, }; public state = { fixedWidthInPxIfExists: undefined, @@ -50,13 +58,35 @@ export class ScalingInput extends React.Component { const { value, startWidthCh, endWidthCh } = props; return ScalingInput.getPhase(startWidthCh, endWidthCh, value); } - public componentDidUpdate(prevProps: ScalingInputProps): void { + public static calculateFontSize(props: ScalingInputProps): number { + const { startWidthCh, endWidthCh, value, maxFontSizePx } = props; + const phase = ScalingInput.getPhase(startWidthCh, endWidthCh, value); + if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { + return maxFontSizePx; + } + const charactersOverMax = value.length - endWidthCh; + const scalingFactor = (1 - percentageToReduceByPerCharacter) ** charactersOverMax; + const fontSize = scalingFactor * maxFontSizePx; + return fontSize; + } + 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); + const prevFontSize = ScalingInput.calculateFontSize(prevProps); + const curFontSize = ScalingInput.calculateFontSize(this.props); // if we went from anything else to end, fix to the current width as it shouldn't change as we grow if (prevPhase !== ScalingInputPhase.End && curPhase === ScalingInputPhase.End) { this.setState({ - fixedWidthInPxIfExists: this._getInputWidthInPx(), + fixedWidthInPxIfExists: snapshot.inputWidthPx, }); } // if we end from end to to anything else, un-fix the width @@ -65,19 +95,24 @@ export class ScalingInput extends React.Component { fixedWidthInPxIfExists: undefined, }); } + // If font size has changed, notify. + if (prevFontSize !== curFontSize) { + this.props.onFontSizeChange(curFontSize); + } } public render(): React.ReactNode { - const { fontColor, onChange, placeholder, value } = this.props; + const { fontColor, onChange, placeholder, value, maxLength } = this.props; const phase = ScalingInput.getPhaseFromProps(this.props); return ( ); } @@ -108,24 +143,4 @@ export class ScalingInput extends React.Component { } return (ref as any).getBoundingClientRect().width; }; - private readonly _calculateNextFontSize = ( - currentFontSizePx: number, - value: string, - startWidthCh: number, - endWidthCh: number, - ): number => { - const phase = ScalingInput.getPhase(startWidthCh, endWidthCh, value); - if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { - return currentFontSizePx; - } - const charactersOverMax = value.length - endWidthCh; - const pixelsToReduceFontSizeBy = charactersOverMax * 5; - const fontSize = currentFontSizePx - pixelsToReduceFontSizeBy; - return fontSize; - }; - private readonly _handleChange = (event: React.ChangeEvent) => { - const value = event.target.value; - const { fontSizePx, startWidthCh, endWidthCh } = this.props; - this.props.onChange(event, this._calculateNextFontSize(fontSizePx, value, startWidthCh, endWidthCh)); - }; } -- cgit v1.2.3 From bdf623dab54132f257057a6949d0a1e245d0b468 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 16:54:08 -0700 Subject: chore: refactor ScalingInput --- packages/instant/src/components/scaling_input.tsx | 27 +++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 7824c10f9..c1111cea9 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -58,9 +58,12 @@ export class ScalingInput extends React.Component ); } - private readonly _calculateWidth = (): string => { - const phase = ScalingInput.getPhaseFromProps(this.props); + private readonly _calculateWidth = (phase: ScalingInputPhase): string => { const { value, startWidthCh, endWidthCh } = this.props; if (_.isUndefined(value)) { return `${startWidthCh}ch`; @@ -136,6 +142,9 @@ export class ScalingInput extends React.Component { + return ScalingInput.calculateFontSizeFromProps(this.props, phase); + }; private readonly _getInputWidthInPx = (): number => { const ref = this._inputRef.current; if (!ref) { -- cgit v1.2.3 From 28f0deb3ebe2f78f98e79d59b8b2a3eacb1c6fef Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 17:42:28 -0700 Subject: chore: final adjustments --- packages/instant/src/components/asset_amount_input.tsx | 2 +- packages/instant/src/components/scaling_input.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index beb21a4cf..bfa857f0e 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -40,7 +40,7 @@ export class AssetAmountInput extends React.Component { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, - maxLength: 10, + maxLength: 9, }; public state = { fixedWidthInPxIfExists: undefined, -- cgit v1.2.3 From b7a5e40c62adfbd8732b3cd98d2c989a6a021c54 Mon Sep 17 00:00:00 2001 From: fragosti Date: Mon, 22 Oct 2018 17:56:50 -0700 Subject: chore: run linter --- packages/instant/src/components/scaling_amount_input.tsx | 1 - packages/instant/src/components/scaling_input.tsx | 6 ++---- packages/instant/src/components/ui/container.tsx | 1 - packages/instant/src/components/ui/flex.tsx | 5 ----- 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 83375af00..9539bfd94 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -6,7 +6,6 @@ import { ColorOption } from '../style/theme'; import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; -import { Container, Text } from './ui'; export interface ScalingAmountInputProps { maxFontSizePx: number; diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 57ebf93ac..10243787a 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -1,12 +1,10 @@ -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import * as ReactDOM from 'react-dom'; import { ColorOption } from '../style/theme'; import { util } from '../util/util'; -import { Container, Input } from './ui'; +import { Input } from './ui'; export enum ScalingInputPhase { Start, @@ -44,7 +42,7 @@ export class ScalingInput extends React.Component = ({ children, className }) => ( -
{children}
-); - export const Flex = styled('div')` display: flex; flex-direction: ${props => props.direction}; -- cgit v1.2.3 From f0c79473bdaeb87f49a9eb59fc88336f02e81546 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 15:01:22 -0700 Subject: fix: dont allow heading to change height when input size changes --- packages/instant/src/components/instant_heading.tsx | 4 +++- packages/instant/src/components/ui/container.tsx | 3 ++- packages/instant/src/components/ui/flex.tsx | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index defe3b8b1..7664d31ae 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -69,7 +69,9 @@ export const InstantHeading: React.StatelessComponent = pro
- + + + diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 8b204826d..293042120 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -1,4 +1,3 @@ - import { ColorOption, styled } from '../../style/theme'; import { cssRuleIfExists } from '../../style/util'; @@ -10,6 +9,7 @@ export interface ContainerProps { bottom?: string; left?: string; width?: string; + height?: string; maxWidth?: string; margin?: string; marginTop?: string; @@ -37,6 +37,7 @@ export const Container = styled('div')` ${props => cssRuleIfExists(props, 'bottom')} ${props => cssRuleIfExists(props, 'left')} ${props => cssRuleIfExists(props, 'width')} + ${props => cssRuleIfExists(props, 'height')} ${props => cssRuleIfExists(props, 'max-width')} ${props => cssRuleIfExists(props, 'margin')} ${props => cssRuleIfExists(props, 'margin-top')} diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx index 2b430129d..d4e14d979 100644 --- a/packages/instant/src/components/ui/flex.tsx +++ b/packages/instant/src/components/ui/flex.tsx @@ -1,4 +1,3 @@ - import { ColorOption, styled } from '../../style/theme'; import { cssRuleIfExists } from '../../style/util'; @@ -8,6 +7,7 @@ export interface FlexProps { justify?: '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; + height?: string; backgroundColor?: ColorOption; className?: string; } @@ -19,6 +19,7 @@ export const Flex = styled('div')` justify-content: ${props => props.justify}; align-items: ${props => props.align}; ${props => cssRuleIfExists(props, 'width')} + ${props => cssRuleIfExists(props, 'height')} background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; `; -- cgit v1.2.3 From 053e147afc1b8471c480a8612cb6bae4c363b21b Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 15:19:01 -0700 Subject: fix: remove the concept of initial with from scaling input and remove phase --- .../src/components/scaling_amount_input.tsx | 2 +- packages/instant/src/components/scaling_input.tsx | 46 ++++++++++------------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 9539bfd94..2baff5621 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -26,7 +26,6 @@ export class ScalingAmountInput extends React.Component const { startWidthCh, endWidthCh, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; return ( onChange={this._handleChange} value={!_.isUndefined(value) ? value.toString() : ''} placeholder="0.00" + emptyInputWidthCh={3.5} /> ); } diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 10243787a..5db878c52 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -7,16 +7,15 @@ import { util } from '../util/util'; import { Input } from './ui'; export enum ScalingInputPhase { - Start, - Scaling, - End, + FixedFontSize, + ScalingFontSize, } export interface ScalingInputProps { - startWidthCh: number; endWidthCh: number; maxFontSizePx: number; - value?: string; + value: string; + emptyInputWidthCh: number; onChange: (event: React.ChangeEvent) => void; onFontSizeChange: (fontSizePx: number) => void; fontColor?: ColorOption; @@ -43,26 +42,23 @@ export class ScalingInput extends React.Component startWidthCh && value.length <= endWidthCh) { - return ScalingInputPhase.Scaling; - } - return ScalingInputPhase.End; + return ScalingInputPhase.ScalingFontSize; } public static getPhaseFromProps(props: ScalingInputProps): ScalingInputPhase { - const { value, startWidthCh, endWidthCh } = props; - return ScalingInput.getPhase(startWidthCh, endWidthCh, value); + const { value, endWidthCh } = props; + return ScalingInput.getPhase(endWidthCh, value); } public static calculateFontSize( endWidthCh: number, maxFontSizePx: number, phase: ScalingInputPhase, - value?: string, + value: string, ): number { - if (_.isUndefined(value) || phase !== ScalingInputPhase.End) { + if (phase !== ScalingInputPhase.ScalingFontSize) { return maxFontSizePx; } const charactersOverMax = value.length - endWidthCh; @@ -89,13 +85,13 @@ export class ScalingInput extends React.Component { - const { value, startWidthCh, endWidthCh } = this.props; - if (_.isUndefined(value)) { - return `${startWidthCh}ch`; + const { value, endWidthCh } = this.props; + if (_.isEmpty(value)) { + return `${this.props.emptyInputWidthCh}ch`; } if (!_.isUndefined(this.state.fixedWidthInPxIfExists)) { return `${this.state.fixedWidthInPxIfExists}px`; } switch (phase) { - case ScalingInputPhase.Start: - return `${startWidthCh}ch`; - case ScalingInputPhase.Scaling: + case ScalingInputPhase.FixedFontSize: return `${value.length}ch`; - case ScalingInputPhase.End: + case ScalingInputPhase.ScalingFontSize: return `${endWidthCh}ch`; default: - return `${startWidthCh}ch`; + return '1ch'; } }; private readonly _calculateFontSize = (phase: ScalingInputPhase): number => { -- cgit v1.2.3 From a5edb0b421afaaa34290dc3ada73da6bca3c556a Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 15:54:18 -0700 Subject: polish: improve scaling significantly --- .../instant/src/components/asset_amount_input.tsx | 3 +- .../src/components/scaling_amount_input.tsx | 7 +-- packages/instant/src/components/scaling_input.tsx | 68 +++++++++++++++------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index bfa857f0e..8cbf2b37a 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -39,8 +39,7 @@ export class AssetAmountInput extends React.Component void; @@ -23,11 +22,11 @@ export class ScalingAmountInput extends React.Component onFontSizeChange: util.boundNoop, }; public render(): React.ReactNode { - const { startWidthCh, endWidthCh, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; + const { textLengthThreshold, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; return ( { public static defaultProps = { onChange: util.boundNoop, onFontSizeChange: util.boundNoop, - maxLength: 9, + maxLength: 8, + scalingSettings: defaultScalingSettings, }; public state = { - fixedWidthInPxIfExists: undefined, + inputWidthPxAtPhaseChange: undefined, }; private readonly _inputRef = React.createRef(); - public static getPhase(endWidthCh: number, value: string): ScalingInputPhase { - if (value.length <= endWidthCh) { + 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, endWidthCh } = props; - return ScalingInput.getPhase(endWidthCh, value); + const { value, textLengthThreshold } = props; + return ScalingInput.getPhase(textLengthThreshold, value); } public static calculateFontSize( - endWidthCh: number, + textLengthThreshold: number, maxFontSizePx: number, phase: ScalingInputPhase, value: string, + percentageToReduceFontSizePerCharacter: number, ): number { if (phase !== ScalingInputPhase.ScalingFontSize) { return maxFontSizePx; } - const charactersOverMax = value.length - endWidthCh; - const scalingFactor = (1 - percentageToReduceByPerCharacter) ** charactersOverMax; + 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 { endWidthCh, value, maxFontSizePx } = props; - return ScalingInput.calculateFontSize(endWidthCh, maxFontSizePx, phase, value); + const { textLengthThreshold, value, maxFontSizePx, scalingSettings } = props; + return ScalingInput.calculateFontSize( + textLengthThreshold, + maxFontSizePx, + phase, + value, + scalingSettings.percentageToReduceFontSizePerCharacter, + ); } public getSnapshotBeforeUpdate(): ScalingInputSnapshot { return { @@ -87,13 +106,13 @@ export class ScalingInput extends React.Component { - const { value, endWidthCh } = this.props; + const { value, textLengthThreshold, scalingSettings } = this.props; if (_.isEmpty(value)) { return `${this.props.emptyInputWidthCh}ch`; } - if (!_.isUndefined(this.state.fixedWidthInPxIfExists)) { - return `${this.state.fixedWidthInPxIfExists}px`; - } switch (phase) { case ScalingInputPhase.FixedFontSize: return `${value.length}ch`; case ScalingInputPhase.ScalingFontSize: - return `${endWidthCh}ch`; + const { inputWidthPxAtPhaseChange } = this.state; + if (!_.isUndefined(inputWidthPxAtPhaseChange)) { + const charactersOverMax = value.length - textLengthThreshold; + const scalingFactor = + (scalingSettings.percentageToIncreaseWidthPerCharacter + 1) ** charactersOverMax; + const width = scalingFactor * inputWidthPxAtPhaseChange; + return `${width}px`; + } + return `${textLengthThreshold}ch`; default: return '1ch'; } -- cgit v1.2.3 From 751b87af962d5b1f9f65514c10de2f7cb0b13c34 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 16:28:08 -0700 Subject: fix: remove unused callback info --- packages/instant/src/components/scaling_amount_input.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index db3062b57..233e29cff 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -12,7 +12,7 @@ export interface ScalingAmountInputProps { textLengthThreshold: number; fontColor?: ColorOption; value?: BigNumber; - onChange: (value?: BigNumber, fontSize?: number) => void; + onChange: (value?: BigNumber) => void; onFontSizeChange: (fontSizePx: number) => void; } @@ -36,7 +36,7 @@ export class ScalingAmountInput extends React.Component /> ); } - private readonly _handleChange = (event: React.ChangeEvent, fontSize?: number): void => { + private readonly _handleChange = (event: React.ChangeEvent): void => { const value = event.target.value; let bigNumberValue; if (!_.isEmpty(value)) { @@ -47,6 +47,6 @@ export class ScalingAmountInput extends React.Component return; } } - this.props.onChange(bigNumberValue, fontSize); + this.props.onChange(bigNumberValue); }; } -- cgit v1.2.3 From 7ccfa8a8afe103e1cc2920724b6f17644fe5629d Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 16:59:31 -0700 Subject: feat: support half-written decimal numbers in BigNumberInput --- .../src/components/scaling_amount_input.tsx | 3 ++- packages/instant/src/util/big_number.ts | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/instant/src/util/big_number.ts diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 233e29cff..23a15305a 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -3,6 +3,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption } from '../style/theme'; +import { BigNumberInput } from '../util/big_number'; import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; @@ -41,7 +42,7 @@ export class ScalingAmountInput extends React.Component let bigNumberValue; if (!_.isEmpty(value)) { try { - bigNumberValue = new BigNumber(event.target.value); + bigNumberValue = new BigNumberInput(event.target.value); } catch { // We don't want to allow values that can't be a BigNumber, so don't even call onChange. return; diff --git a/packages/instant/src/util/big_number.ts b/packages/instant/src/util/big_number.ts new file mode 100644 index 000000000..773eb0cb4 --- /dev/null +++ b/packages/instant/src/util/big_number.ts @@ -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 _hasDecimalPeriod: boolean; + constructor(bigNumberString: string) { + const hasDecimalPeriod = _.endsWith(bigNumberString, '.'); + let internalString = bigNumberString; + if (hasDecimalPeriod) { + internalString = bigNumberString.slice(0, bigNumberString.length - 1); + } + super(internalString); + this._hasDecimalPeriod = hasDecimalPeriod; + } + public toString(): string { + const internalString = super.toString(); + if (this._hasDecimalPeriod) { + return `${internalString}.`; + } + return internalString; + } +} -- cgit v1.2.3 From 8e501e5ec715da17e3319870dbde3cca87940416 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 17:08:34 -0700 Subject: feat: add formatted symbol for asset uitl --- packages/instant/src/util/asset.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index 4e3b2b946..ebeba948e 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -2,7 +2,7 @@ import { AssetProxyId, ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import { assetDataNetworkMapping } from '../data/asset_data_network_mapping'; -import { Asset, AssetMetaData, Network, ZeroExInstantError } from '../types'; +import { Asset, AssetMetaData, Network, ZeroExInstantError, ERC20Asset } from '../types'; export const assetUtils = { createAssetFromAssetData: ( @@ -43,6 +43,16 @@ export const assetUtils = { 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 => { const assetDataGroupIfExists = _.find(assetDataNetworkMapping, value => value[network] === assetData); if (_.isUndefined(assetDataGroupIfExists)) { -- cgit v1.2.3 From 2e184f081e546acbc8ed3e5e05de5a9e5b56a3d8 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 17:17:10 -0700 Subject: feat: add title attribute to label --- packages/instant/src/components/asset_amount_input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index 8cbf2b37a..368ef10c2 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -45,13 +45,13 @@ export class AssetAmountInput extends React.Component - + - {assetUtils.bestNameForAsset(asset)} + {assetUtils.formattedSymbolForAsset(asset)} -- cgit v1.2.3 From 47737d4d0fce56454c9ee2b43782b824b88cb942 Mon Sep 17 00:00:00 2001 From: fragosti Date: Tue, 23 Oct 2018 20:02:50 -0700 Subject: feat: cover more token symbol edge cases --- .../instant/src/components/asset_amount_input.tsx | 21 +++++++++++++++++---- packages/instant/src/components/instant_heading.tsx | 4 ++-- packages/instant/src/components/scaling_input.tsx | 2 +- packages/instant/src/components/ui/container.tsx | 2 ++ packages/instant/src/util/format.ts | 2 +- packages/instant/test/util/format.test.ts | 8 ++++---- 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index 368ef10c2..960b8bc95 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -8,7 +8,7 @@ import { assetUtils } from '../util/asset'; import { util } from '../util/util'; import { ScalingAmountInput } from './scaling_amount_input'; -import { Container, Text } from './ui'; +import { Container, Flex, Text } from './ui'; // Asset amounts only apply to ERC20 assets export interface AssetAmountInputProps { @@ -35,17 +35,17 @@ export class AssetAmountInput extends React.Component + - + { + if (_.isUndefined(asset)) { + return 3; + } + const symbol = asset.metaData.symbol; + if (symbol.length <= 3) { + return 5; + } + if (symbol.length === 5) { + return 3; + } + return 4; + }; } diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index 7664d31ae..c9f0ea95a 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -70,10 +70,10 @@ export const InstantHeading: React.StatelessComponent = pro - + - + {loadingOrAmount(props.quoteState, displaytotalEthBaseAmount(props))} diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 7f8e505de..fadb3466b 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -47,7 +47,7 @@ export class ScalingInput extends React.Component('div')` @@ -50,6 +51,7 @@ export const Container = styled('div')` ${props => cssRuleIfExists(props, 'border-top')} ${props => cssRuleIfExists(props, 'border-bottom')} ${props => cssRuleIfExists(props, 'z-index')} + ${props => cssRuleIfExists(props, 'white-space')} ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')}; background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')}; border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')}; diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts index 8482b1526..ca7c01359 100644 --- a/packages/instant/src/util/format.ts +++ b/packages/instant/src/util/format.ts @@ -24,7 +24,7 @@ export const format = { if (_.isUndefined(ethUnitAmount)) { return defaultText; } - const roundedAmount = ethUnitAmount.round(decimalPlaces); + const roundedAmount = ethUnitAmount.round(decimalPlaces).toDigits(decimalPlaces); return `${roundedAmount} ETH`; }, ethBaseAmountInUsd: ( diff --git a/packages/instant/test/util/format.test.ts b/packages/instant/test/util/format.test.ts index 141df9275..2c9294c78 100644 --- a/packages/instant/test/util/format.test.ts +++ b/packages/instant/test/util/format.test.ts @@ -20,8 +20,8 @@ describe('format', () => { it('converts .432414 ETH in base units to the string `.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`', () => { - expect(format.ethBaseAmount(IRRATIONAL_ETH_IN_BASE_UNITS)).toBe('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.301 ETH'); }); it('returns defaultText param when ethBaseAmount is not defined', () => { const defaultText = 'defaultText'; @@ -38,8 +38,8 @@ describe('format', () => { it('converts BigNumer(.432414) to the string `.4324 ETH`', () => { expect(format.ethUnitAmount(BIG_NUMBER_DECIMAL)).toBe('0.4324 ETH'); }); - it('converts BigNumber(5.3014059295032) to the string `5.3014 ETH`', () => { - expect(format.ethUnitAmount(BIG_NUMBER_IRRATIONAL)).toBe('5.3014 ETH'); + it('converts BigNumber(5.3014059295032) to the string `5.301 ETH`', () => { + expect(format.ethUnitAmount(BIG_NUMBER_IRRATIONAL)).toBe('5.301 ETH'); }); it('returns defaultText param when ethUnitAmount is not defined', () => { const defaultText = 'defaultText'; -- cgit v1.2.3 From f89b314a94f867fa905a1ce18eba9336ee4d1634 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 24 Oct 2018 12:52:32 -0700 Subject: fix: address PR feedback --- packages/instant/src/components/scaling_input.tsx | 8 ++++---- packages/instant/src/style/fonts.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index fadb3466b..6948c86c1 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -53,7 +53,7 @@ export class ScalingInput extends React.Component(); public static getPhase(textLengthThreshold: number, value: string): ScalingInputPhase { if (value.length <= textLengthThreshold) { return ScalingInputPhase.FixedFontSize; @@ -101,8 +101,6 @@ export class ScalingInput extends React.Component { // Inject the inter-ui font into the page - const head = document.head || document.getElementsByTagName('head')[0]; + const appendTo = document.head || document.getElementsByTagName('head')[0] || document.body; const style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(`@import url('https://rsms.me/inter/inter-ui.css')`)); - head.appendChild(style); + appendTo.appendChild(style); }, }; -- cgit v1.2.3 From c5554fe30c199155d4e020028aa4aa1f808918b9 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 24 Oct 2018 12:57:20 -0700 Subject: chore: run linter --- packages/instant/src/components/asset_amount_input.tsx | 2 +- packages/instant/src/util/asset.ts | 2 +- packages/instant/src/util/big_number.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx index 960b8bc95..4d2dc0bd8 100644 --- a/packages/instant/src/components/asset_amount_input.tsx +++ b/packages/instant/src/components/asset_amount_input.tsx @@ -8,7 +8,7 @@ import { assetUtils } from '../util/asset'; import { util } from '../util/util'; import { ScalingAmountInput } from './scaling_amount_input'; -import { Container, Flex, Text } from './ui'; +import { Container, Text } from './ui'; // Asset amounts only apply to ERC20 assets export interface AssetAmountInputProps { diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index ebeba948e..e42727d84 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -2,7 +2,7 @@ import { AssetProxyId, ObjectMap } from '@0x/types'; import * as _ from 'lodash'; import { assetDataNetworkMapping } from '../data/asset_data_network_mapping'; -import { Asset, AssetMetaData, Network, ZeroExInstantError, ERC20Asset } from '../types'; +import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types'; export const assetUtils = { createAssetFromAssetData: ( diff --git a/packages/instant/src/util/big_number.ts b/packages/instant/src/util/big_number.ts index 773eb0cb4..a34d22d76 100644 --- a/packages/instant/src/util/big_number.ts +++ b/packages/instant/src/util/big_number.ts @@ -9,7 +9,7 @@ import * as _ from 'lodash'; * new BigNumberInput(1..) => still throws */ export class BigNumberInput extends BigNumber { - private _hasDecimalPeriod: boolean; + private readonly _hasDecimalPeriod: boolean; constructor(bigNumberString: string) { const hasDecimalPeriod = _.endsWith(bigNumberString, '.'); let internalString = bigNumberString; -- cgit v1.2.3 From 2d9c961d4f0d03cfd2f3c15dd306fad47ad1f259 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 24 Oct 2018 13:05:52 -0700 Subject: feat: change to increasing input width by a constant amount per additional character --- packages/instant/src/components/scaling_input.tsx | 9 ++--- yarn.lock | 48 +---------------------- 2 files changed, 6 insertions(+), 51 deletions(-) diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index 6948c86c1..fd517def8 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -13,7 +13,7 @@ export enum ScalingInputPhase { export interface ScalingSettings { percentageToReduceFontSizePerCharacter: number; - percentageToIncreaseWidthPerCharacter: number; + constantPxToIncreaseWidthPerCharacter: number; } export interface ScalingInputProps { @@ -40,7 +40,7 @@ export interface ScalingInputSnapshot { // These are magic numbers that were determined experimentally. const defaultScalingSettings: ScalingSettings = { percentageToReduceFontSizePerCharacter: 0.125, - percentageToIncreaseWidthPerCharacter: 0.06, + constantPxToIncreaseWidthPerCharacter: 4, }; export class ScalingInput extends React.Component { @@ -148,9 +148,8 @@ export class ScalingInput extends React.Component Date: Wed, 24 Oct 2018 13:38:28 -0700 Subject: fix: weird linting error that depends on types --- packages/instant/src/components/scaling_input.tsx | 2 +- yarn.lock | 39 ++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index fd517def8..c927f9419 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -50,7 +50,7 @@ export class ScalingInput extends React.Component(); diff --git a/yarn.lock b/yarn.lock index 1ea799433..aeddefa31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1900,6 +1900,10 @@ aes-js@^0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d" +aes-js@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072" + agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -3337,7 +3341,7 @@ bs-logger@0.x: dependencies: fast-json-stable-stringify "^2.0.0" -bs58@=4.0.1: +bs58@=4.0.1, bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" dependencies: @@ -3360,6 +3364,14 @@ bs58check@^1.0.8: bs58 "^3.1.0" create-hash "^1.1.0" +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + bser@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -5947,6 +5959,19 @@ ethereumjs-wallet@0.6.0: utf8 "^2.1.1" uuid "^2.0.1" +ethereumjs-wallet@~0.6.0: + version "0.6.2" + resolved "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda" + dependencies: + aes-js "^3.1.1" + bs58check "^2.1.2" + ethereumjs-util "^5.2.0" + hdkey "^1.0.0" + safe-buffer "^5.1.2" + scrypt.js "^0.2.0" + utf8 "^3.0.0" + uuid "^3.3.2" + ethers@~4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65" @@ -7476,6 +7501,14 @@ hdkey@^0.7.0, hdkey@^0.7.1: coinstring "^2.0.0" secp256k1 "^3.0.1" +hdkey@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29" + dependencies: + coinstring "^2.0.0" + safe-buffer "^5.1.1" + secp256k1 "^3.0.1" + he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" @@ -15562,6 +15595,10 @@ utf8@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96" +utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -- cgit v1.2.3 From 379f7c788385cfc15fea8d0bb0a2a39f0c709b8d Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 24 Oct 2018 13:44:00 -0700 Subject: chore: use alternate syntax for styled --- packages/instant/src/components/ui/container.tsx | 5 ++++- packages/instant/src/components/ui/flex.tsx | 5 ++++- packages/instant/src/components/ui/input.tsx | 5 ++++- packages/instant/src/components/ui/text.tsx | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index 7077d0aa3..76b570de7 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -30,7 +30,10 @@ export interface ContainerProps { opacity?: number; } -export const Container = styled('div')` +export const Container = + styled.div < + ContainerProps > + ` box-sizing: border-box; ${props => cssRuleIfExists(props, 'display')} ${props => cssRuleIfExists(props, 'position')} diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx index d4e14d979..5fa3fc95b 100644 --- a/packages/instant/src/components/ui/flex.tsx +++ b/packages/instant/src/components/ui/flex.tsx @@ -12,7 +12,10 @@ export interface FlexProps { className?: string; } -export const Flex = styled('div')` +export const Flex = + styled.div < + FlexProps > + ` display: flex; flex-direction: ${props => props.direction}; flex-wrap: ${props => props.flexWrap}; diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx index 9db7d1c4c..a884ff7cb 100644 --- a/packages/instant/src/components/ui/input.tsx +++ b/packages/instant/src/components/ui/input.tsx @@ -12,7 +12,10 @@ export interface InputProps { onChange?: (event: React.ChangeEvent) => void; } -export const Input = styled('input')` +export const Input = + styled.input < + InputProps > + ` font-size: ${props => props.fontSize}; width: ${props => props.width}; padding: 0.1em 0em; diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx index d23b0034d..fd72f6cc8 100644 --- a/packages/instant/src/components/ui/text.tsx +++ b/packages/instant/src/components/ui/text.tsx @@ -24,7 +24,10 @@ export interface TextProps { } const darkenOnHoverAmount = 0.3; -export const Text = styled('div')` +export const Text = + styled.div < + TextProps > + ` font-family: ${props => props.fontFamily}; font-style: ${props => props.fontStyle}; font-weight: ${props => props.fontWeight}; -- cgit v1.2.3 From ab2759f43105c0f2d441790e138840706c6759f8 Mon Sep 17 00:00:00 2001 From: fragosti Date: Wed, 24 Oct 2018 13:47:00 -0700 Subject: chore: update comments --- packages/instant/src/components/scaling_input.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx index c927f9419..34cb0b5fd 100644 --- a/packages/instant/src/components/scaling_input.tsx +++ b/packages/instant/src/components/scaling_input.tsx @@ -101,13 +101,13 @@ export class ScalingInput extends React.Component Date: Thu, 25 Oct 2018 18:35:06 -0700 Subject: chore: dont override toString of BigNumber and other PR feedback --- .../src/components/animations/slide_animations.tsx | 5 +- .../instant/src/components/asset_amount_input.tsx | 81 -------------- .../src/components/erc20_asset_amount_input.tsx | 84 ++++++++++++++ .../instant/src/components/instant_heading.tsx | 4 +- .../src/components/scaling_amount_input.tsx | 11 +- .../src/containers/selected_asset_amount_input.ts | 123 -------------------- .../selected_erc20_asset_amount_input.ts | 124 +++++++++++++++++++++ packages/instant/src/redux/actions.ts | 5 +- packages/instant/src/redux/reducer.ts | 3 +- packages/instant/src/style/theme.ts | 2 + packages/instant/src/util/asset.ts | 2 +- packages/instant/src/util/big_number.ts | 29 ----- packages/instant/src/util/big_number_input.ts | 29 +++++ 13 files changed, 257 insertions(+), 245 deletions(-) delete mode 100644 packages/instant/src/components/asset_amount_input.tsx create mode 100644 packages/instant/src/components/erc20_asset_amount_input.tsx delete mode 100644 packages/instant/src/containers/selected_asset_amount_input.ts create mode 100644 packages/instant/src/containers/selected_erc20_asset_amount_input.ts delete mode 100644 packages/instant/src/util/big_number.ts create mode 100644 packages/instant/src/util/big_number_input.ts diff --git a/packages/instant/src/components/animations/slide_animations.tsx b/packages/instant/src/components/animations/slide_animations.tsx index 7c8666861..84280372b 100644 --- a/packages/instant/src/components/animations/slide_animations.tsx +++ b/packages/instant/src/components/animations/slide_animations.tsx @@ -21,7 +21,10 @@ export interface SlideAnimationProps { animationDirection?: string; } -export const SlideAnimation = styled('div')` +export const SlideAnimation = + styled.div < + SlideAnimationProps > + ` animation-name: ${props => css` ${props.keyframes}; diff --git a/packages/instant/src/components/asset_amount_input.tsx b/packages/instant/src/components/asset_amount_input.tsx deleted file mode 100644 index 4d2dc0bd8..000000000 --- a/packages/instant/src/components/asset_amount_input.tsx +++ /dev/null @@ -1,81 +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 { ScalingAmountInput } from './scaling_amount_input'; -import { Container, Text } from './ui'; - -// Asset amounts only apply to ERC20 assets -export interface AssetAmountInputProps { - asset?: ERC20Asset; - onChange: (value?: BigNumber, asset?: ERC20Asset) => void; - startingFontSizePx: number; - fontColor?: ColorOption; -} - -export interface AssetAmountInputState { - currentFontSizePx: number; -} - -export class AssetAmountInput extends React.Component { - public static defaultProps = { - onChange: util.boundNoop, - }; - constructor(props: AssetAmountInputProps) { - super(props); - this.state = { - currentFontSizePx: props.startingFontSizePx, - }; - } - public render(): React.ReactNode { - const { asset, onChange, ...rest } = this.props; - return ( - - - - - - - {assetUtils.formattedSymbolForAsset(asset)} - - - - ); - } - private readonly _handleChange = (value?: BigNumber): void => { - this.props.onChange(value, this.props.asset); - }; - private readonly _handleFontSizeChange = (fontSizePx: number): void => { - this.setState({ - currentFontSizePx: fontSizePx, - }); - }; - 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; - }; -} diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx new file mode 100644 index 000000000..583fad28b --- /dev/null +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -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 { + 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 ( + + + + + + + {assetUtils.formattedSymbolForAsset(asset)} + + + + ); + } + 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; + }; +} diff --git a/packages/instant/src/components/instant_heading.tsx b/packages/instant/src/components/instant_heading.tsx index f0a22bccb..df9856277 100644 --- a/packages/instant/src/components/instant_heading.tsx +++ b/packages/instant/src/components/instant_heading.tsx @@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; 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 { AsyncProcessState, OrderState } from '../types'; import { format } from '../util/format'; @@ -48,7 +48,7 @@ export class InstantHeading extends React.Component { - + {iconOrAmounts} diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index 23a15305a..655ae2b74 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -1,9 +1,8 @@ -import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption } from '../style/theme'; -import { BigNumberInput } from '../util/big_number'; +import { BigNumberInput } from '../util/big_number_input'; import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; @@ -12,8 +11,8 @@ export interface ScalingAmountInputProps { maxFontSizePx: number; textLengthThreshold: number; fontColor?: ColorOption; - value?: BigNumber; - onChange: (value?: BigNumber) => void; + value?: BigNumberInput; + onChange: (value?: BigNumberInput) => void; onFontSizeChange: (fontSizePx: number) => void; } @@ -31,7 +30,7 @@ export class ScalingAmountInput extends React.Component onFontSizeChange={onFontSizeChange} fontColor={fontColor} onChange={this._handleChange} - value={!_.isUndefined(value) ? value.toString() : ''} + value={!_.isUndefined(value) ? value.toDisplayString() : ''} placeholder="0.00" emptyInputWidthCh={3.5} /> @@ -42,7 +41,7 @@ export class ScalingAmountInput extends React.Component let bigNumberValue; if (!_.isEmpty(value)) { try { - bigNumberValue = new BigNumberInput(event.target.value); + 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; diff --git a/packages/instant/src/containers/selected_asset_amount_input.ts b/packages/instant/src/containers/selected_asset_amount_input.ts deleted file mode 100644 index f836c6967..000000000 --- a/packages/instant/src/containers/selected_asset_amount_input.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; -import { AssetProxyId } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; -import * as React from 'react'; -import { connect } from 'react-redux'; -import { Dispatch } from 'redux'; - -import { Action, actions } from '../redux/actions'; -import { State } from '../redux/reducer'; -import { ColorOption } from '../style/theme'; -import { AsyncProcessState, ERC20Asset } from '../types'; -import { errorUtil } from '../util/error'; - -import { AssetAmountInput } from '../components/asset_amount_input'; - -export interface SelectedAssetAmountInputProps { - fontColor?: ColorOption; - startingFontSizePx: number; -} - -interface ConnectedState { - assetBuyer?: AssetBuyer; - value?: BigNumber; - asset?: ERC20Asset; -} - -interface ConnectedDispatch { - updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumber, asset?: ERC20Asset) => void; -} - -interface ConnectedProps { - value?: BigNumber; - asset?: ERC20Asset; - onChange: (value?: BigNumber, asset?: ERC20Asset) => void; -} - -type FinalProps = ConnectedProps & SelectedAssetAmountInputProps; - -const mapStateToProps = (state: State, _ownProps: SelectedAssetAmountInputProps): ConnectedState => { - const selectedAsset = state.selectedAsset; - if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) { - return { - value: state.selectedAssetAmount, - }; - } - return { - assetBuyer: state.assetBuyer, - value: state.selectedAssetAmount, - asset: selectedAsset as ERC20Asset, - }; -}; - -const updateBuyQuoteAsync = async ( - assetBuyer: AssetBuyer, - dispatch: Dispatch, - asset: ERC20Asset, - assetAmount: BigNumber, -): Promise => { - // get a new buy quote. - const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); - - // mark quote as pending - dispatch(actions.setQuoteRequestStatePending()); - - let newBuyQuote: BuyQuote | undefined; - try { - newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue); - } catch (error) { - dispatch(actions.setQuoteRequestStateFailure()); - errorUtil.errorFlasher.flashNewError(dispatch, error); - return; - } - // We have a successful new buy quote - errorUtil.errorFlasher.clearError(dispatch); - // invalidate the last buy quote. - dispatch(actions.updateLatestBuyQuote(newBuyQuote)); -}; - -const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true }); - -const mapDispatchToProps = ( - dispatch: Dispatch, - _ownProps: SelectedAssetAmountInputProps, -): ConnectedDispatch => ({ - updateBuyQuote: (assetBuyer, value, asset) => { - // Update the input - dispatch(actions.updateSelectedAssetAmount(value)); - // invalidate the last buy quote. - dispatch(actions.updateLatestBuyQuote(undefined)); - // reset our buy state - dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.NONE })); - - if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { - // even if it's debounced, give them the illusion it's loading - dispatch(actions.setQuoteRequestStatePending()); - // tslint:disable-next-line:no-floating-promises - debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value); - } - }, -}); - -const mergeProps = ( - connectedState: ConnectedState, - connectedDispatch: ConnectedDispatch, - ownProps: SelectedAssetAmountInputProps, -): FinalProps => { - return { - ...ownProps, - asset: connectedState.asset, - value: connectedState.value, - onChange: (value, asset) => { - connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); - }, - }; -}; - -export const SelectedAssetAmountInput: React.ComponentClass = connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(AssetAmountInput); diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts new file mode 100644 index 000000000..078f96cd4 --- /dev/null +++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts @@ -0,0 +1,124 @@ +import { AssetBuyer, BuyQuote } from '@0x/asset-buyer'; +import { AssetProxyId } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import * as _ from 'lodash'; +import * as React from 'react'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; + +import { Action, actions } from '../redux/actions'; +import { State } from '../redux/reducer'; +import { ColorOption } from '../style/theme'; +import { AsyncProcessState, ERC20Asset } from '../types'; +import { BigNumberInput } from '../util/big_number_input'; +import { errorUtil } from '../util/error'; + +import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input'; + +export interface SelectedERC20AssetAmountInputProps { + fontColor?: ColorOption; + startingFontSizePx: number; +} + +interface ConnectedState { + assetBuyer?: AssetBuyer; + value?: BigNumberInput; + asset?: ERC20Asset; +} + +interface ConnectedDispatch { + updateBuyQuote: (assetBuyer?: AssetBuyer, value?: BigNumberInput, asset?: ERC20Asset) => void; +} + +interface ConnectedProps { + value?: BigNumberInput; + asset?: ERC20Asset; + onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; +} + +type FinalProps = ConnectedProps & SelectedERC20AssetAmountInputProps; + +const mapStateToProps = (state: State, _ownProps: SelectedERC20AssetAmountInputProps): ConnectedState => { + const selectedAsset = state.selectedAsset; + if (_.isUndefined(selectedAsset) || selectedAsset.metaData.assetProxyId !== AssetProxyId.ERC20) { + return { + value: state.selectedAssetAmount, + }; + } + return { + assetBuyer: state.assetBuyer, + value: state.selectedAssetAmount, + asset: selectedAsset as ERC20Asset, + }; +}; + +const updateBuyQuoteAsync = async ( + assetBuyer: AssetBuyer, + dispatch: Dispatch, + asset: ERC20Asset, + assetAmount: BigNumber, +): Promise => { + // get a new buy quote. + const baseUnitValue = Web3Wrapper.toBaseUnitAmount(assetAmount, asset.metaData.decimals); + + // mark quote as pending + dispatch(actions.setQuoteRequestStatePending()); + + let newBuyQuote: BuyQuote | undefined; + try { + newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue); + } catch (error) { + dispatch(actions.setQuoteRequestStateFailure()); + errorUtil.errorFlasher.flashNewError(dispatch, error); + return; + } + // We have a successful new buy quote + errorUtil.errorFlasher.clearError(dispatch); + // invalidate the last buy quote. + dispatch(actions.updateLatestBuyQuote(newBuyQuote)); +}; + +const debouncedUpdateBuyQuoteAsync = _.debounce(updateBuyQuoteAsync, 200, { trailing: true }); + +const mapDispatchToProps = ( + dispatch: Dispatch, + _ownProps: SelectedERC20AssetAmountInputProps, +): ConnectedDispatch => ({ + updateBuyQuote: (assetBuyer, value, asset) => { + // Update the input + dispatch(actions.updateSelectedAssetAmount(value)); + // invalidate the last buy quote. + dispatch(actions.updateLatestBuyQuote(undefined)); + // reset our buy state + dispatch(actions.updateBuyOrderState({ processState: AsyncProcessState.NONE })); + + if (!_.isUndefined(value) && !_.isUndefined(asset) && !_.isUndefined(assetBuyer)) { + // even if it's debounced, give them the illusion it's loading + dispatch(actions.setQuoteRequestStatePending()); + // tslint:disable-next-line:no-floating-promises + debouncedUpdateBuyQuoteAsync(assetBuyer, dispatch, asset, value); + } + }, +}); + +const mergeProps = ( + connectedState: ConnectedState, + connectedDispatch: ConnectedDispatch, + ownProps: SelectedERC20AssetAmountInputProps, +): FinalProps => { + return { + ...ownProps, + asset: connectedState.asset, + value: connectedState.value, + onChange: (value, asset) => { + connectedDispatch.updateBuyQuote(connectedState.assetBuyer, value, asset); + }, + }; +}; + +export const SelectedERC20AssetAmountInput: React.ComponentClass = connect( + mapStateToProps, + mapDispatchToProps, + mergeProps, +)(ERC20AssetAmountInput); diff --git a/packages/instant/src/redux/actions.ts b/packages/instant/src/redux/actions.ts index 5a4099f15..46045024b 100644 --- a/packages/instant/src/redux/actions.ts +++ b/packages/instant/src/redux/actions.ts @@ -2,6 +2,8 @@ import { BuyQuote } from '@0x/asset-buyer'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; +import { BigNumberInput } from '../util/big_number_input'; + import { ActionsUnion, OrderState } from '../types'; export interface PlainAction { @@ -36,7 +38,8 @@ export enum ActionTypes { export const actions = { 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), updateLatestBuyQuote: (buyQuote?: BuyQuote) => createAction(ActionTypes.UPDATE_LATEST_BUY_QUOTE, buyQuote), updateSelectedAsset: (assetData?: string) => createAction(ActionTypes.UPDATE_SELECTED_ASSET, assetData), diff --git a/packages/instant/src/redux/reducer.ts b/packages/instant/src/redux/reducer.ts index c6a05ac52..665cba257 100644 --- a/packages/instant/src/redux/reducer.ts +++ b/packages/instant/src/redux/reducer.ts @@ -6,6 +6,7 @@ import * as _ from 'lodash'; import { assetMetaDataMap } from '../data/asset_meta_data_map'; import { Asset, AssetMetaData, AsyncProcessState, DisplayStatus, Network, OrderState } from '../types'; import { assetUtils } from '../util/asset'; +import { BigNumberInput } from '../util/big_number_input'; import { Action, ActionTypes } from './actions'; @@ -14,7 +15,7 @@ export interface State { assetBuyer?: AssetBuyer; assetMetaDataMap: ObjectMap; selectedAsset?: Asset; - selectedAssetAmount?: BigNumber; + selectedAssetAmount?: BigNumberInput; buyOrderState: OrderState; ethUsdPrice?: BigNumber; latestBuyQuote?: BuyQuote; diff --git a/packages/instant/src/style/theme.ts b/packages/instant/src/style/theme.ts index be527a12c..6575ff9f4 100644 --- a/packages/instant/src/style/theme.ts +++ b/packages/instant/src/style/theme.ts @@ -28,4 +28,6 @@ export const theme: Theme = { darkOrange: '#F2994C', }; +export const transparentWhite = 'rgba(255,255,255,0.3)'; + export { styled, css, keyframes, ThemeProvider }; diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts index e42727d84..2c5b6325d 100644 --- a/packages/instant/src/util/asset.ts +++ b/packages/instant/src/util/asset.ts @@ -51,7 +51,7 @@ export const assetUtils = { if (symbol.length <= 5) { return symbol; } - return `${symbol.slice(0, 3)}...`; + return `${symbol.slice(0, 3)}…`; }, getAssociatedAssetDataIfExists: (assetData: string, network: Network): string | undefined => { const assetDataGroupIfExists = _.find(assetDataNetworkMapping, value => value[network] === assetData); diff --git a/packages/instant/src/util/big_number.ts b/packages/instant/src/util/big_number.ts deleted file mode 100644 index a34d22d76..000000000 --- a/packages/instant/src/util/big_number.ts +++ /dev/null @@ -1,29 +0,0 @@ -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 _hasDecimalPeriod: boolean; - constructor(bigNumberString: string) { - const hasDecimalPeriod = _.endsWith(bigNumberString, '.'); - let internalString = bigNumberString; - if (hasDecimalPeriod) { - internalString = bigNumberString.slice(0, bigNumberString.length - 1); - } - super(internalString); - this._hasDecimalPeriod = hasDecimalPeriod; - } - public toString(): string { - const internalString = super.toString(); - if (this._hasDecimalPeriod) { - return `${internalString}.`; - } - return internalString; - } -} diff --git a/packages/instant/src/util/big_number_input.ts b/packages/instant/src/util/big_number_input.ts new file mode 100644 index 000000000..d2a9a8dc5 --- /dev/null +++ b/packages/instant/src/util/big_number_input.ts @@ -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; + } +} -- cgit v1.2.3