Skip to content

Commit 4973865

Browse files
committed
Revert "fix(VAutocomplete/VCombobox): consistent open/close transition (#20768)"
This reverts commit 5967d76.
1 parent 688d33a commit 4973865

File tree

4 files changed

+29
-52
lines changed

4 files changed

+29
-52
lines changed

packages/vuetify/src/components/VAutocomplete/VAutocomplete.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { useItems } from '@/composables/list-items'
2424
import { useLocale } from '@/composables/locale'
2525
import { useMenuActivator } from '@/composables/menuActivator'
2626
import { useProxiedModel } from '@/composables/proxiedModel'
27+
import { makeTransitionProps } from '@/composables/transition'
2728

2829
// Utilities
2930
import { computed, mergeProps, nextTick, ref, shallowRef, watch } from 'vue'
@@ -72,6 +73,7 @@ export const makeVAutocompleteProps = propsFactory({
7273
modelValue: null,
7374
role: 'combobox',
7475
}), ['validationValue', 'dirty', 'appendInnerIcon']),
76+
...makeTransitionProps({ transition: false }),
7577
}, 'VAutocomplete')
7678

7779
type ItemType<T> = T extends readonly (infer U)[] ? U : never
@@ -124,7 +126,6 @@ export const VAutocomplete = genericComponent<new <
124126
const vMenuRef = ref<VMenu>()
125127
const vVirtualScrollRef = ref<VVirtualScroll>()
126128
const selectionIndex = shallowRef(-1)
127-
const _searchLock = shallowRef<string | null>(null)
128129
const { items, transformIn, transformOut } = useItems(props)
129130
const { textColorClasses, textColorStyles } = useTextColor(() => vTextFieldRef.value?.color)
130131
const search = useProxiedModel(props, 'search', '')
@@ -144,10 +145,7 @@ export const VAutocomplete = genericComponent<new <
144145
: model.value.length
145146
})
146147
const form = useForm(props)
147-
const { filteredItems, getMatches } = useFilter(
148-
props,
149-
items,
150-
() => _searchLock.value ?? (isPristine.value ? '' : search.value))
148+
const { filteredItems, getMatches } = useFilter(props, items, () => isPristine.value ? '' : search.value)
151149

152150
const displayItems = computed(() => {
153151
if (props.hideSelected) {
@@ -316,7 +314,6 @@ export const VAutocomplete = genericComponent<new <
316314
isPristine.value = true
317315
vTextFieldRef.value?.focus()
318316
}
319-
_searchLock.value = null
320317
}
321318

322319
function onFocusin (e: FocusEvent) {
@@ -356,7 +353,6 @@ export const VAutocomplete = genericComponent<new <
356353
} else {
357354
const add = set !== false
358355
model.value = add ? [item] : []
359-
_searchLock.value = search.value ?? null
360356
search.value = add && !hasSelectionSlot.value ? item.title : ''
361357

362358
// watch for search watcher to trigger
@@ -379,7 +375,6 @@ export const VAutocomplete = genericComponent<new <
379375
} else {
380376
if (!props.multiple && search.value == null) model.value = []
381377
menu.value = false
382-
_searchLock.value = isPristine.value ? null : (search.value ?? null)
383378
search.value = ''
384379
selectionIndex.value = -1
385380
}
@@ -393,7 +388,7 @@ export const VAutocomplete = genericComponent<new <
393388
isPristine.value = !val
394389
})
395390

396-
watch(menu, val => {
391+
watch(menu, () => {
397392
if (!props.hideSelected && menu.value && model.value.length) {
398393
const index = displayItems.value.findIndex(
399394
item => model.value.some(s => item.value === s.value)
@@ -402,7 +397,6 @@ export const VAutocomplete = genericComponent<new <
402397
index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index)
403398
})
404399
}
405-
if (val) _searchLock.value = null
406400
})
407401

408402
watch(items, (newVal, oldVal) => {
@@ -469,6 +463,7 @@ export const VAutocomplete = genericComponent<new <
469463
maxHeight={ 310 }
470464
openOnClick={ false }
471465
closeOnContentClick={ false }
466+
transition={ props.transition }
472467
onAfterEnter={ onAfterEnter }
473468
onAfterLeave={ onAfterLeave }
474469
{ ...props.menuProps }

packages/vuetify/src/components/VAutocomplete/__tests__/VAutocomplete.spec.browser.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import { VAutocomplete } from '../VAutocomplete'
33
import { VForm } from '@/components/VForm'
44

55
// Utilities
6-
import { generate, render, screen, userEvent, wait, waitAnimationFrame, waitIdle } from '@test'
6+
import { generate, render, screen, userEvent, waitAnimationFrame, waitIdle } from '@test'
77
import { findAllByRole, queryAllByRole, within } from '@testing-library/vue'
8-
import { commands } from '@vitest/browser/context'
98
import { cloneVNode, ref } from 'vue'
109

1110
const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const
@@ -83,7 +82,6 @@ describe('VAutocomplete', () => {
8382
))
8483

8584
await userEvent.click(container)
86-
await wait(100) // waitStable was very flaky here
8785

8886
const menu = await screen.findByRole('listbox')
8987

@@ -130,7 +128,6 @@ describe('VAutocomplete', () => {
130128
))
131129

132130
await userEvent.click(container)
133-
await commands.waitStable('.v-list')
134131

135132
const menu = await screen.findByRole('listbox')
136133

@@ -182,7 +179,6 @@ describe('VAutocomplete', () => {
182179
))
183180

184181
await userEvent.click(container)
185-
await wait(100)
186182

187183
const menu = await screen.findByRole('listbox')
188184

@@ -358,7 +354,6 @@ describe('VAutocomplete', () => {
358354
))
359355

360356
await userEvent.click(element)
361-
await commands.waitStable('.v-list')
362357

363358
await userEvent.click(screen.getAllByRole('option')[0])
364359
expect(selectedItems.value).toBe(1)
@@ -427,7 +422,6 @@ describe('VAutocomplete', () => {
427422

428423
const menuIcon = screen.getByRole('button', { name: /open/i })
429424
await userEvent.click(menuIcon)
430-
await commands.waitStable('.v-list')
431425

432426
const listItems = screen.getAllByRole('option')
433427
expect(listItems).toHaveLength(2)
@@ -450,7 +444,8 @@ describe('VAutocomplete', () => {
450444
))
451445

452446
await userEvent.type(element, 'f')
453-
await expect.poll(() => screen.findAllByRole('option')).toHaveLength(2)
447+
const listItems = screen.getAllByRole('option')
448+
expect(listItems).toHaveLength(2)
454449
expect(selectedItems.value).toBeUndefined()
455450
})
456451

@@ -540,7 +535,6 @@ describe('VAutocomplete', () => {
540535
const getItems = () => screen.queryAllByRole('option')
541536

542537
await userEvent.click(element)
543-
await commands.waitStable('.v-list')
544538
await expect.poll(getItems).toHaveLength(6)
545539

546540
await userEvent.keyboard('Cal')
@@ -621,7 +615,7 @@ describe('VAutocomplete', () => {
621615
))
622616

623617
await userEvent.click(element)
624-
await commands.waitStable('.v-list')
618+
625619
const items = await screen.findAllByRole('option')
626620
expect(items).toHaveLength(2)
627621

@@ -639,7 +633,7 @@ describe('VAutocomplete', () => {
639633
expect(screen.queryByRole('listbox')).toBeNull()
640634

641635
await rerender({ items: ['Foo', 'Bar'] })
642-
await expect(screen.findByRole('listbox')).resolves.toBeVisible()
636+
await expect(screen.findByRole('listbox')).resolves.toBeDisplayed()
643637
})
644638

645639
// https://github.com/vuetifyjs/vuetify/issues/19346

packages/vuetify/src/components/VCombobox/VCombobox.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { transformItem, useItems } from '@/composables/list-items'
2525
import { useLocale } from '@/composables/locale'
2626
import { useMenuActivator } from '@/composables/menuActivator'
2727
import { useProxiedModel } from '@/composables/proxiedModel'
28+
import { makeTransitionProps } from '@/composables/transition'
2829

2930
// Utilities
3031
import { computed, mergeProps, nextTick, ref, shallowRef, watch } from 'vue'
@@ -78,6 +79,7 @@ export const makeVComboboxProps = propsFactory({
7879
modelValue: null,
7980
role: 'combobox',
8081
}), ['validationValue', 'dirty', 'appendInnerIcon']),
82+
...makeTransitionProps({ transition: false }),
8183
}, 'VCombobox')
8284

8385
type ItemType<T> = T extends readonly (infer U)[] ? U : never
@@ -149,7 +151,6 @@ export const VCombobox = genericComponent<new <
149151
const hasSelectionSlot = computed(() => hasChips.value || !!slots.selection)
150152

151153
const _search = shallowRef(!props.multiple && !hasSelectionSlot.value ? model.value[0]?.title ?? '' : '')
152-
const _searchLock = shallowRef<string | null>(null)
153154

154155
const search = computed<string>({
155156
get: () => {
@@ -192,7 +193,7 @@ export const VCombobox = genericComponent<new <
192193
const { filteredItems, getMatches } = useFilter(
193194
props,
194195
items,
195-
() => _searchLock.value ?? (props.alwaysFilter || !isPristine.value ? search.value : '')
196+
() => props.alwaysFilter || !isPristine.value ? search.value : ''
196197
)
197198

198199
const displayItems = computed(() => {
@@ -295,11 +296,16 @@ export const VCombobox = genericComponent<new <
295296
menu.value = false
296297
}
297298

298-
if (highlightFirst.value &&
299-
['Enter', 'Tab'].includes(e.key) &&
300-
!model.value.some(({ value }) => value === displayItems.value[0].value)
301-
) {
302-
select(filteredItems.value[0])
299+
if (['Enter', 'Escape', 'Tab'].includes(e.key)) {
300+
if (
301+
highlightFirst.value &&
302+
['Enter', 'Tab'].includes(e.key) &&
303+
!model.value.some(({ value }) => value === displayItems.value[0].value)
304+
) {
305+
select(filteredItems.value[0])
306+
}
307+
308+
isPristine.value = true
303309
}
304310

305311
if (e.key === 'ArrowDown' && highlightFirst.value) {
@@ -372,7 +378,6 @@ export const VCombobox = genericComponent<new <
372378
isPristine.value = true
373379
vTextFieldRef.value?.focus()
374380
}
375-
_searchLock.value = null
376381
}
377382
/** @param set - null means toggle */
378383
function select (item: ListItem | undefined, set: boolean | null = true) {
@@ -396,7 +401,6 @@ export const VCombobox = genericComponent<new <
396401
} else {
397402
const add = set !== false
398403
model.value = add ? [item] : []
399-
_searchLock.value = _search.value
400404
_search.value = add && !hasSelectionSlot.value ? item.title : ''
401405

402406
// watch for search watcher to trigger
@@ -442,7 +446,7 @@ export const VCombobox = genericComponent<new <
442446
}
443447
})
444448

445-
watch(menu, val => {
449+
watch(menu, () => {
446450
if (!props.hideSelected && menu.value && model.value.length) {
447451
const index = displayItems.value.findIndex(
448452
item => model.value.some(s => (props.valueComparator || deepEqual)(s.value, item.value))
@@ -451,8 +455,6 @@ export const VCombobox = genericComponent<new <
451455
index >= 0 && vVirtualScrollRef.value?.scrollToIndex(index)
452456
})
453457
}
454-
455-
if (val) _searchLock.value = null
456458
})
457459

458460
watch(items, (newVal, oldVal) => {
@@ -518,6 +520,7 @@ export const VCombobox = genericComponent<new <
518520
maxHeight={ 310 }
519521
openOnClick={ false }
520522
closeOnContentClick={ false }
523+
transition={ props.transition }
521524
onAfterEnter={ onAfterEnter }
522525
onAfterLeave={ onAfterLeave }
523526
{ ...props.menuProps }

packages/vuetify/src/components/VCombobox/__tests__/VCombobox.spec.browser.tsx

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { VCombobox } from '../VCombobox'
33
import { VForm } from '@/components/VForm'
44

55
// Utilities
6-
import { generate, render, screen, userEvent, wait, waitAnimationFrame, waitIdle } from '@test'
7-
import { commands } from '@vitest/browser/context'
6+
import { generate, render, screen, userEvent, waitAnimationFrame, waitIdle } from '@test'
87
import { cloneVNode, ref } from 'vue'
98

109
const variants = ['underlined', 'outlined', 'filled', 'solo', 'plain'] as const
@@ -93,10 +92,9 @@ describe('VCombobox', () => {
9392
))
9493

9594
await userEvent.click(element)
96-
await wait(100)
9795
await userEvent.click((await screen.findAllByRole('option'))[0])
9896
expect(model.value).toStrictEqual(items[0])
99-
await expect.poll(() => search.value).toBe(items[0].title)
97+
expect(search.value).toBe(items[0].title)
10098
expect(screen.getByCSS('input')).toHaveValue(items[0].title)
10199
expect(screen.getByCSS('.v-combobox__selection')).toHaveTextContent(items[0].title)
102100

@@ -143,7 +141,6 @@ describe('VCombobox', () => {
143141
const input = screen.getByCSS('input')
144142

145143
await userEvent.click(element)
146-
await wait(100)
147144
await userEvent.click(screen.getAllByRole('option')[0])
148145
expect(model.value).toStrictEqual([items[0]])
149146
expect(search.value).toBeUndefined()
@@ -369,7 +366,6 @@ describe('VCombobox', () => {
369366
))
370367

371368
await userEvent.click(element)
372-
await wait(100)
373369

374370
const options = await screen.findAllByRole('option', { selected: true })
375371
expect(options).toHaveLength(2)
@@ -477,11 +473,10 @@ describe('VCombobox', () => {
477473
))
478474

479475
await userEvent.click(element)
480-
await wait(100)
481476

482477
await userEvent.click(screen.getAllByRole('option')[0])
483478

484-
await expect.poll(() => screen.getByCSS('input')).toHaveValue('0')
479+
expect(screen.getByCSS('input')).toHaveValue('0')
485480
})
486481

487482
it('should conditionally show placeholder', async () => {
@@ -549,8 +544,6 @@ describe('VCombobox', () => {
549544
expect(screen.queryAllByRole('listbox')).toHaveLength(0)
550545

551546
await userEvent.click(element)
552-
await commands.waitStable('.v-list')
553-
554547
expect(screen.queryAllByRole('listbox')).toHaveLength(1)
555548
await userEvent.keyboard('{Escape}')
556549
await expect.poll(() => screen.queryAllByRole('listbox')).toHaveLength(0)
@@ -570,8 +563,6 @@ describe('VCombobox', () => {
570563
))
571564

572565
await userEvent.click(element)
573-
await commands.waitStable('.v-list')
574-
575566
expect(screen.getAllByRole('option')).toHaveLength(6)
576567

577568
await userEvent.keyboard('Cal')
@@ -594,8 +585,6 @@ describe('VCombobox', () => {
594585
))
595586

596587
await userEvent.click(element)
597-
await commands.waitStable('.v-list')
598-
599588
expect(screen.getAllByRole('option')).toHaveLength(6)
600589

601590
await userEvent.keyboard('Cal')
@@ -618,8 +607,6 @@ describe('VCombobox', () => {
618607
))
619608

620609
await userEvent.click(element)
621-
await commands.waitStable('.v-list')
622-
623610
expect(screen.getAllByRole('option')).toHaveLength(6)
624611

625612
await userEvent.keyboard('Cal')
@@ -681,7 +668,6 @@ describe('VCombobox', () => {
681668
})
682669

683670
await userEvent.click(element)
684-
await commands.waitStable('.v-list')
685671
await expect(screen.findByRole('listbox')).resolves.toBeVisible()
686672

687673
await userEvent.click(screen.getAllByRole('option')[0])
@@ -748,9 +734,8 @@ describe('VCombobox', () => {
748734
))
749735

750736
await userEvent.click(element)
751-
await wait(100)
752737
await userEvent.click(screen.getAllByRole('option')[0])
753-
await expect.poll(() => model.value).toStrictEqual({ title: 'Item 1', value: 'item1' })
738+
expect(model.value).toStrictEqual({ title: 'Item 1', value: 'item1' })
754739

755740
await userEvent.click(document.body)
756741
expect(model.value).toStrictEqual({ title: 'Item 1', value: 'item1' })

0 commit comments

Comments
 (0)