Skip to content
This repository was archived by the owner on Mar 27, 2025. It is now read-only.

Commit 7bc0135

Browse files
authored
feat(BFormInput): debounce support fixes bootstrap-vue-next#737 (bootstrap-vue-next#1371)
feat(BFormInput): debounce support fixes bootstrap-vue-next#737 feat(BFormTextarea): debounce support feat(BFormInput): new add prop debounceMaxWait feat(BFormTextarea): new add prop debounceMaxWait refactor(useFormInput): strongly type emit param refactor(useFormInput): useVModel chore(useFormInput): remove unused vars
1 parent a5133aa commit 7bc0135

File tree

3 files changed

+49
-23
lines changed

3 files changed

+49
-23
lines changed

packages/bootstrap-vue-next/src/components/BFormInput/BFormInput.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ const props = withDefaults(
4949
// CommonInputProps
5050
ariaInvalid: undefined,
5151
autocomplete: undefined,
52+
debounce: 0,
53+
debounceMaxWait: undefined,
5254
autofocus: false,
5355
disabled: false,
5456
form: undefined,

packages/bootstrap-vue-next/src/components/BFormTextarea/BFormTextarea.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const props = withDefaults(
4242
// CommonInputProps
4343
ariaInvalid: undefined,
4444
autocomplete: undefined,
45+
debounce: 0,
46+
debounceMaxWait: undefined,
4547
autofocus: false,
4648
disabled: false,
4749
form: undefined,

packages/bootstrap-vue-next/src/composables/useFormInput.ts

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import type {AriaInvalid, Booleanish, Size} from '../types'
22
import {computed, nextTick, onActivated, onMounted, ref, watch} from 'vue'
33
import {useBooleanish, useId} from '.'
44
import {resolveAriaInvalid} from '../utils'
5-
import {useFocus} from '@vueuse/core'
5+
import {useDebounceFn, useFocus, useToNumber, useVModel} from '@vueuse/core'
66

77
export interface CommonInputProps {
88
ariaInvalid?: AriaInvalid
99
autocomplete?: string
1010
autofocus?: Booleanish
1111
disabled?: Booleanish
1212
form?: string
13+
debounce?: string | number
14+
debounceMaxWait?: string | number
1315
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1416
formatter?: (val: any, evt: any) => any
1517
id?: string
@@ -54,24 +56,47 @@ export interface CommonInputProps {
5456
// trim: {type: Boolean, default: false},
5557
// }
5658

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+
) => {
5870
const input = ref<HTMLInputElement | null>(null)
5971
let inputValue: string | null = null
6072
let neverFormatted = true
73+
74+
const modelValue = useVModel(props, 'modelValue', emit)
75+
6176
const computedId = useId(() => props.id, 'input')
6277
const autofocusBoolean = useBooleanish(() => props.autofocus)
6378
const disabledBoolean = useBooleanish(() => props.disabled)
6479
const lazyBoolean = useBooleanish(() => props.lazy)
6580
const lazyFormatterBoolean = useBooleanish(() => props.lazyFormatter)
6681
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)
7382
const stateBoolean = useBooleanish(() => props.state)
7483
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+
)
75100

76101
const {focused} = useFocus(input, {
77102
initialValue: autofocusBoolean.value,
@@ -101,7 +126,7 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
101126

102127
onMounted(() => {
103128
if (input.value) {
104-
input.value.value = props.modelValue as string
129+
input.value.value = modelValue.value as string
105130
}
106131
})
107132

@@ -127,9 +152,9 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
127152

128153
const nextModel = _getModelValue(formattedValue)
129154

130-
if (props.modelValue !== nextModel) {
155+
if (modelValue.value !== nextModel) {
131156
inputValue = value
132-
emit('update:modelValue', nextModel)
157+
updateModelValue(nextModel)
133158
}
134159

135160
emit('input', formattedValue)
@@ -145,10 +170,10 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
145170

146171
if (!lazyBoolean.value) return
147172
inputValue = value
148-
emit('update:modelValue', formattedValue)
173+
updateModelValue(formattedValue)
149174

150175
const nextModel = _getModelValue(formattedValue)
151-
if (props.modelValue !== nextModel) {
176+
if (modelValue.value !== nextModel) {
152177
emit('change', formattedValue)
153178
}
154179
}
@@ -161,7 +186,7 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
161186
const formattedValue = _formatValue(value, evt, true)
162187

163188
inputValue = value
164-
emit('update:modelValue', formattedValue)
189+
updateModelValue(formattedValue)
165190
}
166191

167192
const focus = () => {
@@ -176,15 +201,12 @@ export default (props: Readonly<CommonInputProps>, emit: any) => {
176201
}
177202
}
178203

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+
})
188210

189211
return {
190212
input,

0 commit comments

Comments
 (0)