122 lines
3.6 KiB
TypeScript
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>
|
|
);
|
|
}
|