fix: debounce slider to avoid laggy behavior (#18980)

resolves #18856 
resolves coder/internal#753
This commit is contained in:
Jaayden Halko
2025-07-22 11:15:43 -04:00
committed by GitHub
parent 99adb4a15b
commit dd2fb896eb
@@ -77,14 +77,14 @@ export const DynamicParameter: FC<DynamicParameterProps> = ({
/>
<div className="max-w-lg">
{parameter.form_type === "input" ||
parameter.form_type === "textarea" ? (
parameter.form_type === "textarea" ||
parameter.form_type === "slider" ? (
<DebouncedParameterField
id={id}
parameter={parameter}
value={value}
onChange={onChange}
disabled={disabled}
isPreset={isPreset}
/>
) : (
<ParameterField
@@ -250,7 +250,6 @@ interface DebouncedParameterFieldProps {
onChange: (value: string) => void;
disabled?: boolean;
id: string;
isPreset?: boolean;
}
const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
@@ -259,7 +258,6 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
onChange,
disabled,
id,
isPreset,
}) => {
const [localValue, setLocalValue] = useState(
value !== undefined ? value : validValue(parameter.value),
@@ -271,13 +269,13 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
const prevDebouncedValueRef = useRef<string | undefined>();
const prevValueRef = useRef(value);
// This is necessary in the case of fields being set by preset parameters
// Necessary for dynamic defaults or fields being set by preset parameters
useEffect(() => {
if (isPreset && value !== undefined && value !== prevValueRef.current) {
if (value !== undefined && value !== prevValueRef.current) {
setLocalValue(value);
prevValueRef.current = value;
}
}, [value, isPreset]);
}, [value]);
useEffect(() => {
// Only call onChangeEvent if debouncedLocalValue is different from the previously committed value
@@ -408,6 +406,31 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
</Stack>
);
}
case "slider": {
const numericValue = Number.isFinite(Number(localValue))
? Number(localValue)
: 0;
const { validation_min: min = 0, validation_max: max = 100 } =
parameter.validations[0] ?? {};
return (
<div className="flex flex-row items-baseline gap-3">
<Slider
id={id}
className="mt-2"
value={[numericValue]}
onValueChange={([value]) => {
setLocalValue(value.toString());
}}
min={min ?? undefined}
max={max ?? undefined}
disabled={disabled}
/>
<span className="w-4 font-medium">{numericValue}</span>
</div>
);
}
}
};
@@ -564,25 +587,6 @@ const ParameterField: FC<ParameterFieldProps> = ({
</div>
);
case "slider":
return (
<div className="flex flex-row items-baseline gap-3">
<Slider
id={id}
className="mt-2"
value={[Number.isFinite(Number(value)) ? Number(value) : 0]}
onValueChange={([value]) => {
onChange(value.toString());
}}
min={parameter.validations[0]?.validation_min ?? 0}
max={parameter.validations[0]?.validation_max ?? 100}
disabled={disabled}
/>
<span className="w-4 font-medium">
{Number.isFinite(Number(value)) ? value : "0"}
</span>
</div>
);
case "error":
return <Diagnostics diagnostics={parameter.diagnostics} />;
}