mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): migrate shared/numerical_input from @tremor NumberInput to shadcn Input
- @tremor NumberInput \u2192 shadcn Input type=number. - onChange contract preserved: numeric value, null, or undefined (tremor convention). Empty string or NaN parses as null. - value / defaultValue accepted as number | string | null | undefined. - 'precision' prop accepted for back-compat but not enforced (HTML number input doesn't clamp decimal precision; callers round before persisting). - onWheel \u2192 blur to disable accidental scroll-to-change. - All existing callers keep working \u2014 this component is used from organization_view, AccessGroupBaseForm, edit_user, tag_info, CreateTagModal, cache_settings, and others; all are already passing (number | null | undefined) to onChange. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
372fdedf5b
commit
6e3107d68c
1 changed files with 61 additions and 14 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import { NumberInput } from "@tremor/react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface NumericalInputProps {
|
||||
step?: number;
|
||||
|
|
@ -7,20 +8,33 @@ interface NumericalInputProps {
|
|||
placeholder?: string;
|
||||
min?: number;
|
||||
max?: number;
|
||||
onChange?: any; // Using any to avoid type conflicts with Tremor's NumberInput
|
||||
// Callers pass either an onChange(numberOrNull) signature (the @tremor
|
||||
// contract this component used to expose) or a React.ChangeEventHandler.
|
||||
// We accept both at the signature boundary and bridge to number|null|undefined
|
||||
// inside the component.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChange?: any;
|
||||
value?: number | string | null | undefined;
|
||||
defaultValue?: number | string | null | undefined;
|
||||
name?: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
precision?: number;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reusable numerical input component
|
||||
* @param {Object} props - Component props
|
||||
* @param {number} [props.step=0.01] - Step increment for the input
|
||||
* @param {Object} [props.style] - Custom styles to apply
|
||||
* @param {string} [props.placeholder="Enter a numerical value"] - Placeholder text
|
||||
* @param {number} [props.min] - Minimum value
|
||||
* @param {number} [props.max] - Maximum value
|
||||
* @param {Function} [props.onChange] - On change handler
|
||||
* @param {any} props.rest - Additional props passed to NumberInput
|
||||
* Numerical input. Phase-1 shadcn-migrated replacement for the former
|
||||
* @tremor NumberInput. Accepts the same prop surface so existing callers
|
||||
* continue to work:
|
||||
* - onChange({number | null | undefined}) \u2014 tremor-style
|
||||
* - value / defaultValue as number | string | null | undefined
|
||||
* - step / min / max / precision / placeholder / style / className / disabled
|
||||
*
|
||||
* `precision` is accepted for API-compat but not enforced (HTML input
|
||||
* type=number does not clamp decimal precision; caller code typically
|
||||
* rounds before persisting).
|
||||
*/
|
||||
const NumericalInput: React.FC<NumericalInputProps> = ({
|
||||
step = 0.01,
|
||||
|
|
@ -29,17 +43,50 @@ const NumericalInput: React.FC<NumericalInputProps> = ({
|
|||
min,
|
||||
max,
|
||||
onChange,
|
||||
value,
|
||||
defaultValue,
|
||||
className,
|
||||
disabled,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
precision,
|
||||
...rest
|
||||
}) => {
|
||||
const toValue = (v: number | string | null | undefined): string => {
|
||||
if (v === null || v === undefined) return "";
|
||||
return String(v);
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!onChange) return;
|
||||
const raw = e.target.value;
|
||||
if (raw === "") {
|
||||
onChange(null);
|
||||
return;
|
||||
}
|
||||
const num = Number(raw);
|
||||
if (Number.isNaN(num)) {
|
||||
onChange(null);
|
||||
return;
|
||||
}
|
||||
onChange(num);
|
||||
};
|
||||
|
||||
return (
|
||||
<NumberInput
|
||||
onWheel={(event) => event.currentTarget.blur()}
|
||||
<Input
|
||||
type="number"
|
||||
onWheel={(event) => (event.currentTarget as HTMLInputElement).blur()}
|
||||
step={step}
|
||||
style={style}
|
||||
placeholder={placeholder}
|
||||
min={min}
|
||||
max={max}
|
||||
onChange={onChange}
|
||||
value={value !== undefined ? toValue(value) : undefined}
|
||||
defaultValue={
|
||||
defaultValue !== undefined ? toValue(defaultValue) : undefined
|
||||
}
|
||||
onChange={handleChange}
|
||||
disabled={disabled}
|
||||
className={cn(className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue