mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
126 lines
3.2 KiB
JavaScript
126 lines
3.2 KiB
JavaScript
import React, { PureComponent } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import classnames from 'classnames';
|
|
|
|
function removeLeadingZeroes(str) {
|
|
return str.replace(/^0*(?=\d)/u, '');
|
|
}
|
|
|
|
/**
|
|
* Component that attaches a suffix or unit of measurement trailing user input, ex. 'ETH'. Also
|
|
* allows rendering a child component underneath the input to, for example, display conversions of
|
|
* the shown suffix.
|
|
*/
|
|
export default class UnitInput extends PureComponent {
|
|
static propTypes = {
|
|
dataTestId: PropTypes.string,
|
|
children: PropTypes.node,
|
|
actionComponent: PropTypes.node,
|
|
error: PropTypes.bool,
|
|
onChange: PropTypes.func,
|
|
onBlur: PropTypes.func,
|
|
placeholder: PropTypes.string,
|
|
suffix: PropTypes.string,
|
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
};
|
|
|
|
static defaultProps = {
|
|
value: '',
|
|
placeholder: '0',
|
|
};
|
|
|
|
state = {
|
|
value: this.props.value,
|
|
};
|
|
|
|
componentDidUpdate(prevProps) {
|
|
const { value: prevPropsValue } = prevProps;
|
|
const { value: propsValue } = this.props;
|
|
const { value: stateValue } = this.state;
|
|
|
|
if (prevPropsValue !== propsValue && propsValue !== stateValue) {
|
|
this.setState({ value: propsValue });
|
|
}
|
|
}
|
|
|
|
handleFocus = () => {
|
|
this.unitInput.focus();
|
|
};
|
|
|
|
handleInputFocus = ({ target: { value } }) => {
|
|
if (value === '0') {
|
|
this.setState({ value: '' });
|
|
}
|
|
};
|
|
|
|
handleInputBlur = ({ target: { value } }) => {
|
|
if (value === '') {
|
|
this.setState({ value: '0' });
|
|
}
|
|
|
|
this.props.onBlur && this.props.onBlur(value);
|
|
};
|
|
|
|
handleChange = (event) => {
|
|
const { value: userInput } = event.target;
|
|
let value = userInput;
|
|
|
|
if (userInput.length && userInput.length > 1) {
|
|
value = removeLeadingZeroes(userInput);
|
|
}
|
|
|
|
this.setState({ value });
|
|
this.props.onChange(value);
|
|
};
|
|
|
|
getInputWidth(value) {
|
|
const valueString = String(value);
|
|
const valueLength = valueString.length || 1;
|
|
const decimalPointDeficit = valueString.match(/\./u) ? -0.5 : 0;
|
|
return `${valueLength + decimalPointDeficit + 0.5}ch`;
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
error,
|
|
placeholder,
|
|
suffix,
|
|
actionComponent,
|
|
children,
|
|
dataTestId,
|
|
} = this.props;
|
|
const { value } = this.state;
|
|
|
|
return (
|
|
<div
|
|
className={classnames('unit-input', { 'unit-input--error': error })}
|
|
onClick={this.handleFocus}
|
|
>
|
|
<div className="unit-input__inputs">
|
|
<div className="unit-input__input-container">
|
|
<input
|
|
data-testid={dataTestId}
|
|
type="number"
|
|
dir="ltr"
|
|
className={classnames('unit-input__input')}
|
|
value={value}
|
|
placeholder={placeholder}
|
|
onChange={this.handleChange}
|
|
onBlur={this.handleInputBlur}
|
|
onFocus={this.handleInputFocus}
|
|
style={{ width: this.getInputWidth(value) }}
|
|
ref={(ref) => {
|
|
this.unitInput = ref;
|
|
}}
|
|
autoFocus
|
|
/>
|
|
{suffix ? <div className="unit-input__suffix">{suffix}</div> : null}
|
|
</div>
|
|
{children}
|
|
</div>
|
|
{actionComponent}
|
|
</div>
|
|
);
|
|
}
|
|
}
|