From 0207008c3b08420209605eabada6b07d4c216f35 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Fri, 13 Jan 2023 21:14:49 +0800 Subject: [PATCH 1/7] test(input): add more tests --- src/input-number/useInputNumber.tsx | 4 +- src/input/Input.tsx | 2 +- .../__snapshots__/vitest-input.test.jsx.snap | 176 +++ src/input/__tests__/mount.jsx | 14 + src/input/__tests__/vitest-input.test.jsx | 433 ++++++ src/input/defaultProps.ts | 1 + src/input/index.ts | 2 + src/input/input.en-US.md | 12 +- src/input/input.md | 16 +- src/input/type.ts | 30 +- src/select-input/useSingle.tsx | 9 +- test/snap/__snapshots__/csr.test.jsx.snap | 1184 ++++++++--------- test/utils/index.jsx | 5 + 13 files changed, 1270 insertions(+), 618 deletions(-) create mode 100644 src/input/__tests__/__snapshots__/vitest-input.test.jsx.snap create mode 100644 src/input/__tests__/mount.jsx create mode 100644 src/input/__tests__/vitest-input.test.jsx diff --git a/src/input-number/useInputNumber.tsx b/src/input-number/useInputNumber.tsx index e01bdb82d..3bb1ff7da 100644 --- a/src/input-number/useInputNumber.tsx +++ b/src/input-number/useInputNumber.tsx @@ -117,14 +117,14 @@ export default function useInputNumber 1. -> 1 - const onInnerInputChange = (val: string, { e }: { e: any }) => { + const onInnerInputChange: InputProps['onChange'] = (val, { e }) => { if (!canInputNumber(val, largeNumber)) return; if (props.largeNumber) { onChange(val as T, { type: 'input', e }); return; } // specialCode 新增或删除这些字符时不触发 change 事件 - const isDelete = e.nativeEvent.inputType === 'deleteContentBackward'; + const isDelete = (e as any).nativeEvent.inputType === 'deleteContentBackward'; const inputSpecialCode = specialCode.includes(val.slice(-1)) || val.slice(-2) === '.0'; const deleteSpecialCode = isDelete && specialCode.includes(String(userInput).slice(-1)); if ((!isNaN(Number(val)) && !inputSpecialCode) || deleteSpecialCode) { diff --git a/src/input/Input.tsx b/src/input/Input.tsx index 74087f7a8..6c2c36128 100644 --- a/src/input/Input.tsx +++ b/src/input/Input.tsx @@ -211,7 +211,7 @@ const Input = forwardRefWithStatics( [`${classPrefix}-size-s`]: size === 'small', [`${classPrefix}-size-l`]: size === 'large', [`${classPrefix}-align-${align}`]: align, - [`${classPrefix}-is-${tStatus}`]: tStatus, + [`${classPrefix}-is-${tStatus}`]: tStatus && tStatus !== 'default', [`${classPrefix}-input--prefix`]: prefixIcon || labelContent, [`${classPrefix}-input--suffix`]: suffixIconContent || suffixContent, [`${classPrefix}-input--focused`]: isFocused, diff --git a/src/input/__tests__/__snapshots__/vitest-input.test.jsx.snap b/src/input/__tests__/__snapshots__/vitest-input.test.jsx.snap new file mode 100644 index 000000000..db0c718a8 --- /dev/null +++ b/src/input/__tests__/__snapshots__/vitest-input.test.jsx.snap @@ -0,0 +1,176 @@ +// Vitest Snapshot v1 + +exports[`Input Component > props.align is equal to center 1`] = ` +
+ +
+`; + +exports[`Input Component > props.align is equal to left 1`] = ` +
+ +
+`; + +exports[`Input Component > props.align is equal to right 1`] = ` +
+ +
+`; + +exports[`Input Component > props.label works fine 1`] = ` +
+
+
+
+ + TNode + +
+ +
+
+
+`; + +exports[`Input Component > props.status is equal to default 1`] = ` +
+ +
+`; + +exports[`Input Component > props.status is equal to error 1`] = ` +
+ +
+`; + +exports[`Input Component > props.status is equal to success 1`] = ` +
+ +
+`; + +exports[`Input Component > props.status is equal to warning 1`] = ` +
+ +
+`; + +exports[`Input Component > props.suffix works fine 1`] = ` +
+
+
+ +
+ + TNode + +
+
+
+
+`; + +exports[`Input Component > props.suffixIcon works fine 1`] = ` +
+
+
+ + + + TNode + + +
+
+
+`; diff --git a/src/input/__tests__/mount.jsx b/src/input/__tests__/mount.jsx new file mode 100644 index 000000000..99d256757 --- /dev/null +++ b/src/input/__tests__/mount.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { render } from '@test/utils'; +import { Input } from '..'; + +export function getInputGroupDefaultMount(InputGroup, props) { + return render( + + + + , + ); +} + +export default getInputGroupDefaultMount; diff --git a/src/input/__tests__/vitest-input.test.jsx b/src/input/__tests__/vitest-input.test.jsx new file mode 100644 index 000000000..43dcbb203 --- /dev/null +++ b/src/input/__tests__/vitest-input.test.jsx @@ -0,0 +1,433 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/** + * 该文件由脚本自动生成,如需修改请联系 PMC + * This file generated by scripts of tdesign-api. `npm run api:docs Input React(PC) vitest,finalProject` + * If you need to modify this file, contact PMC first please. + */ +import React from 'react'; +import { fireEvent, vi, render, mockDelay, simulateInputChange } from '@test/utils'; +import { Input, InputGroup } from '..'; +import { getInputGroupDefaultMount } from './mount'; + +describe('Input Component', () => { + const alignClassNameList = [{ 't-align-left': false }, 't-align-center', 't-align-right']; + ['left', 'center', 'right'].forEach((item, index) => { + it(`props.align is equal to ${item}`, () => { + const wrapper = render(); + const container = wrapper.container.querySelector('.t-input'); + if (typeof alignClassNameList[index] === 'string') { + expect(container).toHaveClass(alignClassNameList[index]); + } else if (typeof alignClassNameList[index] === 'object') { + const classNameKey = Object.keys(alignClassNameList[index])[0]; + expect(container.querySelector(`.${classNameKey}`)).toBeFalsy(); + } + expect(container).toMatchSnapshot(); + }); + }); + + it('props.allowInputOverMax works fine', () => { + const { container } = render(); + const inputDom = container.querySelector('input'); + simulateInputChange(inputDom, 'Hello TDesign'); + const attrDom = container.querySelector('input'); + expect(attrDom.value).toBe('Hello'); + }); + + it('props.autocomplete works fine', () => { + const wrapper = render(); + const container = wrapper.container.querySelector('input'); + expect(container.getAttribute('autocomplete')).toBe('https://tdesign.tencent.com/'); + }); + + it(`props.autofocus is equal to false`, () => { + const { container } = render(); + const domWrapper = container.querySelector('input'); + expect(domWrapper.getAttribute('autofocus')).toBeNull(); + }); + it(`props.autofocus is equal to true`, () => { + const { container } = render(); + const domWrapper = container.querySelector('input'); + expect(domWrapper.getAttribute('autofocus')).toBeDefined(); + }); + + it('props.clearable: clear icon should exist on input mouseenter', async () => { + const { container } = render(); + fireEvent.mouseEnter(container.querySelector('.t-input')); + await mockDelay(); + expect(container.querySelector('.t-input__suffix-clear')).toBeTruthy(); + }); + it('props.clearable: click clear icon could clear input value to be empty', async () => { + const onClearFn1 = vi.fn(); + const onChangeFn1 = vi.fn(); + const { container } = render( + , + ); + fireEvent.mouseEnter(container.querySelector('.t-input')); + await mockDelay(300); + expect(container.querySelector('.t-input__suffix-clear')).toBeTruthy(); + fireEvent.click(container.querySelector('.t-input__suffix-clear')); + expect(onClearFn1).toHaveBeenCalled(1); + expect(onClearFn1.mock.calls[0][0].e.stopPropagation).toBeTruthy(); + expect(onClearFn1.mock.calls[0][0].e.type).toBe('click'); + expect(onChangeFn1).toHaveBeenCalled(1); + expect(onChangeFn1.mock.calls[0][0]).toBe(''); + expect(onChangeFn1.mock.calls[0][1].e.stopPropagation).toBeTruthy(); + expect(onChangeFn1.mock.calls[0][1].e.type).toBe('click'); + }); + + it('props.disabled works fine', () => { + // disabled default value is + const wrapper1 = render(); + const container1 = wrapper1.container.querySelector('.t-input'); + expect(container1.querySelector(`.${'t-is-disabled'}`)).toBeFalsy(); + // disabled = true + const wrapper2 = render(); + const container2 = wrapper2.container.querySelector('.t-input'); + expect(container2).toHaveClass('t-is-disabled'); + // disabled = false + const wrapper3 = render(); + const container3 = wrapper3.container.querySelector('.t-input'); + expect(container3.querySelector(`.${'t-is-disabled'}`)).toBeFalsy(); + }); + + it('props.format: focus and blur states have different value', () => { + const { container } = render( `${val} 元`} value="100">); + fireEvent.focus(container.querySelector('input')); + const attrDom = container.querySelector('input'); + expect(attrDom.value).toBe('100'); + fireEvent.blur(container.querySelector('input')); + const attrDom1 = container.querySelector('input'); + expect(attrDom1.value).toBe('100 元'); + }); + + it(`props.inputClass is equal to name1 name2`, () => { + const { container } = render(); + const domWrapper = container.querySelector('.t-input'); + expect(domWrapper).toHaveClass('name1'); + expect(domWrapper).toHaveClass('name2'); + }); + it(`props.inputClass is equal to ['name1', 'name2']`, () => { + const { container } = render(); + const domWrapper = container.querySelector('.t-input'); + expect(domWrapper).toHaveClass('name1'); + expect(domWrapper).toHaveClass('name2'); + }); + it(`props.inputClass is equal to { name1: true, name2: false }`, () => { + const { container } = render(); + const domWrapper = container.querySelector('.t-input'); + expect(domWrapper).toHaveClass('name1'); + expect(domWrapper.classList.contains('name2')).toBeFalsy(); + }); + + it('props.label works fine', () => { + const { container } = render(TNode}>); + expect(container.querySelector('.custom-node')).toBeTruthy(); + expect(container.querySelector('.t-input__prefix')).toBeTruthy(); + expect(container).toMatchSnapshot(); + }); + + it('props.maxcharacter: length of value is over than maxcharacter', () => { + const onChangeFn = vi.fn(); + const { container } = render(); + expect(onChangeFn).toHaveBeenCalled(1); + expect(onChangeFn.mock.calls[0][0]).toBe('你好'); + expect(onChangeFn.mock.calls[0][1].trigger).toBe('initial'); + }); + + it('props.maxlength: length of value is over than maxlength', () => { + const onChangeFn = vi.fn(); + const { container } = render(); + expect(onChangeFn).toHaveBeenCalled(1); + expect(onChangeFn.mock.calls[0][0]).toBe('Hello'); + expect(onChangeFn.mock.calls[0][1].trigger).toBe('initial'); + }); + + it('props.name works fine', () => { + const wrapper = render(); + const container = wrapper.container.querySelector('input'); + expect(container.getAttribute('name')).toBe('input-name'); + }); + + it('props.placeholder works fine', () => { + const wrapper = render(); + const container = wrapper.container.querySelector('input'); + expect(container.getAttribute('placeholder')).toBe('this is input placeholder'); + }); + + it('props.prefixIcon works fine', () => { + const { container } = render(TNode}>); + expect(container.querySelector('.custom-node')).toBeTruthy(); + expect(container.querySelector('.t-input__prefix-icon')).toBeTruthy(); + }); + + it('props.readonly works fine', () => { + // readonly default value is false + const wrapper1 = render(); + const container1 = wrapper1.container.querySelector('.t-input'); + expect(container1.querySelector(`.${'t-is-readonly'}`)).toBeFalsy(); + // readonly = true + const wrapper2 = render(); + const container2 = wrapper2.container.querySelector('.t-input'); + expect(container2).toHaveClass('t-is-readonly'); + // readonly = false + const wrapper3 = render(); + const container3 = wrapper3.container.querySelector('.t-input'); + expect(container3.querySelector(`.${'t-is-readonly'}`)).toBeFalsy(); + }); + + it('props.showClearIconOnEmpty works fine', async () => { + const { container } = render(); + fireEvent.mouseEnter(container.querySelector('.t-input')); + await mockDelay(); + expect(container.querySelector('.t-input__suffix-clear')).toBeTruthy(); + }); + + it('props.showLimitNumber works fine. `{".t-input__limit-number":{"text":"2/5"}}` should exist', () => { + const { container } = render(); + expect(container.querySelector('.t-input__limit-number').textContent).toBe('2/5'); + }); + + const sizeClassNameList = ['t-size-s', { 't-size-m': false }, 't-size-l']; + ['small', 'medium', 'large'].forEach((item, index) => { + it(`props.size is equal to ${item}`, () => { + const wrapper = render(); + const container = wrapper.container.querySelector('.t-input'); + if (typeof sizeClassNameList[index] === 'string') { + expect(container).toHaveClass(sizeClassNameList[index]); + } else if (typeof sizeClassNameList[index] === 'object') { + const classNameKey = Object.keys(sizeClassNameList[index])[0]; + expect(container.querySelector(`.${classNameKey}`)).toBeFalsy(); + } + }); + }); + + const statusClassNameList = [{ 't-is-default': false }, 't-is-success', 't-is-warning', 't-is-error']; + ['default', 'success', 'warning', 'error'].forEach((item, index) => { + it(`props.status is equal to ${item}`, () => { + const wrapper = render(); + const container = wrapper.container.querySelector('.t-input'); + if (typeof statusClassNameList[index] === 'string') { + expect(container).toHaveClass(statusClassNameList[index]); + } else if (typeof statusClassNameList[index] === 'object') { + const classNameKey = Object.keys(statusClassNameList[index])[0]; + expect(container.querySelector(`.${classNameKey}`)).toBeFalsy(); + } + expect(container).toMatchSnapshot(); + }); + }); + + it('props.suffix works fine', () => { + const { container } = render(TNode}>); + expect(container.querySelector('.custom-node')).toBeTruthy(); + expect(container.querySelector('.t-input__suffix')).toBeTruthy(); + expect(container).toMatchSnapshot(); + }); + + it('props.suffixIcon works fine', () => { + const { container } = render(TNode}>); + expect(container.querySelector('.custom-node')).toBeTruthy(); + expect(container.querySelector('.t-input__suffix-icon')).toBeTruthy(); + expect(container).toMatchSnapshot(); + }); + + it('props.tips is equal this is a tip', () => { + const { container } = render(); + expect(container.querySelectorAll('.t-input__tips').length).toBe(1); + }); + + const attributeValues = ['text', 'number', 'url', 'tel', 'password', 'search', 'submit', 'hidden']; + ['text', 'number', 'url', 'tel', 'password', 'search', 'submit', 'hidden'].forEach((item, index) => { + it(`props.type is equal to ${item}`, () => { + const wrapper = render(); + const container = wrapper.container.querySelector('input'); + expect(container.getAttribute('type')).toBe(attributeValues[index]); + }); + }); + + it('props.type is equal password', () => { + const { container } = render(); + expect(container.querySelectorAll('.t-icon-browse-off').length).toBe(1); + }); + + it('props.type: password could be visible by click browse icon', () => { + const { container } = render(); + fireEvent.click(container.querySelector('.t-icon-browse-off')); + expect(container.querySelector('.t-icon-browse')).toBeTruthy(); + const attrDom = container.querySelector('input'); + expect(attrDom.getAttribute('type')).toBe('text'); + fireEvent.click(container.querySelector('.t-icon-browse')); + expect(container.querySelector('.t-icon-browse-off')).toBeTruthy(); + const attrDom1 = container.querySelector('input'); + expect(attrDom1.getAttribute('type')).toBe('password'); + }); + + it('events.blur works fine', async () => { + const onFocusFn = vi.fn(); + const onBlurFn1 = vi.fn(); + const { container } = render(); + fireEvent.focus(container.querySelector('input')); + expect(onFocusFn).toHaveBeenCalled(1); + expect(onFocusFn.mock.calls[0][0]).toBe('initial-input-value'); + expect(onFocusFn.mock.calls[0][1].e.type).toBe('focus'); + fireEvent.blur(container.querySelector('input')); + await mockDelay(300); + expect(onBlurFn1).toHaveBeenCalled(1); + expect(onBlurFn1.mock.calls[0][0]).toBe('initial-input-value'); + expect(onBlurFn1.mock.calls[0][1].e.type).toBe('blur'); + }); + + it('events.change: empty value could trigger change event', () => { + const onChangeFn = vi.fn(); + const { container } = render(); + const inputDom = container.querySelector('input'); + simulateInputChange(inputDom, 'initial value'); + expect(onChangeFn).toHaveBeenCalled(1); + expect(onChangeFn.mock.calls[0][0]).toBe('initial value'); + expect(onChangeFn.mock.calls[0][1].e.type).toBe('change'); + }); + it('events.change: controlled value test', () => { + const onChangeFn = vi.fn(); + const { container } = render(); + const inputDom = container.querySelector('input'); + simulateInputChange(inputDom, 'Hello TDesign'); + const attrDom = container.querySelector('input'); + expect(attrDom.value).toBe('TDesign'); + expect(onChangeFn).toHaveBeenCalled(1); + expect(onChangeFn.mock.calls[0][0]).toBe('Hello TDesign'); + expect(onChangeFn.mock.calls[0][1].e.type).toBe('change'); + }); + it('events.change: uncontrolled value test', () => { + const onChangeFn = vi.fn(); + const { container } = render(); + const inputDom = container.querySelector('input'); + simulateInputChange(inputDom, 'Hello TDesign'); + expect(onChangeFn).toHaveBeenCalled(1); + expect(onChangeFn.mock.calls[0][0]).toBe('Hello TDesign'); + expect(onChangeFn.mock.calls[0][1].e.type).toBe('change'); + }); + + it('events.click works fine', () => { + const fn = vi.fn(); + const { container } = render(); + fireEvent.click(container.querySelector('.t-input')); + expect(fn).toHaveBeenCalled(1); + expect(fn.mock.calls[0][0].e.type).toBe('click'); + }); + + it('events.compositionend works fine', () => { + const onCompositionendFn = vi.fn(); + const { container } = render(); + fireEvent.compositionEnd(container.querySelector('input')); + expect(onCompositionendFn).toHaveBeenCalled(1); + expect(onCompositionendFn.mock.calls[0][0]).toBe('输入结束'); + expect(onCompositionendFn.mock.calls[0][1].e.type).toBe('compositionend'); + }); + + it('events.compositionstart works fine', () => { + const onCompositionstartFn = vi.fn(); + const { container } = render(); + fireEvent.compositionStart(container.querySelector('input')); + expect(onCompositionstartFn).toHaveBeenCalled(1); + expect(onCompositionstartFn.mock.calls[0][0]).toBe('输入开始'); + expect(onCompositionstartFn.mock.calls[0][1].e.type).toBe('compositionstart'); + }); + + it('events.enter works fine', () => { + const onEnterFn1 = vi.fn(); + const { container } = render(); + fireEvent.focus(container.querySelector('input')); + fireEvent.keyDown(container.querySelector('input'), { key: 'Enter', code: 'Enter', charCode: 13 }); + expect(onEnterFn1).toHaveBeenCalled(1); + expect(onEnterFn1.mock.calls[0][0]).toBe('text'); + expect(onEnterFn1.mock.calls[0][1].e.type).toBe('keydown'); + }); + + it('events.focus works fine', () => { + const onFocusFn = vi.fn(); + const { container } = render(); + fireEvent.focus(container.querySelector('input')); + expect(onFocusFn).toHaveBeenCalled(1); + expect(onFocusFn.mock.calls[0][0]).toBe(undefined); + expect(onFocusFn.mock.calls[0][1].e.type).toBe('focus'); + }); + + it('events.keydown works fine', () => { + const onKeydownFn = vi.fn(); + const { container } = render(); + fireEvent.keyDown(container.querySelector('input')); + expect(onKeydownFn).toHaveBeenCalled(1); + expect(onKeydownFn.mock.calls[0][0]).toBe('text'); + expect(onKeydownFn.mock.calls[0][1].e.type).toBe('keydown'); + }); + + it('events.keypress works fine', () => { + const onKeydownFn = vi.fn(); + const { container } = render(); + fireEvent.keyDown(container.querySelector('input')); + expect(onKeydownFn).toHaveBeenCalled(1); + expect(onKeydownFn.mock.calls[0][0]).toBe('text'); + expect(onKeydownFn.mock.calls[0][1].e.type).toBe('keydown'); + }); + + it('events.keyup works fine', () => { + const onKeyupFn = vi.fn(); + const { container } = render(); + fireEvent.keyUp(container.querySelector('input')); + expect(onKeyupFn).toHaveBeenCalled(1); + expect(onKeyupFn.mock.calls[0][0]).toBe('text'); + expect(onKeyupFn.mock.calls[0][1].e.type).toBe('keyup'); + }); + + it('events.mouseenter works fine', async () => { + const onMouseenterFn = vi.fn(); + const { container } = render(); + fireEvent.mouseEnter(container.querySelector('.t-input')); + await mockDelay(); + expect(onMouseenterFn).toHaveBeenCalled(1); + expect(onMouseenterFn.mock.calls[0][0].e.type).toBe('mouseenter'); + }); + + it('events.mouseleave works fine', async () => { + const onMouseleaveFn = vi.fn(); + const { container } = render(); + fireEvent.mouseLeave(container.querySelector('.t-input')); + await mockDelay(); + expect(onMouseleaveFn).toHaveBeenCalled(1); + expect(onMouseleaveFn.mock.calls[0][0].e.type).toBe('mouseleave'); + }); + + it('events.paste works fine', () => { + const onPasteFn = vi.fn(); + const { container } = render(); + expect(onPasteFn).toHaveBeenCalled(1); + expect(onPasteFn.mock.calls[0][0].e.type).toBe('paste'); + }); + + it('events.validate works fine', () => { + const onValidateFn = vi.fn(); + const { container } = render(); + expect(onValidateFn).toHaveBeenCalled(1); + expect(onValidateFn.mock.calls[0][0].error).toBe('exceed-maximum'); + }); + + it('events.wheel works fine', () => { + const onWheelFn = vi.fn(); + const { container } = render(); + expect(onWheelFn).toHaveBeenCalled(1); + expect(onWheelFn.mock.calls[0][0].e.type).toBe('wheel'); + }); +}); + +describe('InputGroup Component', () => { + it('props.separate works fine', () => { + // separate default value is + const { container: container1 } = getInputGroupDefaultMount(InputGroup); + expect(container1.querySelector(`.${'t-input-group--separate'}`)).toBeFalsy(); + // separate = true + const { container: container2 } = getInputGroupDefaultMount(InputGroup, { separate: true }); + expect(container2.firstChild).toHaveClass('t-input-group--separate'); + // separate = false + const { container: container3 } = getInputGroupDefaultMount(InputGroup, { separate: false }); + expect(container3.querySelector(`.${'t-input-group--separate'}`)).toBeFalsy(); + }); +}); diff --git a/src/input/defaultProps.ts b/src/input/defaultProps.ts index 9eba8585b..ffb2faaf1 100644 --- a/src/input/defaultProps.ts +++ b/src/input/defaultProps.ts @@ -16,5 +16,6 @@ export const inputDefaultProps: TdInputProps = { showClearIconOnEmpty: false, showLimitNumber: false, size: 'medium', + status: 'default', type: 'text', }; diff --git a/src/input/index.ts b/src/input/index.ts index 886d7f634..b4116eb0b 100644 --- a/src/input/index.ts +++ b/src/input/index.ts @@ -1,4 +1,5 @@ import _Input from './Input'; +import _InputGroup from './InputGroup'; import './style/index.js'; @@ -7,4 +8,5 @@ export type { InputGroupProps } from './InputGroup'; export * from './type'; export const Input = _Input; +export const InputGroup = _InputGroup; export default Input; diff --git a/src/input/input.en-US.md b/src/input/input.en-US.md index 3c5937f52..1d8be378d 100644 --- a/src/input/input.en-US.md +++ b/src/input/input.en-US.md @@ -26,7 +26,7 @@ readonly | Boolean | false | \- | N showClearIconOnEmpty | Boolean | false | \- | N showLimitNumber | Boolean | false | show limit number text on the right | N size | String | medium | options:small/medium/large。Typescript:`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N -status | String | - | options:default/success/warning/error | N +status | String | default | options:default/success/warning/error | N suffix | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N @@ -34,7 +34,7 @@ type | String | text | options:text/number/url/tel/password/search/submit/hidd value | String / Number | - | Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N defaultValue | String / Number | - | uncontrolled property。Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N onBlur | Function | | Typescript:`(value: InputValue, context: { e: FocusEvent }) => void`
| N -onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent }) => void`
| N +onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
| N onClear | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onCompositionend | Function | | Typescript:`(value: InputValue, context: { e: CompositionEvent }) => void`
trigger on compositionend | N @@ -49,3 +49,11 @@ onMouseleave | Function | | Typescript:`(context: { e: MouseEvent }) => void` onPaste | Function | | Typescript:`(context: { e: ClipboardEvent; pasteValue: string }) => void`
| N onValidate | Function | | Typescript:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
trigger on text length being over max length or max character | N onWheel | Function | | Typescript:`(context: { e: WheelEvent }) => void`
trigger on mouse wheel | N + +### InputGroup Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,Typescript:`React.CSSProperties` | N +separate | Boolean | - | need separate between multiple inputs | N diff --git a/src/input/input.md b/src/input/input.md index 7f704019f..b7cbca35f 100644 --- a/src/input/input.md +++ b/src/input/input.md @@ -14,11 +14,11 @@ autocomplete | String | undefined | 是否开启自动填充功能,HTML5 原 autofocus | Boolean | false | 自动聚焦 | N clearable | Boolean | false | 是否可清空 | N disabled | Boolean | - | 是否禁用输入框 | N -format | Function | - | 【开发中】指定输入框展示值的格式。TS 类型:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N +format | Function | - | 指定输入框展示值的格式。TS 类型:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N inputClass | String / Object / Array | - | t-input 同级类名,示例:'name1 name2 name3' 或 `['name1', 'name2']` 或 `[{ 'name1': true }]`。TS 类型:`ClassName`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N label | TNode | - | 左侧文本。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N maxcharacter | Number | - | 用户最多可以输入的字符个数,一个中文汉字表示两个字符长度。`maxcharacter` 和 `maxlength` 二选一使用 | N -maxlength | Number | - | 用户最多可以输入的文本长度,一个中文等于一个计数长度。值小于等于 0 的时候,则表示不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 | N +maxlength | Number | - | 用户最多可以输入的文本长度,一个中文等于一个计数长度。值为空,则表示不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 | N name | String | - | 名称 | N placeholder | String | undefined | 占位符 | N prefixIcon | TElement | - | 组件前置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N @@ -26,7 +26,7 @@ readonly | Boolean | false | 只读状态 | N showClearIconOnEmpty | Boolean | false | 输入框内容为空时,悬浮状态是否显示清空按钮,默认不显示 | N showLimitNumber | Boolean | false | 是否在输入框右侧显示字数统计 | N size | String | medium | 输入框尺寸。可选项:small/medium/large。TS 类型:`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N -status | String | - | 输入框状态。可选项:default/success/warning/error | N +status | String | default | 输入框状态。可选项:default/success/warning/error | N suffix | TNode | - | 后置图标前的后置内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | 组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N @@ -34,7 +34,7 @@ type | String | text | 输入框类型。可选项:text/number/url/tel/passwor value | String / Number | - | 输入框的值。TS 类型:`InputValue` `type InputValue = string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N defaultValue | String / Number | - | 输入框的值。非受控属性。TS 类型:`InputValue` `type InputValue = string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N onBlur | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent }) => void`
失去焦点时触发 | N -onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent }) => void`
输入框值发生变化时触发 | N +onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 | N onClear | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
清空按钮点击时触发 | N onClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
点击组件时触发 | N onCompositionend | Function | | TS 类型:`(value: InputValue, context: { e: CompositionEvent }) => void`
中文输入结束时触发 | N @@ -49,3 +49,11 @@ onMouseleave | Function | | TS 类型:`(context: { e: MouseEvent }) => void`< onPaste | Function | | TS 类型:`(context: { e: ClipboardEvent; pasteValue: string }) => void`
粘贴事件,`pasteValue` 表示粘贴板的内容 | N onValidate | Function | | TS 类型:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
字数超出限制时触发 | N onWheel | Function | | TS 类型:`(context: { e: WheelEvent }) => void`
输入框中滚动鼠标时触发 | N + +### InputGroup Props + +名称 | 类型 | 默认值 | 说明 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +separate | Boolean | - | 多个输入框之间是否需要间隔 | N diff --git a/src/input/type.ts b/src/input/type.ts index 89517c5ea..fa4668a11 100644 --- a/src/input/type.ts +++ b/src/input/type.ts @@ -42,7 +42,7 @@ export interface TdInputProps { */ disabled?: boolean; /** - * 【开发中】指定输入框展示值的格式 + * 指定输入框展示值的格式 */ format?: InputFormatType; /** @@ -58,7 +58,7 @@ export interface TdInputProps { */ maxcharacter?: number; /** - * 用户最多可以输入的文本长度,一个中文等于一个计数长度。值小于等于 0 的时候,则表示不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 + * 用户最多可以输入的文本长度,一个中文等于一个计数长度。值为空,则表示不限制输入长度。`maxcharacter` 和 `maxlength` 二选一使用 */ maxlength?: number; /** @@ -96,6 +96,7 @@ export interface TdInputProps { size?: SizeEnum; /** * 输入框状态 + * @default default */ status?: 'default' | 'success' | 'warning' | 'error'; /** @@ -128,11 +129,11 @@ export interface TdInputProps { */ onBlur?: (value: InputValue, context: { e: FocusEvent }) => void; /** - * 输入框值发生变化时触发 + * 输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 */ onChange?: ( value: InputValue, - context?: { e?: FormEvent | MouseEvent }, + context?: { e?: FormEvent | MouseEvent; trigger: 'input' | 'initial' | 'clear' }, ) => void; /** * 清空按钮点击时触发 @@ -145,15 +146,15 @@ export interface TdInputProps { /** * 中文输入结束时触发 */ - onCompositionend?: (value: InputValue, context: { e: CompositionEvent }) => void; + onCompositionend?: (value: InputValue, context: { e: CompositionEvent }) => void; /** * 中文输入开始时触发 */ - onCompositionstart?: (value: InputValue, context: { e: CompositionEvent }) => void; + onCompositionstart?: (value: InputValue, context: { e: CompositionEvent }) => void; /** * 回车键按下时触发 */ - onEnter?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onEnter?: (value: InputValue, context: { e: KeyboardEvent }) => void; /** * 获得焦点时触发 */ @@ -161,15 +162,15 @@ export interface TdInputProps { /** * 键盘按下时触发 */ - onKeydown?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onKeydown?: (value: InputValue, context: { e: KeyboardEvent }) => void; /** * 按下字符键时触发(keydown -> keypress -> keyup) */ - onKeypress?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onKeypress?: (value: InputValue, context: { e: KeyboardEvent }) => void; /** * 释放键盘时触发 */ - onKeyup?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onKeyup?: (value: InputValue, context: { e: KeyboardEvent }) => void; /** * 进入输入框时触发 */ @@ -181,7 +182,7 @@ export interface TdInputProps { /** * 粘贴事件,`pasteValue` 表示粘贴板的内容 */ - onPaste?: (context: { e: ClipboardEvent; pasteValue: string }) => void; + onPaste?: (context: { e: ClipboardEvent; pasteValue: string }) => void; /** * 字数超出限制时触发 */ @@ -192,6 +193,13 @@ export interface TdInputProps { onWheel?: (context: { e: WheelEvent }) => void; } +export interface TdInputGroupProps { + /** + * 多个输入框之间是否需要间隔 + */ + separate?: boolean; +} + export type InputFormatType = (value: InputValue) => string; export type InputValue = string; diff --git a/src/select-input/useSingle.tsx b/src/select-input/useSingle.tsx index acd5220e7..0296d762d 100644 --- a/src/select-input/useSingle.tsx +++ b/src/select-input/useSingle.tsx @@ -1,9 +1,9 @@ -import React, { useRef, MouseEvent, FormEvent, useMemo } from 'react'; +import React, { useRef, MouseEvent, useMemo } from 'react'; import isObject from 'lodash/isObject'; import pick from 'lodash/pick'; import classNames from 'classnames'; import { SelectInputCommonProperties } from './interface'; -import Input, { InputValue } from '../input'; +import Input, { TdInputProps } from '../input'; import { TdSelectInputProps } from './type'; import { Loading } from '../loading'; import useConfig from '../hooks/useConfig'; @@ -58,10 +58,7 @@ export default function useSingle(props: TdSelectInputProps) { setInputValue('', { trigger: 'clear' }); }; - const onInnerInputChange = ( - value: InputValue, - context: { e: FormEvent | MouseEvent }, - ) => { + const onInnerInputChange: TdInputProps['onChange'] = (value, context) => { if (props.allowInput) { setInputValue(value, { ...context, trigger: 'input' }); } diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 097d4f71e..541c78ba8 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -4494,7 +4494,7 @@ exports[`csr snapshot test > csr test src/auto-complete/_example/base.jsx 1`] = value="" >
csr test src/auto-complete/_example/base.jsx 1`] = value="" >
csr test src/auto-complete/_example/base.jsx 1`] = value="" >
csr test src/auto-complete/_example/base.jsx 1`] = value="" >
csr test src/auto-complete/_example/filter.jsx 1`] value="" >
csr test src/auto-complete/_example/filter.jsx 1`] value="" >
csr test src/auto-complete/_example/filter.jsx 1`] value="" >
csr test src/auto-complete/_example/filter.jsx 1`] value="" >
csr test src/auto-complete/_example/option.jsx 1`] value="" >
csr test src/auto-complete/_example/option.jsx 1`] value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/size.jsx 1`] = value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/auto-complete/_example/status.jsx 1`] value="" >
csr test src/calendar/_example/base.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/base.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/base.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/base.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/card.jsx 1`] = ` value="卡片风格" >
csr test src/calendar/_example/card.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/card.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/card.jsx 1`] = ` value="卡片风格" >
csr test src/calendar/_example/card.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/card.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/cell.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/cell.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/cell.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/cell.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/cell-append.jsx 1`] value="2020 年" >
csr test src/calendar/_example/cell-append.jsx 1`] value="12 月" >
csr test src/calendar/_example/cell-append.jsx 1`] value="2020 年" >
csr test src/calendar/_example/cell-append.jsx 1`] value="12 月" >
csr test src/calendar/_example/controller-config.js value="2020 年" >
csr test src/calendar/_example/controller-config.js value="12 月" >
csr test src/calendar/_example/controller-config.js value="2020 年" >
csr test src/calendar/_example/controller-config.js value="12 月" >
csr test src/calendar/_example/event-props-api.jsx value="2020 年" >
csr test src/calendar/_example/event-props-api.jsx value="12 月" >
csr test src/calendar/_example/event-props-api.jsx value="2020 年" >
csr test src/calendar/_example/event-props-api.jsx value="12 月" >
csr test src/calendar/_example/events.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/events.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/events.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/events.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/filter.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/filter.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/filter.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/filter.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/first-day-of-week.js value="周三" >
csr test src/calendar/_example/first-day-of-week.js value="2020 年" >
csr test src/calendar/_example/first-day-of-week.js value="12 月" >
csr test src/calendar/_example/first-day-of-week.js value="周三" >
csr test src/calendar/_example/first-day-of-week.js value="2020 年" >
csr test src/calendar/_example/first-day-of-week.js value="12 月" >
csr test src/calendar/_example/head.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/head.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/head.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/head.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/mode.jsx 1`] = ` value="月历" >
csr test src/calendar/_example/mode.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/mode.jsx 1`] = ` value="月历" >
csr test src/calendar/_example/mode.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/range.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/range.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/range.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/range.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/slot-props-api.jsx 1 value="2020 年" >
csr test src/calendar/_example/slot-props-api.jsx 1 value="12 月" >
csr test src/calendar/_example/slot-props-api.jsx 1 value="2020 年" >
csr test src/calendar/_example/slot-props-api.jsx 1 value="12 月" >
csr test src/calendar/_example/value.jsx 1`] = ` value="1998 年" >
csr test src/calendar/_example/value.jsx 1`] = ` value="11 月" >
csr test src/calendar/_example/value.jsx 1`] = ` value="1998 年" >
csr test src/calendar/_example/value.jsx 1`] = ` value="11 月" >
csr test src/calendar/_example/week.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/week.jsx 1`] = ` value="12 月" >
csr test src/calendar/_example/week.jsx 1`] = ` value="2020 年" >
csr test src/calendar/_example/week.jsx 1`] = ` value="12 月" >
csr test src/cascader/_example/base.jsx 1`] = ` value="" >
csr test src/cascader/_example/base.jsx 1`] = ` value="" >
csr test src/cascader/_example/check-strictly.jsx 1 value="1 / 1.2 / 1.2.2" >
csr test src/cascader/_example/check-strictly.jsx 1 value="" >
csr test src/cascader/_example/check-strictly.jsx 1 value="1 / 1.2 / 1.2.2" >
csr test src/cascader/_example/check-strictly.jsx 1 value="" >
csr test src/cascader/_example/collapsed.jsx 1`] = value="" >
csr test src/cascader/_example/collapsed.jsx 1`] = value="" >
csr test src/cascader/_example/collapsed.jsx 1`] = value="" >
csr test src/cascader/_example/collapsed.jsx 1`] = value="" >
csr test src/cascader/_example/disabled.jsx 1`] = ` value="选项一 / 子选项一" >
csr test src/cascader/_example/disabled.jsx 1`] = ` value="" >
csr test src/cascader/_example/disabled.jsx 1`] = ` value="选项一 / 子选项一" >
csr test src/cascader/_example/disabled.jsx 1`] = ` value="" >
csr test src/cascader/_example/ellipsis.jsx 1`] = ` value="" >
csr test src/cascader/_example/ellipsis.jsx 1`] = ` value="" >
csr test src/cascader/_example/filterable.jsx 1`] = value="" >
csr test src/cascader/_example/filterable.jsx 1`] = value="" >
csr test src/cascader/_example/filterable.jsx 1`] = value="" >
csr test src/cascader/_example/filterable.jsx 1`] = value="" >
csr test src/cascader/_example/keys.jsx 1`] = ` value="" >
csr test src/cascader/_example/keys.jsx 1`] = ` value="" >
csr test src/cascader/_example/keys.jsx 1`] = ` value="" >
csr test src/cascader/_example/keys.jsx 1`] = ` value="" >
csr test src/cascader/_example/load.jsx 1`] = ` value="" >
csr test src/cascader/_example/load.jsx 1`] = ` value="" >
csr test src/cascader/_example/max.jsx 1`] = ` value="" >
csr test src/cascader/_example/max.jsx 1`] = ` value="" >
csr test src/cascader/_example/multiple.jsx 1`] = ` value="" >
csr test src/cascader/_example/multiple.jsx 1`] = ` value="" >
csr test src/cascader/_example/show-all-levels.jsx value="" >
csr test src/cascader/_example/show-all-levels.jsx value="" >
csr test src/cascader/_example/show-all-levels.jsx value="" >
csr test src/cascader/_example/show-all-levels.jsx value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/size.jsx 1`] = ` value="" >
csr test src/cascader/_example/trigger.jsx 1`] = ` value="" >
csr test src/cascader/_example/trigger.jsx 1`] = ` value="" >
csr test src/cascader/_example/trigger.jsx 1`] = ` value="" >
csr test src/cascader/_example/trigger.jsx 1`] = ` value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-mode.jsx 1`] = value="" >
csr test src/cascader/_example/value-type.jsx 1`] = value="选项一 / 子选项一" >
csr test src/cascader/_example/value-type.jsx 1`] = value="" >
csr test src/cascader/_example/value-type.jsx 1`] = value="选项一 / 子选项一" >
csr test src/cascader/_example/value-type.jsx 1`] = value="" >
csr test src/checkbox/_example/max.jsx 1`] = ` value="1" >
csr test src/checkbox/_example/max.jsx 1`] = ` value="1" >
csr test src/color-picker/_example/enable-alpha.jsx value="RGB" >
csr test src/color-picker/_example/enable-alpha.jsx value="0" >
csr test src/color-picker/_example/enable-alpha.jsx value="82" >
csr test src/color-picker/_example/enable-alpha.jsx value="217" >
csr test src/color-picker/_example/enable-alpha.jsx value="100%" >
csr test src/color-picker/_example/enable-alpha.jsx value="RGB" >
csr test src/color-picker/_example/enable-alpha.jsx value="0" >
csr test src/color-picker/_example/enable-alpha.jsx value="82" >
csr test src/color-picker/_example/enable-alpha.jsx value="217" >
csr test src/color-picker/_example/enable-alpha.jsx value="100%" >
csr test src/color-picker/_example/panel.jsx 1`] = value="RGB" >
csr test src/color-picker/_example/panel.jsx 1`] = value="0" >
csr test src/color-picker/_example/panel.jsx 1`] = value="82" >
csr test src/color-picker/_example/panel.jsx 1`] = value="217" >
csr test src/color-picker/_example/panel.jsx 1`] = value="RGB" >
csr test src/color-picker/_example/panel.jsx 1`] = value="0" >
csr test src/color-picker/_example/panel.jsx 1`] = value="82" >
csr test src/color-picker/_example/panel.jsx 1`] = value="217" >
csr test src/color-picker/_example/recent-color.jsx value="RGB" >
csr test src/color-picker/_example/recent-color.jsx value="0" >
csr test src/color-picker/_example/recent-color.jsx value="82" >
csr test src/color-picker/_example/recent-color.jsx value="217" >
csr test src/color-picker/_example/recent-color.jsx value="RGB" >
csr test src/color-picker/_example/recent-color.jsx value="0" >
csr test src/color-picker/_example/recent-color.jsx value="82" >
csr test src/color-picker/_example/recent-color.jsx value="217" >
csr test src/color-picker/_example/recent-color.jsx value="RGB" >
csr test src/color-picker/_example/recent-color.jsx value="0" >
csr test src/color-picker/_example/recent-color.jsx value="82" >
csr test src/color-picker/_example/recent-color.jsx value="217" >
csr test src/color-picker/_example/recent-color.jsx value="RGB" >
csr test src/color-picker/_example/recent-color.jsx value="0" >
csr test src/color-picker/_example/recent-color.jsx value="82" >
csr test src/color-picker/_example/recent-color.jsx value="217" >
csr test src/color-picker/_example/status-readonly. value="RGB" >
csr test src/color-picker/_example/status-readonly. value="0" >
csr test src/color-picker/_example/status-readonly. value="82" >
csr test src/color-picker/_example/status-readonly. value="217" >
csr test src/color-picker/_example/status-readonly. value="RGB" >
csr test src/color-picker/_example/status-readonly. value="0" >
csr test src/color-picker/_example/status-readonly. value="82" >
csr test src/color-picker/_example/status-readonly. value="217" >
csr test src/color-picker/_example/swatch-color.jsx value="RGB" >
csr test src/color-picker/_example/swatch-color.jsx value="0" >
csr test src/color-picker/_example/swatch-color.jsx value="82" >
csr test src/color-picker/_example/swatch-color.jsx value="217" >
csr test src/color-picker/_example/swatch-color.jsx value="RGB" >
csr test src/color-picker/_example/swatch-color.jsx value="0" >
csr test src/color-picker/_example/swatch-color.jsx value="82" >
csr test src/color-picker/_example/swatch-color.jsx value="217" >
csr test src/color-picker/_example/swatch-color.jsx value="RGB" >
csr test src/color-picker/_example/swatch-color.jsx value="0" >
csr test src/color-picker/_example/swatch-color.jsx value="82" >
csr test src/color-picker/_example/swatch-color.jsx value="217" >
csr test src/color-picker/_example/swatch-color.jsx value="RGB" >
csr test src/color-picker/_example/swatch-color.jsx value="0" >
csr test src/color-picker/_example/swatch-color.jsx value="82" >
csr test src/color-picker/_example/swatch-color.jsx value="217" >
csr test src/config-provider/_example/calendar.jsx value="2020" >
csr test src/config-provider/_example/calendar.jsx value="December" >
csr test src/config-provider/_example/calendar.jsx value="2020" >
csr test src/config-provider/_example/calendar.jsx value="December" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/date-picker.j value="" >
csr test src/config-provider/_example/others.jsx 1` class="t-input__wrap" >
csr test src/config-provider/_example/others.jsx 1` value="" >
csr test src/config-provider/_example/others.jsx 1` value="" >
csr test src/config-provider/_example/others.jsx 1` class="t-input__wrap" >
csr test src/config-provider/_example/others.jsx 1` class="t-input__wrap" >
csr test src/config-provider/_example/others.jsx 1` value="" >
csr test src/config-provider/_example/others.jsx 1` value="" >
csr test src/config-provider/_example/others.jsx 1` class="t-input__wrap" >
csr test src/config-provider/_example/pagination.js value="10 / page" >
csr test src/config-provider/_example/pagination.js value="1" >
csr test src/config-provider/_example/pagination.js value="10 / page" >
csr test src/config-provider/_example/pagination.js value="1" >
csr test src/date-picker/_example/base.jsx 1`] = ` value="" >
csr test src/date-picker/_example/base.jsx 1`] = ` value="" >
csr test src/date-picker/_example/base.jsx 1`] = ` value="" >
csr test src/date-picker/_example/base.jsx 1`] = ` value="" >
csr test src/date-picker/_example/custom-icon.jsx 1 value="" >
csr test src/date-picker/_example/custom-icon.jsx 1 value="" >
csr test src/date-picker/_example/date-time.jsx 1`] value="2022-02-02 12:11:11" >
csr test src/date-picker/_example/date-time.jsx 1`] value="2022-02-02 pm 12:11:11" >
csr test src/date-picker/_example/date-time.jsx 1`] value="2022-02-02 12:11:11" >
csr test src/date-picker/_example/date-time.jsx 1`] value="2022-02-02 pm 12:11:11" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/disable-date.jsx value="" >
csr test src/date-picker/_example/first-day-of-week value="" >
csr test src/date-picker/_example/first-day-of-week value="" >
csr test src/date-picker/_example/month.jsx 1`] = ` value="" >
csr test src/date-picker/_example/month.jsx 1`] = ` value="" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Jan" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2021" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Jan" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2021" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="Dec" >
csr test src/date-picker/_example/panel.jsx 1`] = ` value="2020" >
csr test src/date-picker/_example/quarter.jsx 1`] = value="" >
csr test src/date-picker/_example/quarter.jsx 1`] = value="" >
csr test src/date-picker/_example/week.jsx 1`] = ` value="" >
csr test src/date-picker/_example/week.jsx 1`] = ` value="" >
csr test src/date-picker/_example/year.jsx 1`] = ` value="" >
csr test src/date-picker/_example/year.jsx 1`] = ` value="" >
csr test src/form/_example/base.jsx 1`] = ` value="" >
csr test src/form/_example/base.jsx 1`] = ` value="" >
csr test src/form/_example/clear-validate.jsx 1`] = class="t-input__wrap" >
csr test src/form/_example/clear-validate.jsx 1`] = class="t-input__wrap" >
csr test src/form/_example/disabled.jsx 1`] = ` class="t-input__wrap" >
csr test src/form/_example/disabled.jsx 1`] = ` value="江苏" >
csr test src/form/_example/disabled.jsx 1`] = ` value="上海" >
csr test src/form/_example/disabled.jsx 1`] = ` value="" >
csr test src/form/_example/disabled.jsx 1`] = ` value="" >
csr test src/form/_example/disabled.jsx 1`] = ` class="t-input__wrap" >
csr test src/form/_example/disabled.jsx 1`] = ` value="江苏" >
csr test src/form/_example/disabled.jsx 1`] = ` value="上海" >
csr test src/form/_example/disabled.jsx 1`] = ` value="" >
csr test src/form/_example/disabled.jsx 1`] = ` value="" >
csr test src/form/_example/error-message.jsx 1`] = class="t-input__wrap" >
csr test src/form/_example/error-message.jsx 1`] = class="t-input__wrap" >
csr test src/form/_example/nested-data.jsx 1`] = ` value="2022-08-08" >
csr test src/form/_example/nested-data.jsx 1`] = ` value="2022-08-08" >
csr test src/icon/_example/IconSelect.jsx 1`] = ` value="edit-1" >
csr test src/icon/_example/IconSelect.jsx 1`] = ` value="edit-1" >
csr test src/input/_example/max-length-count.jsx 1` value="" >
csr test src/input/_example/max-length-count.jsx 1` value="" >
csr test src/input-adornment/_example/select.jsx 1` value="http://" >
csr test src/input-adornment/_example/select.jsx 1` value=".cn" >
csr test src/input-adornment/_example/select.jsx 1` value="http://" >
csr test src/input-adornment/_example/select.jsx 1` value="tencent" >
csr test src/input-adornment/_example/select.jsx 1` value=".cn" >
csr test src/input-adornment/_example/select.jsx 1` value="http://" >
csr test src/input-adornment/_example/select.jsx 1` value=".cn" >
csr test src/input-adornment/_example/select.jsx 1` value="http://" >
csr test src/input-adornment/_example/select.jsx 1` value="tencent" >
csr test src/input-adornment/_example/select.jsx 1` value=".cn" >
csr test src/input-number/_example/align.jsx 1`] = value="100" >
csr test src/input-number/_example/align.jsx 1`] = value="200" >
csr test src/input-number/_example/align.jsx 1`] = value="300" >
csr test src/input-number/_example/align.jsx 1`] = value="100" >
csr test src/input-number/_example/align.jsx 1`] = value="200" >
csr test src/input-number/_example/align.jsx 1`] = value="300" >
csr test src/input-number/_example/align.jsx 1`] = value="100" >
csr test src/input-number/_example/align.jsx 1`] = value="200" >
csr test src/input-number/_example/align.jsx 1`] = value="300" >
csr test src/input-number/_example/align.jsx 1`] = value="100" >
csr test src/input-number/_example/align.jsx 1`] = value="200" >
csr test src/input-number/_example/align.jsx 1`] = value="300" >
csr test src/input-number/_example/auto-width.jsx 1 value="1" >
csr test src/input-number/_example/auto-width.jsx 1 value="1" >
csr test src/input-number/_example/center.jsx 1`] = value="3" >
csr test src/input-number/_example/center.jsx 1`] = value="" >
csr test src/input-number/_example/center.jsx 1`] = value="3" >
csr test src/input-number/_example/center.jsx 1`] = value="" >
csr test src/input-number/_example/default.jsx 1`] value="1" >
csr test src/input-number/_example/default.jsx 1`] value="1" >
csr test src/input-number/_example/format.jsx 1`] = value="0 %" >
csr test src/input-number/_example/format.jsx 1`] = value="0.00 %" >
csr test src/input-number/_example/format.jsx 1`] = value="0 %" >
csr test src/input-number/_example/format.jsx 1`] = value="0.00 %" >
csr test src/input-number/_example/large-number.jsx value="19999999999999999.00" >
csr test src/input-number/_example/large-number.jsx value="0.8975527383412673418" >
csr test src/input-number/_example/large-number.jsx value="19999999999999999.00" >
csr test src/input-number/_example/large-number.jsx value="0.8975527383412673418" >
csr test src/input-number/_example/left.jsx 1`] = ` value="5" >
csr test src/input-number/_example/left.jsx 1`] = ` value="5" >
csr test src/input-number/_example/normal.jsx 1`] = value="10" >
csr test src/input-number/_example/normal.jsx 1`] = value="" >
csr test src/input-number/_example/normal.jsx 1`] = value="10" >
csr test src/input-number/_example/normal.jsx 1`] = value="10" >
csr test src/input-number/_example/normal.jsx 1`] = value="" >
csr test src/input-number/_example/normal.jsx 1`] = value="10" >
csr test src/input-number/_example/size.jsx 1`] = ` value="3" >
csr test src/input-number/_example/size.jsx 1`] = ` value="6" >
csr test src/input-number/_example/size.jsx 1`] = ` value="9" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="10" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="10" >
csr test src/input-number/_example/size.jsx 1`] = ` value="3" >
csr test src/input-number/_example/size.jsx 1`] = ` value="6" >
csr test src/input-number/_example/size.jsx 1`] = ` value="9" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="10" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="5" >
csr test src/input-number/_example/size.jsx 1`] = ` value="10" >
csr test src/input-number/_example/status.jsx 1`] = value="" >
csr test src/input-number/_example/status.jsx 1`] = value="" >
csr test src/input-number/_example/step.jsx 1`] = ` value="3.20" >
csr test src/input-number/_example/step.jsx 1`] = ` value="3.20" >
csr test src/pagination/_example/base.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/base.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/jump.jsx 1`] = ` value="20 / page" >
csr test src/pagination/_example/jump.jsx 1`] = ` value="1" >
csr test src/pagination/_example/jump.jsx 1`] = ` value="20 / page" >
csr test src/pagination/_example/jump.jsx 1`] = ` value="1" >
csr test src/pagination/_example/mini.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/mini.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/more.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/more.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/more.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/more.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/page-num.jsx 1`] = value="20 / page" >
csr test src/pagination/_example/page-num.jsx 1`] = value="20 / page" >
csr test src/pagination/_example/simple.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/simple.jsx 1`] = ` value="1" >
csr test src/pagination/_example/simple.jsx 1`] = ` value="5 / page" >
csr test src/pagination/_example/simple.jsx 1`] = ` value="1" >
csr test src/pagination/_example/simple-mini.jsx 1` value="5 / page" >
csr test src/pagination/_example/simple-mini.jsx 1` value="1" >
csr test src/pagination/_example/simple-mini.jsx 1` value="5 / page" >
csr test src/pagination/_example/simple-mini.jsx 1` value="1" >
csr test src/pagination/_example/total.jsx 1`] = ` value="10 / page" >
csr test src/pagination/_example/total.jsx 1`] = ` value="10 / page" >
csr test src/select/_example/base.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/base.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/collapsed.jsx 1`] = ` value="" >
csr test src/select/_example/collapsed.jsx 1`] = ` value="" >
csr test src/select/_example/collapsed.jsx 1`] = ` value="" >
csr test src/select/_example/collapsed.jsx 1`] = ` value="" >
csr test src/select/_example/creatable.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/creatable.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/custom-options.jsx 1`] value="用户一" >
csr test src/select/_example/custom-options.jsx 1`] value="用户一" >
csr test src/select/_example/custom-selected.jsx 1` value=" " >
csr test src/select/_example/custom-selected.jsx 1` value="" >
csr test src/select/_example/custom-selected.jsx 1` value=" " >
csr test src/select/_example/custom-selected.jsx 1` value="" >
csr test src/select/_example/disabled.jsx 1`] = ` value="Apple" >
csr test src/select/_example/disabled.jsx 1`] = ` value="Apple" >
csr test src/select/_example/filterable.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/filterable.jsx 1`] = ` value="" >
csr test src/select/_example/filterable.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/filterable.jsx 1`] = ` value="" >
csr test src/select/_example/group.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/group.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/keys.jsx 1`] = ` value="已选择的选项" >
csr test src/select/_example/keys.jsx 1`] = ` value="" >
csr test src/select/_example/keys.jsx 1`] = ` value="已选择的选项" >
csr test src/select/_example/keys.jsx 1`] = ` value="" >
csr test src/select/_example/label-in-value.jsx 1`] value="Apple" >
csr test src/select/_example/label-in-value.jsx 1`] value="Apple" >
csr test src/select/_example/label-in-value.jsx 1`] value="" >
csr test src/select/_example/label-in-value.jsx 1`] value="Apple" >
csr test src/select/_example/label-in-value.jsx 1`] value="Apple" >
csr test src/select/_example/label-in-value.jsx 1`] value="" >
csr test src/select/_example/max.jsx 1`] = ` value="" >
csr test src/select/_example/max.jsx 1`] = ` value="" >
csr test src/select/_example/multiple.jsx 1`] = ` value="" >
csr test src/select/_example/multiple.jsx 1`] = ` value="" >
csr test src/select/_example/multiple.jsx 1`] = ` value="" >
csr test src/select/_example/multiple.jsx 1`] = ` value="" >
csr test src/select/_example/noborder.jsx 1`] = ` value="已选择的选项" >
csr test src/select/_example/noborder.jsx 1`] = ` value="已选择的选项" >
csr test src/select/_example/options.jsx 1`] = ` value="Apple" >
csr test src/select/_example/options.jsx 1`] = ` value="Apple" >
csr test src/select/_example/panel.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/panel.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/panel.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/panel.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/popup-props.jsx 1`] = value="固定300px宽度" >
csr test src/select/_example/popup-props.jsx 1`] = value="下拉框强制和输入框同宽" >
csr test src/select/_example/popup-props.jsx 1`] = value="固定300px宽度" >
csr test src/select/_example/popup-props.jsx 1`] = value="下拉框强制和输入框同宽" >
csr test src/select/_example/prefix.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/prefix.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/remote-search.jsx 1`] class="t-input__wrap" >
csr test src/select/_example/remote-search.jsx 1`] class="t-input__wrap" >
csr test src/select/_example/scroll-top.jsx 1`] = ` value="第 50 项" >
csr test src/select/_example/scroll-top.jsx 1`] = ` value="第 50 项" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/size.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select/_example/status.jsx 1`] = ` class="t-input__wrap" >
csr test src/select-input/_example/autocomplete.jsx value="" >
csr test src/select-input/_example/autocomplete.jsx value="" >
csr test src/select-input/_example/autowidth.jsx 1` value="tdesign-vue" >
csr test src/select-input/_example/autowidth.jsx 1` value="tdesign-vue" >
csr test src/select-input/_example/autowidth-multip value="" >
csr test src/select-input/_example/autowidth-multip value="" >
csr test src/select-input/_example/borderless.jsx 1 value="tdesign-vue" >
csr test src/select-input/_example/borderless.jsx 1 value="tdesign-vue" >
csr test src/select-input/_example/borderless-multi value="" >
csr test src/select-input/_example/borderless-multi value="" >
csr test src/select-input/_example/collapsed-items. value="" >
csr test src/select-input/_example/collapsed-items. value="" >
csr test src/select-input/_example/collapsed-items. value="" >
csr test src/select-input/_example/collapsed-items. value="" >
csr test src/select-input/_example/custom-tag.jsx 1 value=" " >
csr test src/select-input/_example/custom-tag.jsx 1 value="" >
csr test src/select-input/_example/custom-tag.jsx 1 value="" >
csr test src/select-input/_example/custom-tag.jsx 1 value=" " >
csr test src/select-input/_example/custom-tag.jsx 1 value="" >
csr test src/select-input/_example/custom-tag.jsx 1 value="" >
csr test src/select-input/_example/excess-tags-disp value="" >
csr test src/select-input/_example/excess-tags-disp value="" >
csr test src/select-input/_example/excess-tags-disp value="" >
csr test src/select-input/_example/excess-tags-disp value="" >
csr test src/select-input/_example/label-suffix.jsx value="tdesign-vue" >
csr test src/select-input/_example/label-suffix.jsx value="tdesign-vue" >
csr test src/select-input/_example/label-suffix.jsx value="tdesign-vue" >
csr test src/select-input/_example/label-suffix.jsx value="tdesign-vue" >
csr test src/select-input/_example/multiple.jsx 1`] value="" >
csr test src/select-input/_example/multiple.jsx 1`] value="" >
csr test src/select-input/_example/single.jsx 1`] = value="tdesign-vue" >
csr test src/select-input/_example/single.jsx 1`] = value="tdesign-vue" >
csr test src/select-input/_example/status.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/status.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/status.jsx 1`] = class="t-input__wrap" >
csr test src/select-input/_example/status.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/status.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/status.jsx 1`] = class="t-input__wrap" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/select-input/_example/width.jsx 1`] = value="TDesign" >
csr test src/slider/_example/input-number.jsx 1`] = value="10" >
csr test src/slider/_example/input-number.jsx 1`] = value="10" >
csr test src/slider/_example/input-number.jsx 1`] = value="80" >
csr test src/slider/_example/input-number.jsx 1`] = value="10" >
csr test src/slider/_example/input-number.jsx 1`] = value="10" >
csr test src/slider/_example/input-number.jsx 1`] = value="80" >
csr test src/slider/_example/input-number-vertical. value="10" >
csr test src/slider/_example/input-number-vertical. value="10" >
csr test src/slider/_example/input-number-vertical. value="80" >
csr test src/slider/_example/input-number-vertical. value="10" >
csr test src/slider/_example/input-number-vertical. value="10" >
csr test src/slider/_example/input-number-vertical. value="80" >
csr test src/table/_example/affix.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/affix.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/base.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/base.jsx 1`] = ` value="2" >
csr test src/table/_example/base.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/base.jsx 1`] = ` value="2" >
csr test src/table/_example/custom-col.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/custom-col.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/custom-col-button.jsx 1 value="5 / page" >
csr test src/table/_example/custom-col-button.jsx 1 value="5 / page" >
csr test src/table/_example/editable-row.jsx 1`] = value="审批通过" >
csr test src/table/_example/editable-row.jsx 1`] = value="" >
csr test src/table/_example/editable-row.jsx 1`] = value="2022-01-01" >
csr test src/table/_example/editable-row.jsx 1`] = value="审批通过" >
csr test src/table/_example/editable-row.jsx 1`] = value="" >
csr test src/table/_example/editable-row.jsx 1`] = value="2022-01-01" >
csr test src/table/_example/filter-controlled.jsx 1 value="5 / page" >
csr test src/table/_example/filter-controlled.jsx 1 value="1" >
csr test src/table/_example/filter-controlled.jsx 1 value="5 / page" >
csr test src/table/_example/filter-controlled.jsx 1 value="1" >
csr test src/table/_example/pagination.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/pagination.jsx 1`] = ` value="2" >
csr test src/table/_example/pagination.jsx 1`] = ` value="5 / page" >
csr test src/table/_example/pagination.jsx 1`] = ` value="2" >
csr test src/table/_example/pagination-ajax.jsx 1`] value="5 / page" >
csr test src/table/_example/pagination-ajax.jsx 1`] value="1" >
csr test src/table/_example/pagination-ajax.jsx 1`] value="5 / page" >
csr test src/table/_example/pagination-ajax.jsx 1`] value="1" >
csr test src/table/_example/tree.jsx 1`] = ` value="10 / page" >
csr test src/table/_example/tree.jsx 1`] = ` value="10 / page" >
csr test src/time-picker/_example/disabled.jsx 1`] class="t-input__wrap" >
csr test src/time-picker/_example/disabled.jsx 1`] class="t-input__wrap" >
csr test src/time-picker/_example/disabled.jsx 1`] class="t-input__wrap" >
csr test src/time-picker/_example/disabled.jsx 1`] class="t-input__wrap" >
csr test src/time-picker/_example/hide-clear-button value="12:00:00" >
csr test src/time-picker/_example/hide-clear-button value="12:00:00" >
csr test src/time-picker/_example/hide-clear-button value="12:00:00" >
csr test src/time-picker/_example/hide-clear-button value="12:00:00" >
csr test src/time-picker/_example/hm.jsx 1`] = ` value="12:00" >
csr test src/time-picker/_example/hm.jsx 1`] = ` value="12:59:59:000" >
csr test src/time-picker/_example/hm.jsx 1`] = ` value="12:00" >
csr test src/time-picker/_example/hm.jsx 1`] = ` value="12:59:59:000" >
csr test src/time-picker/_example/hms.jsx 1`] = ` value="12:00:00" >
csr test src/time-picker/_example/hms.jsx 1`] = ` value="12:00:00" >
csr test src/time-picker/_example/keyboard.jsx 1`] value="12:08:00" >
csr test src/time-picker/_example/keyboard.jsx 1`] value="12:08:00" >
csr test src/time-picker/_example/show-steps.jsx 1` class="t-input__wrap" >
csr test src/time-picker/_example/show-steps.jsx 1` class="t-input__wrap" >
csr test src/time-picker/_example/twelve-hour-merid class="t-input__wrap" >
csr test src/time-picker/_example/twelve-hour-merid class="t-input__wrap" >
csr test src/transfer/_example/pagination.jsx 1`] = value="1" >
csr test src/transfer/_example/pagination.jsx 1`] = value="1" >
csr test src/transfer/_example/pagination.jsx 1`] = value="1" >
csr test src/transfer/_example/pagination.jsx 1`] = value="1" >
csr test src/tree-select/_example/base.jsx 1`] = ` value="广东省" >
csr test src/tree-select/_example/base.jsx 1`] = ` value="广东省" >
csr test src/tree-select/_example/collapsed.jsx 1`] value="" >
csr test src/tree-select/_example/collapsed.jsx 1`] value="" >
csr test src/tree-select/_example/collapsed.jsx 1`] value="" >
csr test src/tree-select/_example/collapsed.jsx 1`] value="" >
csr test src/tree-select/_example/filterable.jsx 1` value="" >
csr test src/tree-select/_example/filterable.jsx 1` value="" >
csr test src/tree-select/_example/filterable.jsx 1` value="" >
csr test src/tree-select/_example/filterable.jsx 1` value="" >
csr test src/tree-select/_example/lazy.jsx 1`] = ` value="null" >
csr test src/tree-select/_example/lazy.jsx 1`] = ` value="null" >
csr test src/tree-select/_example/multiple.jsx 1`] value="" >
csr test src/tree-select/_example/multiple.jsx 1`] value="" >
csr test src/tree-select/_example/prefix.jsx 1`] = value="" >
csr test src/tree-select/_example/prefix.jsx 1`] = value="" >
csr test src/tree-select/_example/props.jsx 1`] = ` value="深圳市" >
csr test src/tree-select/_example/props.jsx 1`] = ` value="深圳市" >
csr test src/tree-select/_example/valuedisplay.jsx value=" " >
csr test src/tree-select/_example/valuedisplay.jsx value="" >
csr test src/tree-select/_example/valuedisplay.jsx value=" " >
csr test src/tree-select/_example/valuedisplay.jsx value="" >
csr test src/tree-select/_example/valuetype.jsx 1`] value="深圳市" >
csr test src/tree-select/_example/valuetype.jsx 1`] value="" >
csr test src/tree-select/_example/valuetype.jsx 1`] value="深圳市" >
csr test src/tree-select/_example/valuetype.jsx 1`] value="" >
resolve(true), timeout); }); } + +export function simulateInputChange(dom, text) { + fireEvent.change(dom, { target: { value: text } }); +} From ed602bce0d8e5d75ae95f6a588256490b926034f Mon Sep 17 00:00:00 2001 From: lincao Date: Sat, 14 Jan 2023 19:37:59 +0800 Subject: [PATCH 2/7] =?UTF-8?q?test(input):=20=E8=A1=A5=E5=85=85input?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/input/Input.tsx | 23 +++++++++++++++++++---- src/input/__tests__/vitest-input.test.jsx | 12 +++++++----- src/input/defaultProps.ts | 1 - test/utils/index.jsx | 12 +++++++++++- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/input/Input.tsx b/src/input/Input.tsx index 6c2c36128..7be74f721 100644 --- a/src/input/Input.tsx +++ b/src/input/Input.tsx @@ -76,6 +76,7 @@ const Input = forwardRefWithStatics( keepWrapperWidth, showLimitNumber, allowInputOverMax, + name, format, onClick, onClear, @@ -97,7 +98,6 @@ const Input = forwardRefWithStatics( } = props; const [value, onChange] = useControlled(props, 'value', onChangeFromProps); - const { limitNumber, getValueByLimitNumber, tStatus } = useLengthLimit({ value: value === undefined ? undefined : String(value), status, @@ -176,6 +176,17 @@ const Input = forwardRefWithStatics( setRenderType(type); }, [type]); + // 初始判断长度,如超限自动截断并触发onchange + useEffect(() => { + if (value) { + const limitedValue = getValueByLimitNumber(value); + if (limitedValue.length !== value.length && !allowInputOverMax) { + onChange?.(limitedValue, { trigger: 'initial' }); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const innerValue = composingRef.current ? composingValue : value ?? ''; const formatDisplayValue = format && !isFocused ? format(innerValue) : innerValue; @@ -199,6 +210,7 @@ const Input = forwardRefWithStatics( onFocus={handleFocus} onBlur={handleBlur} onPaste={handlePaste} + name={name} /> ); @@ -244,7 +256,10 @@ const Input = forwardRefWithStatics( setRenderType(toggleType); } - function handleChange(e: React.ChangeEvent | React.CompositionEvent) { + function handleChange( + e: React.ChangeEvent | React.CompositionEvent, + trigger = 'input', + ) { let { value: newStr } = e.currentTarget; if (composingRef.current) { setComposingValue(newStr); @@ -254,11 +269,11 @@ const Input = forwardRefWithStatics( } // 完成中文输入时同步一次 composingValue setComposingValue(newStr); - onChange(newStr, { e }); + onChange(newStr, { e, trigger }); } } function handleClear(e: React.MouseEvent) { - onChange?.('', { e }); + onChange?.('', { e, trigger: 'clear' }); onClear?.({ e }); } function handleKeyDown(e: React.KeyboardEvent) { diff --git a/src/input/__tests__/vitest-input.test.jsx b/src/input/__tests__/vitest-input.test.jsx index 43dcbb203..f17ff4866 100644 --- a/src/input/__tests__/vitest-input.test.jsx +++ b/src/input/__tests__/vitest-input.test.jsx @@ -5,7 +5,7 @@ * If you need to modify this file, contact PMC first please. */ import React from 'react'; -import { fireEvent, vi, render, mockDelay, simulateInputChange } from '@test/utils'; +import { fireEvent, vi, render, mockDelay, simulateInputChange, simulateClipboardPaste } from '@test/utils'; import { Input, InputGroup } from '..'; import { getInputGroupDefaultMount } from './mount'; @@ -347,7 +347,7 @@ describe('Input Component', () => { const { container } = render(); fireEvent.focus(container.querySelector('input')); expect(onFocusFn).toHaveBeenCalled(1); - expect(onFocusFn.mock.calls[0][0]).toBe(undefined); + expect(onFocusFn.mock.calls[0][0]).toBe(''); expect(onFocusFn.mock.calls[0][1].e.type).toBe('focus'); }); @@ -398,8 +398,9 @@ describe('Input Component', () => { it('events.paste works fine', () => { const onPasteFn = vi.fn(); - const { container } = render(); - expect(onPasteFn).toHaveBeenCalled(1); + const { getByDisplayValue } = render(); + simulateClipboardPaste(getByDisplayValue(''), 'hello'); + expect(onPasteFn).toHaveBeenCalled(); expect(onPasteFn.mock.calls[0][0].e.type).toBe('paste'); }); @@ -412,7 +413,8 @@ describe('Input Component', () => { it('events.wheel works fine', () => { const onWheelFn = vi.fn(); - const { container } = render(); + const { getByDisplayValue } = render(); + fireEvent.wheel(getByDisplayValue('')); expect(onWheelFn).toHaveBeenCalled(1); expect(onWheelFn.mock.calls[0][0].e.type).toBe('wheel'); }); diff --git a/src/input/defaultProps.ts b/src/input/defaultProps.ts index ffb2faaf1..9eba8585b 100644 --- a/src/input/defaultProps.ts +++ b/src/input/defaultProps.ts @@ -16,6 +16,5 @@ export const inputDefaultProps: TdInputProps = { showClearIconOnEmpty: false, showLimitNumber: false, size: 'medium', - status: 'default', type: 'text', }; diff --git a/test/utils/index.jsx b/test/utils/index.jsx index f9c882f36..5d0a2a879 100644 --- a/test/utils/index.jsx +++ b/test/utils/index.jsx @@ -1,8 +1,9 @@ import '@testing-library/jest-dom'; import _userEvent from '@testing-library/user-event'; +import { fireEvent, createEvent } from '@testing-library/react'; + export * from '@testing-library/react'; export * from 'vitest'; -import { fireEvent } from '@testing-library/react'; export const userEvent = _userEvent; @@ -22,3 +23,12 @@ export function mockDelay(timeout = 300) { export function simulateInputChange(dom, text) { fireEvent.change(dom, { target: { value: text } }); } + +export function simulateClipboardPaste(dom, text) { + const paste = createEvent.paste(dom, { + clipboardData: { + getData: () => text, + }, + }); + fireEvent(dom, paste); +} From d653e342957f333340132a26338223238a7636d7 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sat, 14 Jan 2023 19:43:07 +0800 Subject: [PATCH 3/7] test: add some more auto-complete and input unit tests --- src/auto-complete/AutoComplete.tsx | 12 +- src/auto-complete/OptionList.tsx | 31 ++++- src/auto-complete/__tests__/mount.jsx | 11 ++ .../__tests__/vitest-auto-complete.test.jsx | 129 ++++++++++++++++-- src/auto-complete/_example/base.jsx | 1 - src/auto-complete/auto-complete.en-US.md | 2 +- src/auto-complete/auto-complete.md | 2 +- src/auto-complete/type.ts | 10 +- src/input/__tests__/vitest-input.test.jsx | 9 +- src/input/defaultProps.ts | 2 +- src/input/input.en-US.md | 4 +- src/input/input.md | 4 +- src/input/type.ts | 10 +- .../__tests__/vitest-tag-input.test.jsx | 7 + src/tag-input/tag-input.en-US.md | 2 +- src/tag-input/tag-input.md | 2 +- src/tag-input/type.ts | 8 +- test/utils/index.jsx | 28 ++++ 18 files changed, 229 insertions(+), 45 deletions(-) create mode 100644 src/tag-input/__tests__/vitest-tag-input.test.jsx diff --git a/src/auto-complete/AutoComplete.tsx b/src/auto-complete/AutoComplete.tsx index d22a6a305..efdb9e3e2 100644 --- a/src/auto-complete/AutoComplete.tsx +++ b/src/auto-complete/AutoComplete.tsx @@ -1,4 +1,4 @@ -import React, { FormEvent, forwardRef, useRef, useState, useImperativeHandle } from 'react'; +import React, { forwardRef, useRef, useState, useImperativeHandle } from 'react'; import classNames from 'classnames'; import useControlled from '../hooks/useControlled'; import { ClassName, StyledProps } from '../common'; @@ -6,7 +6,7 @@ import { AutoCompleteOption, TdAutoCompleteProps } from './type'; import { autoCompleteDefaultProps } from './defaultProps'; import useCommonClassName from '../hooks/useCommonClassName'; import { useLocaleReceiver } from '../locale/LocalReceiver'; -import Input, { InputProps, InputRef } from '../input'; +import Input, { InputProps, InputRef, TdInputProps } from '../input'; import Popup, { PopupProps, PopupRef } from '../popup'; import AutoCompleteOptionList, { OptionsListProps } from './OptionList'; @@ -27,6 +27,7 @@ const AutoComplete = forwardRef((props, ref) const [global] = useLocaleReceiver('input'); const [popupVisible, setPopupVisible] = useState(false); + const optionListRef = useRef(null); useImperativeHandle(ref, () => ({ inputRef: inputRef.current, @@ -59,7 +60,7 @@ const AutoComplete = forwardRef((props, ref) return classNames(classes); })(); - const onInputChange = (value: string, context: { e: FormEvent }) => { + const onInputChange: TdInputProps['onChange'] = (value, context) => { setTValue(value, context); }; @@ -75,6 +76,10 @@ const AutoComplete = forwardRef((props, ref) const onInnerFocus: InputProps['onFocus'] = (value, context) => { setPopupVisible(true); props.onFocus?.({ ...context, value }); + const timer = setTimeout(() => { + optionListRef.current?.addKeyboardListener(); + clearTimeout(timer); + }, 0); }; const onInnerBlur: InputProps['onBlur'] = (value, context) => { @@ -130,6 +135,7 @@ const AutoComplete = forwardRef((props, ref) // 联想词列表 const listContent = ( | KeyboardEvent | any }) => void; } -const OptionsList = (props: OptionsListProps) => { +export interface OptionsListRef { + addKeyboardListener: () => void; + removeKeyboardListener: () => void; +} + +const OptionsList = forwardRef((props: OptionsListProps, ref) => { const { value, onSelect, popupVisible } = props; const [active, setActive] = useState(''); const { classPrefix } = useConfig(); @@ -91,14 +97,27 @@ const OptionsList = (props: OptionsListProps) => { } }; + const addKeyboardListener = () => { + on(document, 'keydown', onKeyInnerPress); + }; + + const removeKeyboardListener = () => { + off(document, 'keydown', onKeyInnerPress); + }; + + useImperativeHandle(ref, () => ({ + addKeyboardListener, + removeKeyboardListener, + })); + useEffect(() => { if (popupVisible) { - document.addEventListener('keydown', onKeyInnerPress); + addKeyboardListener(); } else { - document.removeEventListener('keydown', onKeyInnerPress); + removeKeyboardListener(); } return () => { - document.removeEventListener('keydown', onKeyInnerPress); + removeKeyboardListener(); }; // eslint-disable-next-line }, [popupVisible]); @@ -130,7 +149,7 @@ const OptionsList = (props: OptionsListProps) => { })} ); -}; +}); OptionsList.displayName = 'OptionsList'; diff --git a/src/auto-complete/__tests__/mount.jsx b/src/auto-complete/__tests__/mount.jsx index 710e6a81a..4d19448be 100644 --- a/src/auto-complete/__tests__/mount.jsx +++ b/src/auto-complete/__tests__/mount.jsx @@ -11,6 +11,17 @@ export function getNormalAutoCompleteMount(AutoComplete, props, events) { text: 'SecondKeyword', }, 'ThirdKeyword', + { + label: 'READONLY_KEYWORD', + }, + { + text: 'DISABLED_KEYWORD', + }, ]; return render(); } + +export function getOptionSlotAutoCompleteMount(AutoComplete, props, events) { + const options = ['First', { label:
First Keyword
, text: 'First Keyword' }]; + return render(); +} diff --git a/src/auto-complete/__tests__/vitest-auto-complete.test.jsx b/src/auto-complete/__tests__/vitest-auto-complete.test.jsx index 3e4d14e3a..38262ca6e 100644 --- a/src/auto-complete/__tests__/vitest-auto-complete.test.jsx +++ b/src/auto-complete/__tests__/vitest-auto-complete.test.jsx @@ -1,12 +1,13 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ /** * 该文件由脚本自动生成,如需修改请联系 PMC * This file generated by scripts of tdesign-api. `npm run api:docs AutoComplete React(PC) vitest,finalProject` * If you need to modify this file, contact PMC first please. */ import React from 'react'; -import { fireEvent, vi, render, mockDelay } from '@test/utils'; +import { fireEvent, vi, render, mockDelay, simulateKeydownEvent } from '@test/utils'; import { AutoComplete } from '..'; -import { getNormalAutoCompleteMount } from './mount'; +import { getNormalAutoCompleteMount, getOptionSlotAutoCompleteMount } from './mount'; describe('AutoComplete Component', () => { it(`props.autofocus is equal to false`, () => { @@ -47,10 +48,10 @@ describe('AutoComplete Component', () => { await mockDelay(); expect(container.querySelector('.t-input__suffix-clear')).toBeTruthy(); fireEvent.click(container.querySelector('.t-input__suffix-clear')); - expect(onClearFn1).toHaveBeenCalled(); + expect(onClearFn1).toHaveBeenCalled(1); expect(onClearFn1.mock.calls[0][0].e.stopPropagation).toBeTruthy(); expect(onClearFn1.mock.calls[0][0].e.type).toBe('click'); - expect(onChangeFn1).toHaveBeenCalled(); + expect(onChangeFn1).toHaveBeenCalled(1); expect(onChangeFn1.mock.calls[0][0]).toBe(''); expect(onChangeFn1.mock.calls[0][1].e.stopPropagation).toBeTruthy(); expect(onChangeFn1.mock.calls[0][1].e.type).toBe('click'); @@ -100,11 +101,27 @@ describe('AutoComplete Component', () => { const customNodeDom = document.querySelector('.custom-node'); expect(customNodeDom).toBeDefined(); }); - it('props.options: 3 options should exist', () => { + it('props.options: 5 options should exist', () => { const { container } = getNormalAutoCompleteMount(AutoComplete); fireEvent.focus(container.querySelector('input')); const tSelectOptionDom = document.querySelectorAll('.t-select-option'); - expect(tSelectOptionDom.length).toBe(3); + expect(tSelectOptionDom.length).toBe(5); + }); + it('props.options: expect empty options with no panel', () => { + const { container } = render(); + fireEvent.focus(container.querySelector('input')); + const tAutocompletePanelDom = document.querySelectorAll('.t-autocomplete__panel'); + expect(tAutocompletePanelDom.length).toBe(0); + }); + it('props.options: define one option', () => { + const { container } = getOptionSlotAutoCompleteMount(AutoComplete, { + popupProps: { overlayClassName: 'option-slot-class-name' }, + }); + fireEvent.focus(container.querySelector('input')); + const optionSlotClassNameCustomSlotOptionDom = document.querySelector( + '.option-slot-class-name .custom-slot-option', + ); + expect(optionSlotClassNameCustomSlotOptionDom.textContent).toBe('First Keyword'); }); it('props.panelBottomContent works fine', () => { @@ -130,11 +147,28 @@ describe('AutoComplete Component', () => { }); it(`props.placeholder is equal to 'type keyword to search'`, () => { - const { container } = render(); + const { container } = render(); const domWrapper = container.querySelector('input'); expect(domWrapper.getAttribute('placeholder')).toBe('type keyword to search'); }); + it('props.popupProps works fine', () => { + const { container } = getNormalAutoCompleteMount(AutoComplete, { + popupProps: { overlayClassName: 'custom-class-name' }, + }); + fireEvent.focus(container.querySelector('input')); + const customClassNameDom = document.querySelector('.custom-class-name'); + expect(customClassNameDom).toBeDefined(); + }); + it('props.popupProps works fine', () => { + const { container } = getNormalAutoCompleteMount(AutoComplete, { + popupProps: { overlayInnerClassName: 'custom-class-name' }, + }); + fireEvent.focus(container.querySelector('input')); + const customClassNameDom = document.querySelector('.custom-class-name'); + expect(customClassNameDom).toBeDefined(); + }); + it('props.readonly works fine', () => { // readonly default value is const wrapper1 = getNormalAutoCompleteMount(AutoComplete); @@ -164,16 +198,22 @@ describe('AutoComplete Component', () => { }); }); - ['default', 'success', 'warning', 'error'].forEach((item) => { + const statusClassNameList = [{ 't-is-default': false }, 't-is-success', 't-is-warning', 't-is-error']; + ['default', 'success', 'warning', 'error'].forEach((item, index) => { it(`props.status is equal to ${item}`, () => { const wrapper = getNormalAutoCompleteMount(AutoComplete, { status: item }); const container = wrapper.container.querySelector('.t-input'); - expect(container).toHaveClass(`t-is-${item}`); + if (typeof statusClassNameList[index] === 'string') { + expect(container).toHaveClass(statusClassNameList[index]); + } else if (typeof statusClassNameList[index] === 'object') { + const classNameKey = Object.keys(statusClassNameList[index])[0]; + expect(container.querySelector(`.${classNameKey}`)).toBeFalsy(); + } }); }); it('props.tips is equal this is a tip', () => { - const { container } = render(); + const { container } = render(); expect(container.querySelector('.t-input__tips')).toBeTruthy(); }); @@ -185,7 +225,7 @@ describe('AutoComplete Component', () => { }); it(`props.value is equal to 'DefaultKeyword'`, () => { - const { container } = render(); + const { container } = render(); const domWrapper = container.querySelector('input'); expect(domWrapper.value).toBe('DefaultKeyword'); }); @@ -195,20 +235,36 @@ describe('AutoComplete Component', () => { const onBlurFn1 = vi.fn(); const { container } = getNormalAutoCompleteMount(AutoComplete, {}, { onFocus: onFocusFn, onBlur: onBlurFn1 }); fireEvent.focus(container.querySelector('input')); - expect(onFocusFn).toHaveBeenCalled(); + expect(onFocusFn).toHaveBeenCalled(1); expect(onFocusFn.mock.calls[0][0].e.type).toBe('focus'); fireEvent.blur(container.querySelector('input')); await mockDelay(300); - expect(onBlurFn1).toHaveBeenCalled(); + expect(onBlurFn1).toHaveBeenCalled(1); expect(onBlurFn1.mock.calls[0][0].e.type).toBe('blur'); }); + it('events.compositionend works fine', () => { + const onCompositionendFn = vi.fn(); + const { container } = render(); + fireEvent.compositionEnd(container.querySelector('input')); + expect(onCompositionendFn).toHaveBeenCalled(1); + expect(onCompositionendFn.mock.calls[0][0].e.type).toBe('compositionend'); + }); + + it('events.compositionstart works fine', () => { + const onCompositionstartFn = vi.fn(); + const { container } = render(); + fireEvent.compositionStart(container.querySelector('input')); + expect(onCompositionstartFn).toHaveBeenCalled(1); + expect(onCompositionstartFn.mock.calls[0][0].e.type).toBe('compositionstart'); + }); + it('events.enter works fine', () => { const onEnterFn1 = vi.fn(); const { container } = getNormalAutoCompleteMount(AutoComplete, {}, { onEnter: onEnterFn1 }); fireEvent.focus(container.querySelector('input')); fireEvent.keyDown(container.querySelector('input'), { key: 'Enter', code: 'Enter', charCode: 13 }); - expect(onEnterFn1).toHaveBeenCalled(); + expect(onEnterFn1).toHaveBeenCalled(1); expect(onEnterFn1.mock.calls[0][0].e.type).toBe('keydown'); expect(/Enter/i.test(onEnterFn1.mock.calls[0][0].e.key)).toBeTruthy(); }); @@ -218,7 +274,50 @@ describe('AutoComplete Component', () => { const { container } = getNormalAutoCompleteMount(AutoComplete, {}, { onFocus: onFocusFn }); fireEvent.focus(container.querySelector('input')); expect(container.querySelector('.t-is-focused')).toBeTruthy(); - expect(onFocusFn).toHaveBeenCalled(); + expect(onFocusFn).toHaveBeenCalled(1); expect(onFocusFn.mock.calls[0][0].e.type).toBe('focus'); }); + + it('events.select works fine', () => { + const onSelectFn1 = vi.fn(); + const { container } = getNormalAutoCompleteMount( + AutoComplete, + { popupProps: { overlayClassName: 'select-event-class-name' } }, + { onSelect: onSelectFn1 }, + ); + fireEvent.focus(container.querySelector('input')); + fireEvent.click(document.querySelector('.select-event-class-name .t-select-option')); + expect(onSelectFn1).toHaveBeenCalled(1); + expect(onSelectFn1.mock.calls[0][0]).toBe('FirstKeyword'); + expect(onSelectFn1.mock.calls[0][1].e.type).toBe('click'); + }); + it('events.select: keyboard operations: ArrowDown & ArrowUp & Enter', async () => { + const onSelectFn6 = vi.fn(); + const { container } = getNormalAutoCompleteMount(AutoComplete, {}, { onSelect: onSelectFn6 }); + fireEvent.focus(container.querySelector('input')); + simulateKeydownEvent(document, 'ArrowDown'); + await mockDelay(10); + const domWrapper1 = document.querySelector('.t-select-option:first-child'); + expect(domWrapper1).toHaveClass('t-select-option--hover'); + simulateKeydownEvent(document, 'ArrowDown'); + await mockDelay(10); + const domWrapper2 = document.querySelector('.t-select-option:nth-child(2)'); + expect(domWrapper2).toHaveClass('t-select-option--hover'); + simulateKeydownEvent(document, 'ArrowUp'); + await mockDelay(10); + const domWrapper3 = document.querySelector('.t-select-option:first-child'); + expect(domWrapper3).toHaveClass('t-select-option--hover'); + simulateKeydownEvent(document, 'ArrowUp'); + await mockDelay(10); + const domWrapper4 = document.querySelector('.t-select-option:nth-child(5)'); + expect(domWrapper4).toHaveClass('t-select-option--hover'); + simulateKeydownEvent(document, 'ArrowDown'); + await mockDelay(10); + const domWrapper5 = document.querySelector('.t-select-option:first-child'); + expect(domWrapper5).toHaveClass('t-select-option--hover'); + simulateKeydownEvent(document, 'Enter'); + expect(onSelectFn6).toHaveBeenCalled(1); + expect(onSelectFn6.mock.calls[0][0]).toBe('FirstKeyword'); + expect(onSelectFn6.mock.calls[0][1].e.type).toBe('keydown'); + }); }); diff --git a/src/auto-complete/_example/base.jsx b/src/auto-complete/_example/base.jsx index 440432118..07cd238b8 100644 --- a/src/auto-complete/_example/base.jsx +++ b/src/auto-complete/_example/base.jsx @@ -50,7 +50,6 @@ const AutoCompleteBase = () => { highlightKeyword filterable={false} clearable - autofocus={true} placeholder="请输入关键词搜索" onBlur={() => { console.log('blur'); diff --git a/src/auto-complete/auto-complete.en-US.md b/src/auto-complete/auto-complete.en-US.md index 5af736b84..e2d32bb53 100644 --- a/src/auto-complete/auto-complete.en-US.md +++ b/src/auto-complete/auto-complete.en-US.md @@ -29,7 +29,7 @@ triggerElement | TNode | - | Typescript:`string \| TNode`。[see more ts defin value | String | - | \- | N defaultValue | String | - | uncontrolled property | N onBlur | Function | | Typescript:`(context: { e: FocusEvent; value: string }) => void`
| N -onChange | Function | | Typescript:`(value: string, context?: { e?: InputEvent \| MouseEvent \| KeyboardEvent }) => void`
| N +onChange | Function | | Typescript:`(value: string, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent \| KeyboardEvent }) => void`
| N onClear | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onCompositionend | Function | | Typescript:`(context: { e: CompositionEvent; value: string }) => void`
trigger on compositionend | N onCompositionstart | Function | | Typescript:`(context: { e: CompositionEvent; value: string }) => void`
trigger on compositionstart | N diff --git a/src/auto-complete/auto-complete.md b/src/auto-complete/auto-complete.md index 5fc1ece72..a6e6ca744 100644 --- a/src/auto-complete/auto-complete.md +++ b/src/auto-complete/auto-complete.md @@ -29,7 +29,7 @@ triggerElement | TNode | - | 触发显示联想词下拉框的元素,默认为 value | String | - | 输入框的值,即当前指定的联想词 | N defaultValue | String | - | 输入框的值,即当前指定的联想词。非受控属性 | N onBlur | Function | | TS 类型:`(context: { e: FocusEvent; value: string }) => void`
失去焦点时触发 | N -onChange | Function | | TS 类型:`(value: string, context?: { e?: InputEvent \| MouseEvent \| KeyboardEvent }) => void`
输入框值发生变化时触发 | N +onChange | Function | | TS 类型:`(value: string, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent \| KeyboardEvent }) => void`
输入框值发生变化时触发 | N onClear | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
清空按钮点击时触发 | N onCompositionend | Function | | TS 类型:`(context: { e: CompositionEvent; value: string }) => void`
中文输入结束时触发 | N onCompositionstart | Function | | TS 类型:`(context: { e: CompositionEvent; value: string }) => void`
中文输入开始时触发 | N diff --git a/src/auto-complete/type.ts b/src/auto-complete/type.ts index 8bfc889e4..6fea8b877 100644 --- a/src/auto-complete/type.ts +++ b/src/auto-complete/type.ts @@ -110,7 +110,9 @@ export interface TdAutoCompleteProps | MouseEvent | KeyboardEvent }, + context?: { + e?: FormEvent | MouseEvent | CompositionEvent | KeyboardEvent; + }, ) => void; /** * 清空按钮点击时触发 @@ -119,11 +121,11 @@ export interface TdAutoCompleteProps; value: string }) => void; + onCompositionend?: (context: { e: CompositionEvent; value: string }) => void; /** * 中文输入开始时触发 */ - onCompositionstart?: (context: { e: CompositionEvent; value: string }) => void; + onCompositionstart?: (context: { e: CompositionEvent; value: string }) => void; /** * 回车键按下时触发 */ @@ -135,7 +137,7 @@ export interface TdAutoCompleteProps | KeyboardEvent }) => void; + onSelect?: (value: string, context: { e: MouseEvent | KeyboardEvent }) => void; } export type AutoCompleteOption = string | AutoCompleteOptionObj; diff --git a/src/input/__tests__/vitest-input.test.jsx b/src/input/__tests__/vitest-input.test.jsx index 43dcbb203..558a416d9 100644 --- a/src/input/__tests__/vitest-input.test.jsx +++ b/src/input/__tests__/vitest-input.test.jsx @@ -74,6 +74,13 @@ describe('Input Component', () => { expect(onChangeFn1.mock.calls[0][1].e.stopPropagation).toBeTruthy(); expect(onChangeFn1.mock.calls[0][1].e.type).toBe('click'); }); + it('props.clearable: type=password, browseIcon and clearableIcon works fine', async () => { + const { container } = render(); + expect(container.querySelector('.t-icon-browse-off')).toBeTruthy(); + fireEvent.mouseEnter(container.querySelector('.t-input')); + await mockDelay(300); + expect(container.querySelector('.t-input__suffix-clear')).toBeTruthy(); + }); it('props.disabled works fine', () => { // disabled default value is @@ -347,7 +354,7 @@ describe('Input Component', () => { const { container } = render(); fireEvent.focus(container.querySelector('input')); expect(onFocusFn).toHaveBeenCalled(1); - expect(onFocusFn.mock.calls[0][0]).toBe(undefined); + expect(onFocusFn.mock.calls[0][0]).toBe(''); expect(onFocusFn.mock.calls[0][1].e.type).toBe('focus'); }); diff --git a/src/input/defaultProps.ts b/src/input/defaultProps.ts index ffb2faaf1..9bde98022 100644 --- a/src/input/defaultProps.ts +++ b/src/input/defaultProps.ts @@ -16,6 +16,6 @@ export const inputDefaultProps: TdInputProps = { showClearIconOnEmpty: false, showLimitNumber: false, size: 'medium', - status: 'default', + status: undefined, type: 'text', }; diff --git a/src/input/input.en-US.md b/src/input/input.en-US.md index 1d8be378d..7d7abdcd8 100644 --- a/src/input/input.en-US.md +++ b/src/input/input.en-US.md @@ -26,7 +26,7 @@ readonly | Boolean | false | \- | N showClearIconOnEmpty | Boolean | false | \- | N showLimitNumber | Boolean | false | show limit number text on the right | N size | String | medium | options:small/medium/large。Typescript:`SizeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N -status | String | default | options:default/success/warning/error | N +status | String | undefined | options:default/success/warning/error | N suffix | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N @@ -34,7 +34,7 @@ type | String | text | options:text/number/url/tel/password/search/submit/hidd value | String / Number | - | Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N defaultValue | String / Number | - | uncontrolled property。Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N onBlur | Function | | Typescript:`(value: InputValue, context: { e: FocusEvent }) => void`
| N -onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
| N +onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
| N onClear | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onCompositionend | Function | | Typescript:`(value: InputValue, context: { e: CompositionEvent }) => void`
trigger on compositionend | N diff --git a/src/input/input.md b/src/input/input.md index b7cbca35f..1933e6114 100644 --- a/src/input/input.md +++ b/src/input/input.md @@ -26,7 +26,7 @@ readonly | Boolean | false | 只读状态 | N showClearIconOnEmpty | Boolean | false | 输入框内容为空时,悬浮状态是否显示清空按钮,默认不显示 | N showLimitNumber | Boolean | false | 是否在输入框右侧显示字数统计 | N size | String | medium | 输入框尺寸。可选项:small/medium/large。TS 类型:`SizeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N -status | String | default | 输入框状态。可选项:default/success/warning/error | N +status | String | undefined | 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化。可选项:default/success/warning/error | N suffix | TNode | - | 后置图标前的后置内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | 组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N @@ -34,7 +34,7 @@ type | String | text | 输入框类型。可选项:text/number/url/tel/passwor value | String / Number | - | 输入框的值。TS 类型:`InputValue` `type InputValue = string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N defaultValue | String / Number | - | 输入框的值。非受控属性。TS 类型:`InputValue` `type InputValue = string`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/input/type.ts) | N onBlur | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent }) => void`
失去焦点时触发 | N -onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 | N +onChange | Function | | TS 类型:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制 | N onClear | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
清空按钮点击时触发 | N onClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
点击组件时触发 | N onCompositionend | Function | | TS 类型:`(value: InputValue, context: { e: CompositionEvent }) => void`
中文输入结束时触发 | N diff --git a/src/input/type.ts b/src/input/type.ts index fa4668a11..4f36ab1f1 100644 --- a/src/input/type.ts +++ b/src/input/type.ts @@ -95,8 +95,7 @@ export interface TdInputProps { */ size?: SizeEnum; /** - * 输入框状态 - * @default default + * 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化 */ status?: 'default' | 'success' | 'warning' | 'error'; /** @@ -133,7 +132,10 @@ export interface TdInputProps { */ onChange?: ( value: InputValue, - context?: { e?: FormEvent | MouseEvent; trigger: 'input' | 'initial' | 'clear' }, + context?: { + e?: FormEvent | MouseEvent | CompositionEvent; + trigger: 'input' | 'initial' | 'clear'; + }, ) => void; /** * 清空按钮点击时触发 @@ -154,7 +156,7 @@ export interface TdInputProps { /** * 回车键按下时触发 */ - onEnter?: (value: InputValue, context: { e: KeyboardEvent }) => void; + onEnter?: (value: InputValue, context: { e: KeyboardEvent }) => void; /** * 获得焦点时触发 */ diff --git a/src/tag-input/__tests__/vitest-tag-input.test.jsx b/src/tag-input/__tests__/vitest-tag-input.test.jsx new file mode 100644 index 000000000..6ea13615a --- /dev/null +++ b/src/tag-input/__tests__/vitest-tag-input.test.jsx @@ -0,0 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/** + * 该文件由脚本自动生成,如需修改请联系 PMC + * This file generated by scripts of tdesign-api. `npm run api:docs TagInput React(PC) vitest,finalProject` + * If you need to modify this file, contact PMC first please. + */ +import React from 'react'; diff --git a/src/tag-input/tag-input.en-US.md b/src/tag-input/tag-input.en-US.md index f8ec1fcd7..71710e2db 100644 --- a/src/tag-input/tag-input.en-US.md +++ b/src/tag-input/tag-input.en-US.md @@ -38,7 +38,7 @@ onClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
onDragSort | Function | | Typescript:`(context: TagInputDragSortContext) => void`
trigger on drag sort。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface TagInputDragSortContext { newTags: TagInputValue; currentIndex: number; current: string \| number; targetIndex: number; target: string \| number }`
| N onEnter | Function | | Typescript:`(value: TagInputValue, context: { e: KeyboardEvent; inputValue: InputValue }) => void`
| N onFocus | Function | | Typescript:`(value: TagInputValue, context: { inputValue: InputValue; e: FocusEvent }) => void`
trigger on focus | N -onInputChange | Function | | Typescript:`(value: InputValue, context?: InputValueChangeContext) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface InputValueChangeContext { e?: InputEvent \| MouseEvent \| KeyboardEvent; trigger: 'input' \| 'clear' \| 'enter' }`
| N +onInputChange | Function | | Typescript:`(value: InputValue, context?: InputValueChangeContext) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface InputValueChangeContext { e?: InputEvent \| MouseEvent \| CompositionEvent \| KeyboardEvent; trigger: 'input' \| 'clear' \| 'enter' }`
| N onMouseenter | Function | | Typescript:`(context: { e: MouseEvent }) => void`
trigger on mouseenter | N onMouseleave | Function | | Typescript:`(context: { e: MouseEvent }) => void`
trigger on mouseleave | N onPaste | Function | | Typescript:`(context: { e: ClipboardEvent; pasteValue: string }) => void`
| N diff --git a/src/tag-input/tag-input.md b/src/tag-input/tag-input.md index 8bb83dcbf..22c1a0c39 100644 --- a/src/tag-input/tag-input.md +++ b/src/tag-input/tag-input.md @@ -38,7 +38,7 @@ onClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
onDragSort | Function | | TS 类型:`(context: TagInputDragSortContext) => void`
【开发中】拖拽排序时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface TagInputDragSortContext { newTags: TagInputValue; currentIndex: number; current: string \| number; targetIndex: number; target: string \| number }`
| N onEnter | Function | | TS 类型:`(value: TagInputValue, context: { e: KeyboardEvent; inputValue: InputValue }) => void`
按键按下 Enter 时触发 | N onFocus | Function | | TS 类型:`(value: TagInputValue, context: { inputValue: InputValue; e: FocusEvent }) => void`
聚焦时触发 | N -onInputChange | Function | | TS 类型:`(value: InputValue, context?: InputValueChangeContext) => void`
输入框值发生变化时触发,`context.trigger` 表示触发输入框值变化的来源:文本输入触发、清除按钮触发、回车键触发等。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface InputValueChangeContext { e?: InputEvent \| MouseEvent \| KeyboardEvent; trigger: 'input' \| 'clear' \| 'enter' }`
| N +onInputChange | Function | | TS 类型:`(value: InputValue, context?: InputValueChangeContext) => void`
输入框值发生变化时触发,`context.trigger` 表示触发输入框值变化的来源:文本输入触发、清除按钮触发、回车键触发等。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/tag-input/type.ts)。
`interface InputValueChangeContext { e?: InputEvent \| MouseEvent \| CompositionEvent \| KeyboardEvent; trigger: 'input' \| 'clear' \| 'enter' }`
| N onMouseenter | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
进入输入框时触发 | N onMouseleave | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
离开输入框时触发 | N onPaste | Function | | TS 类型:`(context: { e: ClipboardEvent; pasteValue: string }) => void`
粘贴事件,`pasteValue` 表示粘贴板的内容 | N diff --git a/src/tag-input/type.ts b/src/tag-input/type.ts index e840db852..a912e7dc9 100644 --- a/src/tag-input/type.ts +++ b/src/tag-input/type.ts @@ -8,7 +8,7 @@ import { InputProps } from '../input'; import { InputValue } from '../input'; import { TagProps } from '../tag'; import { TNode, TElement } from '../common'; -import { MouseEvent, KeyboardEvent, ClipboardEvent, FocusEvent, FormEvent } from 'react'; +import { MouseEvent, KeyboardEvent, ClipboardEvent, FocusEvent, FormEvent, CompositionEvent } from 'react'; export interface TdTagInputProps { /** @@ -188,7 +188,11 @@ export interface TagInputDragSortContext { } export interface InputValueChangeContext { - e?: FormEvent | MouseEvent | KeyboardEvent; + e?: + | FormEvent + | MouseEvent + | CompositionEvent + | KeyboardEvent; trigger: 'input' | 'clear' | 'enter'; } diff --git a/test/utils/index.jsx b/test/utils/index.jsx index f9c882f36..6cf44787b 100644 --- a/test/utils/index.jsx +++ b/test/utils/index.jsx @@ -22,3 +22,31 @@ export function mockDelay(timeout = 300) { export function simulateInputChange(dom, text) { fireEvent.change(dom, { target: { value: text } }); } + +export function simulateKeydownEvent(dom, type) { + let event; + switch (type) { + case 'ArrowDown': + event = new KeyboardEvent('keydown', { key: 'ArrowDown', code: 'ArrowDown', charCode: 40 }); + break; + case 'ArrowUp': + event = new KeyboardEvent('keydown', { key: 'ArrowUp', code: 'ArrowUp', charCode: 38 }); + break; + case 'ArrowLeft': + event = new KeyboardEvent('keydown', { key: 'ArrowLeft', code: 'ArrowLeft', charCode: 37 }); + break; + case 'ArrowRight': + event = new KeyboardEvent('keydown', { key: 'ArrowRight', code: 'ArrowRight', charCode: 36 }); + break; + case 'Escape': + event = new KeyboardEvent('keydown', { key: 'Escape', code: 'Escape', charCode: 27 }); + break; + case 'Enter': + event = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', charCode: 13 }); + break; + default: + console.warn('Event Type is Error'); + break; + } + dom.dispatchEvent(event); +} From d8cf7348fe9ee6ff44d29f1ef329303b244874e7 Mon Sep 17 00:00:00 2001 From: chaishi <974383157@qq.com> Date: Sat, 14 Jan 2023 20:02:56 +0800 Subject: [PATCH 4/7] fix(auto-complete): ts error --- src/range-input/__tests__/vitest-range-input.test.jsx | 7 +++++++ src/range-input/defaultProps.ts | 7 ++++++- src/range-input/range-input.en-US.md | 8 ++++---- src/range-input/range-input.md | 8 ++++---- src/range-input/type.ts | 8 +++++--- 5 files changed, 26 insertions(+), 12 deletions(-) create mode 100644 src/range-input/__tests__/vitest-range-input.test.jsx diff --git a/src/range-input/__tests__/vitest-range-input.test.jsx b/src/range-input/__tests__/vitest-range-input.test.jsx new file mode 100644 index 000000000..0f202cb28 --- /dev/null +++ b/src/range-input/__tests__/vitest-range-input.test.jsx @@ -0,0 +1,7 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/** + * 该文件由脚本自动生成,如需修改请联系 PMC + * This file generated by scripts of tdesign-api. `npm run api:docs RangeInput React(PC) vitest,finalProject` + * If you need to modify this file, contact PMC first please. + */ +import React from 'react'; diff --git a/src/range-input/defaultProps.ts b/src/range-input/defaultProps.ts index 575b73edd..1fb76f00c 100644 --- a/src/range-input/defaultProps.ts +++ b/src/range-input/defaultProps.ts @@ -10,7 +10,12 @@ export const rangeInputDefaultProps: TdRangeInputProps = { separator: '-', showClearIconOnEmpty: false, size: 'medium', + status: 'default', defaultValue: [], }; -export const rangeInputPopupDefaultProps: TdRangeInputPopupProps = { autoWidth: false, readonly: false }; +export const rangeInputPopupDefaultProps: TdRangeInputPopupProps = { + autoWidth: false, + readonly: false, + status: 'default', +}; diff --git a/src/range-input/range-input.en-US.md b/src/range-input/range-input.en-US.md index 6b4dd4f39..3751a0daa 100644 --- a/src/range-input/range-input.en-US.md +++ b/src/range-input/range-input.en-US.md @@ -19,14 +19,14 @@ readonly | Boolean | false | \- | N separator | TNode | '-' | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N showClearIconOnEmpty | Boolean | false | \- | N size | String | medium | options:small/medium/large | N -status | String | - | options:default/success/warning/error | N +status | String | default | options:default/success/warning/error | N suffix | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N value | Array | [] | Typescript:`RangeInputValue` `type RangeInputValue = Array`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N defaultValue | Array | [] | uncontrolled property。Typescript:`RangeInputValue` `type RangeInputValue = Array`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N onBlur | Function | | Typescript:`(value: RangeInputValue, context?: { e?: FocusEvent; position?: RangeInputPosition }) => void`
| N -onChange | Function | | Typescript:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent; position?: RangeInputPosition; trigger?: 'input' \| 'clear' }) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputPosition = 'first' \| 'second' \| 'all'`
| N +onChange | Function | | Typescript:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; position?: RangeInputPosition; trigger?: 'input' \| 'initial' \| 'clear' }) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputPosition = 'first' \| 'second' \| 'all'`
| N onClear | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N onClick | Function | | Typescript:`(context?: { e?: MouseEvent; position?: RangeInputPosition }) => void`
| N onEnter | Function | | Typescript:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent; position?: RangeInputPosition }) => void`
| N @@ -54,12 +54,12 @@ autoWidth | Boolean | false | \- | N disabled | Boolean | - | \- | N inputValue | Array | - | Typescript:`RangeInputValue` | N defaultInputValue | Array | - | uncontrolled property。Typescript:`RangeInputValue` | N -panel | TElement | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +panel | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N popupProps | Object | - | Typescript:`PopupProps`,[Popup API Documents](./popup?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N popupVisible | Boolean | - | \- | N rangeInputProps | Object | - | Typescript:`RangeInputProps`,[RangeInput API Documents](./range-input?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N readonly | Boolean | false | \- | N -status | String | - | options:default/success/warning/error | N +status | String | default | options:default/success/warning/error | N tips | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N onInputChange | Function | | Typescript:`(value: RangeInputValue, context?: RangeInputValueChangeContext) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputValueChangeContext = { e?: InputEvent \| MouseEvent; trigger?: 'input' \| 'clear', position?: RangeInputPosition }`
| N onPopupVisibleChange | Function | | Typescript:`(visible: boolean, context: PopupVisibleChangeContext) => void`
[see more ts definition](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`import { PopupVisibleChangeContext } from '@Popup'`
| N diff --git a/src/range-input/range-input.md b/src/range-input/range-input.md index f0c95d51a..4a468b7e8 100644 --- a/src/range-input/range-input.md +++ b/src/range-input/range-input.md @@ -19,14 +19,14 @@ readonly | Boolean | false | 只读状态 | N separator | TNode | '-' | 范围分隔符。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N showClearIconOnEmpty | Boolean | false | 输入框内容为空时,悬浮状态是否显示清空按钮,默认不显示 | N size | String | medium | 输入框尺寸。可选项:small/medium/large | N -status | String | - | 输入框状态。可选项:default/success/warning/error | N +status | String | default | 输入框状态。可选项:default/success/warning/error | N suffix | TNode | - | 后置图标前的后置内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N suffixIcon | TElement | - | 组件后置图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N tips | TNode | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N value | Array | [] | 范围输入框的值。TS 类型:`RangeInputValue` `type RangeInputValue = Array`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N defaultValue | Array | [] | 范围输入框的值。非受控属性。TS 类型:`RangeInputValue` `type RangeInputValue = Array`。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N onBlur | Function | | TS 类型:`(value: RangeInputValue, context?: { e?: FocusEvent; position?: RangeInputPosition }) => void`
范围输入框失去焦点时触发 | N -onChange | Function | | TS 类型:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent; position?: RangeInputPosition; trigger?: 'input' \| 'clear' }) => void`
范围输入框值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputPosition = 'first' \| 'second' \| 'all'`
| N +onChange | Function | | TS 类型:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; position?: RangeInputPosition; trigger?: 'input' \| 'initial' \| 'clear' }) => void`
范围输入框值发生变化时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputPosition = 'first' \| 'second' \| 'all'`
| N onClear | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
清空按钮点击时触发 | N onClick | Function | | TS 类型:`(context?: { e?: MouseEvent; position?: RangeInputPosition }) => void`
范围输入框点击时触发 | N onEnter | Function | | TS 类型:`(value: RangeInputValue, context?: { e?: InputEvent \| MouseEvent; position?: RangeInputPosition }) => void`
回车键按下时触发 | N @@ -54,12 +54,12 @@ autoWidth | Boolean | false | 宽度随内容自适应 | N disabled | Boolean | - | 是否禁用范围输入框,值为数组表示可分别控制某一个输入框是否禁用 | N inputValue | Array | - | 输入框的值。TS 类型:`RangeInputValue` | N defaultInputValue | Array | - | 输入框的值。非受控属性。TS 类型:`RangeInputValue` | N -panel | TElement | - | 下拉框内容,可完全自定义。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +panel | TNode | - | 下拉框内容,可完全自定义。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N popupProps | Object | - | 透传 Popup 浮层组件全部属性。TS 类型:`PopupProps`,[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N popupVisible | Boolean | - | 是否显示下拉框 | N rangeInputProps | Object | - | 透传 RangeInput 组件全部属性。TS 类型:`RangeInputProps`,[RangeInput API Documents](./range-input?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts) | N readonly | Boolean | false | 只读状态,值为真会隐藏输入框,且无法打开下拉框 | N -status | String | - | 输入框状态。可选项:default/success/warning/error | N +status | String | default | 输入框状态。可选项:default/success/warning/error | N tips | TNode | - | 输入框下方提示文本,会根据不同的 `status` 呈现不同的样式。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N onInputChange | Function | | TS 类型:`(value: RangeInputValue, context?: RangeInputValueChangeContext) => void`
输入框值发生变化时触发,`context.trigger` 表示触发输入框值变化的来源:文本输入触发、清除按钮触发等。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`type RangeInputValueChangeContext = { e?: InputEvent \| MouseEvent; trigger?: 'input' \| 'clear', position?: RangeInputPosition }`
| N onPopupVisibleChange | Function | | TS 类型:`(visible: boolean, context: PopupVisibleChangeContext) => void`
下拉框显示或隐藏时触发。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/range-input/type.ts)。
`import { PopupVisibleChangeContext } from '@Popup'`
| N diff --git a/src/range-input/type.ts b/src/range-input/type.ts index 6316c8118..a61e8ee0b 100644 --- a/src/range-input/type.ts +++ b/src/range-input/type.ts @@ -9,7 +9,7 @@ import { PopupProps } from '../popup'; import { RangeInputProps } from '../range-input'; import { PopupVisibleChangeContext } from '../popup'; import { TNode, TElement } from '../common'; -import { MouseEvent, FocusEvent, FormEvent } from 'react'; +import { MouseEvent, FocusEvent, FormEvent, CompositionEvent } from 'react'; export interface TdRangeInputProps { /** @@ -67,6 +67,7 @@ export interface TdRangeInputProps { size?: 'small' | 'medium' | 'large'; /** * 输入框状态 + * @default default */ status?: 'default' | 'success' | 'warning' | 'error'; /** @@ -104,9 +105,9 @@ export interface TdRangeInputProps { onChange?: ( value: RangeInputValue, context?: { - e?: FormEvent | MouseEvent; + e?: FormEvent | MouseEvent | CompositionEvent; position?: RangeInputPosition; - trigger?: 'input' | 'clear'; + trigger?: 'input' | 'initial' | 'clear'; }, ) => void; /** @@ -198,6 +199,7 @@ export interface TdRangeInputPopupProps { readonly?: boolean; /** * 输入框状态 + * @default default */ status?: 'default' | 'success' | 'warning' | 'error'; /** From a443dc0fd69caff3680c188744677806afd6ed07 Mon Sep 17 00:00:00 2001 From: lincao Date: Sat, 14 Jan 2023 20:06:28 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat(input):=20change=20=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8F=82=E6=95=B0=20trigger=EF=BC=8C?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E8=A1=A8=E7=A4=BA=E8=A7=A6=E5=8F=91=E6=9D=A5?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/input/Input.tsx | 4 +- test/snap/__snapshots__/csr.test.jsx.snap | 132 +++++++--------------- 2 files changed, 43 insertions(+), 93 deletions(-) diff --git a/src/input/Input.tsx b/src/input/Input.tsx index 7be74f721..4abf5b604 100644 --- a/src/input/Input.tsx +++ b/src/input/Input.tsx @@ -32,6 +32,8 @@ export interface InputRef extends React.RefObject { select: () => void; } +type InputContextTrigger = 'input' | 'clear' | 'initial'; + const renderIcon = (classPrefix: string, type: 'prefix' | 'suffix', icon: TNode | TElement) => { const result = parseTNode(icon); @@ -258,7 +260,7 @@ const Input = forwardRefWithStatics( function handleChange( e: React.ChangeEvent | React.CompositionEvent, - trigger = 'input', + trigger: InputContextTrigger = 'input', ) { let { value: newStr } = e.currentTarget; if (composingRef.current) { diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 541c78ba8..8f7804bf4 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -4490,11 +4490,11 @@ exports[`csr snapshot test > csr test src/auto-complete/_example/base.jsx 1`] = class="t-auto-complete" >
csr test src/auto-complete/_example/base.jsx 1`] =
-
-
-
-
-
    -
  • -
    - 第一个默认联想词 -
    -
  • -
  • -
    - 第二个默认联想词 -
    -
  • -
  • -
    - 第三个默认联想词 -
    -
  • -
-
-
-
-
, "container":
csr test src/auto-complete/_example/base.jsx 1`] = class="t-auto-complete" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/config-provider/_example/date-picker.j class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-presets-alt. class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-presets-alt. class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-presets-alt. class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-presets-alt. class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-range.jsx 1` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-range.jsx 1` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-range.jsx 1` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/date-range.jsx 1` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/disable-date.jsx class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/disable-date.jsx class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/month.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/month.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/quarter.jsx 1`] = class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/quarter.jsx 1`] = class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/week.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/week.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/year.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/date-picker/_example/year.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/range-input/_example/base.jsx 1`] = ` />
csr test src/range-input/_example/base.jsx 1`] = ` , "container":
csr test src/range-input/_example/popup.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/range-input/_example/popup.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/range-input/_example/size.jsx 1`] = ` class="t-space-item" >
csr test src/time-picker/_example/range.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
csr test src/time-picker/_example/range.jsx 1`] = ` class="t-range-input-popup t-range-input-popup" >
Date: Sat, 14 Jan 2023 23:07:06 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix(autocomplete):=20=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E7=AE=AD=E5=A4=B4=E9=80=89=E6=8B=A9=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=8C=E8=A1=A5=E5=85=85=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +-- src/auto-complete/AutoComplete.tsx | 3 ++- src/auto-complete/OptionList.tsx | 28 +++++++++++++++++----------- src/auto-complete/_example/base.jsx | 12 ++++++------ 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index c8f11d418..368ac9d73 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,7 @@ "changelog": "node script/generate-changelog.js", "init": "node script/init-component", "robot": "publish-cli robot-msg", - "prepare": "husky install", - "update:coverage-badge": "node script/generate-coverage.js" + "prepare": "husky install" }, "config": { "commitizen": { diff --git a/src/auto-complete/AutoComplete.tsx b/src/auto-complete/AutoComplete.tsx index efdb9e3e2..ea8d6fb57 100644 --- a/src/auto-complete/AutoComplete.tsx +++ b/src/auto-complete/AutoComplete.tsx @@ -133,7 +133,7 @@ const AutoComplete = forwardRef((props, ref) /> ); // 联想词列表 - const listContent = ( + const listContent = Array.isArray(props.options) && ( ((props, ref) {bottomContent}
) : null; + const popupProps = { ...props.popupProps, overlayInnerStyle: getOverlayStyle, diff --git a/src/auto-complete/OptionList.tsx b/src/auto-complete/OptionList.tsx index 6568290ab..e4a8f989b 100644 --- a/src/auto-complete/OptionList.tsx +++ b/src/auto-complete/OptionList.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState, MouseEvent, useEffect, useImperativeHandle, forwardRef } from 'react'; +import React, { useMemo, useState, useRef, MouseEvent, useEffect, useImperativeHandle, forwardRef } from 'react'; import classNames from 'classnames'; import isFunction from 'lodash/isFunction'; import useConfig from '../hooks/useConfig'; @@ -27,8 +27,9 @@ export interface OptionsListRef { const OptionsList = forwardRef((props: OptionsListProps, ref) => { const { value, onSelect, popupVisible } = props; - const [active, setActive] = useState(''); const { classPrefix } = useConfig(); + const [active, setActive] = useState(''); + const activeIndexRef = useRef(-1); const classes = `${classPrefix}-select__list`; const optionClasses = [ @@ -84,16 +85,17 @@ const OptionsList = forwardRef((props: Options // 键盘事件,上下选择 const onKeyInnerPress = (e: KeyboardEvent) => { - if (e.code === 'ArrowUp' || e.key === 'ArrowUp') { - const index = tOptions.findIndex((item) => item.text === active); - const newIndex = index - 1 < 0 ? tOptions.length - 1 : index - 1; - setActive(tOptions[newIndex].text); - } else if (e.code === 'ArrowDown' || e.key === 'ArrowDown') { - const index = tOptions.findIndex((item) => item.text === active); - const newIndex = index + 1 >= tOptions.length ? 0 : index + 1; + if (e.code === 'Enter' || e.key === 'Enter') { + onSelect?.(tOptions[activeIndexRef.current].text, { e }); + } else { + const index = activeIndexRef.current; + let newIndex; + if (e.code === 'ArrowUp' || e.key === 'ArrowUp') { + newIndex = index - 1 < 0 ? tOptions.length - 1 : index - 1; + } else if (e.code === 'ArrowDown' || e.key === 'ArrowDown') { + newIndex = index + 1 >= tOptions.length ? 0 : index + 1; + } setActive(tOptions[newIndex].text); - } else if (e.code === 'Enter' || e.key === 'Enter') { - onSelect?.(active, { e }); } }; @@ -128,6 +130,10 @@ const OptionsList = forwardRef((props: Options } }, [value]); + useEffect(() => { + activeIndexRef.current = tOptions.findIndex((item) => item.text === active); + }, [active, tOptions]); + if (!tOptions.length) return null; return (
    diff --git a/src/auto-complete/_example/base.jsx b/src/auto-complete/_example/base.jsx index 07cd238b8..4cb8a9dc0 100644 --- a/src/auto-complete/_example/base.jsx +++ b/src/auto-complete/_example/base.jsx @@ -27,11 +27,7 @@ const AutoCompleteBase = () => { timer = setTimeout(() => { const text = '搜索联想词'; const pureValue = val.replace(`第一个${text}`, '').replace(`第二个${text}`, '').replace(`第三个${text}`, ''); - setOptions([ - `${pureValue}第一个${text}`, - `${pureValue}第二个${text}`, - `${pureValue}第三个${text}` - ]); + setOptions([`${pureValue}第一个${text}`, `${pureValue}第二个${text}`, `${pureValue}第三个${text}`]); clearTimeout(timer); }, 100); }; @@ -66,7 +62,11 @@ const AutoCompleteBase = () => { placeholder="请输入关键词搜索(自定义右侧图标)" className="t-demo-autocomplete__search" inputProps={{ - suffix: , + suffix: ( + + ), }} /> From 571693e9a323ada7da4de76680ba457c7d4bb08f Mon Sep 17 00:00:00 2001 From: carolin913 Date: Sun, 15 Jan 2023 16:56:51 +0800 Subject: [PATCH 7/7] =?UTF-8?q?ci:=20=E5=88=A0=E9=99=A4=E7=A9=BA=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/range-input/__tests__/vitest-range-input.test.jsx | 7 ------- src/tag-input/__tests__/vitest-tag-input.test.jsx | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 src/range-input/__tests__/vitest-range-input.test.jsx delete mode 100644 src/tag-input/__tests__/vitest-tag-input.test.jsx diff --git a/src/range-input/__tests__/vitest-range-input.test.jsx b/src/range-input/__tests__/vitest-range-input.test.jsx deleted file mode 100644 index 0f202cb28..000000000 --- a/src/range-input/__tests__/vitest-range-input.test.jsx +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/** - * 该文件由脚本自动生成,如需修改请联系 PMC - * This file generated by scripts of tdesign-api. `npm run api:docs RangeInput React(PC) vitest,finalProject` - * If you need to modify this file, contact PMC first please. - */ -import React from 'react'; diff --git a/src/tag-input/__tests__/vitest-tag-input.test.jsx b/src/tag-input/__tests__/vitest-tag-input.test.jsx deleted file mode 100644 index 6ea13615a..000000000 --- a/src/tag-input/__tests__/vitest-tag-input.test.jsx +++ /dev/null @@ -1,7 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -/** - * 该文件由脚本自动生成,如需修改请联系 PMC - * This file generated by scripts of tdesign-api. `npm run api:docs TagInput React(PC) vitest,finalProject` - * If you need to modify this file, contact PMC first please. - */ -import React from 'react';