@@ -2,14 +2,16 @@ import type {AriaInvalid, Booleanish, Size} from '../types'
2
2
import { computed , nextTick , onActivated , onMounted , ref , watch } from 'vue'
3
3
import { useBooleanish , useId } from '.'
4
4
import { resolveAriaInvalid } from '../utils'
5
- import { useFocus } from '@vueuse/core'
5
+ import { useDebounceFn , useFocus , useToNumber , useVModel } from '@vueuse/core'
6
6
7
7
export interface CommonInputProps {
8
8
ariaInvalid ?: AriaInvalid
9
9
autocomplete ?: string
10
10
autofocus ?: Booleanish
11
11
disabled ?: Booleanish
12
12
form ?: string
13
+ debounce ?: string | number
14
+ debounceMaxWait ?: string | number
13
15
// eslint-disable-next-line @typescript-eslint/no-explicit-any
14
16
formatter ?: ( val : any , evt : any ) => any
15
17
id ?: string
@@ -54,24 +56,47 @@ export interface CommonInputProps {
54
56
// trim: {type: Boolean, default: false},
55
57
// }
56
58
57
- export default ( props : Readonly < CommonInputProps > , emit : any ) => {
59
+ export default (
60
+ props : Readonly < CommonInputProps > ,
61
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
+ emit : ( ( evt : 'update:modelValue' , val : any ) => void ) &
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ ( ( evt : 'change' , val : any ) => void ) &
65
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ ( ( evt : 'blur' , val : any ) => void ) &
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ ( ( evt : 'input' , val : any ) => void )
69
+ ) => {
58
70
const input = ref < HTMLInputElement | null > ( null )
59
71
let inputValue : string | null = null
60
72
let neverFormatted = true
73
+
74
+ const modelValue = useVModel ( props , 'modelValue' , emit )
75
+
61
76
const computedId = useId ( ( ) => props . id , 'input' )
62
77
const autofocusBoolean = useBooleanish ( ( ) => props . autofocus )
63
78
const disabledBoolean = useBooleanish ( ( ) => props . disabled )
64
79
const lazyBoolean = useBooleanish ( ( ) => props . lazy )
65
80
const lazyFormatterBoolean = useBooleanish ( ( ) => props . lazyFormatter )
66
81
const numberBoolean = useBooleanish ( ( ) => props . number )
67
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
68
- const plaintextBoolean = useBooleanish ( ( ) => props . plaintext )
69
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
- const readonlyBoolean = useBooleanish ( ( ) => props . readonly )
71
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
72
- const requiredBoolean = useBooleanish ( ( ) => props . required )
73
82
const stateBoolean = useBooleanish ( ( ) => props . state )
74
83
const trimBoolean = useBooleanish ( ( ) => props . trim )
84
+ const debounceNumber = useToNumber ( computed ( ( ) => props . debounce ?? 0 ) )
85
+ const debounceMaxWaitNumber = useToNumber ( computed ( ( ) => props . debounceMaxWait ?? NaN ) )
86
+ const computedDebounceValueWithLazy = computed ( ( ) =>
87
+ lazyBoolean . value === true ? 0 : debounceNumber . value
88
+ )
89
+ const computedDebounceMaxWaitValueWithLazy = computed ( ( ) =>
90
+ lazyBoolean . value === true ? NaN : debounceMaxWaitNumber . value
91
+ )
92
+
93
+ const updateModelValue = useDebounceFn (
94
+ ( value : string | number | undefined ) => {
95
+ modelValue . value = value
96
+ } ,
97
+ computedDebounceValueWithLazy ,
98
+ { maxWait : computedDebounceMaxWaitValueWithLazy }
99
+ )
75
100
76
101
const { focused} = useFocus ( input , {
77
102
initialValue : autofocusBoolean . value ,
@@ -101,7 +126,7 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
101
126
102
127
onMounted ( ( ) => {
103
128
if ( input . value ) {
104
- input . value . value = props . modelValue as string
129
+ input . value . value = modelValue . value as string
105
130
}
106
131
} )
107
132
@@ -127,9 +152,9 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
127
152
128
153
const nextModel = _getModelValue ( formattedValue )
129
154
130
- if ( props . modelValue !== nextModel ) {
155
+ if ( modelValue . value !== nextModel ) {
131
156
inputValue = value
132
- emit ( 'update:modelValue' , nextModel )
157
+ updateModelValue ( nextModel )
133
158
}
134
159
135
160
emit ( 'input' , formattedValue )
@@ -145,10 +170,10 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
145
170
146
171
if ( ! lazyBoolean . value ) return
147
172
inputValue = value
148
- emit ( 'update:modelValue' , formattedValue )
173
+ updateModelValue ( formattedValue )
149
174
150
175
const nextModel = _getModelValue ( formattedValue )
151
- if ( props . modelValue !== nextModel ) {
176
+ if ( modelValue . value !== nextModel ) {
152
177
emit ( 'change' , formattedValue )
153
178
}
154
179
}
@@ -161,7 +186,7 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
161
186
const formattedValue = _formatValue ( value , evt , true )
162
187
163
188
inputValue = value
164
- emit ( 'update:modelValue' , formattedValue )
189
+ updateModelValue ( formattedValue )
165
190
}
166
191
167
192
const focus = ( ) => {
@@ -176,15 +201,12 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
176
201
}
177
202
}
178
203
179
- watch (
180
- ( ) => props . modelValue ,
181
- ( newValue ) => {
182
- if ( ! input . value ) return
183
- input . value . value = inputValue && neverFormatted ? inputValue : ( newValue as string )
184
- inputValue = null
185
- neverFormatted = true
186
- }
187
- )
204
+ watch ( modelValue , ( newValue ) => {
205
+ if ( ! input . value ) return
206
+ input . value . value = inputValue && neverFormatted ? inputValue : ( newValue as string )
207
+ inputValue = null
208
+ neverFormatted = true
209
+ } )
188
210
189
211
return {
190
212
input,
0 commit comments