fix(Input/Textarea): add v-model modifiers (#856)

This commit is contained in:
max
2023-11-10 11:05:58 +01:00
committed by GitHub
parent 6f0bfb5d89
commit 68f6956d6e
3 changed files with 89 additions and 6 deletions

View File

@@ -14,6 +14,7 @@
v-bind="attrs"
@input="onInput"
@blur="onBlur"
@change="onChange"
>
<slot />
@@ -36,9 +37,10 @@ import { ref, computed, toRef, onMounted, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { twMerge, twJoin } from 'tailwind-merge'
import UIcon from '../elements/Icon.vue'
import { defu } from 'defu'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig } from '../../utils'
import { mergeConfig, looseToNumber } from '../../utils'
import type { NestedKeyOf, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
@@ -156,6 +158,10 @@ export default defineComponent({
ui: {
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
default: undefined
},
modelModifiers: {
type: Object as PropType<{ trim?: boolean, lazy?: boolean, number?: boolean }>,
default: () => ({})
}
},
emits: ['update:modelValue', 'blur'],
@@ -164,6 +170,8 @@ export default defineComponent({
const { emitFormBlur, emitFormInput, size, color, inputId, name } = useFormGroup(props, config)
const modelModifiers = ref(defu({}, props.modelModifiers, { trim: false, lazy: false, number: false }))
const input = ref<HTMLInputElement | null>(null)
const autoFocus = () => {
@@ -172,11 +180,40 @@ export default defineComponent({
}
}
const onInput = (event: InputEvent) => {
emit('update:modelValue', (event.target as HTMLInputElement).value)
// Custom function to handle the v-model properties
const updateInput = (value: string) => {
if (modelModifiers.value.trim) {
value = value.trim()
}
if (modelModifiers.value.number || props.type === 'number') {
value = looseToNumber(value)
}
emit('update:modelValue', value)
emitFormInput()
}
const onInput = (event: InputEvent) => {
if (!modelModifiers.value.lazy) {
updateInput((event.target as HTMLInputElement).value)
}
}
const onChange = (event: InputEvent) => {
const value = (event.target as HTMLInputElement).value
if (modelModifiers.value.lazy) {
updateInput(value)
}
// Update trimmed input so that it has same behaviour as native input https://github.com/vuejs/core/blob/5ea8a8a4fab4e19a71e123e4d27d051f5e927172/packages/runtime-dom/src/directives/vModel.ts#L63
if (modelModifiers.value.trim) {
(event.target as HTMLInputElement).value = value.trim()
}
}
const onBlur = (event: FocusEvent) => {
emitFormBlur()
emit('blur', event)
@@ -280,6 +317,7 @@ export default defineComponent({
trailingIconClass,
trailingWrapperIconClass,
onInput,
onChange,
onBlur
}
}

View File

@@ -14,6 +14,7 @@
v-bind="attrs"
@input="onInput"
@blur="onBlur"
@change="onChange"
/>
</div>
</template>
@@ -22,9 +23,10 @@
import { ref, computed, toRef, watch, onMounted, nextTick, defineComponent } from 'vue'
import type { PropType } from 'vue'
import { twMerge, twJoin } from 'tailwind-merge'
import { defu } from 'defu'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig } from '../../utils'
import { mergeConfig, looseToNumber } from '../../utils'
import type { NestedKeyOf, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
@@ -119,6 +121,10 @@ export default defineComponent({
ui: {
type: Object as PropType<Partial<typeof config & { strategy?: Strategy }>>,
default: undefined
},
modelModifiers: {
type: Object as PropType<{ trim?: boolean, lazy?: boolean, number?: boolean }>,
default: () => ({})
}
},
emits: ['update:modelValue', 'blur'],
@@ -127,6 +133,8 @@ export default defineComponent({
const { emitFormBlur, emitFormInput, inputId, color, size, name } = useFormGroup(props, config)
const modelModifiers = ref(defu({}, props.modelModifiers, { trim: false, lazy: false, number: false }))
const textarea = ref<HTMLTextAreaElement | null>(null)
const autoFocus = () => {
@@ -157,11 +165,38 @@ export default defineComponent({
}
}
// Custom function to handle the v-model properties
const updateInput = (value: string) => {
if (modelModifiers.value.trim) {
value = value.trim()
}
if (modelModifiers.value.number) {
value = looseToNumber(value)
}
emit('update:modelValue', value)
emitFormInput()
}
const onInput = (event: InputEvent) => {
autoResize()
if (!modelModifiers.value.lazy) {
updateInput((event.target as HTMLInputElement).value)
}
}
emit('update:modelValue', (event.target as HTMLInputElement).value)
emitFormInput()
const onChange = (event: InputEvent) => {
const value = (event.target as HTMLInputElement).value
if (modelModifiers.value.lazy) {
updateInput(value)
}
// Update trimmed input so that it has same behaviour as native input
if (modelModifiers.value.trim) {
(event.target as HTMLInputElement).value = value.trim()
}
}
const onBlur = (event: FocusEvent) => {
@@ -211,6 +246,7 @@ export default defineComponent({
// eslint-disable-next-line vue/no-dupe-keys
textareaClass,
onInput,
onChange,
onBlur
}
}