Skip to content

Commit

Permalink
fix(VAutocomplete/VCombobox): disallow auto-select-first via pure blur
Browse files Browse the repository at this point in the history
fixes #19929
  • Loading branch information
yuwu9145 committed Jun 2, 2024
1 parent 3c04145 commit 2368668
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 67 deletions.
15 changes: 6 additions & 9 deletions packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ export const VAutocomplete = genericComponent<new <
menu.value = false
}

if (highlightFirst.value && e.key === 'Enter') {
if (
highlightFirst.value &&
['Enter', 'Tab'].includes(e.key) &&
!model.value.some(({ value }) => value === displayItems.value[0].value)
) {
select(displayItems.value[0])
}

Expand Down Expand Up @@ -369,15 +373,8 @@ export const VAutocomplete = genericComponent<new <
nextTick(() => isSelecting.value = false)
} else {
if (!props.multiple && search.value == null) model.value = []
else if (
highlightFirst.value &&
!listHasFocus.value &&
!model.value.some(({ value }) => value === displayItems.value[0].value)
) {
select(displayItems.value[0])
}
menu.value = false
if (props.multiple || hasSelectionSlot.value) search.value = ''
if (!model.value.some(({ title }) => title === search.value)) search.value = ''
selectionIndex.value = -1
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,33 +464,92 @@ describe('VAutocomplete', () => {
.should('not.have.class', 'v-autocomplete--active-menu')
})

it('should auto-select-first item when pressing enter', () => {
const selectedItems = ref(undefined)
describe('auto-select-first', () => {
it('should auto-select-first item when pressing enter', () => {
const selectedItems = ref(undefined)

cy
.mount(() => (
<VAutocomplete
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-autocomplete')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-autocomplete input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-autocomplete input')
.trigger('keydown', { key: keyValues.enter, waitForAnimations: false })
.get('.v-list-item')
.should('have.length', 1)
.then(_ => {
expect(selectedItems.value).to.deep.equal(['California'])
})
cy
.mount(() => (
<VAutocomplete
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-autocomplete')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-autocomplete input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-autocomplete input')
.trigger('keydown', { key: keyValues.enter, waitForAnimations: false })
.get('.v-list-item')
.should('have.length', 1)
.then(_ => {
expect(selectedItems.value).to.deep.equal(['California'])
})
})

it('should auto-select-first item when pressing tab', () => {
const selectedItems = ref([])

cy
.mount(() => (
<VAutocomplete
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-autocomplete')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-autocomplete input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.realPress('Tab')
.get('.v-list-item')
.should('have.length', 0)
.then(_ => {
expect(selectedItems.value).to.deep.equal(['California'])
})
})

it('should not auto-select-first item when blur', () => {
const selectedItems = ref(undefined)

cy
.mount(() => (
<VAutocomplete
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-autocomplete')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-autocomplete input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-autocomplete input')
.blur()
.get('.v-list-item')
.should('have.length', 0)
.should(_ => {
expect(selectedItems.value).to.deep.equal(undefined)
})
})
})

// https://github.com/vuetifyjs/vuetify/issues/18796
Expand Down
17 changes: 6 additions & 11 deletions packages/vuetify/src/components/VCombobox/VCombobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,12 @@ export const VCombobox = genericComponent<new <
menu.value = false
}

if (['Enter', 'Escape'].includes(e.key)) {
if (highlightFirst.value && e.key === 'Enter') {
if (['Enter', 'Escape', 'Tab'].includes(e.key)) {
if (
highlightFirst.value &&
['Enter', 'Tab'].includes(e.key) &&
!model.value.some(({ value }) => value === displayItems.value[0].value)
) {
select(filteredItems.value[0])
}

Expand Down Expand Up @@ -412,15 +416,6 @@ export const VCombobox = genericComponent<new <
selectionIndex.value = -1
menu.value = false

if (
highlightFirst.value &&
!listHasFocus.value &&
!model.value.some(({ value }) => value === displayItems.value[0].value)
) {
select(displayItems.value[0])
return
}

if (search.value) {
if (props.multiple) {
select(transformItem(props, search.value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,27 +593,86 @@ describe('VCombobox', () => {
.should('not.have.class', 'v-combobox--active-menu')
})

it('should auto-select-first item when pressing enter', () => {
cy
.mount(() => (
<VCombobox
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-combobox')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-combobox input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-combobox input')
.trigger('keydown', { key: keyValues.enter, waitForAnimations: false })
.get('.v-list-item')
.should('have.length', 6)
describe('auto-select-first', () => {
it('should auto-select-first item when pressing enter', () => {
cy
.mount(() => (
<VCombobox
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-combobox')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-combobox input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-combobox input')
.trigger('keydown', { key: keyValues.enter, waitForAnimations: false })
.get('.v-list-item')
.should('have.length', 6)
})

it('should auto-select-first item when pressing tab', () => {
const selectedItems = ref([])

cy
.mount(() => (
<VCombobox
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-combobox')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-combobox input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.realPress('Tab')
.get('.v-list-item')
.should('have.length', 0)
.then(_ => {
expect(selectedItems.value).to.deep.equal(['California'])
})
})

it('should not auto-select-first item when blur', () => {
const selectedItems = ref(undefined)

cy
.mount(() => (
<VCombobox
v-model={ selectedItems.value }
items={['California', 'Colorado', 'Florida', 'Georgia', 'Texas', 'Wyoming']}
multiple
autoSelectFirst
/>
))
.get('.v-combobox')
.click()
.get('.v-list-item')
.should('have.length', 6)
.get('.v-combobox input')
.type('Cal')
.get('.v-list-item').eq(0)
.should('have.class', 'v-list-item--active')
.get('.v-combobox input')
.blur()
.get('.v-list-item')
.should('have.length', 0)
.should(_ => {
expect(selectedItems.value).to.deep.equal(['Cal'])
})
})
})

it(`doesn't add duplicate values`, () => {
Expand Down

0 comments on commit 2368668

Please sign in to comment.