/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the Chameleon License found in the * LICENSE file in the root directory of this source tree. */ import { ChangeEvent, useEffect, useState } from "react"; export type InputRangeProps = { value: number; step?: number; min?: number; max?: number; integerOnly?: boolean; slider?: boolean; optional?: boolean; placeholder?: string; label?: string; className?: string; onValueChange: (n: any) => void; }; export function InputRange({ value, onValueChange, step = 0.1, min = 0, max = 1, integerOnly = false, slider = true, optional = false, placeholder, label, className, }: InputRangeProps) { const [tempValue, setTempValue] = useState(""); const [tempOptionalValue, setTempOptionalValue] = useState(0); const [valid, setValid] = useState(true); const [skipped, setSkipped] = useState(optional); /* * Here we first validate the value and then run the update callback if the value is valid. */ function validate(valueString: string, updateFn: (value: any) => void) { setTempValue(valueString); const parseFn = integerOnly ? parseInt : parseFloat; const n = parseFn(valueString) || NaN; const integerCheck = integerOnly ? Math.floor(n) === n : true; if (skipped) { updateFn(null); setValid(true); } else if (n && n >= min && n <= max && integerCheck) { updateFn(n); setValid(true); } else { setValid(false); } } function handleOptional(evt: ChangeEvent) { // if checked, skip should be false if (evt.currentTarget.checked === skipped) { setSkipped(!skipped); } } useEffect(() => { setTempValue(`${value}`); }, [value, setTempValue]); useEffect(() => { if (skipped) { setTempOptionalValue(value); validate("", onValueChange); } else if (optional && !value) { validate(`${tempOptionalValue || min}`, onValueChange); } }, [skipped, tempOptionalValue, setTempOptionalValue]); const input = (
{slider && ( validate(evt.currentTarget.value, onValueChange)} /> )} validate(evt.currentTarget.value, onValueChange)} className={`input ${valid ? "border-gray-200" : "border-red-300"} w-24`} />
); return label ? (
{input}
) : ( input ); }