From 2368668d49b322a1ac7aa5a9d602676affdef9b2 Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Sun, 2 Jun 2024 14:19:05 +1000 Subject: [PATCH] fix(VAutocomplete/VCombobox): disallow auto-select-first via pure blur fixes #19929 --- .../VAutocomplete/VAutocomplete.tsx | 15 +-- .../__tests__/VAutocomplete.spec.cy.tsx | 111 ++++++++++++++---- .../src/components/VCombobox/VCombobox.tsx | 17 +-- .../VCombobox/__tests__/VCombobox.spec.cy.tsx | 101 ++++++++++++---- 4 files changed, 177 insertions(+), 67 deletions(-) diff --git a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx index b111a890618..59eeccb193d 100644 --- a/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx +++ b/packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx @@ -238,7 +238,11 @@ export const VAutocomplete = genericComponent value === displayItems.value[0].value) + ) { select(displayItems.value[0]) } @@ -369,15 +373,8 @@ export const VAutocomplete = genericComponent 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 } }) diff --git a/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx b/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx index 601258f1082..bfc87cf239f 100644 --- a/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx +++ b/packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.cy.tsx @@ -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(() => ( - - )) - .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(() => ( + + )) + .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(() => ( + + )) + .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(() => ( + + )) + .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 diff --git a/packages/vuetify/src/components/VCombobox/VCombobox.tsx b/packages/vuetify/src/components/VCombobox/VCombobox.tsx index cff4ae00550..bc1fbe1fe36 100644 --- a/packages/vuetify/src/components/VCombobox/VCombobox.tsx +++ b/packages/vuetify/src/components/VCombobox/VCombobox.tsx @@ -290,8 +290,12 @@ export const VCombobox = genericComponent value === displayItems.value[0].value) + ) { select(filteredItems.value[0]) } @@ -412,15 +416,6 @@ export const VCombobox = genericComponent value === displayItems.value[0].value) - ) { - select(displayItems.value[0]) - return - } - if (search.value) { if (props.multiple) { select(transformItem(props, search.value)) diff --git a/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx b/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx index d8dc1c89515..616753caf0c 100644 --- a/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx +++ b/packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.cy.tsx @@ -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(() => ( - - )) - .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(() => ( + + )) + .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(() => ( + + )) + .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(() => ( + + )) + .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`, () => {