feat(components): [input] add count-graphemes

This commit is contained in:
btea
2023-03-15 09:53:49 +08:00
parent 7987f6f73e
commit ab77eafdb1
3 changed files with 42 additions and 7 deletions

View File

@@ -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 |

View File

@@ -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>

View File

@@ -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)