new-personal-site/components/lib/form/Input/NumberInputButtons.tsx
Benjamin Toby a0a0ab8ee4 Updates
2025-07-20 10:35:54 +01:00

122 lines
3.6 KiB
TypeScript

import React from "react";
import Row from "../../layout/Row";
import { Info, Minus, Plus } from "lucide-react";
import twuiNumberfy from "../../utils/numberfy";
import { InputProps } from ".";
let pressInterval: any;
let pressTimeout: any;
type Props = Pick<InputProps<any>, "min" | "max" | "step"> & {
updateValue: (v: string) => void;
getNormalizedValue: (v: string) => void;
buttonDownRef: React.MutableRefObject<boolean>;
inputRef: React.RefObject<HTMLInputElement | null>;
};
/**
* # Input Number Text Buttons
*/
export default function NumberInputButtons({
getNormalizedValue,
updateValue,
min,
max,
step,
buttonDownRef,
inputRef,
}: Props) {
const PRESS_TRIGGER_TIMEOUT = 200;
const DEFAULT_STEP = 1;
function incrementDownPress() {
window.clearTimeout(pressTimeout);
pressTimeout = setTimeout(() => {
buttonDownRef.current = true;
pressInterval = setInterval(() => {
increment();
}, 50);
}, PRESS_TRIGGER_TIMEOUT);
}
function incrementDownCancel() {
buttonDownRef.current = false;
window.clearTimeout(pressTimeout);
window.clearInterval(pressInterval);
}
function decrementDownPress() {
pressTimeout = setTimeout(() => {
buttonDownRef.current = true;
pressInterval = setInterval(() => {
decrement();
}, 50);
}, PRESS_TRIGGER_TIMEOUT);
}
function decrementDownCancel() {
buttonDownRef.current = false;
window.clearTimeout(pressTimeout);
window.clearInterval(pressInterval);
}
function increment() {
const existingValue = inputRef.current?.value;
const existingNumberValue = twuiNumberfy(existingValue);
if (max && existingNumberValue >= twuiNumberfy(max)) {
return updateValue(String(max));
} else if (min && existingNumberValue < twuiNumberfy(min)) {
return updateValue(String(min));
} else {
updateValue(
String(existingNumberValue + twuiNumberfy(step || DEFAULT_STEP))
);
}
}
function decrement() {
const existingValue = inputRef.current?.value;
const existingNumberValue = twuiNumberfy(existingValue);
if (min && existingNumberValue <= twuiNumberfy(min)) {
updateValue(String(min));
} else {
updateValue(
String(existingNumberValue - twuiNumberfy(step || DEFAULT_STEP))
);
}
}
return (
<Row className="flex-nowrap gap-1 -my-2 ml-auto -mr-2">
<Row
className="rounded-full w-8 h-8 cursor-pointer touch-none select-none justify-center"
onClick={(e) => {
e.preventDefault();
decrement();
}}
onMouseDown={decrementDownPress}
onTouchStart={decrementDownPress}
onMouseUp={decrementDownCancel}
onTouchEnd={decrementDownCancel}
>
<Minus size={20} />
</Row>
<Row
className="rounded-full w-8 h-8 cursor-pointer touch-none select-none justify-center"
onClick={(e) => {
e.preventDefault();
increment();
}}
onMouseDown={incrementDownPress}
onTouchStart={incrementDownPress}
onMouseUp={incrementDownCancel}
onTouchEnd={incrementDownCancel}
>
<Plus size={20} />
</Row>
</Row>
);
}