@@ -2583,16 +2411,12 @@ exports[`Input > Input suffixVue demo works fine 1`] = `
>
diff --git a/src/input/__test__/index.test.jsx b/src/input/__test__/index.test.jsx
index e47b00cd3..436098eb1 100644
--- a/src/input/__test__/index.test.jsx
+++ b/src/input/__test__/index.test.jsx
@@ -1,7 +1,7 @@
import { nextTick, ref, onMounted } from 'vue';
import { mount } from '@vue/test-utils';
import { describe, it, expect, vi } from 'vitest';
-import Input from '../input.vue';
+import Input from '../input';
import { CloseCircleFilledIcon, InfoCircleFilledIcon, AppIcon } from 'tdesign-icons-vue-next';
@@ -110,16 +110,6 @@ describe('Input.vue', async () => {
expect(input.element.getAttribute('autocomplete')).toBe('On');
});
- it(': size', async () => {
- const sizeList = ['', 'small', 'meddium', 'large'];
- sizeList.forEach((size, index) => {
- const wrapper = mount(() =>
);
- if (size) {
- expect(wrapper.classes()).toContain(`t-input--size-${size}`);
- }
- });
- });
-
it(': layout', async () => {
const layoutList = ['', 'vertical', 'horizontal'];
layoutList.forEach((layout, index) => {
diff --git a/src/input/index.ts b/src/input/index.ts
index 92764832a..888f98a92 100644
--- a/src/input/index.ts
+++ b/src/input/index.ts
@@ -1,5 +1,5 @@
import { withInstall, WithInstallType } from '../shared';
-import Input from './input.vue';
+import Input from './input';
import './style';
import { TdInputProps } from './type';
diff --git a/src/input/input.en-US.md b/src/input/input.en-US.md
index 16e1b5a80..5d583e44e 100644
--- a/src/input/input.en-US.md
+++ b/src/input/input.en-US.md
@@ -2,36 +2,37 @@
:: BASE_DOC ::
## API
+
### Input Props
name | type | default | description | required
-- | -- | -- | -- | --
-align | String | left | options:left/center/right | N
-allowInputOverMax | Boolean | false | \- | N
-autocomplete | String | undefined | \- | N
-autofocus | Boolean | false | \- | N
-borderless | Boolean | false | \- | N
-clearable | Boolean | false | \- | N
-disabled | Boolean | - | \- | N
-format | Function | - | Typescript:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/input/type.ts) | N
-label | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-layout | String | horizontal | options:vertical/horizontal | N
+align | String | left | text align type。options: left/center/right | N
+allowInputOverMax | Boolean | false | allow to continue input on value length is over `maxlength` or `maxcharacter` | N
+autocomplete | String | undefined | attribute of input element, [see here](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) | N
+autofocus | Boolean | false | autofocus on first rendered | N
+borderless | Boolean | false | input without border | N
+clearable | Boolean | false | show clear icon, clicked to clear input value | N
+disabled | Boolean | - | make input to be disabled | N
+format | Function | - | input value formatter, `type=number` does not work. if you need to format number, `InputNumber` Component might be better。Typescript:`InputFormatType` `type InputFormatType = (value: InputValue) => string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/input/type.ts) | N
+label | String / Slot / Function | - | text on the left of input。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+layout | String | horizontal | options: vertical/horizontal | N
maxcharacter | Number | - | \- | N
maxlength | Number | - | \- | N
name | String | - | \- | N
placeholder | String | undefined | \- | N
prefixIcon | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
readonly | Boolean | false | \- | N
-size | String | small | options:small/medium。Typescript:`'medium' \| 'small'` | N
-status | String | undefined | options:default/success/warning/error | N
-suffix | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-suffixIcon | Slot / Function | - | Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-tips | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
-type | String | text | options:text/number/url/tel/password/search/submit/hidden | N
-value | String / Number | '' | `v-model` and `v-model:value` is supported。Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/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-mobile-vue/tree/develop/src/input/type.ts) | N
+size | String | small | `deprecated`。options: small/medium。Typescript:`'medium' \| 'small'` | N
+status | String | undefined | options: default/success/warning/error | N
+suffix | String / Slot / Function | - | suffix content before suffixIcon。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+suffixIcon | Slot / Function | - | suffix icon of input。Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+tips | String / Slot / Function | - | tips on the bottom of input, different `status` can make tips to be different color。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
+type | String | text | type attribute of input element. if you are using `type=number`, `InputNumber` Component might be better。options: text/number/url/tel/password/search/submit/hidden | N
+value | String / Number | '' | input value。`v-model` and `v-model:value` is supported。Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/input/type.ts) | N
+defaultValue | String / Number | '' | input value。uncontrolled property。Typescript:`InputValue` `type InputValue = string`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/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 \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
| N
+onChange | Function | | Typescript:`(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' }) => void`
trigger on input value changed | N
onClear | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N
onFocus | Function | | Typescript:`(value: InputValue, context: { e: FocusEvent }) => void`
| N
onValidate | Function | | Typescript:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
trigger on text length being over max length or max character | N
@@ -41,13 +42,13 @@ onValidate | Function | | Typescript:`(context: { error?: 'exceed-maximum' \|
name | params | description
-- | -- | --
blur | `(value: InputValue, context: { e: FocusEvent })` | \-
-change | `(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' })` | \-
+change | `(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' })` | trigger on input value changed
clear | `(context: { e: MouseEvent })` | \-
focus | `(value: InputValue, context: { e: FocusEvent })` | \-
validate | `(context: { error?: 'exceed-maximum' \| 'below-minimum' })` | trigger on text length being over max length or max character
+### CSS 变量
-### CSS Variables
The component provides the following CSS variables, which can be used to customize styles.
Name | Default Value | Description
-- | -- | --
@@ -70,4 +71,4 @@ Name | Default Value | Description
--td-input-suffix-text-color | @font-gray-1 | -
--td-input-vertical-padding | 16px | -
--td-input-warning-text-color | @warning-color | -
---td-input-warning-tips-color | @warning-color | -
+--td-input-warning-tips-color | @warning-color | -
\ No newline at end of file
diff --git a/src/input/input.md b/src/input/input.md
index c55cea368..d35bb4fcc 100644
--- a/src/input/input.md
+++ b/src/input/input.md
@@ -1,9 +1,10 @@
:: BASE_DOC ::
## API
+
### Input Props
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
align | String | left | 文本内容位置,居左/居中/居右。可选项:left/center/right | N
allowInputOverMax | Boolean | false | 超出 `maxlength` 或 `maxcharacter` 之后是否允许继续输入 | N
@@ -33,7 +34,7 @@ onBlur | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent
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
onFocus | Function | | TS 类型:`(value: InputValue, context: { e: FocusEvent }) => void`
获得焦点时触发 | N
-onValidate | Function | | 【暂不支持】TS 类型:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
字数超出限制时触发 | N
+onValidate | Function | | TS 类型:`(context: { error?: 'exceed-maximum' \| 'below-minimum' }) => void`
【暂不支持】字数超出限制时触发 | N
### Input Events
@@ -43,10 +44,10 @@ blur | `(value: InputValue, context: { e: FocusEvent })` | 失去焦点时触发
change | `(value: InputValue, context?: { e?: InputEvent \| MouseEvent \| CompositionEvent; trigger: 'input' \| 'initial' \| 'clear' })` | 输入框值发生变化时触发。`trigger=initial` 表示传入的数据不符合预期,组件自动处理后触发 change 告知父组件。如:初始值长度超过 `maxlength` 限制
clear | `(context: { e: MouseEvent })` | 清空按钮点击时触发
focus | `(value: InputValue, context: { e: FocusEvent })` | 获得焦点时触发
-validate | `(context: { error?: 'exceed-maximum' \| 'below-minimum' })` | 字数超出限制时触发
-
+validate | `(context: { error?: 'exceed-maximum' \| 'below-minimum' })` | 【暂不支持】字数超出限制时触发
### CSS 变量
+
组件提供了下列 CSS 变量,可用于自定义样式。
名称 | 默认值 | 描述
-- | -- | --
@@ -69,4 +70,4 @@ validate | `(context: { error?: 'exceed-maximum' \| 'below-minimum' })` | 字数
--td-input-suffix-text-color | @font-gray-1 | -
--td-input-vertical-padding | 16px | -
--td-input-warning-text-color | @warning-color | -
---td-input-warning-tips-color | @warning-color | -
+--td-input-warning-tips-color | @warning-color | -
\ No newline at end of file
diff --git a/src/input/input.tsx b/src/input/input.tsx
new file mode 100644
index 000000000..b328f0fe7
--- /dev/null
+++ b/src/input/input.tsx
@@ -0,0 +1,214 @@
+import { PropType, ref, computed, defineComponent, toRefs, nextTick, watch } from 'vue';
+import { CloseCircleFilledIcon as TCloseCircleFilledIcon } from 'tdesign-icons-vue-next';
+import { useFocus } from '@vueuse/core';
+import config from '../config';
+import InputProps from './props';
+import { InputValue, TdInputProps } from './type';
+import { getCharacterLength, useDefault, extendAPI } from '../shared';
+import { useFormDisabled } from '../form/hooks';
+import { usePrefixClass } from '@/hooks/useClass';
+import { useTNodeJSX } from '@/hooks/tnode';
+
+const { prefix } = config;
+const name = `${prefix}-input`;
+
+export default defineComponent({
+ name,
+ props: {
+ ...InputProps,
+ labelAlign: {
+ type: String,
+ default: 'top',
+ },
+ pattern: {
+ type: String,
+ },
+ inputmode: {
+ type: String as PropType<'search' | 'text' | 'none' | 'url' | 'tel' | 'email' | 'numeric' | 'decimal'>,
+ validator(val: string): boolean {
+ if (!val) return true;
+ return ['search', 'text', 'none', 'url', 'tel', 'email', 'numeric', 'decimal'].includes(val);
+ },
+ },
+ },
+ setup(props, context) {
+ const readerTNodeJSX = useTNodeJSX();
+ const inputClass = usePrefixClass('input');
+ const isDisabled = useFormDisabled();
+
+ const inputRef = ref();
+ const { autofocus } = toRefs(props);
+ const [innerValue] = useDefault
(props, context.emit, 'value', 'change');
+
+ const status = props.status || 'default';
+
+ const { focused } = useFocus(inputRef, { initialValue: props.autofocus });
+
+ const inputClasses = computed(() => [
+ `${inputClass.value}__control`,
+ {
+ [`${inputClass.value}--${props.align}`]: props.align !== 'left',
+ [`${inputClass.value}--${status}`]: status,
+ [`${inputClass.value}__control--disabled`]: isDisabled.value,
+ },
+ ]);
+
+ const rootClasses = computed(() => [
+ inputClass.value,
+ {
+ [`${inputClass.value}--layout-${props.layout}`]: props.layout,
+ [`${inputClass.value}--center`]: props.labelAlign === 'center',
+ [`${inputClass.value}--border`]: !props.borderless,
+ },
+ ]);
+
+ const setInputValue = (v: InputValue = '') => {
+ const input = inputRef.value as HTMLInputElement;
+ const sV = String(v);
+ if (!input) {
+ return;
+ }
+ if (input.value !== sV) {
+ input.value = sV;
+ }
+ };
+
+ const handleInput = (e: Event) => {
+ // 中文输入的时候inputType是insertCompositionText所以中文输入的时候禁止触发。
+ if (e instanceof InputEvent) {
+ const checkInputType = e.inputType && e.inputType === 'insertCompositionText';
+ if (e.isComposing || checkInputType) return;
+ }
+ inputValueChangeHandle(e);
+ };
+
+ const inputValueChangeHandle = (e: Event) => {
+ const { value } = e.target as HTMLInputElement;
+ const { allowInputOverMax, maxcharacter } = props;
+ if (!allowInputOverMax && maxcharacter && maxcharacter > 0 && !Number.isNaN(maxcharacter)) {
+ const { length = 0, characters = '' } = getCharacterLength(value, maxcharacter) as {
+ length: number;
+ characters: string;
+ };
+ innerValue.value = characters;
+ } else {
+ innerValue.value = value;
+ }
+ nextTick(() => setInputValue(innerValue.value));
+ };
+
+ const focus = () => {
+ focused.value = true;
+ };
+
+ const blur = () => {
+ focused.value = false;
+ // inputRef.value?.blur();
+ };
+
+ extendAPI({ focus, blur });
+
+ const handleClear = (e: MouseEvent) => {
+ innerValue.value = '';
+ focused.value = true;
+ props.onClear?.({ e });
+ };
+ const handleFocus = (e: FocusEvent) => {
+ props.onFocus?.(innerValue.value, { e });
+ };
+ const handleBlur = (e: FocusEvent) => {
+ props.onBlur?.(innerValue.value, { e });
+ };
+
+ const handleCompositionend = (e: CompositionEvent) => {
+ inputValueChangeHandle(e);
+ };
+
+ watch(autofocus, (autofocus, prevAutofocus) => {
+ if (autofocus === true) {
+ nextTick(() => {
+ focused.value = true;
+ });
+ }
+ });
+
+ return () => {
+ const readerPrefix = () => {
+ const prefixIcon = readerTNodeJSX('prefixIcon');
+ const label = readerTNodeJSX('label');
+
+ return (
+
+ );
+ };
+ const readerClearable = () => {
+ if (props.clearable && innerValue.value && innerValue.value.length > 0) {
+ return (
+
+
+
+ );
+ }
+ return null;
+ };
+ const readerSuffix = () => {
+ const suffix = readerTNodeJSX('suffix');
+ if (!suffix) {
+ return null;
+ }
+ return {suffix}
;
+ };
+
+ const readerSuffixIcon = () => {
+ const suffixIcon = readerTNodeJSX('suffixIcon');
+ if (!suffixIcon) {
+ return null;
+ }
+ return {suffixIcon}
;
+ };
+
+ const readerTips = () => {
+ const tips = readerTNodeJSX('tips');
+ if (!tips) {
+ return null;
+ }
+ return {tips}
;
+ };
+
+ return (
+
+ );
+ };
+ },
+});
diff --git a/src/input/input.vue b/src/input/input.vue
deleted file mode 100644
index 1f2e6efbc..000000000
--- a/src/input/input.vue
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-
-
-
diff --git a/src/input/props.ts b/src/input/props.ts
index 80375a15c..289010ecf 100644
--- a/src/input/props.ts
+++ b/src/input/props.ts
@@ -32,7 +32,7 @@ export default {
clearable: Boolean,
/** 是否禁用输入框 */
disabled: Boolean,
- /** 指定输入框展示值的格式 */
+ /** 【暂不支持】指定输入框展示值的格式 */
format: {
type: Function as PropType,
},
@@ -73,15 +73,6 @@ export default {
},
/** 只读状态 */
readonly: Boolean,
- /** 已废弃。输入框尺寸 */
- size: {
- type: String as PropType,
- default: 'small' as TdInputProps['size'],
- validator(val: TdInputProps['size']): boolean {
- if (!val) return true;
- return ['small', 'medium'].includes(val);
- },
- },
/** 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化 */
status: {
type: String as PropType,
@@ -134,6 +125,6 @@ export default {
onClear: Function as PropType,
/** 获得焦点时触发 */
onFocus: Function as PropType,
- /** 字数超出限制时触发 */
+ /** 【暂不支持】字数超出限制时触发 */
onValidate: Function as PropType,
};
diff --git a/src/input/type.ts b/src/input/type.ts
index e90f65c49..c30a8da28 100644
--- a/src/input/type.ts
+++ b/src/input/type.ts
@@ -41,7 +41,7 @@ export interface TdInputProps {
*/
disabled?: boolean;
/**
- * 指定输入框展示值的格式
+ * 【暂不支持】指定输入框展示值的格式
*/
format?: InputFormatType;
/**
@@ -79,11 +79,6 @@ export interface TdInputProps {
* @default false
*/
readonly?: boolean;
- /**
- * 已废弃。输入框尺寸
- * @default small
- */
- size?: 'medium' | 'small';
/**
* 输入框状态。默认情况会由组件内部根据实际情况呈现,如果文本过长引起的状态变化
*/
@@ -140,7 +135,7 @@ export interface TdInputProps {
*/
onFocus?: (value: InputValue, context: { e: FocusEvent }) => void;
/**
- * 字数超出限制时触发
+ * 【暂不支持】字数超出限制时触发
*/
onValidate?: (context: { error?: 'exceed-maximum' | 'below-minimum' }) => void;
}