Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 1x 1x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x 25x | import { FC } from 'react'
import { NumericFormat } from 'react-number-format'
import { InputProps } from '@/shared/ui'
import { Input } from '@tmk/ui-kit'
export interface NumericInputProps extends Omit<InputProps, 'value' | 'type'> {
decimalScale?: number
thousandSeparator?: string
value: string | number | null
allowNegative?: boolean
onlyInteger?: boolean
}
export const NumericInput: FC<NumericInputProps> = ({ name, label, onlyInteger = false, ...rest }) => {
const isNumberCodeKey = (key: string) => {
const keyValue = parseInt(key, 10)
return !isNaN(keyValue) && keyValue >= 0 && keyValue <= 9
}
const isLetterCodeKey = (key: string) => {
const keyValue = key.charCodeAt(0)
return (
(keyValue >= 65 && keyValue <= 90) ||
(keyValue >= 97 && keyValue <= 122) ||
(keyValue >= 1040 && keyValue <= 1103)
)
}
return (
<NumericFormat
{...rest}
id={name}
name={name}
customInput={Input}
value={rest.value === null ? '' : rest.value}
label={label}
// @ts-ignore - у NumericFormat неправильно указан тип в интерфейсе, поэтому приходится использовать ignore
// #50710 - убрал number, как так уже не нужно но возможно понадобится в будущем
//type='number'
onKeyDown={e => {
const controlKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Backspace', 'Delete', 'Tab']
const isNotNumberKey = isLetterCodeKey(e.key)
const isControllingKey = controlKeys.includes(e.key)
if (onlyInteger && !isNumberCodeKey(e.key) && !isControllingKey) {
e.preventDefault()
}
if (isNotNumberKey && !isControllingKey) {
e.preventDefault()
}
const selectionStart = e.currentTarget.selectionStart || 0
if (!rest.allowNegative) {
if (e.key === '-') {
e.preventDefault()
}
}
// Кастомная валидация для decimalScale, которая в библиотеке почему-то не срабатывает
if (rest.decimalScale) {
const value = e.target.value
const dotIndex = value.indexOf('.')
const isAfterDot = selectionStart > dotIndex
if (dotIndex !== -1 && value.length - dotIndex > rest.decimalScale && isNumberCodeKey(e.key) && isAfterDot) {
e.preventDefault()
}
}
}}
/>
)
}
|