refactor(web): number inputs to use Base UI NumberField (#33539)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
yyh
2026-03-17 18:45:02 +08:00
committed by GitHub
parent d1961c261e
commit 3db1ba36e0
30 changed files with 1340 additions and 1273 deletions

View File

@ -112,6 +112,63 @@ describe('ParamItem', () => {
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 0.8)
})
it('should reset the textbox and slider when users clear the input', async () => {
const user = userEvent.setup()
const StatefulParamItem = () => {
const [value, setValue] = useState(defaultProps.value)
return (
<ParamItem
{...defaultProps}
value={value}
onChange={(key: string, nextValue: number) => {
defaultProps.onChange(key, nextValue)
setValue(nextValue)
}}
/>
)
}
render(<StatefulParamItem />)
const input = screen.getByRole('textbox')
await user.clear(input)
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 0)
expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow', '0')
await user.tab()
expect(input).toHaveValue('0')
})
it('should clamp out-of-range text edits before updating state', async () => {
const user = userEvent.setup()
const StatefulParamItem = () => {
const [value, setValue] = useState(defaultProps.value)
return (
<ParamItem
{...defaultProps}
value={value}
onChange={(key: string, nextValue: number) => {
defaultProps.onChange(key, nextValue)
setValue(nextValue)
}}
/>
)
}
render(<StatefulParamItem />)
const input = screen.getByRole('textbox')
await user.clear(input)
await user.type(input, '1.5')
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 1)
expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow', '100')
})
it('should pass scaled value to slider when max < 5', () => {
render(<ParamItem {...defaultProps} value={0.5} />)
const slider = screen.getByRole('slider')

View File

@ -3,7 +3,14 @@ import type { FC } from 'react'
import Slider from '@/app/components/base/slider'
import Switch from '@/app/components/base/switch'
import Tooltip from '@/app/components/base/tooltip'
import { InputNumber } from '../input-number'
import {
NumberField,
NumberFieldControls,
NumberFieldDecrement,
NumberFieldGroup,
NumberFieldIncrement,
NumberFieldInput,
} from '../ui/number-field'
type Props = {
className?: string
@ -36,7 +43,7 @@ const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1,
}}
/>
)}
<span className="system-sm-semibold mr-1 text-text-secondary">{name}</span>
<span className="mr-1 text-text-secondary system-sm-semibold">{name}</span>
{!noTooltip && (
<Tooltip
triggerClassName="w-4 h-4 shrink-0"
@ -47,20 +54,22 @@ const ParamItem: FC<Props> = ({ className, id, name, noTooltip, tip, step = 0.1,
</div>
<div className="mt-1 flex items-center">
<div className="mr-3 flex shrink-0 items-center">
<InputNumber
<NumberField
disabled={!enable}
type="number"
min={min}
max={max}
step={step}
amount={step}
size="regular"
value={value}
onChange={(value) => {
onChange(id, value)
}}
className="w-[72px]"
/>
onValueChange={nextValue => onChange(id, nextValue ?? min)}
>
<NumberFieldGroup size="regular">
<NumberFieldInput size="regular" className="w-[72px]" />
<NumberFieldControls>
<NumberFieldIncrement size="regular" />
<NumberFieldDecrement size="regular" />
</NumberFieldControls>
</NumberFieldGroup>
</NumberField>
</div>
<div className="flex grow items-center">
<Slider