diff --git a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx
index 606fec2100..cff6e24306 100644
--- a/src/packages/inputnumber/__tests__/inputnumber.spec.tsx
+++ b/src/packages/inputnumber/__tests__/inputnumber.spec.tsx
@@ -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'
@@ -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()
@@ -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()
@@ -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()
@@ -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()
@@ -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()
@@ -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(
)
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(
)
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')
})
@@ -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(
-
+
)
const input = container.querySelectorAll('input')[0]
input.value = '200'
- fireEvent.input(input)
- expect(change).toBeCalled()
+ await act(async () => {
+ fireEvent.input(input)
+ })
+ expect(overlimit).toBeCalled()
})
diff --git a/src/packages/inputnumber/demos/h5/demo8.tsx b/src/packages/inputnumber/demos/h5/demo8.tsx
index e66949dddf..76c5beee75 100644
--- a/src/packages/inputnumber/demos/h5/demo8.tsx
+++ b/src/packages/inputnumber/demos/h5/demo8.tsx
@@ -6,22 +6,25 @@ const Demo8 = () => {
const overlimit = (e: any) => {
console.log('超出限制事件触发', e)
}
- const onChange = (value: string | number) => {
+
+ const beforeChange = (value: number | string): Promise => {
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 (
setInputValue(Number(value))}
onOverlimit={overlimit}
- async
/>
)
}
diff --git a/src/packages/inputnumber/demos/taro/demo8.tsx b/src/packages/inputnumber/demos/taro/demo8.tsx
index 6b59ffac5e..d157476fdc 100644
--- a/src/packages/inputnumber/demos/taro/demo8.tsx
+++ b/src/packages/inputnumber/demos/taro/demo8.tsx
@@ -3,42 +3,45 @@ import { 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 => {
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 (
<>
setInputValue(Number(value))}
onOverlimit={overlimit}
- async
/>
{
- SetShow(false)
+ setShow(false)
}}
/>
>
diff --git a/src/packages/inputnumber/doc.en-US.md b/src/packages/inputnumber/doc.en-US.md
index beb3542914..c241362a7d 100644
--- a/src/packages/inputnumber/doc.en-US.md
+++ b/src/packages/inputnumber/doc.en-US.md
@@ -121,9 +121,10 @@ 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` |
+| ~~async~~`2.8.0` | Support for asynchronous modification | `boolean` | `false` |
+| select`2.7.0` | 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` | `-` |
| 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` | `-` |
diff --git a/src/packages/inputnumber/doc.md b/src/packages/inputnumber/doc.md
index d2afd0b4d1..796702b0cf 100644
--- a/src/packages/inputnumber/doc.md
+++ b/src/packages/inputnumber/doc.md
@@ -121,9 +121,10 @@ import { InputNumber } from '@nutui/nutui-react'
| digits | 设置保留的小数位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` |
-| async | 支持异步修改 | `boolean` | `false` |
-| select | 支持取消文本全选中 | `boolean` | `true` |
+| ~~async~~`2.8.0` | 支持异步修改 | `boolean` | `false` |
+| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` |
| formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` |
+| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` |
| onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` |
diff --git a/src/packages/inputnumber/doc.taro.md b/src/packages/inputnumber/doc.taro.md
index fb9a619b1c..5c4c446245 100644
--- a/src/packages/inputnumber/doc.taro.md
+++ b/src/packages/inputnumber/doc.taro.md
@@ -114,8 +114,9 @@ import { InputNumber } from '@nutui/nutui-react-taro'
| digits | 设置保留的小数位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` |
-| async | 支持异步修改 | `boolean` | `false` |
+| ~~async~~`2.8.0` | 支持异步修改 | `boolean` | `false` |
| formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` |
+| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` |
| onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onMinus | 点击减少按钮时触发 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 点击不可用的按钮时触发 | `(e: MouseEvent) => void` | `-` |
diff --git a/src/packages/inputnumber/doc.zh-TW.md b/src/packages/inputnumber/doc.zh-TW.md
index 5a1cb78e4c..4d7f253b40 100644
--- a/src/packages/inputnumber/doc.zh-TW.md
+++ b/src/packages/inputnumber/doc.zh-TW.md
@@ -113,8 +113,10 @@ import { InputNumber } from '@nutui/nutui-react'
| digits | 設置保留的小數位 | `string` \| `number` | `0` |
| disabled | 禁用所有功能 | `boolean` | `false` |
| readOnly | 只讀狀態禁用輸入框操作行為 | `boolean` | `false` |
-| async | 支持異步修改 | `boolean` | `false` |
+| ~~async~~`2.8.0` | 支持異步修改 | `boolean` | `false` |
+| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` |
| formatter | 指定輸入框展示值的格式 | `function(value: number \| string): string` | `-` |
+| beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` |
| onPlus | 點擊增加按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
| onMinus | 點擊減少按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
| onOverlimit | 點擊不可用的按鈕時觸發 | `(e: MouseEvent) => void` | `-` |
diff --git a/src/packages/inputnumber/inputnumber.taro.tsx b/src/packages/inputnumber/inputnumber.taro.tsx
index 451057b9ff..3c3ab17b26 100644
--- a/src/packages/inputnumber/inputnumber.taro.tsx
+++ b/src/packages/inputnumber/inputnumber.taro.tsx
@@ -10,6 +10,7 @@ import classNames from 'classnames'
import { InputProps } from '@tarojs/components'
import { usePropsValue } from '@/utils/use-props-value'
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
+import { bound } from '@/utils/bound'
export interface InputNumberProps extends BasicComponent {
value: number | string
@@ -22,7 +23,6 @@ export interface InputNumberProps extends BasicComponent {
readOnly: boolean
step: number
digits: number
- async: boolean
select: boolean
formatter?: (value?: string | number) => string
onPlus: (e: React.MouseEvent) => void
@@ -30,6 +30,7 @@ export interface InputNumberProps extends BasicComponent {
onOverlimit: (e: React.MouseEvent | ChangeEvent) => void
onBlur: (e: React.FocusEvent) => void
onFocus: (e: React.FocusEvent) => void
+ beforeChange: (value: number | string) => boolean | Promise
onChange: (
param: string | number,
e: React.MouseEvent | ChangeEvent
@@ -43,11 +44,10 @@ const defaultProps = {
allowEmpty: false,
min: 1,
max: 9999,
- type: 'digit',
step: 1,
digits: 0,
- async: false,
select: true,
+ beforeChange: (value) => Promise.resolve(true),
} as InputNumberProps
const classPrefix = `nut-inputnumber`
@@ -67,7 +67,6 @@ export const InputNumber: FunctionComponent<
allowEmpty,
digits,
step,
- async,
select,
className,
style,
@@ -78,6 +77,7 @@ export const InputNumber: FunctionComponent<
onBlur,
onFocus,
onChange,
+ beforeChange,
...restProps
} = {
...defaultProps,
@@ -101,23 +101,16 @@ export const InputNumber: FunctionComponent<
? parseFloat(defaultValue)
: defaultValue,
finalValue: 0,
- onChange: (value) => {},
})
- const bound = (value: number, min: number, max: number) => {
- let res = value
- if (min !== undefined) {
- res = Math.max(Number(min), res)
- }
- if (max !== undefined) {
- res = Math.min(Number(max), res)
- }
- return res
- }
+
const format = (value: number | null | string): string => {
if (value === null) return ''
// 如果超过 min 或 max, 需要纠正
- if (typeof value === 'string') value = parseFloat(value)
- const fixedValue = bound(value, Number(min), Number(max))
+ const fixedValue = bound(
+ typeof value === 'string' ? parseFloat(value) : value,
+ Number(min),
+ Number(max)
+ )
if (formatter) {
return formatter(fixedValue)
}
@@ -126,57 +119,53 @@ export const InputNumber: FunctionComponent<
}
return fixedValue.toString()
}
+
const [inputValue, setInputValue] = useState(format(shadowValue))
useEffect(() => {
- if (!focused && !async) {
- setShadowValue(bound(Number(shadowValue), Number(min), Number(max)))
+ if (!focused) {
setInputValue(format(shadowValue))
}
}, [focused, shadowValue])
- useEffect(() => {
- if (async) {
- setShadowValue(bound(Number(value), Number(min), Number(max)))
- setInputValue(format(value))
- }
- }, [value])
-
- const calcNextValue = (current: any, step: any, symbol: number) => {
+ const calcNextValue = (current: any, stepValue: any, symbol: number) => {
const dig = digits + 1
- return (
- (parseFloat(current || '0') * dig + parseFloat(step) * dig * symbol) / dig
- )
+ const currentValue = parseFloat(current || '0')
+ const stepAmount = parseFloat(stepValue) * symbol
+ return (currentValue * dig + stepAmount * dig) / dig
}
- const update = (negative: boolean, e: React.MouseEvent) => {
- if (step !== undefined) {
- const shouldOverBoundary = calcNextValue(
- shadowValue,
- step,
- negative ? -1 : 1
- )
- const nextValue = bound(shouldOverBoundary, Number(min), Number(max))
- setShadowValue(nextValue)
- if (
- negative
- ? shouldOverBoundary < Number(min)
- : shouldOverBoundary > Number(max)
- ) {
- onOverlimit?.(e)
- } else {
- onChange?.(nextValue, e)
- }
+
+ const update = async (negative: boolean, e: React.MouseEvent) => {
+ if (step === undefined) return
+ negative ? onMinus?.(e) : onPlus?.(e)
+
+ const shouldOverBoundary = calcNextValue(
+ shadowValue,
+ step,
+ negative ? -1 : 1
+ )
+ const maybeResume = await beforeChange(Number(shouldOverBoundary))
+ if (!maybeResume) return
+
+ const nextValue = bound(shouldOverBoundary, Number(min), Number(max))
+ setShadowValue(nextValue)
+ if (
+ negative
+ ? shouldOverBoundary < Number(min)
+ : shouldOverBoundary > Number(max)
+ ) {
+ onOverlimit?.(e)
+ } else {
+ onChange?.(nextValue, e)
}
}
- const handleReduce = (e: React.MouseEvent) => {
+ const handleReduce = async (e: React.MouseEvent) => {
if (disabled) return
- onMinus?.(e)
- update(true, e)
+ await update(true, e)
}
- const handlePlus = (e: React.MouseEvent) => {
+ const handlePlus = async (e: React.MouseEvent) => {
if (disabled) return
- onPlus?.(e)
- update(false, e)
+ await update(false, e)
}
const parseValue = (text: string) => {
@@ -184,38 +173,26 @@ export const InputNumber: FunctionComponent<
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
- ) => {
- 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) => {
+ const handleInputChange = async (e: React.ChangeEvent) => {
// 设置 input 值, 在 blur 时格式化
setInputValue(e.target.value)
const valueStr = parseValue(e.target.value)
- if (valueStr === null) {
- if (allowEmpty) {
- setShadowValue(null)
- } else {
- setShadowValue(defaultValue)
- }
+ const maybeResume = await beforeChange(Number(valueStr))
+ if (!maybeResume) return
+
+ setShadowValue(
+ // eslint-disable-next-line no-nested-ternary
+ valueStr === null ? (allowEmpty ? null : defaultValue) : valueStr
+ )
+
+ if (
+ valueStr !== null &&
+ (Number(valueStr) < Number(min) || Number(valueStr) > Number(max))
+ ) {
+ onOverlimit?.(e)
} else {
- setShadowValue(clampValue(valueStr) as any)
+ onChange?.(parseFloat(valueStr || '0').toFixed(digits), e)
}
- !async && handleValueChange(valueStr, e)
}
const handleFocus = (e: React.FocusEvent) => {
setFocused(true)
@@ -228,18 +205,9 @@ export const InputNumber: FunctionComponent<
}
const handleBlur = (e: React.FocusEvent) => {
setFocused(false)
- onBlur?.(e)
+ onBlur && 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)
+ onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
}
return (
@@ -252,8 +220,6 @@ export const InputNumber: FunctionComponent<
/>
string
onPlus: (e: React.MouseEvent) => void
@@ -28,6 +28,7 @@ export interface InputNumberProps extends BasicComponent {
onOverlimit: (e: React.MouseEvent | ChangeEvent) => void
onBlur: (e: React.FocusEvent) => void
onFocus: (e: React.FocusEvent) => void
+ beforeChange: (value: number | string) => boolean | Promise
onChange: (
param: string | number,
e: React.MouseEvent | ChangeEvent
@@ -43,8 +44,8 @@ const defaultProps = {
max: 9999,
step: 1,
digits: 0,
- async: false,
select: true,
+ beforeChange: (value) => Promise.resolve(true),
} as InputNumberProps
const classPrefix = `nut-inputnumber`
@@ -63,7 +64,6 @@ export const InputNumber: FunctionComponent<
allowEmpty,
digits,
step,
- async,
select,
className,
style,
@@ -74,6 +74,7 @@ export const InputNumber: FunctionComponent<
onBlur,
onFocus,
onChange,
+ beforeChange,
...restProps
} = {
...defaultProps,
@@ -97,23 +98,16 @@ export const InputNumber: FunctionComponent<
? parseFloat(defaultValue)
: defaultValue,
finalValue: 0,
- onChange: (value) => {},
})
- const bound = (value: number, min: number, max: number) => {
- let res = value
- if (min !== undefined) {
- res = Math.max(Number(min), res)
- }
- if (max !== undefined) {
- res = Math.min(Number(max), res)
- }
- return res
- }
+
const format = (value: number | null | string): string => {
if (value === null) return ''
// 如果超过 min 或 max, 需要纠正
- if (typeof value === 'string') value = parseFloat(value)
- const fixedValue = bound(value, Number(min), Number(max))
+ const fixedValue = bound(
+ typeof value === 'string' ? parseFloat(value) : value,
+ Number(min),
+ Number(max)
+ )
if (formatter) {
return formatter(fixedValue)
}
@@ -122,57 +116,53 @@ export const InputNumber: FunctionComponent<
}
return fixedValue.toString()
}
+
const [inputValue, setInputValue] = useState(format(shadowValue))
useEffect(() => {
- if (!focused && !async) {
- setShadowValue(bound(Number(shadowValue), Number(min), Number(max)))
+ if (!focused) {
setInputValue(format(shadowValue))
}
}, [focused, shadowValue])
- useEffect(() => {
- if (async) {
- setShadowValue(bound(Number(value), Number(min), Number(max)))
- setInputValue(format(value))
- }
- }, [value])
-
- const calcNextValue = (current: any, step: any, symbol: number) => {
+ const calcNextValue = (current: any, stepValue: any, symbol: number) => {
const dig = digits + 1
- return (
- (parseFloat(current || '0') * dig + parseFloat(step) * dig * symbol) / dig
- )
+ const currentValue = parseFloat(current || '0')
+ const stepAmount = parseFloat(stepValue) * symbol
+ return (currentValue * dig + stepAmount * dig) / dig
}
- const update = (negative: boolean, e: React.MouseEvent) => {
- if (step !== undefined) {
- const shouldOverBoundary = calcNextValue(
- shadowValue,
- step,
- negative ? -1 : 1
- )
- const nextValue = bound(shouldOverBoundary, Number(min), Number(max))
- setShadowValue(nextValue)
- if (
- negative
- ? shouldOverBoundary < Number(min)
- : shouldOverBoundary > Number(max)
- ) {
- onOverlimit?.(e)
- } else {
- onChange?.(nextValue, e)
- }
+
+ const update = async (negative: boolean, e: React.MouseEvent) => {
+ if (step === undefined) return
+ negative ? onMinus?.(e) : onPlus?.(e)
+
+ const shouldOverBoundary = calcNextValue(
+ shadowValue,
+ step,
+ negative ? -1 : 1
+ )
+ const maybeResume = await beforeChange(Number(shouldOverBoundary))
+ if (!maybeResume) return
+
+ const nextValue = bound(shouldOverBoundary, Number(min), Number(max))
+ setShadowValue(nextValue)
+ if (
+ negative
+ ? shouldOverBoundary < Number(min)
+ : shouldOverBoundary > Number(max)
+ ) {
+ onOverlimit?.(e)
+ } else {
+ onChange?.(nextValue, e)
}
}
- const handleReduce = (e: React.MouseEvent) => {
+ const handleReduce = async (e: React.MouseEvent) => {
if (disabled) return
- onMinus?.(e)
- update(true, e)
+ await update(true, e)
}
- const handlePlus = (e: React.MouseEvent) => {
+ const handlePlus = async (e: React.MouseEvent) => {
if (disabled) return
- onPlus?.(e)
- update(false, e)
+ await update(false, e)
}
const parseValue = (text: string) => {
@@ -180,38 +170,26 @@ export const InputNumber: FunctionComponent<
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
- ) => {
- 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) => {
+ const handleInputChange = async (e: React.ChangeEvent) => {
// 设置 input 值, 在 blur 时格式化
setInputValue(e.target.value)
const valueStr = parseValue(e.target.value)
- if (valueStr === null) {
- if (allowEmpty) {
- setShadowValue(null)
- } else {
- setShadowValue(defaultValue)
- }
+ const maybeResume = await beforeChange(Number(valueStr))
+ if (!maybeResume) return
+
+ setShadowValue(
+ // eslint-disable-next-line no-nested-ternary
+ valueStr === null ? (allowEmpty ? null : defaultValue) : valueStr
+ )
+
+ if (
+ valueStr !== null &&
+ (Number(valueStr) < Number(min) || Number(valueStr) > Number(max))
+ ) {
+ onOverlimit?.(e)
} else {
- setShadowValue(clampValue(valueStr) as any)
+ onChange?.(parseFloat(valueStr || '0').toFixed(digits), e)
}
- !async && handleValueChange(valueStr, e)
}
const handleFocus = (e: React.FocusEvent) => {
setFocused(true)
@@ -224,18 +202,9 @@ export const InputNumber: FunctionComponent<
}
const handleBlur = (e: React.FocusEvent) => {
setFocused(false)
- onBlur?.(e)
+ onBlur && 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)
+ onChange?.(parseFloat(valueStr || '0').toFixed(digits) as any, e)
}
return (