From ea28c8a437cddd0c2cb69809a23f1f9a0ceba0dc Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 28 May 2018 14:11:23 -0230 Subject: Replaces currency-input.js with NumericInput --- ui/app/components/send/currency-display.js | 57 ++++++++++++++++------ .../send-amount-row/send-amount-row.component.js | 6 +-- .../tests/send-amount-row-component.test.js | 38 +++++++-------- ui/app/css/itcss/components/currency-display.scss | 22 +++++++++ 4 files changed, 85 insertions(+), 38 deletions(-) (limited to 'ui') diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index 90fb2b66c..b98ebee09 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -1,10 +1,10 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const CurrencyInput = require('../currency-input') const { conversionUtil, multiplyCurrencies } = require('../../conversion-util') const currencyFormatter = require('currency-formatter') const currencies = require('currency-formatter/currencies') +const NumericInput = require('react-numeric-input') module.exports = CurrencyDisplay @@ -21,21 +21,36 @@ function toHexWei (value) { }) } +CurrencyDisplay.prototype.componentWillMount = function () { + this.setState({ + valueToRender: this.getValueToRender(this.props), + }) +} + +CurrencyDisplay.prototype.componentWillReceiveProps = function (nextProps) { + const currentValueToRender = this.getValueToRender(this.props) + const newValueToRender = this.getValueToRender(nextProps) + if (currentValueToRender !== newValueToRender) { + this.setState({ + valueToRender: newValueToRender, + }) + } +} + CurrencyDisplay.prototype.getAmount = function (value) { const { selectedToken } = this.props const { decimals } = selectedToken || {} const multiplier = Math.pow(10, Number(decimals || 0)) - const sendAmount = multiplyCurrencies(value, multiplier, {toNumericBase: 'hex'}) + const sendAmount = multiplyCurrencies(value || '0', multiplier, {toNumericBase: 'hex'}) return selectedToken ? sendAmount : toHexWei(value) } -CurrencyDisplay.prototype.getValueToRender = function () { - const { selectedToken, conversionRate, value } = this.props - +CurrencyDisplay.prototype.getValueToRender = function ({ selectedToken, conversionRate, value }) { + if (value === '0x0') return '' const { decimals, symbol } = selectedToken || {} const multiplier = Math.pow(10, Number(decimals || 0)) @@ -76,6 +91,19 @@ CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValu : convertedValue } +CurrencyDisplay.prototype.handleChange = function (newVal) { + this.setState({ valueToRender: newVal }) + this.props.onChange(this.getAmount(newVal)) +} + +CurrencyDisplay.prototype.getInputWidth = function (valueToRender, readOnly) { + const valueString = String(valueToRender) + const valueLength = valueString.length || 1 + const dynamicBuffer = readOnly ? 0 : 1 + const decimalPointDeficit = !readOnly && valueString.match(/\./) ? -0.5 : 0 + return (valueLength + dynamicBuffer + decimalPointDeficit) + 'ch' +} + CurrencyDisplay.prototype.render = function () { const { className = 'currency-display', @@ -85,10 +113,10 @@ CurrencyDisplay.prototype.render = function () { convertedCurrency, readOnly = false, inError = false, - handleChange, + onBlur, } = this.props + const { valueToRender } = this.state - const valueToRender = this.getValueToRender() const convertedValueToRender = this.getConvertedValueToRender(valueToRender) return h('div', { @@ -103,21 +131,20 @@ CurrencyDisplay.prototype.render = function () { h('div.currency-display__input-wrapper', [ - h(readOnly ? 'input' : CurrencyInput, { + h(NumericInput, { className: primaryBalanceClassName, value: `${valueToRender}`, - placeholder: '0', + placeholder: `0 ${primaryCurrency}`, readOnly, ...(!readOnly ? { - onInputChange: newValue => { - handleChange(this.getAmount(newValue)) - }, - inputRef: input => { this.currencyInput = input }, + onChange: e => this.handleChange(e), + onBlur: () => onBlur(this.getAmount(valueToRender)), } : {}), + style: false, + format: num => `${num} ${primaryCurrency}`, + parse: stringWithCurrency => stringWithCurrency && stringWithCurrency.match(/^([.\d]+)/)[1], }), - h('span.currency-display__currency-symbol', primaryCurrency), - ]), ]), diff --git a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js index b094d0cd5..8aefeed4a 100644 --- a/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js +++ b/ui/app/components/send_/send-content/send-amount-row/send-amount-row.component.js @@ -49,11 +49,10 @@ export default class SendAmountRow extends Component { }) } - handleAmountChange (amount) { + updateAmount (amount) { const { updateSendAmount, setMaxModeTo } = this.props setMaxModeTo(false) - this.validateAmount(amount) updateSendAmount(amount) } @@ -78,7 +77,8 @@ export default class SendAmountRow extends Component { this.handleAmountChange(newAmount)} + onBlur={newAmount => this.updateAmount(newAmount)} + onChange={newAmount => this.validateAmount(newAmount)} inError={inError} primaryCurrency={primaryCurrency || 'ETH'} selectedToken={selectedToken} diff --git a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js b/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js index 31d2e2515..2205579ca 100644 --- a/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js +++ b/ui/app/components/send_/send-content/send-amount-row/tests/send-amount-row-component.test.js @@ -14,7 +14,7 @@ const propsMethodSpies = { updateSendAmountError: sinon.spy(), } -sinon.spy(SendAmountRow.prototype, 'handleAmountChange') +sinon.spy(SendAmountRow.prototype, 'updateAmount') sinon.spy(SendAmountRow.prototype, 'validateAmount') describe('SendAmountRow Component', function () { @@ -45,7 +45,7 @@ describe('SendAmountRow Component', function () { propsMethodSpies.updateSendAmount.resetHistory() propsMethodSpies.updateSendAmountError.resetHistory() SendAmountRow.prototype.validateAmount.resetHistory() - SendAmountRow.prototype.handleAmountChange.resetHistory() + SendAmountRow.prototype.updateAmount.resetHistory() }) describe('validateAmount', () => { @@ -71,11 +71,11 @@ describe('SendAmountRow Component', function () { }) - describe('handleAmountChange', () => { + describe('updateAmount', () => { it('should call setMaxModeTo', () => { assert.equal(propsMethodSpies.setMaxModeTo.callCount, 0) - instance.handleAmountChange('someAmount') + instance.updateAmount('someAmount') assert.equal(propsMethodSpies.setMaxModeTo.callCount, 1) assert.deepEqual( propsMethodSpies.setMaxModeTo.getCall(0).args, @@ -83,19 +83,9 @@ describe('SendAmountRow Component', function () { ) }) - it('should call this.validateAmount', () => { - assert.equal(SendAmountRow.prototype.validateAmount.callCount, 0) - instance.handleAmountChange('someAmount') - assert.equal(SendAmountRow.prototype.validateAmount.callCount, 1) - assert.deepEqual( - propsMethodSpies.updateSendAmount.getCall(0).args, - ['someAmount'] - ) - }) - it('should call updateSendAmount', () => { assert.equal(propsMethodSpies.updateSendAmount.callCount, 0) - instance.handleAmountChange('someAmount') + instance.updateAmount('someAmount') assert.equal(propsMethodSpies.updateSendAmount.callCount, 1) assert.deepEqual( propsMethodSpies.updateSendAmount.getCall(0).args, @@ -136,7 +126,8 @@ describe('SendAmountRow Component', function () { const { conversionRate, convertedCurrency, - handleChange, + onBlur, + onChange, inError, primaryCurrency, selectedToken, @@ -148,11 +139,18 @@ describe('SendAmountRow Component', function () { assert.equal(primaryCurrency, 'mockPrimaryCurrency') assert.deepEqual(selectedToken, { address: 'mockTokenAddress' }) assert.equal(value, 'mockAmount') - assert.equal(SendAmountRow.prototype.handleAmountChange.callCount, 0) - handleChange('mockNewAmount') - assert.equal(SendAmountRow.prototype.handleAmountChange.callCount, 1) + assert.equal(SendAmountRow.prototype.updateAmount.callCount, 0) + onBlur('mockNewAmount') + assert.equal(SendAmountRow.prototype.updateAmount.callCount, 1) + assert.deepEqual( + SendAmountRow.prototype.updateAmount.getCall(0).args, + ['mockNewAmount'] + ) + assert.equal(SendAmountRow.prototype.validateAmount.callCount, 0) + onChange('mockNewAmount') + assert.equal(SendAmountRow.prototype.validateAmount.callCount, 1) assert.deepEqual( - SendAmountRow.prototype.handleAmountChange.getCall(0).args, + SendAmountRow.prototype.validateAmount.getCall(0).args, ['mockNewAmount'] ) }) diff --git a/ui/app/css/itcss/components/currency-display.scss b/ui/app/css/itcss/components/currency-display.scss index 36d843c79..3560b0b0c 100644 --- a/ui/app/css/itcss/components/currency-display.scss +++ b/ui/app/css/itcss/components/currency-display.scss @@ -47,10 +47,32 @@ &__input-wrapper { position: relative; display: flex; + + input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + display: none; + } + + input[type="number"]:hover::-webkit-inner-spin-button { + -webkit-appearance: none; + display: none; + } } &__currency-symbol { margin-top: 1px; color: $scorpion; } + + .react-numeric-input { + input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + display: none; + } + + input[type="number"]:hover::-webkit-inner-spin-button { + -webkit-appearance: none; + display: none; + } + } } \ No newline at end of file -- cgit v1.2.3 From f33bb3e2fd8ba1cc30dac11017f26ba82c26a82d Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 29 May 2018 16:24:44 -0230 Subject: Stop using external NumericInput component. --- ui/app/components/send/currency-display.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'ui') diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index b98ebee09..60032bca4 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -4,7 +4,6 @@ const inherits = require('util').inherits const { conversionUtil, multiplyCurrencies } = require('../../conversion-util') const currencyFormatter = require('currency-formatter') const currencies = require('currency-formatter/currencies') -const NumericInput = require('react-numeric-input') module.exports = CurrencyDisplay @@ -92,6 +91,7 @@ CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValu } CurrencyDisplay.prototype.handleChange = function (newVal) { + console.log(`%^ 95 newVal`, newVal); this.setState({ valueToRender: newVal }) this.props.onChange(this.getAmount(newVal)) } @@ -124,27 +124,34 @@ CurrencyDisplay.prototype.render = function () { style: { borderColor: inError ? 'red' : null, }, - onClick: () => this.currencyInput && this.currencyInput.focus(), + onClick: () => { + this.currencyInput && this.currencyInput.focus() + }, }, [ h('div.currency-display__primary-row', [ h('div.currency-display__input-wrapper', [ - h(NumericInput, { + h('input', { className: primaryBalanceClassName, value: `${valueToRender}`, - placeholder: `0 ${primaryCurrency}`, + placeholder: '0', + type: 'number', readOnly, ...(!readOnly ? { - onChange: e => this.handleChange(e), + onChange: e => this.handleChange(e.target.value), onBlur: () => onBlur(this.getAmount(valueToRender)), } : {}), - style: false, - format: num => `${num} ${primaryCurrency}`, - parse: stringWithCurrency => stringWithCurrency && stringWithCurrency.match(/^([.\d]+)/)[1], + ref: input => { this.currencyInput = input }, + style: { + width: this.getInputWidth(valueToRender, readOnly), + }, + min: 0, }), + h('span.currency-display__currency-symbol', primaryCurrency), + ]), ]), -- cgit v1.2.3 From 2e1d962b1a36eb0369d00e1e18c0bb810c871590 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 29 May 2018 22:15:21 -0230 Subject: Remove currency input from input-number --- ui/app/components/input-number.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ui') diff --git a/ui/app/components/input-number.js b/ui/app/components/input-number.js index 5600e35ee..de5fcca54 100644 --- a/ui/app/components/input-number.js +++ b/ui/app/components/input-number.js @@ -1,7 +1,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const CurrencyInput = require('./currency-input') const { addCurrencies, conversionGTE, @@ -51,14 +50,15 @@ InputNumber.prototype.render = function () { const { unitLabel, step = 1, placeholder, value = 0 } = this.props return h('div.customize-gas-input-wrapper', {}, [ - h(CurrencyInput, { + h('input', { className: 'customize-gas-input', value, placeholder, type: 'number', - onInputChange: newValue => { - this.setValue(newValue) + onChange: e => { + this.setValue(e.target.value) }, + min: 0, }), h('span.gas-tooltip-input-detail', {}, [unitLabel]), h('div.gas-tooltip-input-arrows', {}, [ -- cgit v1.2.3 From 7f23e017b22ecdc111c2c14f97d632f5490cb5c8 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 29 May 2018 22:20:17 -0230 Subject: Delete currency-input.js --- ui/app/components/currency-input.js | 113 ----------------------------- ui/app/components/send/currency-display.js | 1 - 2 files changed, 114 deletions(-) delete mode 100644 ui/app/components/currency-input.js (limited to 'ui') diff --git a/ui/app/components/currency-input.js b/ui/app/components/currency-input.js deleted file mode 100644 index ece3eb43d..000000000 --- a/ui/app/components/currency-input.js +++ /dev/null @@ -1,113 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits - -module.exports = CurrencyInput - -inherits(CurrencyInput, Component) -function CurrencyInput (props) { - Component.call(this) - - const sanitizedValue = sanitizeValue(props.value) - - this.state = { - value: sanitizedValue, - emptyState: false, - focused: false, - } -} - -function removeNonDigits (str) { - return str.match(/\d|$/g).join('') -} - -// Removes characters that are not digits, then removes leading zeros -function sanitizeInteger (val) { - return String(parseInt(removeNonDigits(val) || '0', 10)) -} - -function sanitizeDecimal (val) { - return removeNonDigits(val) -} - -// Take a single string param and returns a non-negative integer or float as a string. -// Breaks the input into three parts: the integer, the decimal point, and the decimal/fractional part. -// Removes leading zeros from the integer, and non-digits from the integer and decimal -// The integer is returned as '0' in cases where it would be empty. A decimal point is -// included in the returned string if one is included in the param -// Examples: -// sanitizeValue('0') -> '0' -// sanitizeValue('a') -> '0' -// sanitizeValue('010.') -> '10.' -// sanitizeValue('0.005') -> '0.005' -// sanitizeValue('22.200') -> '22.200' -// sanitizeValue('.200') -> '0.200' -// sanitizeValue('a.b.1.c,89.123') -> '0.189123' -function sanitizeValue (value) { - let [ , integer, point, decimal] = (/([^.]*)([.]?)([^.]*)/).exec(value) - - integer = sanitizeInteger(integer) || '0' - decimal = sanitizeDecimal(decimal) - - return `${integer}${point}${decimal}` -} - -CurrencyInput.prototype.handleChange = function (newValue) { - const { onInputChange } = this.props - const { value } = this.state - - let parsedValue = newValue - const newValueLastIndex = newValue.length - 1 - - if (value === '0' && newValue[newValueLastIndex] === '0') { - parsedValue = parsedValue.slice(0, newValueLastIndex) - } - const sanitizedValue = sanitizeValue(parsedValue) - this.setState({ - value: sanitizedValue, - emptyState: newValue === '' && sanitizedValue === '0', - }) - onInputChange(sanitizedValue) -} - -// If state.value === props.value plus a decimal point, or at least one -// zero or a decimal point and at least one zero, then this returns state.value -// after it is sanitized with getValueParts -CurrencyInput.prototype.getValueToRender = function () { - const { value } = this.props - const { value: stateValue } = this.state - - const trailingStateString = (new RegExp(`^${value}(.+)`)).exec(stateValue) - const trailingDecimalAndZeroes = trailingStateString && (/^[.0]0*/).test(trailingStateString[1]) - - return sanitizeValue(trailingDecimalAndZeroes - ? stateValue - : value) -} - -CurrencyInput.prototype.render = function () { - const { - className, - placeholder, - readOnly, - inputRef, - type, - } = this.props - const { emptyState, focused } = this.state - - const inputSizeMultiplier = readOnly ? 1 : 1.2 - - const valueToRender = this.getValueToRender() - return h('input', { - className, - type, - value: emptyState ? '' : valueToRender, - placeholder: focused ? '' : placeholder, - size: valueToRender.length * inputSizeMultiplier, - readOnly, - onFocus: () => this.setState({ focused: true, emptyState: valueToRender === '0' }), - onBlur: () => this.setState({ focused: false, emptyState: false }), - onChange: e => this.handleChange(e.target.value), - ref: inputRef, - }) -} diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index 60032bca4..0b52a69b5 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -91,7 +91,6 @@ CurrencyDisplay.prototype.getConvertedValueToRender = function (nonFormattedValu } CurrencyDisplay.prototype.handleChange = function (newVal) { - console.log(`%^ 95 newVal`, newVal); this.setState({ valueToRender: newVal }) this.props.onChange(this.getAmount(newVal)) } -- cgit v1.2.3 From 67c74cd5b6dba059f954be6867a20e1f97197f7d Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 31 May 2018 12:07:23 -0230 Subject: Fix currency display send integration tests. --- ui/app/components/send/currency-display.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ui') diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index 0b52a69b5..ff61bd1e7 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -49,7 +49,7 @@ CurrencyDisplay.prototype.getAmount = function (value) { } CurrencyDisplay.prototype.getValueToRender = function ({ selectedToken, conversionRate, value }) { - if (value === '0x0') return '' + if (value === '0x0') return '0' const { decimals, symbol } = selectedToken || {} const multiplier = Math.pow(10, Number(decimals || 0)) -- cgit v1.2.3 From 990b69c6552b5571391ea5fbf05b5fbef1e0ab10 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 31 May 2018 12:23:12 -0230 Subject: Improve input width calculation in currency-display.js --- ui/app/components/send/currency-display.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'ui') diff --git a/ui/app/components/send/currency-display.js b/ui/app/components/send/currency-display.js index ff61bd1e7..360dd15d4 100644 --- a/ui/app/components/send/currency-display.js +++ b/ui/app/components/send/currency-display.js @@ -98,9 +98,8 @@ CurrencyDisplay.prototype.handleChange = function (newVal) { CurrencyDisplay.prototype.getInputWidth = function (valueToRender, readOnly) { const valueString = String(valueToRender) const valueLength = valueString.length || 1 - const dynamicBuffer = readOnly ? 0 : 1 - const decimalPointDeficit = !readOnly && valueString.match(/\./) ? -0.5 : 0 - return (valueLength + dynamicBuffer + decimalPointDeficit) + 'ch' + const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0 + return (valueLength + decimalPointDeficit + 0.75) + 'ch' } CurrencyDisplay.prototype.render = function () { -- cgit v1.2.3