import React, {useState, useRef} from 'react' import useMeasure from 'use-measure' import styles from './styles.module.css' function truncateFixed(num, fixed) { var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?'); return num.toString().match(re)[0]; } export default function Input({label, prefix, numDecimals, error, hint, name, value, onChange, onBlur, isValid}){ const [currentDecimals, setCurrentDecimals] = useState((numDecimals === undefined || value === undefined || value === '') ? -1 : numDecimals) const currentValue = value === undefined ? 0 : typeof value === 'number' ? value : typeof value === 'string' ? parseInt(value || '0', 10) : 0 const spanRef = useRef(); const {width} = useMeasure(spanRef); const updateParent = value => onChange({target: {value}}) const onKeyDown = (ev) => { const {key} = ev switch(key) { case 'Backspace': setCurrentDecimals(dec => Math.max(dec - 1, -1)) if(currentDecimals > 0) { updateParent(parseFloat(truncateFixed(currentValue, currentDecimals - 1))) } else { updateParent(Math.floor(currentValue / 10)) } break; case '.': setCurrentDecimals(0) break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': const digit = parseInt(key, 10) // If we're still in the whole numbers if(currentDecimals < 0) { updateParent(currentValue * 10 + digit) } else if (currentDecimals === 0) { // Add decimal setCurrentDecimals(dec => dec + 1) updateParent(parseFloat(currentValue.toFixed(0) + '.' + digit)) } else if (currentDecimals < numDecimals) { // Add to existing decimals setCurrentDecimals(dec => dec + 1) updateParent(parseFloat(currentValue.toFixed(currentDecimals) + digit)) } else { // Can we play a tick noise of some sort? } break; default: return; } ev.preventDefault(); } const filledText = ((prefix + ' ') || '') + (Math.floor(currentValue) || '0') + (currentDecimals >= 0 ? '.' : '') + (currentDecimals > 0 ? currentValue.toFixed(currentDecimals).split('.')[1] : '') const remainingText = (currentDecimals < 0 ? '.' : '') + (numDecimals !== undefined && currentDecimals < numDecimals ? '0'.repeat(numDecimals - Math.max(currentDecimals, 0)) : '') return (
{}} onKeyDown={onKeyDown} onBlur={onBlur} />
{filledText} {remainingText}
{(hint || error) && {error || (isValid ? '' : hint)}}
) }