diff --git a/package-lock.json b/package-lock.json index f8f2659f85..d2b932e3bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "antd-mobile", - "version": "5.39.0", + "version": "5.40.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "antd-mobile", - "version": "5.39.0", + "version": "5.40.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/src/components/virtual-input/demos/demo1.tsx b/src/components/virtual-input/demos/demo1.tsx index c3e14ec2e9..b154a761e9 100644 --- a/src/components/virtual-input/demos/demo1.tsx +++ b/src/components/virtual-input/demos/demo1.tsx @@ -6,13 +6,15 @@ const TWO_DIGIT_NUMBER_REGEX = /^(([1-9]\d{0,11})|0)(\.\d{0,2}?)?$/ export default () => { const [value, setValue] = useState('') + const ref = React.useRef(null) return ( <> } + ref={ref} + keyboard={} /> @@ -24,6 +26,13 @@ export default () => { /> + + } + /> + + { } }} placeholder='请输入内容' - keyboard={} + keyboard={} + style={{ + '--font-size': '40px', + }} /> -
+
) } diff --git a/src/components/virtual-input/tests/virtual-input.test.tsx b/src/components/virtual-input/tests/virtual-input.test.tsx index 8197deba26..3fecd5bed1 100644 --- a/src/components/virtual-input/tests/virtual-input.test.tsx +++ b/src/components/virtual-input/tests/virtual-input.test.tsx @@ -280,16 +280,16 @@ describe('VirtualInput', () => { if (caretContainer != null) { expect(getCaretPosition(caretContainer)).toBe(3) - // click '1' left side in inputbox, caret position should be 0 + // click '1' left side in inputbox, caret position should move to end clickSiblingElements(caretContainer, 0, true) await waitFor(() => { expect( document.querySelector(`.${KeyBoardClassPrefix}-popup`) ).toBeVisible() }) - expect(getCaretPosition(caretContainer)).toBe(0) + expect(getCaretPosition(caretContainer)).toBe(3) - // click '9' by keyboard, content should be '9123', caret position should be 1 + // click '9' by keyboard, content should be '1239', caret position should be ended fireEvent.touchEnd(screen.getByText('9')) await waitFor(() => { expect( @@ -298,8 +298,8 @@ describe('VirtualInput', () => { }) expect( document.querySelector(`.${classPrefix}-content`) - ).toHaveTextContent('9123') - expect(getCaretPosition(caretContainer)).toBe(1) + ).toHaveTextContent('1239') + expect(getCaretPosition(caretContainer)).toBe(4) // click delete by keyboard, content should be '123', caret position should be 1 fireEvent.touchEnd(screen.getByTitle('清除')) @@ -311,7 +311,7 @@ describe('VirtualInput', () => { expect( document.querySelector(`.${classPrefix}-content`) ).toHaveTextContent('123') - expect(getCaretPosition(caretContainer)).toBe(0) + expect(getCaretPosition(caretContainer)).toBe(3) // click input box, caret position should be 3 fireEvent.click(document.querySelector(`.${classPrefix}-content`) as any) @@ -324,7 +324,7 @@ describe('VirtualInput', () => { } }) - test('只支持两位金额的受控组件,光标处理正常', async () => { + test('controlled component with 2-digit decimal amount should handle cursor correctly', async () => { const KeyBoardClassPrefix = 'adm-number-keyboard' const Wrapper = () => { const [value, setValue] = React.useState('0') @@ -371,7 +371,7 @@ describe('VirtualInput', () => { if (caretContainer != null) { expect(getCaretPosition(caretContainer)).toBe(3) - // 输入小数部分 + // Input decimal part fireEvent.touchEnd(screen.getByTitle('.')) fireEvent.touchEnd(screen.getByTitle('4')) fireEvent.touchEnd(screen.getByTitle('5')) @@ -381,7 +381,7 @@ describe('VirtualInput', () => { ).toHaveTextContent('103.45') expect(getCaretPosition(caretContainer)).toBe(6) - // 光标移动到 10x3.45, 输入小数点无效 + // Move cursor to between 10 and 3.45, decimal input should be invalid clickSiblingElements(caretContainer, 2, true) await waitFor(() => { expect( @@ -395,22 +395,8 @@ describe('VirtualInput', () => { ).toHaveTextContent('103.45') expect(getCaretPosition(caretContainer)).toBe(2) - // 光标移动到 x103.45,输入 0 无效 - clickSiblingElements(caretContainer, 0, true) - await waitFor(() => { - expect( - document.querySelector(`.${KeyBoardClassPrefix}-popup`) - ).toBeVisible() - }) - expect(getCaretPosition(caretContainer)).toBe(0) - fireEvent.touchEnd(screen.getByTitle('.')) - expect( - document.querySelector(`.${classPrefix}-content`) - ).toHaveTextContent('103.45') - expect(getCaretPosition(caretContainer)).toBe(0) - - // 光标移动到 1x03.45,并删除 1 - clickSiblingElements(caretContainer, 0, false) + // Move cursor between 1 and 03.45, then delete 1 + clickSiblingElements(caretContainer, 1, true) await waitFor(() => { expect( document.querySelector(`.${KeyBoardClassPrefix}-popup`) @@ -418,7 +404,7 @@ describe('VirtualInput', () => { }) expect(getCaretPosition(caretContainer)).toBe(1) - fireEvent.touchEnd(screen.getByTitle('清除')) // 点删除 + fireEvent.touchEnd(screen.getByTitle('清除')) // Click delete await waitFor(() => { expect( document.querySelector(`.${KeyBoardClassPrefix}-popup`) @@ -427,10 +413,10 @@ describe('VirtualInput', () => { expect( document.querySelector(`.${classPrefix}-content`) ).toHaveTextContent('3.45') - expect(getCaretPosition(caretContainer)).toBe(4) // 变为 3.45 光标到最末尾 + expect(getCaretPosition(caretContainer)).toBe(4) // Value becomes 3.45 with cursor at end - // 光标移动到 3x.45,并删除 3 - clickSiblingElements(caretContainer, 0, false) + // Move cursor between 3 and .45, then delete 3 + clickSiblingElements(caretContainer, 1, true) await waitFor(() => { expect( document.querySelector(`.${KeyBoardClassPrefix}-popup`) @@ -438,7 +424,7 @@ describe('VirtualInput', () => { }) expect(getCaretPosition(caretContainer)).toBe(1) - fireEvent.touchEnd(screen.getByTitle('清除')) // 点删除 + fireEvent.touchEnd(screen.getByTitle('清除')) // Click delete await waitFor(() => { expect( document.querySelector(`.${KeyBoardClassPrefix}-popup`) @@ -447,15 +433,15 @@ describe('VirtualInput', () => { expect( document.querySelector(`.${classPrefix}-content`) ).toHaveTextContent('0.45') - expect(getCaretPosition(caretContainer)).toBe(4) // 变为 0.45 光标到最末尾 + expect(getCaretPosition(caretContainer)).toBe(4) // Value becomes 0.45 with cursor at end - // 全部删除,最后为 0 + // Delete all, value becomes 0 fireEvent.click(document.querySelector(`.${classPrefix}-clear`) as any) expect( document.querySelector(`.${classPrefix}-content`) ).toHaveTextContent('0') - fireEvent.touchEnd(screen.getByTitle('9')) // 在 0 时输入 9,则为 9 + fireEvent.touchEnd(screen.getByTitle('9')) // When value is 0, input 9 becomes 9 expect( document.querySelector(`.${classPrefix}-content`) ).toHaveTextContent('9') diff --git a/src/components/virtual-input/virtual-input.tsx b/src/components/virtual-input/virtual-input.tsx index 23b587066f..24a328d64b 100644 --- a/src/components/virtual-input/virtual-input.tsx +++ b/src/components/virtual-input/virtual-input.tsx @@ -128,7 +128,7 @@ export const VirtualInput = forwardRef( value.substring(0, caretPosition) + v + value.substring(caretPosition) - // 临时记录,用于后续光标位置 + // Temporarily store for subsequent cursor positioning keyboardDataRef.current = { newValue, mode: 'input' } setValue(newValue) keyboard.props.onInput?.(v) @@ -138,7 +138,7 @@ export const VirtualInput = forwardRef( const newValue = value.substring(0, caretPosition - 1) + value.substring(caretPosition) - // 临时记录,用于后续光标位置 + // Temporarily store for subsequent cursor positioning keyboardDataRef.current = { newValue, mode: 'delete' } setValue(newValue) keyboard.props.onDelete?.() @@ -160,19 +160,22 @@ export const VirtualInput = forwardRef( getContainer: null, } as NumberKeyboardProps) - // 点击输入框时,将光标置于最后 + // When clicking input box, place cursor at end const setCaretPositionToEnd = () => { setCaretPosition(value.length) } - // 点击单个字符时,根据点击位置置于字符前或后 + // When clicking character, position cursor before or after based on click position const changeCaretPosition = (index: number) => (e: React.MouseEvent) => { e.stopPropagation() - + if (index === 0) { + setCaretPosition(value.length) + return + } const rect = (e.target as HTMLElement).getBoundingClientRect() const midX = rect.left + rect.width / 2 const clickX = e.clientX - // 点击区域是否偏右 + // Check if click area is right-biased const isRight = clickX > midX setCaretPosition(isRight ? index + 1 : index) @@ -187,8 +190,8 @@ export const VirtualInput = forwardRef( className={classNames(classPrefix, { [`${classPrefix}-disabled`]: mergedProps.disabled, })} - tabIndex={mergedProps.disabled ? undefined : 0} role='textbox' + tabIndex={mergedProps.disabled ? undefined : 0} onFocus={onFocus} onBlur={onBlur} onClick={mergedProps.onClick} @@ -196,6 +199,7 @@ export const VirtualInput = forwardRef(
( {i} ))} -
- {hasFocus &&
} -
+ {hasFocus && ( +
+
+
+ )} {chars.slice(caretPosition).map((i: string, index: number) => (