From adf3f0f5929dba72187a591107248bb4f1a4ed7a Mon Sep 17 00:00:00 2001 From: oasis Date: Thu, 20 Feb 2025 10:15:37 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix(inputnumber):=20=E5=A2=9E=E5=8A=A0=20be?= =?UTF-8?q?foreChange=EF=BC=8C=E4=BC=98=E5=8C=96=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__tests__/inputnumber.spec.tsx | 57 +++-- src/packages/inputnumber/demos/h5/demo8.tsx | 35 +-- src/packages/inputnumber/demos/taro/demo8.tsx | 43 ++-- src/packages/inputnumber/doc.en-US.md | 20 +- src/packages/inputnumber/doc.md | 20 +- src/packages/inputnumber/doc.taro.md | 25 +- src/packages/inputnumber/doc.zh-TW.md | 19 +- src/packages/inputnumber/inputnumber.taro.tsx | 234 +++++++----------- src/packages/inputnumber/inputnumber.tsx | 152 +++++------- 9 files changed, 269 insertions(+), 336 deletions(-) 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 faa2bb50d2..76c5beee75 100644 --- a/src/packages/inputnumber/demos/h5/demo8.tsx +++ b/src/packages/inputnumber/demos/h5/demo8.tsx @@ -1,30 +1,31 @@ import React, { useState } from 'react' -import { Cell, InputNumber, Toast } from '@nutui/nutui-react' +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) => { + + 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} + /> ) } export default Demo8 diff --git a/src/packages/inputnumber/demos/taro/demo8.tsx b/src/packages/inputnumber/demos/taro/demo8.tsx index a308b3a3e8..d157476fdc 100644 --- a/src/packages/inputnumber/demos/taro/demo8.tsx +++ b/src/packages/inputnumber/demos/taro/demo8.tsx @@ -1,40 +1,47 @@ import React, { useState } from 'react' -import { Cell, InputNumber, Toast } from '@nutui/nutui-react-taro' +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} + /> { - SetShow(false) + setShow(false) }} /> diff --git a/src/packages/inputnumber/doc.en-US.md b/src/packages/inputnumber/doc.en-US.md index 7491ec24d3..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` | `-` | @@ -139,16 +140,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` | diff --git a/src/packages/inputnumber/doc.md b/src/packages/inputnumber/doc.md index a8f17a582e..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` | `-` | @@ -139,16 +140,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` | diff --git a/src/packages/inputnumber/doc.taro.md b/src/packages/inputnumber/doc.taro.md index cec8fb8f7a..d81b5a9f56 100644 --- a/src/packages/inputnumber/doc.taro.md +++ b/src/packages/inputnumber/doc.taro.md @@ -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) => void` | `-` | +| beforeChange | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | +| onPlus | 点击增加按钮时触发 | `(e: ITouchEvent) => void` | `-` | +| onMinus | 点击减少按钮时触发 | `(e: ITouchEvent) => void` | `-` | +| onOverlimit | 点击不可用的按钮时触发 | `(e: ITouchEvent \| ChangeEvent) => void` | `-` | +| onChange | 值改变时触发 | `(param: string \| number, e: ITouchEvent \| ChangeEvent) => void` | `-` | | onFocus | 输入框获得焦点时触发 | `(e: FocusEvent) => void` | `-` | | onBlur | 输入框失去焦点时触发 | `(e: ChangeEvent) => void` | `-` | @@ -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` | diff --git a/src/packages/inputnumber/doc.zh-TW.md b/src/packages/inputnumber/doc.zh-TW.md index 53efde519b..c0524201f1 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` | `-` | @@ -130,16 +132,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` | diff --git a/src/packages/inputnumber/inputnumber.taro.tsx b/src/packages/inputnumber/inputnumber.taro.tsx index 0da91a128a..c2dabcc9e8 100644 --- a/src/packages/inputnumber/inputnumber.taro.tsx +++ b/src/packages/inputnumber/inputnumber.taro.tsx @@ -1,16 +1,16 @@ import React, { + ChangeEvent, + FunctionComponent, useEffect, useRef, - FunctionComponent, useState, - ChangeEvent, } from 'react' -import classNames from 'classnames' -import { ITouchEvent, InputProps, View, Text } from '@tarojs/components' import { Minus, Plus } from '@nutui/icons-react-taro' +import classNames from 'classnames' +import { InputProps, ITouchEvent, View } from '@tarojs/components' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' -import { harmony } from '@/utils/platform-taro' +import { bound } from '@/utils/bound' export interface InputNumberProps extends BasicComponent { value: number | string @@ -23,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: ITouchEvent) => void @@ -31,9 +30,10 @@ export interface InputNumberProps extends BasicComponent { onOverlimit: (e: ITouchEvent | ChangeEvent) => void onBlur: (e: React.FocusEvent) => void onFocus: (e: React.FocusEvent) => void + beforeChange: (value: number | string) => boolean | Promise onChange: ( param: string | number, - e: ITouchEvent | ChangeEvent + e: ITouchEvent | React.MouseEvent | ChangeEvent ) => void } @@ -44,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` @@ -68,7 +67,6 @@ export const InputNumber: FunctionComponent< allowEmpty, digits, step, - async, select, className, style, @@ -79,13 +77,15 @@ export const InputNumber: FunctionComponent< onBlur, onFocus, onChange, + beforeChange, ...restProps } = { ...defaultProps, ...props, } - const isHarmony = harmony() - const classes = classNames(classPrefix, className) + const classes = classNames(classPrefix, className, { + [`${classPrefix}-disabled`]: disabled, + }) const [focused, setFocused] = useState(false) const inputRef = useRef(null) useEffect(() => { @@ -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: ITouchEvent) => { - 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: ITouchEvent) => { + 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: ITouchEvent) => { + const handleReduce = async (e: ITouchEvent) => { if (disabled) return - onMinus?.(e) - update(true, e) + await update(true, e) } - const handlePlus = (e: ITouchEvent) => { + const handlePlus = async (e: ITouchEvent) => { if (disabled) return - onPlus?.(e) - update(false, e) + await update(false, e) } const parseValue = (text: string) => { @@ -184,40 +173,28 @@ 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: any) => { + 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: any) => { + const handleFocus = (e: React.FocusEvent) => { setFocused(true) setInputValue( shadowValue !== undefined && shadowValue !== null @@ -226,48 +203,24 @@ export const InputNumber: FunctionComponent< ) onFocus?.(e) } - const handleBlur = (e: any) => { + 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 ( - {isHarmony ? ( - - - - - ) : ( - - )} + - {isHarmony ? ( - - + - - ) : ( - - )} + ) diff --git a/src/packages/inputnumber/inputnumber.tsx b/src/packages/inputnumber/inputnumber.tsx index 4b58a875cc..dcafa54c1c 100644 --- a/src/packages/inputnumber/inputnumber.tsx +++ b/src/packages/inputnumber/inputnumber.tsx @@ -9,6 +9,7 @@ import { Minus, Plus } from '@nutui/icons-react' import classNames from 'classnames' import { usePropsValue } from '@/hooks/use-props-value' import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { bound } from '@/utils/bound' export interface InputNumberProps extends BasicComponent { value: number | string @@ -20,7 +21,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 @@ -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,55 +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) => { @@ -178,39 +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) @@ -223,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 ( From 51451b764edee9807ba6d105e4991ed814c9322f Mon Sep 17 00:00:00 2001 From: oasis Date: Fri, 7 Mar 2025 20:51:58 +0800 Subject: [PATCH 2/5] docs: update --- src/packages/inputnumber/doc.en-US.md | 3 +-- src/packages/inputnumber/doc.md | 3 +-- src/packages/inputnumber/doc.zh-TW.md | 3 +-- .../doc/docs/react/migrate-from-v2.en-US.md | 16 ++++++++++------ .../doc/docs/react/migrate-from-v2.md | 7 ++++++- .../doc/docs/taro/migrate-from-v2.en-US.md | 16 ++++++++++------ .../sites-react/doc/docs/taro/migrate-from-v2.md | 16 ++++++++++------ 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/packages/inputnumber/doc.en-US.md b/src/packages/inputnumber/doc.en-US.md index c241362a7d..7cca75b232 100644 --- a/src/packages/inputnumber/doc.en-US.md +++ b/src/packages/inputnumber/doc.en-US.md @@ -121,8 +121,7 @@ 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~~`2.8.0` | Support for asynchronous modification | `boolean` | `false` | -| select`2.7.0` | Support deselect all text | `boolean` | `true` | +| 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` | `-` | | onPlus | Triggered when the Add button is clicked | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/doc.md b/src/packages/inputnumber/doc.md index 796702b0cf..7b4127eb97 100644 --- a/src/packages/inputnumber/doc.md +++ b/src/packages/inputnumber/doc.md @@ -121,8 +121,7 @@ import { InputNumber } from '@nutui/nutui-react' | digits | 设置保留的小数位 | `string` \| `number` | `0` | | disabled | 禁用所有功能 | `boolean` | `false` | | readOnly | 只读状态禁用输入框操作行为 | `boolean` | `false` | -| ~~async~~`2.8.0` | 支持异步修改 | `boolean` | `false` | -| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` | +| select | 支持取消文本全选中 | `boolean` | `true` | | formatter | 指定输入框展示值的格式 | `function(value: number \| string): string` | `-` | | beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | | onPlus | 点击增加按钮时触发 | `(e: MouseEvent) => void` | `-` | diff --git a/src/packages/inputnumber/doc.zh-TW.md b/src/packages/inputnumber/doc.zh-TW.md index c0524201f1..163f4fbd12 100644 --- a/src/packages/inputnumber/doc.zh-TW.md +++ b/src/packages/inputnumber/doc.zh-TW.md @@ -113,8 +113,7 @@ import { InputNumber } from '@nutui/nutui-react' | digits | 設置保留的小數位 | `string` \| `number` | `0` | | disabled | 禁用所有功能 | `boolean` | `false` | | readOnly | 只讀狀態禁用輸入框操作行為 | `boolean` | `false` | -| ~~async~~`2.8.0` | 支持異步修改 | `boolean` | `false` | -| select`2.7.0` | 支持取消文本全选中 | `boolean` | `true` | +| select | 支持取消文本全选中 | `boolean` | `true` | | formatter | 指定輸入框展示值的格式 | `function(value: number \| string): string` | `-` | | beforeChange`2.8.0` | 输入值变化前的回调函数,返回 false 可阻止输入,支持返回 Promise | `(value: number \| string) => boolean \| Promise` | `-` | | onPlus | 點擊增加按鈕時觸發 | `(e: MouseEvent) => void` | `-` | diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md index 12f8bea46a..2cd65ead5e 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.en-US.md @@ -152,12 +152,16 @@ If your project uses these components, please read the documentation carefully a [//]: # '#### Form' [//]: # '#### Form.Item' [//]: # '#### Input' -[//]: # '#### InputNumber' -[//]: # '#### NumberKeyboard' -[//]: # '#### Picker' -[//]: # '#### Radio' -[//]: # '### Radio.Group' -[//]: # '#### Range' + +#### InputNumber + +- Remove async, which can be replaced by beforeChange +- Add beforeChange to handle asynchronous calls + [//]: # '#### NumberKeyboard' + [//]: # '#### Picker' + [//]: # '#### Radio' + [//]: # '### Radio.Group' + [//]: # '#### Range' #### Rate diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md index 2170b494f3..7b32bf6b7c 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md @@ -152,7 +152,12 @@ plugins: [ [//]: # '#### Form' [//]: # '#### Form.Item' [//]: # '#### Input' -[//]: # '#### InputNumber' + +#### InputNumber + +- 移除 `async`, 可通过 `beforeChange` 替代 +- 增加 `beforeChange`, 处理异步调用 + [//]: # '#### NumberKeyboard' [//]: # '#### Picker' [//]: # '#### Radio' diff --git a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md index 12f8bea46a..2cd65ead5e 100644 --- a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md +++ b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.en-US.md @@ -152,12 +152,16 @@ If your project uses these components, please read the documentation carefully a [//]: # '#### Form' [//]: # '#### Form.Item' [//]: # '#### Input' -[//]: # '#### InputNumber' -[//]: # '#### NumberKeyboard' -[//]: # '#### Picker' -[//]: # '#### Radio' -[//]: # '### Radio.Group' -[//]: # '#### Range' + +#### InputNumber + +- Remove async, which can be replaced by beforeChange +- Add beforeChange to handle asynchronous calls + [//]: # '#### NumberKeyboard' + [//]: # '#### Picker' + [//]: # '#### Radio' + [//]: # '### Radio.Group' + [//]: # '#### Range' #### Rate diff --git a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md index 2170b494f3..b4fca3eebd 100644 --- a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md @@ -152,12 +152,16 @@ plugins: [ [//]: # '#### Form' [//]: # '#### Form.Item' [//]: # '#### Input' -[//]: # '#### InputNumber' -[//]: # '#### NumberKeyboard' -[//]: # '#### Picker' -[//]: # '#### Radio' -[//]: # '### Radio.Group' -[//]: # '#### Range' + +#### InputNumber + +- 移除 `async`, 可通过 `beforeChange` 替代 +- 增加 `beforeChange`, 处理异步调用 + [//]: # '#### NumberKeyboard' + [//]: # '#### Picker' + [//]: # '#### Radio' + [//]: # '### Radio.Group' + [//]: # '#### Range' #### Rate From fc7c7fa4341ab34b422b1496b9d941abc1844fa2 Mon Sep 17 00:00:00 2001 From: oasis Date: Fri, 7 Mar 2025 21:10:30 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=E8=B6=85=E6=9C=80=E5=A4=A7=E6=9C=80?= =?UTF-8?q?=E5=B0=8F=E5=80=BC=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/inputnumber/inputnumber.taro.tsx | 2 +- src/packages/inputnumber/inputnumber.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/inputnumber/inputnumber.taro.tsx b/src/packages/inputnumber/inputnumber.taro.tsx index c2dabcc9e8..d7a54e5b21 100644 --- a/src/packages/inputnumber/inputnumber.taro.tsx +++ b/src/packages/inputnumber/inputnumber.taro.tsx @@ -140,7 +140,7 @@ export const InputNumber: FunctionComponent< negative ? onMinus?.(e) : onPlus?.(e) const shouldOverBoundary = calcNextValue( - shadowValue, + bound(Number(shadowValue), Number(min), Number(max)), step, negative ? -1 : 1 ) diff --git a/src/packages/inputnumber/inputnumber.tsx b/src/packages/inputnumber/inputnumber.tsx index dcafa54c1c..8aebd644a3 100644 --- a/src/packages/inputnumber/inputnumber.tsx +++ b/src/packages/inputnumber/inputnumber.tsx @@ -137,7 +137,7 @@ export const InputNumber: FunctionComponent< negative ? onMinus?.(e) : onPlus?.(e) const shouldOverBoundary = calcNextValue( - shadowValue, + bound(Number(shadowValue), Number(min), Number(max)), step, negative ? -1 : 1 ) From 26288e6247fcaa827117e711e6e4d31f85566868 Mon Sep 17 00:00:00 2001 From: oasis Date: Fri, 7 Mar 2025 21:43:28 +0800 Subject: [PATCH 4/5] fix: review --- src/packages/inputnumber/demos/h5/demo8.tsx | 18 ++++++++++-------- src/packages/inputnumber/demos/taro/demo8.tsx | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/packages/inputnumber/demos/h5/demo8.tsx b/src/packages/inputnumber/demos/h5/demo8.tsx index 76c5beee75..4da62e02d2 100644 --- a/src/packages/inputnumber/demos/h5/demo8.tsx +++ b/src/packages/inputnumber/demos/h5/demo8.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { InputNumber, Toast } from '@nutui/nutui-react' +import { Cell, InputNumber, Toast } from '@nutui/nutui-react' const Demo8 = () => { const [inputValue, setInputValue] = useState(0) @@ -19,13 +19,15 @@ const Demo8 = () => { } return ( - setInputValue(Number(value))} - onOverlimit={overlimit} - /> + + setInputValue(Number(value))} + onOverlimit={overlimit} + /> + ) } export default Demo8 diff --git a/src/packages/inputnumber/demos/taro/demo8.tsx b/src/packages/inputnumber/demos/taro/demo8.tsx index d157476fdc..311d283a46 100644 --- a/src/packages/inputnumber/demos/taro/demo8.tsx +++ b/src/packages/inputnumber/demos/taro/demo8.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react' -import { InputNumber, Toast } from '@nutui/nutui-react-taro' +import { Cell, InputNumber, Toast } from '@nutui/nutui-react-taro' const Demo8 = () => { const [inputValue, setInputValue] = useState(0) @@ -29,13 +29,15 @@ const Demo8 = () => { return ( <> - setInputValue(Number(value))} - onOverlimit={overlimit} - /> + + setInputValue(Number(value))} + onOverlimit={overlimit} + /> + Date: Tue, 11 Mar 2025 14:45:33 +0800 Subject: [PATCH 5/5] fix: harmony --- src/packages/inputnumber/inputnumber.taro.tsx | 44 ++++--------------- src/packages/inputnumber/inputnumber.tsx | 31 ++----------- src/types/spec/inputnumber/base.ts | 12 ++--- 3 files changed, 18 insertions(+), 69 deletions(-) diff --git a/src/packages/inputnumber/inputnumber.taro.tsx b/src/packages/inputnumber/inputnumber.taro.tsx index d7a54e5b21..08c0751d21 100644 --- a/src/packages/inputnumber/inputnumber.taro.tsx +++ b/src/packages/inputnumber/inputnumber.taro.tsx @@ -1,41 +1,11 @@ -import React, { - ChangeEvent, - FunctionComponent, - useEffect, - useRef, - useState, -} from 'react' +import React, { FunctionComponent, useEffect, useRef, useState } from 'react' import { Minus, Plus } from '@nutui/icons-react-taro' import classNames from 'classnames' -import { InputProps, ITouchEvent, View } from '@tarojs/components' +import { ITouchEvent, View } from '@tarojs/components' import { usePropsValue } from '@/hooks/use-props-value' -import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { ComponentDefaults } from '@/utils/typings' import { bound } from '@/utils/bound' - -export interface InputNumberProps extends BasicComponent { - value: number | string - defaultValue: number | string - allowEmpty: boolean - min: number | string - max: number | string - type?: Extract - disabled: boolean - readOnly: boolean - step: number - digits: number - select: boolean - formatter?: (value?: string | number) => string - onPlus: (e: ITouchEvent) => void - onMinus: (e: ITouchEvent) => void - onOverlimit: (e: ITouchEvent | ChangeEvent) => void - onBlur: (e: React.FocusEvent) => void - onFocus: (e: React.FocusEvent) => void - beforeChange: (value: number | string) => boolean | Promise - onChange: ( - param: string | number, - e: ITouchEvent | React.MouseEvent | ChangeEvent - ) => void -} +import { TaroInputNumberProps } from '@/types' const defaultProps = { ...ComponentDefaults, @@ -48,11 +18,11 @@ const defaultProps = { digits: 0, select: true, beforeChange: (value) => Promise.resolve(true), -} as InputNumberProps +} as TaroInputNumberProps const classPrefix = `nut-inputnumber` export const InputNumber: FunctionComponent< - Partial & + Partial & Omit, 'onChange' | 'onBlur'> > = (props) => { const { @@ -214,6 +184,7 @@ export const InputNumber: FunctionComponent< string - onPlus: (e: React.MouseEvent) => void - onMinus: (e: React.MouseEvent) => void - 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 - ) => void -} +import { WebInputNumberProps } from '@/types' const defaultProps = { ...ComponentDefaults, @@ -40,11 +17,11 @@ const defaultProps = { digits: 0, select: true, beforeChange: (value) => Promise.resolve(true), -} as InputNumberProps +} as WebInputNumberProps const classPrefix = `nut-inputnumber` export const InputNumber: FunctionComponent< - Partial & + Partial & Omit, 'onChange' | 'onBlur'> > = (props) => { const { diff --git a/src/types/spec/inputnumber/base.ts b/src/types/spec/inputnumber/base.ts index 7102b00e36..f6930618cd 100644 --- a/src/types/spec/inputnumber/base.ts +++ b/src/types/spec/inputnumber/base.ts @@ -1,23 +1,23 @@ -import { SimpleValue } from '../../base/atoms' import { BaseProps } from '../../base/props' +import { SimpleValue } from '../../base/atoms' export interface BaseInputNumber extends BaseProps { - value?: SimpleValue - defaultValue?: SimpleValue + value: SimpleValue + defaultValue: SimpleValue + allowEmpty: boolean min: SimpleValue max: SimpleValue - allowEmpty: boolean disabled: boolean readOnly: boolean step: number digits: number - async: boolean select: boolean - formatter?: (value?: string | number) => string + formatter?: (value?: SimpleValue) => string onPlus: (e: any) => void onMinus: (e: any) => void onOverlimit: (e: any) => void onBlur: (e: any) => void onFocus: (e: any) => void + beforeChange: (value: SimpleValue) => boolean | Promise onChange: (param: string | number, e: any) => void }