Skip to content

Commit

Permalink
fix(Input/Textarea): add v-model modifiers (#856)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxsteinwand committed Nov 10, 2023
1 parent 6f0bfb5 commit 68f6956
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 6 deletions.
44 changes: 41 additions & 3 deletions src/runtime/components/forms/Input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
v-bind="attrs"
@input="onInput"
@blur="onBlur"
@change="onChange"
>
<slot />

Expand All @@ -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'
Expand Down Expand Up @@ -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'],
Expand All @@ -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 = () => {
Expand All @@ -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)
Expand Down Expand Up @@ -280,6 +317,7 @@ export default defineComponent({
trailingIconClass,
trailingWrapperIconClass,
onInput,
onChange,
onBlur
}
}
Expand Down
42 changes: 39 additions & 3 deletions src/runtime/components/forms/Textarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
v-bind="attrs"
@input="onInput"
@blur="onBlur"
@change="onChange"
/>
</div>
</template>
Expand All @@ -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'
Expand Down Expand Up @@ -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'],
Expand All @@ -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 = () => {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -211,6 +246,7 @@ export default defineComponent({
// eslint-disable-next-line vue/no-dupe-keys
textareaClass,
onInput,
onChange,
onBlur
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,13 @@ export function getSlotsChildren (slots: any) {
return children
}

/**
* "123-foo" will be parsed to 123
* This is used for the .number modifier in v-model
*/
export function looseToNumber (val: any): any {
const n = parseFloat(val)
return isNaN(n) ? val : n
}

export * from './lodash'

1 comment on commit 68f6956

@vercel
Copy link

@vercel vercel bot commented on 68f6956 Nov 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ui – ./

ui.nuxt.com
ui-git-dev-nuxt-js.vercel.app
ui-nuxt-js.vercel.app

Please sign in to comment.