toggle-corp/react-store

View on GitHub
components/Input/DigitalInput/index.js

Summary

Maintainability
A
0 mins
Test Coverage
import PropTypes from 'prop-types';
import React from 'react';
import {
    padStart,
    isFalsy,
    _cs,
} from '@togglecorp/fujs';

import RawInput from '../RawInput';


import styles from './styles.scss';

const propTypes = {
    onChange: PropTypes.func,
    value: PropTypes.string,
    padLength: PropTypes.number,
    className: PropTypes.string,
};
const defaultProps = {
    value: '',
    onChange: undefined,
    padLength: 2,
    className: '',
};

export default class DigitalInput extends React.PureComponent {
    static propTypes = propTypes;

    static defaultProps = defaultProps;

    static padAndTrim = (value, padLength) => {
        if (isFalsy(value, [''])) {
            return '';
        }
        return padStart(+value % (10 ** padLength), padLength, '0');
    }

    static getNewValue = (newValue, oldValue, padLength) => {
        // NOTE: to identify a backspace, we look at the length of
        // old value and new value. (New value will be shorter than old value)
        // However, when value is changed from arrows in number input,
        // this algorithm cannot differentiate between the two.
        if (
            isFalsy(newValue, [''])
            || (
                oldValue !== undefined
                && oldValue.length > newValue.length
                && newValue.match(/^0+$/)
            )
        ) {
            return '';
        }
        const newerValue = DigitalInput.padAndTrim(newValue, padLength);
        return newerValue;
    }

    handleChange = (event) => {
        const { value } = event.target;
        const {
            value: valueFromProps,
            padLength,
            onChange,
        } = this.props;

        if (onChange) {
            const newValue = DigitalInput.getNewValue(value, valueFromProps, padLength);
            onChange(newValue);
        }
    }

    render() {
        const {
            className: classNameFromProps,
            onChange, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
            padLength, // eslint-disable-line no-unused-vars, @typescript-eslint/no-unused-vars
            ...otherProps
        } = this.props;

        const className = _cs(
            classNameFromProps,
            'digital-input',
            styles.digitalInput,
        );

        return (
            <RawInput
                className={className}
                type="number"
                onChange={this.handleChange}
                {...otherProps}
            />
        );
    }
}