I have a custom input component that shows a value, it has 2 icons that increase or decrease the value. But now I want to be able to call the increment or decrement function when the user long presses on the button such that the input just increases/decreases in real-time. Just like how the default input field with type number works.
The input looks like this
This is the component
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'
import { cn } from '@/lib/utils'
import { useLongPress } from '@uidotdev/usehooks'
interface AdjustableQuantityProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string
inputWrapperStyle?: string
inputStyle?: string
value: number | undefined
valueSuffix?: string
onChangeHandler: (value: number | undefined) => void
onIncrementHandler?: (value: number | undefined) => void
onDecrementHandler?: (value: number | undefined) => void
min?: number
max?: number
hideZeroValue?: boolean
enableLongPress?: boolean
}
const AdjustableQuantity: React.FC<AdjustableQuantityProps> = ({
label = '',
inputWrapperStyle = '',
inputStyle = '',
value,
valueSuffix = '',
onChangeHandler,
onIncrementHandler,
onDecrementHandler,
min = 1,
max = 100,
hideZeroValue = false,
enableLongPress = false,
...rest
}) => {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value.replace(/[^0-9]/g, '')
const numericValue = inputValue === '' ? undefined : Number(inputValue)
onChangeHandler(numericValue)
}
const handleIncrement = () => {
if (hideZeroValue && value === undefined) {
onChangeHandler(0)
} else if (value !== undefined && value < max) {
onIncrementHandler ? onIncrementHandler(value) : onChangeHandler(value + 1)
}
}
const handleDecrement = () => {
if (hideZeroValue && value === 0) {
onChangeHandler(undefined)
} else if (value !== undefined && value > min) {
onDecrementHandler ? onDecrementHandler(value) : onChangeHandler(value - 1)
}
}
const longPressIncrement = useLongPress(() => handleIncrement(), {
onStart: (event) => console.log('Press started'),
onFinish: (event) => console.log('Press Finished'),
onCancel: (event) => console.log('Press cancelled'),
threshold: 500
})
// const longPressDecrement = useLongPress(() => handleDecrement(), {
const longPressDecrement = useLongPress(() => handleDecrement(), {
onStart: (event) => console.log('Press started'),
onFinish: (event) => console.log('Press Finished'),
onCancel: (event) => console.log('Press cancelled'),
threshold: 500
})
return (
<div className="flex items-center">
{label && <p className="mr-2 text-14 capitalize">{label}</p>}
<div
className={cn(
'mr-3 flex items-center justify-between rounded-[0.313rem] border border-tenzr-neutral-400 p-2 h-[2.25rem]',
inputWrapperStyle
)}
>
<input
type="text"
onChange={(e) => {
if (hideZeroValue) {
handleChange(e)
} else {
onChangeHandler(Number(e.target.value))
}
}}
value={hideZeroValue && value === undefined ? '' : value}
min={0}
className={`flex w-1/5 items-center justify-center bg-transparent focus:outline-none ${inputStyle}`}
{...rest}
/>
{valueSuffix}
<div className="flex items-center space-x-2">
<KeyboardArrowDownIcon
{...(enableLongPress && longPressDecrement)}
onClick={handleDecrement}
className={`${
(hideZeroValue && value === 0) || (value !== undefined && value > min)
? 'cursor-pointer'
: 'cursor-not-allowed text-gray-300'
}`}
/>
<KeyboardArrowUpIcon
{...(enableLongPress && longPressIncrement)}
onClick={handleIncrement}
className={`${
(value === undefined && hideZeroValue) || (value !== undefined && value < max)
? 'cursor-pointer'
: 'cursor-not-allowed text-gray-300'
}`}
/>
</div>
</div>
</div>
)
}
export default AdjustableQuantity
Currently, the function is called onLongpress but the result does not continue to update. It just calls once.
This is how the component is being called.
value={weight}
onChangeHandler={(value: number | undefined) => setWeight(value)}
inputWrapperStyle="h-[2.5rem] w-[7.625rem] pl-4"
inputStyle="!w-full"
min={0}
hideZeroValue={true}
enableLongPress
/>