Skip to content

Commit

Permalink
fix(inputnumber): 增加 beforeChange,优化异步逻辑 (#3006)
Browse files Browse the repository at this point in the history
* fix(inputnumber): 增加 beforeChange,优化异步逻辑

* docs: update

* fix: 超最大最小值设置

* fix: review

* fix: harmony
  • Loading branch information
oasis-cloud authored Mar 12, 2025
1 parent f74b3c1 commit 3a94dfe
Show file tree
Hide file tree
Showing 14 changed files with 295 additions and 341 deletions.
57 changes: 33 additions & 24 deletions src/packages/inputnumber/__tests__/inputnumber.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react'
import { render, fireEvent, waitFor, act } from '@testing-library/react'
import '@testing-library/jest-dom'

import { InputNumber } from '../inputnumber'
Expand All @@ -9,7 +9,7 @@ test('should render modelValue', () => {
expect(container.querySelector('input')?.value).toBe('12')
})

test('should add step 2 when trigger click plus button', () => {
test('should add step 2 when trigger click plus button', async () => {
const overlimit = vi.fn()
const add = vi.fn()
const change = vi.fn()
Expand All @@ -23,13 +23,16 @@ test('should add step 2 when trigger click plus button', () => {
/>
)
const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0]
fireEvent.click(iconPlus)
await act(async () => {
fireEvent.click(iconPlus)
})

expect(overlimit).not.toBeCalled()
expect(add).toBeCalled()
expect(add).toHaveBeenCalled()
expect(change.mock.calls[0][0]).toBe(3)
})

test('should minis step 2 when trigger click minis button', () => {
test('should minis step 2 when trigger click minis button', async () => {
const overlimit = vi.fn()
const reduce = vi.fn()
const change = vi.fn()
Expand All @@ -43,13 +46,15 @@ test('should minis step 2 when trigger click minis button', () => {
/>
)
const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0]
fireEvent.click(iconMinus)
await act(async () => {
fireEvent.click(iconMinus)
})
expect(overlimit).not.toBeCalled()
expect(reduce).toBeCalled()
expect(change.mock.calls[0][0]).toBe(1)
})

test('should render max props', () => {
test('should render max props', async () => {
const overlimit = vi.fn()
const add = vi.fn()
const change = vi.fn()
Expand All @@ -64,13 +69,15 @@ test('should render max props', () => {
/>
)
const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0]
fireEvent.click(iconPlus)
await act(async () => {
fireEvent.click(iconPlus)
})
expect(overlimit).toBeCalled()
expect(add).toBeCalled()
expect(change).not.toBeCalled()
})

test('should render min props', () => {
test('should render min props', async () => {
const overlimit = vi.fn()
const reduce = vi.fn()
const change = vi.fn()
Expand All @@ -85,7 +92,9 @@ test('should render min props', () => {
/>
)
const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0]
fireEvent.click(iconMinus)
await act(async () => {
fireEvent.click(iconMinus)
})
expect(overlimit).toBeCalled()
expect(reduce).toBeCalled()
expect(change).not.toBeCalled()
Expand All @@ -104,23 +113,27 @@ test('should not trigger click when disabled props to be true', () => {
expect(container.querySelector('input')?.value).toBe('1')
})

test('should not focus input when readOnly props to be true', () => {
test('should not focus input when readOnly props to be true', async () => {
const focus = vi.fn()
const { container } = render(
<InputNumber readOnly defaultValue={2} onFocus={focus} />
)
const iconMinus = container.querySelectorAll('.nut-icon-Minus')[0]
fireEvent.click(iconMinus)
await act(async () => {
fireEvent.click(iconMinus)
})
expect(container.querySelector('input')?.value).toBe('1')
expect(focus).not.toBeCalled()
})

test('should render decimal when step props to be 0.2', () => {
test('should render decimal when step props to be 0.2', async () => {
const { container } = render(
<InputNumber step={0.2} digits={1} defaultValue={2} />
)
const iconPlus = container.querySelectorAll('.nut-icon-Plus')[0]
fireEvent.click(iconPlus)
await act(async () => {
fireEvent.click(iconPlus)
})
expect(container.querySelector('input')?.value).toBe('2.2')
})

Expand Down Expand Up @@ -158,19 +171,15 @@ test('allowEmpty', () => {
})
})

test('should overlimit when input', () => {
const change = vi.fn()
test('should overlimit when input', async () => {
const overlimit = vi.fn()
const { container } = render(
<InputNumber
defaultValue={2}
max={100}
onChange={change}
onOverlimit={overlimit}
/>
<InputNumber defaultValue={2} max={100} onOverlimit={overlimit} />
)
const input = container.querySelectorAll('input')[0]
input.value = '200'
fireEvent.input(input)
expect(change).toBeCalled()
await act(async () => {
fireEvent.input(input)
})
expect(overlimit).toBeCalled()
})
23 changes: 13 additions & 10 deletions src/packages/inputnumber/demos/h5/demo8.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@ const Demo8 = () => {
const overlimit = (e: any) => {
console.log('超出限制事件触发', e)
}
const onChange = (value: string | number) => {

const beforeChange = (value: number | string): Promise<boolean> => {
Toast.show({ icon: 'loading', content: '异步演示2秒后更改' })
console.log('onChange', value)
setTimeout(() => {
setInputValue(Number(value))
Toast.clear()
}, 2000)

return new Promise((resolve) => {
setTimeout(() => {
Toast.clear()
resolve(true)
}, 500)
})
}

return (
<Cell>
<InputNumber
value={inputValue}
min={-6}
max={6}
onChange={onChange}
min={-9999}
beforeChange={beforeChange}
onChange={(value) => setInputValue(Number(value))}
onOverlimit={overlimit}
async
/>
</Cell>
)
Expand Down
39 changes: 24 additions & 15 deletions src/packages/inputnumber/demos/taro/demo8.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,47 @@ import { Cell, InputNumber, Toast } from '@nutui/nutui-react-taro'

const Demo8 = () => {
const [inputValue, setInputValue] = useState(0)
const [show, SetShow] = useState(false)
const [toastMsg, SetToastMsg] = useState('')
const [toastType, SetToastType] = useState('text')
const [show, setShow] = useState(false)
const [toastMsg, setToastMsg] = useState('')
const [toastType, setToastType] = useState('text')

const toastShow = (msg: any, type: string) => {
SetToastMsg(msg)
SetToastType(type)
SetShow(true)
setToastMsg(msg)
setToastType(type)
setShow(true)
}
const overlimit = (e: any) => {
console.log('超出限制事件触发', e)
}
const onChange = (value: string | number) => {

const beforeChange = (value: number | string): Promise<boolean> => {
toastShow('异步演示 2 秒后更改', 'loading')
console.log('onChange', value)
setTimeout(() => {
setInputValue(Number(value))
SetShow(false)
}, 2000)

return new Promise((resolve) => {
setTimeout(() => {
setShow(false)
resolve(true)
}, 500)
})
}

return (
<>
<Cell>
<InputNumber value={inputValue} min="-6" onChange={onChange} async />
<InputNumber
value={inputValue}
min={-9999}
beforeChange={beforeChange}
onChange={(value) => setInputValue(Number(value))}
onOverlimit={overlimit}
/>
</Cell>

<Toast
type={toastType}
visible={show}
content={toastMsg}
onClose={() => {
SetShow(false)
setShow(false)
}}
/>
</>
Expand Down
17 changes: 9 additions & 8 deletions src/packages/inputnumber/doc.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ Asynchronous modification through `change` event and `model-value`
| digits | Set reserved decimal places | `string` \| `number` | `0` |
| disabled | Disable all features | `boolean` | `false` |
| readOnly | Read only status disables input box operation behavior | `boolean` | `false` |
| async | Support for asynchronous modification | `boolean` | `false` |
| select | Support deselect all text | `boolean` | `true` |
| formatter | Specifies the format of the value displayed in the input box | `function(value: number \| string): string` | `-` |
| beforeChange`2.8.0` | Callback function before the input value changes, return false to prevent input, support returning Promise | `(value: number \| string) => boolean \| Promise<boolean>` | `-` |
| onPlus | Triggered when the Add button is clicked | `(e: MouseEvent) => void` | `-` |
| onMinus | Triggered when the decrease button is clicked | `(e: MouseEvent) => void` | `-` |
| onOverlimit | Triggered when an unavailable button is clicked | `(e: MouseEvent) => void` | `-` |
Expand All @@ -139,16 +139,17 @@ The component provides the following CSS variables, which can be used to customi

| Name | Description | Default Value |
| --- | --- | --- |
| \--nutui-inputnumber-input-width | The width of the input in the number input box | `26px` |
| \--nutui-inputnumber-input-height | The height of the input in the number input box | `20px` |
| \--nutui-inputnumber-input-width | The width of the input in the number input box | `40px` |
| \--nutui-inputnumber-input-height | The height of the input in the number input box | `24px` |
| \--nutui-inputnumber-input-background-color | The background color of the input in the number input box | `$color-background` |
| \--nutui-inputnumber-input-font-color | The font size color of the input in the number input box | `$color-title` |
| \--nutui-inputnumber-input-font-size | The font size of the input in the number input box | `12px` |
| \--nutui-inputnumber-input-font-size | The font size of the input in the number input box | `14px` |
| \--nutui-inputnumber-input-border | The border value of the input in the number input box | `0` |
| \--nutui-inputnumber-input-border-radius | The rounded corners of the input in the number input box | `4px` |
| \--nutui-inputnumber-input-margin | The rounded corners of the input in the number input box | `0px` |
| \--nutui-inputnumber-button-width | The width of the left and right buttons of the number input box | `20px` |
| \--nutui-inputnumber-button-height | The height of the left and right buttons of the number input box | `20px` |
| \--nutui-inputnumber-input-border-radius | The rounded corners of the input in the number input box | `6px` |
| \--nutui-inputnumber-input-margin | The rounded corners of the input in the number input box | `0` |
| \--nutui-inputnumber-button-width | The width of the left and right buttons of the number input box | `14px` |
| \--nutui-inputnumber-button-height | The height of the left and right buttons of the number input box | `16px` |
| \--nutui-inputnumber-button-border-radius | The rounded corners of the left and right buttons of the number input box | `30px` |
| \--nutui-inputnumber-button-background-color | The background color of the left and right buttons of the number input box | `transparent` |
| \--nutui-inputnumber-icon-color | The color of the icon in the number input box | `$color-text` |
| \--nutui-inputnumber-icon-size | The size of the icon in the number input box | `8px` |
Expand Down
17 changes: 9 additions & 8 deletions src/packages/inputnumber/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ import { InputNumber } from '@nutui/nutui-react'
| digits | 设置保留的小数位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` |
| async | 支持异步修改 | `boolean` | `false` |
| select | 支持取消文本全选中 | `boolean` | `true` |
| formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` |
| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise<boolean>` | `-` |
| onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` |
Expand All @@ -139,16 +139,17 @@ import { InputNumber } from '@nutui/nutui-react'

| 名称 | 说明 | 默认值 |
| --- | --- | --- |
| \--nutui-inputnumber-input-width | 数字输入框中input的宽度 | `26px` |
| \--nutui-inputnumber-input-height | 数字输入框中input的高度 | `20px` |
| \--nutui-inputnumber-input-width | 数字输入框中input的宽度 | `40px` |
| \--nutui-inputnumber-input-height | 数字输入框中input的高度 | `24px` |
| \--nutui-inputnumber-input-background-color | 数字输入框中input的背景颜色 | `$color-background` |
| \--nutui-inputnumber-input-font-color | 数字输入框中input的字号颜色 | `$color-title` |
| \--nutui-inputnumber-input-font-size | 数字输入框中input的字号大小 | `12px` |
| \--nutui-inputnumber-input-font-size | 数字输入框中input的字号大小 | `14px` |
| \--nutui-inputnumber-input-border | 数字输入框中input的border值 | `0` |
| \--nutui-inputnumber-input-border-radius | 数字输入框中input的圆角 | `4px` |
| \--nutui-inputnumber-input-margin | 数字输入框中input的margin值 | `0px` |
| \--nutui-inputnumber-button-width | 数字输入框左右按钮的宽度 | `20px` |
| \--nutui-inputnumber-button-height | 数字输入框左右按钮的高度 | `20px` |
| \--nutui-inputnumber-input-border-radius | 数字输入框中input的圆角 | `6px` |
| \--nutui-inputnumber-input-margin | 数字输入框中input的margin值 | `0` |
| \--nutui-inputnumber-button-width | 数字输入框左右按钮的宽度 | `14px` |
| \--nutui-inputnumber-button-height | 数字输入框左右按钮的高度 | `16px` |
| \--nutui-inputnumber-button-border-radius | 数字输入框左右按钮的圆角 | `30px` |
| \--nutui-inputnumber-button-background-color | 数字输入框左右按钮的背景色 | `transparent` |
| \--nutui-inputnumber-icon-color | 数字输入框中icon的颜色 | `$color-text` |
| \--nutui-inputnumber-icon-size | 数字输入框中icon的大小 | `8px` |
Expand Down
25 changes: 13 additions & 12 deletions src/packages/inputnumber/doc.taro.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ import { InputNumber } from '@nutui/nutui-react-taro'
| digits | 设置保留的小数位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` |
| async | 支持异步修改 | `boolean` | `false` |
| formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` |
| onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onChange | 值改变时触发 | `(param: string \| number, e: MouseEvent \| ChangeEvent<HTMLInputElement>) => void` | `-` |
| beforeChange | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise<boolean>` | `-` |
| onPlus | 点击增加按钮时触发 | `(e: ITouchEvent) => void` | `-` |
| onMinus | 点击减少按钮时触发 | `(e: ITouchEvent) => void` | `-` |
| onOverlimit | 点击不可用的按钮时触发 | `(e: ITouchEvent \| ChangeEvent<HTMLInputElement>) => void` | `-` |
| onChange | 值改变时触发 | `(param: string \| number, e: ITouchEvent \| ChangeEvent<HTMLInputElement>) => void` | `-` |
| onFocus | 输入框获得焦点时触发 | `(e: FocusEvent<HTMLInputElement>) => void` | `-` |
| onBlur | 输入框失去焦点时触发 | `(e: ChangeEvent<HTMLInputElement>) => void` | `-` |

Expand All @@ -131,16 +131,17 @@ import { InputNumber } from '@nutui/nutui-react-taro'

| 名称 | 说明 | 默认值 |
| --- | --- | --- |
| \--nutui-inputnumber-input-width | 数字输入框中input的宽度 | `26px` |
| \--nutui-inputnumber-input-height | 数字输入框中input的高度 | `20px` |
| \--nutui-inputnumber-input-width | 数字输入框中input的宽度 | `40px` |
| \--nutui-inputnumber-input-height | 数字输入框中input的高度 | `24px` |
| \--nutui-inputnumber-input-background-color | 数字输入框中input的背景颜色 | `$color-background` |
| \--nutui-inputnumber-input-font-color | 数字输入框中input的字号颜色 | `$color-title` |
| \--nutui-inputnumber-input-font-size | 数字输入框中input的字号大小 | `12px` |
| \--nutui-inputnumber-input-font-size | 数字输入框中input的字号大小 | `14px` |
| \--nutui-inputnumber-input-border | 数字输入框中input的border值 | `0` |
| \--nutui-inputnumber-input-border-radius | 数字输入框中input的圆角 | `4px` |
| \--nutui-inputnumber-input-margin | 数字输入框中input的margin值 | `0px` |
| \--nutui-inputnumber-button-width | 数字输入框左右按钮的宽度 | `20px` |
| \--nutui-inputnumber-button-height | 数字输入框左右按钮的高度 | `20px` |
| \--nutui-inputnumber-input-border-radius | 数字输入框中input的圆角 | `6px` |
| \--nutui-inputnumber-input-margin | 数字输入框中input的margin值 | `0` |
| \--nutui-inputnumber-button-width | 数字输入框左右按钮的宽度 | `14px` |
| \--nutui-inputnumber-button-height | 数字输入框左右按钮的高度 | `16px` |
| \--nutui-inputnumber-button-border-radius | 数字输入框左右按钮的圆角 | `30px` |
| \--nutui-inputnumber-button-background-color | 数字输入框左右按钮的背景色 | `transparent` |
| \--nutui-inputnumber-icon-color | 数字输入框中icon的颜色 | `$color-text` |
| \--nutui-inputnumber-icon-size | 数字输入框中icon的大小 | `8px` |
Expand Down
18 changes: 10 additions & 8 deletions src/packages/inputnumber/doc.zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ import { InputNumber } from '@nutui/nutui-react'
| digits | 設置保留的小數位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只讀狀態禁用輸入框操作行為 | `boolean` | `false` |
| async | 支持異步修改 | `boolean` | `false` |
| select | 支持取消文本全选中 | `boolean` | `true` |
| formatter | 指定輸入框展示值的格式 | `function(value: number \| string): string` | `-` |
| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise<boolean>` | `-` |
| onPlus | 點擊增加按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
| onMinus | 點擊減少按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 點擊不可用的按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
Expand All @@ -130,16 +131,17 @@ import { InputNumber } from '@nutui/nutui-react'

| 名稱 | 說明 | 默認值 |
| --- | --- | --- |
| \--nutui-inputnumber-input-width | 數字輸入框中input的寬度 | `26px` |
| \--nutui-inputnumber-input-height | 數字輸入框中input的高度 | `20px` |
| \--nutui-inputnumber-input-width | 數字輸入框中input的寬度 | `40px` |
| \--nutui-inputnumber-input-height | 數字輸入框中input的高度 | `24px` |
| \--nutui-inputnumber-input-background-color | 數字輸入框中input的背景顏色 | `$color-background` |
| \--nutui-inputnumber-input-font-color | 數字輸入框中input的字號顏色 | `$color-title` |
| \--nutui-inputnumber-input-font-size | 數字輸入框中input的字號大小 | `12px` |
| \--nutui-inputnumber-input-font-size | 數字輸入框中input的字號大小 | `14px` |
| \--nutui-inputnumber-input-border | 數字輸入框中input的border值 | `0` |
| \--nutui-inputnumber-input-border-radius | 數字輸入框中input的圓角 | `4px` |
| \--nutui-inputnumber-input-margin | 數字輸入框中input的margin值 | `0px` |
| \--nutui-inputnumber-button-width | 數字輸入框左右按鈕的寬度 | `20px` |
| \--nutui-inputnumber-button-height | 數字輸入框左右按鈕的高度 | `20px` |
| \--nutui-inputnumber-input-border-radius | 數字輸入框中input的圓角 | `6px` |
| \--nutui-inputnumber-input-margin | 數字輸入框中input的margin值 | `0` |
| \--nutui-inputnumber-button-width | 數字輸入框左右按鈕的寬度 | `14px` |
| \--nutui-inputnumber-button-height | 數字輸入框左右按鈕的高度 | `16px` |
| \--nutui-inputnumber-button-border-radius | 數字輸入框左右按鈕的圓角 | `30px` |
| \--nutui-inputnumber-button-background-color | 數字輸入框左右按鈕的背景色 | `transparent` |
| \--nutui-inputnumber-icon-color | 數字輸入框中icon的顏色 | `$color-text` |
| \--nutui-inputnumber-icon-size | 數字輸入框中icon的大小 | `8px` |
Expand Down
Loading

0 comments on commit 3a94dfe

Please sign in to comment.