Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(inputNumber): correct onChange, onOverlimit event triggering timing when async & sync #2509

Merged
merged 11 commits into from
Aug 2, 2024
17 changes: 17 additions & 0 deletions src/packages/inputnumber/__tests__/inputnumber.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,20 @@ test('allowEmpty', () => {
expect(container.querySelector('input')?.value).toBe('')
})
})

test('should overlimit when input', () => {
const change = vi.fn()
const overlimit = vi.fn()
const { container } = render(
<InputNumber
defaultValue={2}
max={100}
onChange={change}
onOverlimit={overlimit}
/>
)
const input = container.querySelectorAll('input')[0]
input.value = '200'
fireEvent.input(input)
expect(change).toBeCalled()
})
12 changes: 10 additions & 2 deletions src/packages/inputnumber/demos/h5/demo3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import React from 'react'
import { InputNumber, Toast } from '@nutui/nutui-react'

const Demo3 = () => {
const overlimit = () => {
const overlimit = (e: any) => {
Toast.show({ content: '超出限制事件触发', icon: 'warn' })
}
return (
<InputNumber defaultValue={10} min={10} max={20} onOverlimit={overlimit} />
<InputNumber
defaultValue={10}
min={10}
max={20}
onOverlimit={overlimit}
onChange={(v) => {
console.log('onChange', v)
}}
/>
)
}
export default Demo3
15 changes: 14 additions & 1 deletion src/packages/inputnumber/demos/h5/demo8.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,26 @@ import { InputNumber, Toast } from '@nutui/nutui-react'

const Demo8 = () => {
const [inputValue, setInputValue] = useState(0)
const overlimit = (e: any) => {
console.log('超出限制事件触发', e)
}
const onChange = (value: string | number) => {
Toast.show({ icon: 'loading', content: '异步演示2秒后更改' })
console.log('onChange', value)
setTimeout(() => {
setInputValue(Number(value))
Toast.clear()
}, 2000)
}
return <InputNumber value={inputValue} min={-6} onChange={onChange} async />
return (
<InputNumber
value={inputValue}
min={-6}
max={6}
onChange={onChange}
onOverlimit={overlimit}
async
/>
)
}
export default Demo8
3 changes: 3 additions & 0 deletions src/packages/inputnumber/demos/taro/demo3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const Demo3 = () => {
min={10}
max={20}
onOverlimit={overlimit}
onChange={(v) => {
console.log('onChange', v)
}}
/>
<Toast
type={toastType}
Expand Down
13 changes: 12 additions & 1 deletion src/packages/inputnumber/demos/taro/demo8.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,27 @@ const Demo8 = () => {
SetToastType(type)
SetShow(true)
}
const overlimit = (e: any) => {
console.log('超出限制事件触发', e)
}
const onChange = (value: string | number) => {
toastShow('异步演示 2 秒后更改', 'loading')
console.log('onChange', value)
setTimeout(() => {
setInputValue(Number(value))
SetShow(false)
}, 2000)
}
return (
<>
<InputNumber value={inputValue} min="-6" onChange={onChange} async />
<InputNumber
value={inputValue}
min={-6}
max={6}
onChange={onChange}
onOverlimit={overlimit}
async
/>
<Toast
type={toastType}
visible={show}
Expand Down
45 changes: 34 additions & 11 deletions src/packages/inputnumber/inputnumber.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface InputNumberProps extends BasicComponent {
formatter?: (value?: string | number) => string
onPlus: (e: React.MouseEvent) => void
onMinus: (e: React.MouseEvent) => void
onOverlimit: (e: React.MouseEvent) => void
onOverlimit: (e: React.MouseEvent | ChangeEvent<HTMLInputElement>) => void
onBlur: (e: React.FocusEvent<HTMLInputElement>) => void
onFocus: (e: React.FocusEvent<HTMLInputElement>) => void
onChange: (
Expand Down Expand Up @@ -181,7 +181,25 @@ export const InputNumber: FunctionComponent<
if (text === '-') return null
return text
}
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const clampValue = (valueStr: string | null) => {
if (valueStr === null) return defaultValue
const val = Number(parseFloat(valueStr || '0').toFixed(digits))
return Math.max(Number(min), Math.min(Number(max), val))
}
const handleValueChange = (
valueStr: string | null,
e: React.ChangeEvent<HTMLInputElement>
) => {
const val = clampValue(valueStr)
// input暂不触发onOverlimit
// if (val !== Number(e.target.value)) {
// onOverlimit?.(e)
// }
if (val !== Number(shadowValue)) {
onChange?.(val, e)
}
}
const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {
// 设置 input 值, 在 blur 时格式化
setInputValue(e.target.value)
const valueStr = parseValue(e.target.value)
Expand All @@ -192,11 +210,9 @@ export const InputNumber: FunctionComponent<
setShadowValue(defaultValue)
}
} else {
setShadowValue(valueStr as any)
}
if (!async) {
onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
setShadowValue(clampValue(valueStr) as any)
}
!async && handleValueChange(valueStr, e)
}
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
setFocused(true)
Expand All @@ -205,15 +221,22 @@ export const InputNumber: FunctionComponent<
? bound(Number(shadowValue), Number(min), Number(max)).toString()
: ''
)
onFocus && onFocus(e)
onFocus?.(e)
}
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
setFocused(false)
onBlur && onBlur(e)
if (async) {
const valueStr = parseValue(e.target.value)
onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
onBlur?.(e)
const valueStr = parseValue(e.target.value)
if (valueStr === null) {
if (allowEmpty) {
setShadowValue(null)
} else {
setShadowValue(defaultValue)
}
} else {
setShadowValue(clampValue(valueStr) as any)
}
async && handleValueChange(valueStr, e)
}

return (
Expand Down
43 changes: 33 additions & 10 deletions src/packages/inputnumber/inputnumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
formatter?: (value?: string | number) => string
onPlus: (e: React.MouseEvent) => void
onMinus: (e: React.MouseEvent) => void
onOverlimit: (e: React.MouseEvent) => void
onOverlimit: (e: React.MouseEvent | ChangeEvent<HTMLInputElement>) => void
onBlur: (e: React.FocusEvent<HTMLInputElement>) => void
onFocus: (e: React.FocusEvent<HTMLInputElement>) => void
onChange: (
Expand Down Expand Up @@ -177,6 +177,24 @@
if (text === '-') return null
return text
}
const clampValue = (valueStr: string | null) => {
if (valueStr === null) return defaultValue
const val = Number(parseFloat(valueStr || '0').toFixed(digits))
return Math.max(Number(min), Math.min(Number(max), val))
}
const handleValueChange = (
valueStr: string | null,
e: React.ChangeEvent<HTMLInputElement>
) => {
const val = clampValue(valueStr)
// input暂不触发onOverlimit
// if (val !== Number(e.target.value)) {
// onOverlimit?.(e)
// }
if (val !== Number(shadowValue)) {
onChange?.(val, e)
}
}
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// 设置 input 值, 在 blur 时格式化
setInputValue(e.target.value)
Expand All @@ -188,11 +206,9 @@
setShadowValue(defaultValue)
}
} else {
setShadowValue(valueStr as any)
}
if (!async) {
onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
setShadowValue(clampValue(valueStr) as any)
}
!async && handleValueChange(valueStr, e)
}
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
setFocused(true)
Expand All @@ -201,15 +217,22 @@
? bound(Number(shadowValue), Number(min), Number(max)).toString()
: ''
)
onFocus && onFocus(e)
onFocus?.(e)
}
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
setFocused(false)
onBlur && onBlur(e)
if (async) {
const valueStr = parseValue(e.target.value)
onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
onBlur?.(e)
const valueStr = parseValue(e.target.value)
if (valueStr === null) {
if (allowEmpty) {
setShadowValue(null)
} else {
setShadowValue(defaultValue)
}

Check warning on line 231 in src/packages/inputnumber/inputnumber.tsx

View check run for this annotation

Codecov / codecov/patch

src/packages/inputnumber/inputnumber.tsx#L227-L231

Added lines #L227 - L231 were not covered by tests
} else {
setShadowValue(clampValue(valueStr) as any)
}
async && handleValueChange(valueStr, e)
Comment on lines +224 to +235
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

代码无误,但请添加测试!

handleBlur 函数基于夹紧输入设置影子值,并在异步模式下有条件地调用 handleValueChange

根据静态分析工具的提示,以下代码行未覆盖测试:#L226-L230。请添加相应的测试。

您希望我生成单元测试代码还是创建一个 GitHub issue 来跟踪此任务?

Tools
GitHub Check: codecov/patch

[warning] 226-230: src/packages/inputnumber/inputnumber.tsx#L226-L230
Added lines #L226 - L230 were not covered by tests

}

return (
Expand Down
Loading