Skip to content

Commit b7df7f0

Browse files
committed
fix(inputs): normalise inheriting readonly and disabled from form
fixes #20730
1 parent 54e430f commit b7df7f0

File tree

6 files changed

+31
-28
lines changed

6 files changed

+31
-28
lines changed

Diff for: packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export const VAutocomplete = genericComponent<new <
166166
: typeof props.counterValue === 'number' ? props.counterValue
167167
: model.value.length
168168
})
169-
const form = useForm()
169+
const form = useForm(props)
170170
const { filteredItems, getMatches } = useFilter(props, items, () => isPristine.value ? '' : search.value)
171171

172172
const displayItems = computed(() => {
@@ -192,7 +192,7 @@ export const VAutocomplete = genericComponent<new <
192192

193193
const menuDisabled = computed(() => (
194194
(props.hideNoData && !displayItems.value.length) ||
195-
props.readonly || form?.isReadonly.value
195+
form.isReadonly.value || form.isDisabled.value
196196
))
197197

198198
const listRef = ref<VList>()
@@ -224,7 +224,7 @@ export const VAutocomplete = genericComponent<new <
224224
}
225225
}
226226
function onKeydown (e: KeyboardEvent) {
227-
if (props.readonly || form?.isReadonly.value) return
227+
if (form.isReadonly.value) return
228228

229229
const selectionStart = vTextFieldRef.value.selectionStart
230230
const length = model.value.length
@@ -450,7 +450,7 @@ export const VAutocomplete = genericComponent<new <
450450
props.class,
451451
]}
452452
style={ props.style }
453-
readonly={ props.readonly }
453+
readonly={ form.isReadonly.value }
454454
placeholder={ isDirty ? undefined : props.placeholder }
455455
onClick:clear={ onClear }
456456
onMousedown:control={ onMousedownControl }

Diff for: packages/vuetify/src/components/VCombobox/VCombobox.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ export const VCombobox = genericComponent<new <
165165
return props.multiple ? transformed : (transformed[0] ?? null)
166166
}
167167
)
168-
const form = useForm()
168+
const form = useForm(props)
169169

170170
const hasChips = computed(() => !!(props.chips || slots.chip))
171171
const hasSelectionSlot = computed(() => hasChips.value || !!slots.selection)
@@ -243,7 +243,7 @@ export const VCombobox = genericComponent<new <
243243

244244
const menuDisabled = computed(() => (
245245
(props.hideNoData && !displayItems.value.length) ||
246-
props.readonly || form?.isReadonly.value
246+
form.isReadonly.value || form.isDisabled.value
247247
))
248248

249249
const listRef = ref<VList>()
@@ -276,7 +276,7 @@ export const VCombobox = genericComponent<new <
276276
}
277277
// eslint-disable-next-line complexity
278278
function onKeydown (e: KeyboardEvent) {
279-
if (isComposingIgnoreKey(e) || props.readonly || form?.isReadonly.value) return
279+
if (isComposingIgnoreKey(e) || form.isReadonly.value) return
280280

281281
const selectionStart = vTextFieldRef.value.selectionStart
282282
const length = model.value.length
@@ -494,7 +494,7 @@ export const VCombobox = genericComponent<new <
494494
props.class,
495495
]}
496496
style={ props.style }
497-
readonly={ props.readonly }
497+
readonly={ form.isReadonly.value }
498498
placeholder={ isDirty ? undefined : props.placeholder }
499499
onClick:clear={ onClear }
500500
onMousedown:control={ onMousedownControl }

Diff for: packages/vuetify/src/components/VSelect/VSelect.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export const VSelect = genericComponent<new <
167167
: typeof props.counterValue === 'number' ? props.counterValue
168168
: model.value.length
169169
})
170-
const form = useForm()
170+
const form = useForm(props)
171171
const selectedValues = computed(() => model.value.map(selection => selection.value))
172172
const isFocused = shallowRef(false)
173173
const label = computed(() => menu.value ? props.closeText : props.openText)
@@ -184,7 +184,7 @@ export const VSelect = genericComponent<new <
184184

185185
const menuDisabled = computed(() => (
186186
(props.hideNoData && !displayItems.value.length) ||
187-
props.readonly || form?.isReadonly.value
187+
form.isReadonly.value || form.isDisabled.value
188188
))
189189

190190
const computedMenuProps = computed(() => {
@@ -215,7 +215,7 @@ export const VSelect = genericComponent<new <
215215
}
216216
}
217217
function onKeydown (e: KeyboardEvent) {
218-
if (!e.key || props.readonly || form?.isReadonly.value) return
218+
if (!e.key || form.isReadonly.value) return
219219

220220
if (['Enter', ' ', 'ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) {
221221
e.preventDefault()

Diff for: packages/vuetify/src/composables/form.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ export function createForm (props: FormProps) {
192192
}
193193
}
194194

195-
export function useForm () {
196-
return inject(FormKey, null)
195+
export function useForm (props?: { readonly: boolean | null, disabled: boolean | null }) {
196+
const form = inject(FormKey, null)
197+
return {
198+
...form,
199+
isReadonly: computed(() => !!(props?.readonly ?? form?.isReadonly.value)),
200+
isDisabled: computed(() => !!(props?.disabled ?? form?.isDisabled.value)),
201+
}
197202
}

Diff for: packages/vuetify/src/composables/validation.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,20 @@ export function useValidation (
8383
) {
8484
const model = useProxiedModel(props, 'modelValue')
8585
const validationModel = computed(() => props.validationValue === undefined ? model.value : props.validationValue)
86-
const form = useForm()
86+
const form = useForm(props)
8787
const internalErrorMessages = ref<string[]>([])
8888
const isPristine = shallowRef(true)
8989
const isDirty = computed(() => !!(
9090
wrapInArray(model.value === '' ? null : model.value).length ||
9191
wrapInArray(validationModel.value === '' ? null : validationModel.value).length
9292
))
93-
const isDisabled = computed(() => !!(props.disabled ?? form?.isDisabled.value))
94-
const isReadonly = computed(() => !!(props.readonly ?? form?.isReadonly.value))
9593
const errorMessages = computed(() => {
9694
return props.errorMessages?.length
9795
? wrapInArray(props.errorMessages).concat(internalErrorMessages.value).slice(0, Math.max(0, +props.maxErrors))
9896
: internalErrorMessages.value
9997
})
10098
const validateOn = computed(() => {
101-
let value = (props.validateOn ?? form?.validateOn.value) || 'input'
99+
let value = (props.validateOn ?? form.validateOn?.value) || 'input'
102100
if (value === 'lazy') value = 'input lazy'
103101
if (value === 'eager') value = 'input eager'
104102
const set = new Set(value?.split(' ') ?? [])
@@ -125,16 +123,16 @@ export function useValidation (
125123
return {
126124
[`${name}--error`]: isValid.value === false,
127125
[`${name}--dirty`]: isDirty.value,
128-
[`${name}--disabled`]: isDisabled.value,
129-
[`${name}--readonly`]: isReadonly.value,
126+
[`${name}--disabled`]: form.isDisabled.value,
127+
[`${name}--readonly`]: form.isReadonly.value,
130128
}
131129
})
132130

133131
const vm = getCurrentInstance('validation')
134132
const uid = computed(() => props.name ?? unref(id))
135133

136134
onBeforeMount(() => {
137-
form?.register({
135+
form.register?.({
138136
id: uid.value,
139137
vm,
140138
validate,
@@ -144,14 +142,14 @@ export function useValidation (
144142
})
145143

146144
onBeforeUnmount(() => {
147-
form?.unregister(uid.value)
145+
form.unregister?.(uid.value)
148146
})
149147

150148
onMounted(async () => {
151149
if (!validateOn.value.lazy) {
152150
await validate(!validateOn.value.eager)
153151
}
154-
form?.update(uid.value, isValid.value, errorMessages.value)
152+
form.update?.(uid.value, isValid.value, errorMessages.value)
155153
})
156154

157155
useToggleScope(() => validateOn.value.input || (validateOn.value.invalidInput && isValid.value === false), () => {
@@ -175,7 +173,7 @@ export function useValidation (
175173
})
176174

177175
watch([isValid, errorMessages], () => {
178-
form?.update(uid.value, isValid.value, errorMessages.value)
176+
form.update?.(uid.value, isValid.value, errorMessages.value)
179177
})
180178

181179
async function reset () {
@@ -228,8 +226,8 @@ export function useValidation (
228226
return {
229227
errorMessages,
230228
isDirty,
231-
isDisabled,
232-
isReadonly,
229+
isDisabled: form.isDisabled,
230+
isReadonly: form.isReadonly,
233231
isPristine,
234232
isValid,
235233
isValidating,

Diff for: packages/vuetify/src/labs/VNumberInput/VNumberInput.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ export const VNumberInput = genericComponent<VNumberInputSlots>()({
9191
const stepDecimals = computed(() => getDecimals(props.step))
9292
const modelDecimals = computed(() => typeof model.value === 'number' ? getDecimals(model.value) : 0)
9393

94-
const form = useForm()
94+
const form = useForm(props)
9595
const controlsDisabled = computed(() => (
96-
props.disabled || props.readonly || form?.isReadonly.value
96+
form.isDisabled.value || form.isReadonly.value
9797
))
9898

9999
const canIncrease = computed(() => {
@@ -119,7 +119,7 @@ export const VNumberInput = genericComponent<VNumberInputSlots>()({
119119
const decrementSlotProps = computed(() => ({ click: onClickDown }))
120120

121121
onMounted(() => {
122-
if (!props.readonly && !props.disabled) {
122+
if (!controlsDisabled.value) {
123123
clampModel()
124124
}
125125
})

0 commit comments

Comments
 (0)