From 6510454337dd5add86522c0eb5621a3f55ac062d Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Fri, 19 Oct 2018 14:58:12 -0700
Subject: feat: add scaling input component

---
 packages/instant/src/components/scaling_input.tsx | 82 +++++++++++++++++++++++
 1 file changed, 82 insertions(+)
 create mode 100644 packages/instant/src/components/scaling_input.tsx

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<HTMLInputElement>) => void;
+    fontColor?: ColorOption;
+    placeholder?: string;
+}
+// Magic value obtained via trial-and-error
+const scalingRateToMaintainSameWidth = 0.1;
+export class ScalingInput extends React.Component<ScalingInputProps> {
+    public static defaultProps = {
+        onChange: util.boundNoop,
+    };
+    public render(): React.ReactNode {
+        const { fontColor, onChange, placeholder, value } = this.props;
+        const phase = this._getPhase();
+        return (
+            <Input
+                fontColor={fontColor}
+                onChange={onChange}
+                value={value}
+                placeholder={placeholder}
+                fontSize={this._calculateFontSize(phase)}
+                width={this._calculateWidth(phase)}
+            />
+        );
+    }
+    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 <francesco.agosti93@gmail.com>
Date: Mon, 22 Oct 2018 10:50:25 -0700
Subject: feat: have basic scaling amount input working

---
 packages/instant/src/components/scaling_input.tsx | 101 ++++++++++++++++------
 1 file changed, 75 insertions(+), 26 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<HTMLInputElement>) => void;
+    onChange: (event: React.ChangeEvent<HTMLInputElement>, 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<ScalingInputProps> {
     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 (
             <Input
+                ref={this._inputRef as any}
                 fontColor={fontColor}
-                onChange={onChange}
+                onChange={this._handleChange}
                 value={value}
                 placeholder={placeholder}
-                fontSize={this._calculateFontSize(phase)}
-                width={this._calculateWidth(phase)}
+                fontSize={`${this.props.fontSizePx}px`}
+                width={this._calculateWidth()}
             />
         );
     }
-    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<ScalingInputProps> {
                 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<HTMLInputElement>) => {
+        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 921492e8186697e477c27d76bd7eb58ce2454765 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Mon, 22 Oct 2018 16:45:48 -0700
Subject: feature: reduce font size by a percentage instead of a constant

---
 packages/instant/src/components/scaling_input.tsx | 73 ++++++++++++++---------
 1 file changed, 44 insertions(+), 29 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index a2c4ba342..7824c10f9 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -17,21 +17,29 @@ export enum ScalingInputPhase {
 export interface ScalingInputProps {
     startWidthCh: number;
     endWidthCh: number;
-    fontSizePx: number;
+    maxFontSizePx: number;
     value?: string;
-    onChange: (event: React.ChangeEvent<HTMLInputElement>, fontSize: number) => void;
+    onChange: (event: React.ChangeEvent<HTMLInputElement>) => 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<ScalingInputProps> {
+export interface ScalingInputSnapshot {
+    inputWidthPx: number;
+}
+// This is a magic number that was determined experimentally.
+const percentageToReduceByPerCharacter = 0.15;
+export class ScalingInput extends React.Component<ScalingInputProps, ScalingInputState> {
     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<ScalingInputProps> {
         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<ScalingInputProps> {
                 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 (
             <Input
                 ref={this._inputRef as any}
                 fontColor={fontColor}
-                onChange={this._handleChange}
+                onChange={onChange}
                 value={value}
                 placeholder={placeholder}
-                fontSize={`${this.props.fontSizePx}px`}
+                fontSize={`${ScalingInput.calculateFontSize(this.props)}px`}
                 width={this._calculateWidth()}
+                maxLength={maxLength}
             />
         );
     }
@@ -108,24 +143,4 @@ export class ScalingInput extends React.Component<ScalingInputProps> {
         }
         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<HTMLInputElement>) => {
-        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 <francesco.agosti93@gmail.com>
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(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
         const { value, startWidthCh, endWidthCh } = props;
         return ScalingInput.getPhase(startWidthCh, endWidthCh, value);
     }
-    public static calculateFontSize(props: ScalingInputProps): number {
-        const { startWidthCh, endWidthCh, value, maxFontSizePx } = props;
-        const phase = ScalingInput.getPhase(startWidthCh, endWidthCh, value);
+    public static calculateFontSize(
+        endWidthCh: number,
+        maxFontSizePx: number,
+        phase: ScalingInputPhase,
+        value?: string,
+    ): number {
         if (_.isUndefined(value) || phase !== ScalingInputPhase.End) {
             return maxFontSizePx;
         }
@@ -69,6 +72,10 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
         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);
+    }
     public getSnapshotBeforeUpdate(): ScalingInputSnapshot {
         return {
             inputWidthPx: this._getInputWidthInPx(),
@@ -81,8 +88,8 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
     ): void {
         const prevPhase = ScalingInput.getPhaseFromProps(prevProps);
         const curPhase = ScalingInput.getPhaseFromProps(this.props);
-        const prevFontSize = ScalingInput.calculateFontSize(prevProps);
-        const curFontSize = ScalingInput.calculateFontSize(this.props);
+        const prevFontSize = ScalingInput.calculateFontSizeFromProps(prevProps, prevPhase);
+        const curFontSize = ScalingInput.calculateFontSizeFromProps(this.props, curPhase);
         // 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({
@@ -110,14 +117,13 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
                 onChange={onChange}
                 value={value}
                 placeholder={placeholder}
-                fontSize={`${ScalingInput.calculateFontSize(this.props)}px`}
-                width={this._calculateWidth()}
+                fontSize={`${this._calculateFontSize(phase)}px`}
+                width={this._calculateWidth(phase)}
                 maxLength={maxLength}
             />
         );
     }
-    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<ScalingInputProps, ScalingInpu
                 return `${startWidthCh}ch`;
         }
     };
+    private readonly _calculateFontSize = (phase: ScalingInputPhase): number => {
+        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 <francesco.agosti93@gmail.com>
Date: Mon, 22 Oct 2018 17:42:28 -0700
Subject: chore: final adjustments

---
 packages/instant/src/components/scaling_input.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index c1111cea9..57ebf93ac 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -34,12 +34,12 @@ export interface ScalingInputSnapshot {
     inputWidthPx: number;
 }
 // This is a magic number that was determined experimentally.
-const percentageToReduceByPerCharacter = 0.15;
+const percentageToReduceByPerCharacter = 0.18;
 export class ScalingInput extends React.Component<ScalingInputProps, ScalingInputState> {
     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 <francesco.agosti93@gmail.com>
Date: Mon, 22 Oct 2018 17:56:50 -0700
Subject: chore: run linter

---
 packages/instant/src/components/scaling_input.tsx | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
     public state = {
         fixedWidthInPxIfExists: undefined,
     };
-    private _inputRef = React.createRef();
+    private readonly _inputRef = React.createRef();
     public static getPhase(startWidthCh: number, endWidthCh: number, value?: string): ScalingInputPhase {
         if (_.isUndefined(value) || value.length <= startWidthCh) {
             return ScalingInputPhase.Start;
-- 
cgit v1.2.3


From 053e147afc1b8471c480a8612cb6bae4c363b21b Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Tue, 23 Oct 2018 15:19:01 -0700
Subject: fix: remove the concept of initial with from scaling input and remove
 phase

---
 packages/instant/src/components/scaling_input.tsx | 46 ++++++++++-------------
 1 file changed, 20 insertions(+), 26 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<HTMLInputElement>) => void;
     onFontSizeChange: (fontSizePx: number) => void;
     fontColor?: ColorOption;
@@ -43,26 +42,23 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
         fixedWidthInPxIfExists: undefined,
     };
     private readonly _inputRef = React.createRef();
-    public static getPhase(startWidthCh: number, endWidthCh: number, value?: string): ScalingInputPhase {
-        if (_.isUndefined(value) || value.length <= startWidthCh) {
-            return ScalingInputPhase.Start;
+    public static getPhase(endWidthCh: number, value: string): ScalingInputPhase {
+        if (value.length <= endWidthCh) {
+            return ScalingInputPhase.FixedFontSize;
         }
-        if (value.length > 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<ScalingInputProps, ScalingInpu
         const prevFontSize = ScalingInput.calculateFontSizeFromProps(prevProps, prevPhase);
         const curFontSize = ScalingInput.calculateFontSizeFromProps(this.props, curPhase);
         // 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) {
+        if (prevPhase !== ScalingInputPhase.ScalingFontSize && curPhase === ScalingInputPhase.ScalingFontSize) {
             this.setState({
                 fixedWidthInPxIfExists: snapshot.inputWidthPx,
             });
         }
         // if we end from end to to anything else, un-fix the width
-        if (prevPhase === ScalingInputPhase.End && curPhase !== ScalingInputPhase.End) {
+        if (prevPhase === ScalingInputPhase.ScalingFontSize && curPhase !== ScalingInputPhase.ScalingFontSize) {
             this.setState({
                 fixedWidthInPxIfExists: undefined,
             });
@@ -122,22 +118,20 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
         );
     }
     private readonly _calculateWidth = (phase: ScalingInputPhase): string => {
-        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 <francesco.agosti93@gmail.com>
Date: Tue, 23 Oct 2018 15:54:18 -0700
Subject: polish: improve scaling significantly

---
 packages/instant/src/components/scaling_input.tsx | 68 +++++++++++++++--------
 1 file changed, 46 insertions(+), 22 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

diff --git a/packages/instant/src/components/scaling_input.tsx b/packages/instant/src/components/scaling_input.tsx
index 5db878c52..7f8e505de 100644
--- a/packages/instant/src/components/scaling_input.tsx
+++ b/packages/instant/src/components/scaling_input.tsx
@@ -11,8 +11,13 @@ export enum ScalingInputPhase {
     ScalingFontSize,
 }
 
+export interface ScalingSettings {
+    percentageToReduceFontSizePerCharacter: number;
+    percentageToIncreaseWidthPerCharacter: number;
+}
+
 export interface ScalingInputProps {
-    endWidthCh: number;
+    textLengthThreshold: number;
     maxFontSizePx: number;
     value: string;
     emptyInputWidthCh: number;
@@ -21,54 +26,68 @@ export interface ScalingInputProps {
     fontColor?: ColorOption;
     placeholder?: string;
     maxLength?: number;
+    scalingSettings: ScalingSettings;
 }
 
 export interface ScalingInputState {
-    fixedWidthInPxIfExists?: number;
+    inputWidthPxAtPhaseChange?: number;
 }
 
 export interface ScalingInputSnapshot {
     inputWidthPx: number;
 }
-// This is a magic number that was determined experimentally.
-const percentageToReduceByPerCharacter = 0.18;
+
+// These are magic numbers that were determined experimentally.
+const defaultScalingSettings: ScalingSettings = {
+    percentageToReduceFontSizePerCharacter: 0.125,
+    percentageToIncreaseWidthPerCharacter: 0.06,
+};
+
 export class ScalingInput extends React.Component<ScalingInputProps, ScalingInputState> {
     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<ScalingInputProps, ScalingInpu
         // if we went from anything else to end, fix to the current width as it shouldn't change as we grow
         if (prevPhase !== ScalingInputPhase.ScalingFontSize && curPhase === ScalingInputPhase.ScalingFontSize) {
             this.setState({
-                fixedWidthInPxIfExists: snapshot.inputWidthPx,
+                inputWidthPxAtPhaseChange: snapshot.inputWidthPx,
             });
         }
         // if we end from end to to anything else, un-fix the width
         if (prevPhase === ScalingInputPhase.ScalingFontSize && curPhase !== ScalingInputPhase.ScalingFontSize) {
             this.setState({
-                fixedWidthInPxIfExists: undefined,
+                inputWidthPxAtPhaseChange: undefined,
             });
         }
         // If font size has changed, notify.
@@ -118,18 +137,23 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
         );
     }
     private readonly _calculateWidth = (phase: ScalingInputPhase): string => {
-        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 47737d4d0fce56454c9ee2b43782b824b88cb942 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Tue, 23 Oct 2018 20:02:50 -0700
Subject: feat: cover more token symbol edge cases

---
 packages/instant/src/components/scaling_input.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
     public static defaultProps = {
         onChange: util.boundNoop,
         onFontSizeChange: util.boundNoop,
-        maxLength: 8,
+        maxLength: 7,
         scalingSettings: defaultScalingSettings,
     };
     public state = {
-- 
cgit v1.2.3


From f89b314a94f867fa905a1ce18eba9336ee4d1634 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
Date: Wed, 24 Oct 2018 12:52:32 -0700
Subject: fix: address PR feedback

---
 packages/instant/src/components/scaling_input.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
     public state = {
         inputWidthPxAtPhaseChange: undefined,
     };
-    private readonly _inputRef = React.createRef();
+    private readonly _inputRef = React.createRef<HTMLInputElement>();
     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<ScalingInputProps, ScalingInpu
     ): void {
         const prevPhase = ScalingInput.getPhaseFromProps(prevProps);
         const curPhase = ScalingInput.getPhaseFromProps(this.props);
-        const prevFontSize = ScalingInput.calculateFontSizeFromProps(prevProps, prevPhase);
-        const curFontSize = ScalingInput.calculateFontSizeFromProps(this.props, curPhase);
         // if we went from anything else to end, fix to the current width as it shouldn't change as we grow
         if (prevPhase !== ScalingInputPhase.ScalingFontSize && curPhase === ScalingInputPhase.ScalingFontSize) {
             this.setState({
@@ -115,6 +113,8 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
                 inputWidthPxAtPhaseChange: undefined,
             });
         }
+        const prevFontSize = ScalingInput.calculateFontSizeFromProps(prevProps, prevPhase);
+        const curFontSize = ScalingInput.calculateFontSizeFromProps(this.props, curPhase);
         // If font size has changed, notify.
         if (prevFontSize !== curFontSize) {
             this.props.onFontSizeChange(curFontSize);
@@ -166,6 +166,6 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
         if (!ref) {
             return 0;
         }
-        return (ref as any).getBoundingClientRect().width;
+        return ref.getBoundingClientRect().width;
     };
 }
-- 
cgit v1.2.3


From 2d9c961d4f0d03cfd2f3c15dd306fad47ad1f259 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
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 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInputState> {
@@ -148,9 +148,8 @@ export class ScalingInput extends React.Component<ScalingInputProps, ScalingInpu
                 const { inputWidthPxAtPhaseChange } = this.state;
                 if (!_.isUndefined(inputWidthPxAtPhaseChange)) {
                     const charactersOverMax = value.length - textLengthThreshold;
-                    const scalingFactor =
-                        (scalingSettings.percentageToIncreaseWidthPerCharacter + 1) ** charactersOverMax;
-                    const width = scalingFactor * inputWidthPxAtPhaseChange;
+                    const scalingAmount = scalingSettings.constantPxToIncreaseWidthPerCharacter * charactersOverMax;
+                    const width = inputWidthPxAtPhaseChange + scalingAmount;
                     return `${width}px`;
                 }
                 return `${textLengthThreshold}ch`;
-- 
cgit v1.2.3


From c7a063ca47c3a5b62fe070ba10055b575c1707de Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
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 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
         maxLength: 7,
         scalingSettings: defaultScalingSettings,
     };
-    public state = {
+    public state: ScalingInputState = {
         inputWidthPxAtPhaseChange: undefined,
     };
     private readonly _inputRef = React.createRef<HTMLInputElement>();
-- 
cgit v1.2.3


From ab2759f43105c0f2d441790e138840706c6759f8 Mon Sep 17 00:00:00 2001
From: fragosti <francesco.agosti93@gmail.com>
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(-)

(limited to 'packages/instant/src/components/scaling_input.tsx')

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<ScalingInputProps, ScalingInpu
     ): 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 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 end from end to to anything else, un-fix the width
+        // if we went from scaling to fixed, revert back to scaling using `ch`
         if (prevPhase === ScalingInputPhase.ScalingFontSize && curPhase !== ScalingInputPhase.ScalingFontSize) {
             this.setState({
                 inputWidthPxAtPhaseChange: undefined,
-- 
cgit v1.2.3

