добрый вечер.
нужна помощь с компонентом инпута.
что есть на данный момент
1) есть инпут. по дефолту в пропсе type стоит number. в онченже велью прогоняется через регулярку, которая отсекает знаки, и на выходе не вводится ничего кроме целых чисел.
2) пропс с максимально допустимым числом.
3) есть псевдо кнопки + - которые добавляют\уменшают велью на какое-то n-число.
4) если число большое, вида 1000000, то на onBlur велью конвертируется в стрингу, подставляются запятые и велью становится 1,000,000. на OnFocus, соотвественно, он опять number, и запятые пропадают.
собственно задача - при кликах на + - я попадаю в онблюр и не могу сделать декремент\инкремент потому что он в этот момент стринга.
единстенное до чего додумался, это переключение в фокус и нулевой таймаут на блюр, но это не сработало.
const Input = ({
onChange,
disabled,
numStep = 1,
min = 0,
max,
value,
placeholder,
className,
type = 'number',
onBlur,
onFocus,
isPriceInput
}) => {
// STATES
const [isFocused, setIsFocused] = useState(false);
const [isEditing, setEditing] = useState(false);
// HANDLES
const handle = {
change: (e) => {
let inputValue = e.target ? onlyNumbers(e.target.value) : e;
if (inputValue !== '') {
// inputValue = inputValue.toString().replace(/\D/g, '');
inputValue = parseFloat(inputValue) || '';
if (min && +min > +inputValue) {
inputValue = +min;
} else if (max && +max < +inputValue) inputValue = +max;
}
onChange(inputValue.toString());
},
toggleEdit: () => {
setEditing(!isEditing);
onChange('');
},
focus: (e) => {
setIsFocused(true);
if (isPriceInput) onChange(removeComma(value));
if (onFocus) onFocus(e);
},
blur: (e) => {
setIsFocused(false);
setEditing(false);
if (isPriceInput) onChange(addCommas(value));
if (onBlur) onBlur(e);
},
decrement: () => {
handle.change(+value - +numStep);
},
increment: () => {
handle.change(+value + +numStep);
}
};
useEffect(() => {
if (isEditing || isFocused) inputRef.current.focus();
}, [isEditing, isFocused]);
const uniProps = {
className: `input ${className}`,
placeholder,
value: value || '',
disabled,
onChange: handle.change,
onFocus: handle.focus,
onBlur: handle.blur,
onKeyUp: handle.keyUp,
min,
max,
...(maskChar ? { maskChar } : {}),
...(formatChars ? { formatChars } : {})
};
return (
<div className='input__wrap'>
<input {...uniProps} ref={inputRef} type={type} />
<div className='input__nums'>
<button
onClick={() => handle.decrement()}
className={cn(`input__num-btn`, { disabled: value <= min })}
>
<Minus />
</button>
<button
onClick={() => handle.increment()}
className={cn(`input__num-btn`, { disabled: value >= max })}
>
<Plus />
</button>
</div>
</div>
);
export default Input;
addCommas: (value) => {
value = value.toString();
const isFraction = value.includes('.');
const valueBeforeDot = isFraction
? value.slice(0, value.indexOf('.'))
: value;
const intPart = valueBeforeDot
.split('')
.reverse()
.reduce(
(acc, item, idx) =>
idx % 3 === 0 && idx !== 0 ? [...acc, ',', item] : [...acc, item],
[]
)
.reverse()
.join('');
return isFraction ? intPart + value.slice(value.indexOf('.')) : intPart;
},
removeComma: (value) => {
return parseFloat(value.replace(/\,/g, ''));
}
},
onlyNumbers: (value, isDot = false) => {
const val =
value.slice(0, 1) !== '0' && value.slice(0, 1) !== '.'
? value
: value.slice(1);
if (isDot) return twoDigitAfterDot(val.replace(/[^0-9.]/g, ''));
else return +val.toString().replace(/\D/g, '');
},