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

@ -190,7 +190,7 @@ describe('IndexMethod', () => {
expect(screen.getByText(/stepTwo\.qualified/)).toBeInTheDocument()
})
it('should handle keywordNumber of 0', () => {
it('should handle minimum keywordNumber', () => {
render(<IndexMethod {...defaultProps} keywordNumber={0} />)
const input = screen.getByRole('textbox')
expect(input).toHaveValue('0')

View File

@ -24,9 +24,8 @@ describe('KeyWordNumber', () => {
it('should render tooltip with question icon', () => {
render(<KeyWordNumber {...defaultProps} />)
// RiQuestionLine renders as an svg
const container = screen.getByText(/form\.numberOfKeywords/).closest('div')?.parentElement
const questionIcon = container?.querySelector('svg')
const questionIcon = container?.querySelector('.i-ri-question-line')
expect(questionIcon).toBeInTheDocument()
})
@ -88,15 +87,22 @@ describe('KeyWordNumber', () => {
expect(handleChange).toHaveBeenCalled()
})
it('should not call onKeywordNumberChange with undefined value', () => {
it('should reset to 0 when users clear the input', () => {
const handleChange = vi.fn()
render(<KeyWordNumber {...defaultProps} onKeywordNumberChange={handleChange} />)
const input = screen.getByRole('textbox')
fireEvent.change(input, { target: { value: '' } })
// When value is empty/undefined, handleInputChange should not call onKeywordNumberChange
expect(handleChange).not.toHaveBeenCalled()
expect(handleChange).toHaveBeenCalledWith(0)
})
it('should clamp out-of-range edits before updating state', () => {
const handleChange = vi.fn()
render(<KeyWordNumber {...defaultProps} onKeywordNumberChange={handleChange} />)
fireEvent.change(screen.getByRole('textbox'), { target: { value: '60' } })
expect(handleChange).toHaveBeenLastCalledWith(50)
})
})

View File

@ -1,10 +1,19 @@
import { RiQuestionLine } from '@remixicon/react'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { InputNumber } from '@/app/components/base/input-number'
import Slider from '@/app/components/base/slider'
import Tooltip from '@/app/components/base/tooltip'
import {
NumberField,
NumberFieldControls,
NumberFieldDecrement,
NumberFieldGroup,
NumberFieldIncrement,
NumberFieldInput,
} from '@/app/components/base/ui/number-field'
const MIN_KEYWORD_NUMBER = 0
const MAX_KEYWORD_NUMBER = 50
type KeyWordNumberProps = {
keywordNumber: number
@ -17,35 +26,44 @@ const KeyWordNumber = ({
}: KeyWordNumberProps) => {
const { t } = useTranslation()
const handleInputChange = useCallback((value: number | undefined) => {
if (value)
onKeywordNumberChange(value)
const handleInputChange = useCallback((value: number | null) => {
onKeywordNumberChange(value ?? MIN_KEYWORD_NUMBER)
}, [onKeywordNumberChange])
return (
<div className="flex items-center gap-x-1">
<div className="flex grow items-center gap-x-0.5">
<div className="system-xs-medium truncate text-text-secondary">
<div className="truncate text-text-secondary system-xs-medium">
{t('form.numberOfKeywords', { ns: 'datasetSettings' })}
</div>
<Tooltip
popupContent="number of keywords"
popupContent={t('form.numberOfKeywords', { ns: 'datasetSettings' })}
>
<RiQuestionLine className="h-3.5 w-3.5 text-text-quaternary" />
<span className="i-ri-question-line h-3.5 w-3.5 text-text-quaternary" />
</Tooltip>
</div>
<Slider
className="mr-3 w-[206px] shrink-0"
value={keywordNumber}
max={50}
min={MIN_KEYWORD_NUMBER}
max={MAX_KEYWORD_NUMBER}
onChange={onKeywordNumberChange}
/>
<InputNumber
wrapperClassName="shrink-0 w-12"
type="number"
<NumberField
className="w-12 shrink-0"
min={MIN_KEYWORD_NUMBER}
max={MAX_KEYWORD_NUMBER}
value={keywordNumber}
onChange={handleInputChange}
/>
onValueChange={handleInputChange}
>
<NumberFieldGroup size="regular">
<NumberFieldInput size="regular" />
<NumberFieldControls>
<NumberFieldIncrement size="regular" />
<NumberFieldDecrement size="regular" />
</NumberFieldControls>
</NumberFieldGroup>
</NumberField>
</div>
)
}