mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [input] add count-graphemes
This commit is contained in:
@@ -128,6 +128,7 @@ input/length-limiting
|
||||
| show-word-limit | whether show word count, only works when `type` is 'text' or 'textarea' | ^[boolean] | false |
|
||||
| placeholder | placeholder of Input | ^[string] | — |
|
||||
| clearable | whether to show clear button, only works when `type` is not 'textarea' | ^[boolean] | false |
|
||||
| count-graphemes | Count graphemes of input value. If it's set, native maxlength and minlength won't be used. | ^[Function]`(value: string) => number` | — |
|
||||
| formatter | specifies the format of the value presented input.(only works when `type` is 'text') | ^[Function]`(value: string \| number) => string` | — |
|
||||
| parser | specifies the value extracted from formatter input.(only works when `type` is 'text') | ^[Function]`(value: string) => string` | — |
|
||||
| show-password | whether to show toggleable password input | ^[boolean] | false |
|
||||
|
||||
@@ -166,6 +166,12 @@ export const inputProps = buildProps({
|
||||
type: definePropType<StyleValue>([Object, Array, String]),
|
||||
default: () => mutable({} as const),
|
||||
},
|
||||
/**
|
||||
* @description Count graphemes of input value. If it's set, native maxlength and minlength won't be used.
|
||||
*/
|
||||
countGraphemes: {
|
||||
type: Function,
|
||||
},
|
||||
} as const)
|
||||
export type InputProps = ExtractPropTypes<typeof inputProps>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
</el-icon>
|
||||
<span v-if="isWordLimitVisible" :class="nsInput.e('count')">
|
||||
<span :class="nsInput.e('count-inner')">
|
||||
{{ textLength }} / {{ attrs.maxlength }}
|
||||
{{ textLength }} / {{ maxlength }}
|
||||
</span>
|
||||
</span>
|
||||
<el-icon
|
||||
@@ -132,7 +132,7 @@
|
||||
:style="countStyle"
|
||||
:class="nsInput.e('count')"
|
||||
>
|
||||
{{ textLength }} / {{ attrs.maxlength }}
|
||||
{{ textLength }} / {{ maxlength }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
@@ -168,6 +168,7 @@ import {
|
||||
NOOP,
|
||||
ValidateComponentsMap,
|
||||
debugWarn,
|
||||
isFunction,
|
||||
isKorean,
|
||||
isObject,
|
||||
} from '@element-plus/utils'
|
||||
@@ -224,9 +225,20 @@ const wrapperKls = computed(() => [
|
||||
|
||||
const attrs = useAttrs({
|
||||
excludeKeys: computed<string[]>(() => {
|
||||
return Object.keys(containerAttrs.value)
|
||||
const _attrs = Object.keys(containerAttrs.value)
|
||||
if (props.countGraphemes) {
|
||||
_attrs.push('maxlength', 'minlength')
|
||||
}
|
||||
return _attrs
|
||||
}),
|
||||
})
|
||||
const maxlength = computed(() => {
|
||||
if (props.showWordLimit && rawAttrs.maxlength) {
|
||||
return rawAttrs.maxlength
|
||||
}
|
||||
return 0
|
||||
})
|
||||
|
||||
const { form, formItem } = useFormItem()
|
||||
const { inputId } = useFormItemInputId(props, {
|
||||
formItemContext: formItem,
|
||||
@@ -245,6 +257,7 @@ const isComposing = ref(false)
|
||||
const passwordVisible = ref(false)
|
||||
const countStyle = ref<StyleValue>()
|
||||
const textareaCalcStyle = shallowRef(props.inputStyle)
|
||||
const saveValue = ref('')
|
||||
|
||||
const _ref = computed(() => input.value || textarea.value)
|
||||
|
||||
@@ -287,18 +300,26 @@ const showPwdVisible = computed(
|
||||
const isWordLimitVisible = computed(
|
||||
() =>
|
||||
props.showWordLimit &&
|
||||
!!attrs.value.maxlength &&
|
||||
!!maxlength.value &&
|
||||
(props.type === 'text' || props.type === 'textarea') &&
|
||||
!inputDisabled.value &&
|
||||
!props.readonly &&
|
||||
!props.showPassword
|
||||
)
|
||||
const textLength = computed(() => nativeInputValue.value.length)
|
||||
const textLength = computed(() => {
|
||||
if (
|
||||
props.countGraphemes &&
|
||||
isFunction(props.countGraphemes) &&
|
||||
props.showWordLimit
|
||||
) {
|
||||
return props.countGraphemes(nativeInputValue.value)
|
||||
}
|
||||
return nativeInputValue.value.length
|
||||
})
|
||||
const inputExceed = computed(
|
||||
() =>
|
||||
// show exceed style if length of initial value greater then maxlength
|
||||
!!isWordLimitVisible.value &&
|
||||
textLength.value > Number(attrs.value.maxlength)
|
||||
!!isWordLimitVisible.value && textLength.value > Number(maxlength.value)
|
||||
)
|
||||
const suffixVisible = computed(
|
||||
() =>
|
||||
@@ -356,6 +377,12 @@ const handleInput = async (event: Event) => {
|
||||
value = props.formatter(value)
|
||||
}
|
||||
|
||||
if (props.countGraphemes && isFunction(props.countGraphemes)) {
|
||||
const graphemes = props.countGraphemes(value)
|
||||
if (graphemes > Number(maxlength.value)) {
|
||||
value = saveValue.value
|
||||
}
|
||||
}
|
||||
// should not emit input during composition
|
||||
// see: https://github.com/ElemeFE/element/issues/10516
|
||||
if (isComposing.value) return
|
||||
@@ -366,6 +393,7 @@ const handleInput = async (event: Event) => {
|
||||
setNativeInputValue()
|
||||
return
|
||||
}
|
||||
saveValue.value = value
|
||||
|
||||
emit(UPDATE_MODEL_EVENT, value)
|
||||
emit('input', value)
|
||||
|
||||
Reference in New Issue
Block a user