refactor(components): [input] use type-based definitions (#23366)

* refactor(components): [input] use type-based props definitions

* fix: update

* chore: rename evt to eve

* refactor: add comments

* Update packages/components/input/src/input.vue

Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>

* fix: import markRaw

* chore: change deps

* chore: revert catalog comment

* refactor: remove generic type

* refactor: revert InputInstance

* docs: update deprecated

* fix: update

* chore: remove CSSProperties

---------

Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>
This commit is contained in:
rzzf
2026-01-17 04:49:45 +08:00
committed by GitHub
parent 5d2526eb72
commit fcf8698c78
3 changed files with 166 additions and 9 deletions

View File

@@ -121,7 +121,7 @@ input/length-limiting
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ----------- |
| type | type of input, see more in [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types) | ^[string]`'text' \| 'textarea' \| 'number' \| 'password' \| 'email' \| 'search' \| 'tel' \| 'url'` | text |
| model-value / v-model | binding value | ^[string] / ^[number] | — |
| model-modifiers ^(2.11.5) | v-model modifiers, reference [Vue modifiers](https://vuejs.org/guide/essentials/forms.html#modifiers) | ^[object]`{ lazy?: boolean, number?: boolean, trim?: boolean }` | — |
| model-modifiers ^(2.11.5) | v-model modifiers, reference [Vue modifiers](https://vuejs.org/guide/essentials/forms.html#modifiers) | ^[object]`{ lazy?: true, number?: true, trim?: true }` | — |
| maxlength | same as `maxlength` in native input | ^[string] / ^[number] | — |
| minlength | same as `minlength` in native input | ^[string] / ^[number] | — |
| show-word-limit | whether show word count, only works when `type` is 'text' or 'textarea' | ^[boolean] | false |

View File

@@ -10,16 +10,17 @@ import { useAriaProps, useSizeProp } from '@element-plus/hooks'
import { CircleClose } from '@element-plus/icons-vue'
import type {
ExtractPropTypes,
Component,
ExtractPublicPropTypes,
HTMLAttributes,
StyleValue,
} from 'vue'
import type { ComponentSize } from '@element-plus/constants'
export type InputModelModifiers = {
lazy?: boolean
number?: boolean
trim?: boolean
lazy?: true
number?: true
trim?: true
}
export type InputAutoSize = { minRows?: number; maxRows?: number } | boolean
// Some commonly used values for input type
@@ -34,6 +35,141 @@ export type InputType =
| 'url'
| (string & NonNullable<unknown>)
export interface InputProps {
/**
* @description native input id
*/
id?: string
/**
* @description input box size
*/
size?: ComponentSize
/**
* @description whether to disable
*/
disabled?: boolean
/**
* @description binding value
*/
modelValue?: string | number | null | undefined
/**
* @description v-model modifiers, reference [Vue modifiers](https://vuejs.org/guide/essentials/forms.html#modifiers)
*/
modelModifiers?: InputModelModifiers
/**
* @description same as `maxlength` in native input
*/
maxlength?: string | number
/**
* @description same as `minlength` in native input
*/
minlength?: string | number
/**
* @description type of input, see more in [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Form_%3Cinput%3E_types)
*/
type?: InputType
/**
* @description control the resizability
*/
resize?: 'none' | 'both' | 'horizontal' | 'vertical'
/**
* @description whether textarea has an adaptive height
*/
autosize?: InputAutoSize
/**
* @description native input autocomplete
* - When the number of literal types in a union exceeds 315, the TS2590 error occurs. see: https://github.com/vuejs/core/issues/10514
*/
autocomplete?: string // HTMLInputElement['autocomplete']
/**
* @description format content
*/
formatter?: (value: string) => string
/**
* @description parse content
*/
parser?: (value: string) => string
/**
* @description placeholder
*/
placeholder?: string
/**
* @description native input form
*/
form?: string
/**
* @description native input readonly
*/
readonly?: boolean
/**
* @description whether to show clear button
*/
clearable?: boolean
/**
* @description custom clear icon component
*/
clearIcon?: string | Component
/**
* @description toggleable password input
*/
showPassword?: boolean
/**
* @description word count
*/
showWordLimit?: boolean
/**
* @description word count position, valid when `show-word-limit` is true
*/
wordLimitPosition?: 'inside' | 'outside'
/**
* @description suffix icon
*/
suffixIcon?: string | Component
/**
* @description prefix icon
*/
prefixIcon?: string | Component
/**
* @description container role, internal properties provided for use by the picker component
*/
containerRole?: string
/**
* @description input tabindex
*/
tabindex?: string | number
/**
* @description whether to trigger form validation
*/
validateEvent?: boolean
/**
* @description input or textarea element style
*/
inputStyle?: StyleValue
/**
* @description native input autofocus
*/
autofocus?: boolean
/**
* @description number of rows of textarea, only works when `type` is 'textarea'
*/
rows?: number
/**
* @description native `aria-label` attribute
*/
ariaLabel?: string
/**
* @description native input mode for virtual keyboards
*/
inputmode?: HTMLAttributes['inputmode']
/**
* @description same as `name` in native input
*/
name?: string
}
/**
* @deprecated Removed after 3.0.0, Use `InputProps` instead.
*/
export const inputProps = buildProps({
/**
* @description native input id
@@ -227,7 +363,10 @@ export const inputProps = buildProps({
*/
name: String,
} as const)
export type InputProps = ExtractPropTypes<typeof inputProps>
/**
* @deprecated Removed after 3.0.0, Use `InputProps` instead.
*/
export type InputPropsPublic = ExtractPublicPropTypes<typeof inputProps>
export const inputEmits = {

View File

@@ -163,6 +163,7 @@
<script lang="ts" setup>
import {
computed,
markRaw,
nextTick,
onMounted,
ref,
@@ -175,7 +176,11 @@ import {
import { useResizeObserver } from '@vueuse/core'
import { isNil } from 'lodash-unified'
import { ElIcon } from '@element-plus/components/icon'
import { Hide as IconHide, View as IconView } from '@element-plus/icons-vue'
import {
CircleClose as IconCircleClose,
Hide as IconHide,
View as IconView,
} from '@element-plus/icons-vue'
import {
useFormDisabled,
useFormItem,
@@ -202,9 +207,10 @@ import {
UPDATE_MODEL_EVENT,
} from '@element-plus/constants'
import { calcTextareaHeight, looseToNumber } from './utils'
import { inputEmits, inputProps } from './input'
import { inputEmits } from './input'
import type { StyleValue } from 'vue'
import type { InputProps } from './input'
type TargetElement = HTMLInputElement | HTMLTextAreaElement
@@ -213,7 +219,19 @@ defineOptions({
name: COMPONENT_NAME,
inheritAttrs: false,
})
const props = defineProps(inputProps)
const props = withDefaults(defineProps<InputProps>(), {
disabled: undefined,
modelValue: '',
modelModifiers: () => ({}),
type: 'text',
autocomplete: 'off',
clearIcon: markRaw(IconCircleClose),
wordLimitPosition: 'inside',
tabindex: 0,
validateEvent: true,
inputStyle: () => ({}),
rows: 2,
})
const emit = defineEmits(inputEmits)
const rawAttrs = useRawAttrs()