Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/vuetify/src/components/VFileInput/VFileInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ export const VFileInput = genericComponent<VFileInputSlots>()({

useRender(() => {
const hasCounter = !!(slots.counter || props.counter)
const hasDetails = !!(hasCounter || slots.details)
const hasDetails = !!(
(hasCounter && (props.hideDetails !== 'auto' || !!model.value?.length)) ||
slots.details
)
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs)
const { modelValue: _, ...inputProps } = VInput.filterProps(props)
const fieldProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,5 +186,18 @@ describe('VFileInput', () => {
expect(input.files).toHaveLength(0)
})

// https://github.com/vuetifyjs/vuetify/issues/19998
it('hides details when using hide-details="auto" and counter without files', async () => {
const model = ref<File[]>([])
const { queryByCSS } = render(() => (
<VFileInput hideDetails="auto" counter v-model={ model.value }></VFileInput>
))

expect(queryByCSS('.v-input__details')).toBeNull()

model.value = [oneMBFile]
await expect.poll(() => queryByCSS('.v-input__details')).not.toBeNull()
})

showcase({ stories })
})
5 changes: 4 additions & 1 deletion packages/vuetify/src/components/VTextField/VTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,10 @@ export const VTextField = genericComponent<VTextFieldSlots>()({

useRender(() => {
const hasCounter = !!(slots.counter || (props.counter !== false && props.counter != null))
const hasDetails = !!(hasCounter || slots.details)
const hasDetails = !!(
(hasCounter && (props.hideDetails !== 'auto' || props.persistentCounter || isFocused.value)) ||
slots.details
)
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs)
const { modelValue: _, ...inputProps } = VInput.filterProps(props)
const fieldProps = VField.filterProps(props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ describe('VTextField', () => {
expect(element).toHaveTextContent('0')
})

// https://github.com/vuetifyjs/vuetify/issues/19998
it('hides details when using hide-details="auto" and counter without focus', async () => {
const { element, queryByCSS } = render(() => (
<VTextField hideDetails="auto" counter></VTextField>
))

expect(queryByCSS('.v-input__details')).toBeNull()

await userEvent.click(element)
expect(queryByCSS('.v-input__details')).not.toBeNull()
})

it('keeps -0 with v-model.number', async () => {
const model = ref()
const { element } = render(() => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ describe('VTextField', () => {
expect(details.attributes('id')).toBe('input-4-messages')
})

it('should have aria-describedby when hide-details is "auto" and has counter', () => {
// https://github.com/vuetifyjs/vuetify/issues/19998
it('should not have details when hide-details is "auto" and has counter without focus', async () => {
const wrapper = mountFunction(
<VTextField
id="input-5"
Expand All @@ -188,13 +189,15 @@ describe('VTextField', () => {
/>
)

const input = wrapper.find('input')
expect(input.attributes('aria-describedby')).toBe('input-5-messages')
// Should not have details section without focus
expect(wrapper.find('.v-input__details').exists()).toBe(false)
expect(wrapper.find('input').attributes('aria-describedby')).toBeUndefined()

// Should have details section with counter
const details = wrapper.find('.v-input__details')
expect(details.exists()).toBe(true)
expect(details.attributes('id')).toBe('input-5-messages')
// Should have details section with counter when focused
wrapper.find('input').trigger('focus')
await wrapper.vm.$nextTick()
expect(wrapper.find('.v-input__details').exists()).toBe(true)
expect(wrapper.find('.v-input__details').attributes('id')).toBe('input-5-messages')
})

it('should have aria-describedby when hide-details is "auto" and has details slot', () => {
Expand Down
5 changes: 4 additions & 1 deletion packages/vuetify/src/components/VTextarea/VTextarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ export const VTextarea = genericComponent<VTextareaSlots>()({

useRender(() => {
const hasCounter = !!(slots.counter || props.counter || props.counterValue)
const hasDetails = !!(hasCounter || slots.details)
const hasDetails = !!(
(hasCounter && (props.hideDetails !== 'auto' || props.persistentCounter || isFocused.value)) ||
slots.details
)
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs)
const { modelValue: _, ...inputProps } = VInput.filterProps(props)
const fieldProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,16 @@ describe('VTextarea', () => {
await userEvent.keyboard('Lorem ipsum dolor')
expect(rows.value).toBe(2)
})

// https://github.com/vuetifyjs/vuetify/issues/19998
it('hides details when using hide-details="auto" and counter without focus', async () => {
const { element, queryByCSS } = render(() => (
<VTextarea hideDetails="auto" counter></VTextarea>
))

expect(queryByCSS('.v-input__details')).toBeNull()

await userEvent.click(element)
expect(queryByCSS('.v-input__details')).not.toBeNull()
})
})