diff --git a/src/components/forms/auto-complete/RuiAutoComplete.spec.ts b/src/components/forms/auto-complete/RuiAutoComplete.spec.ts index 403d7ee..46903ab 100644 --- a/src/components/forms/auto-complete/RuiAutoComplete.spec.ts +++ b/src/components/forms/auto-complete/RuiAutoComplete.spec.ts @@ -164,7 +164,14 @@ describe('autocomplete', () => { // Even if the options changed, the search value should not be touch as long as the focus still there, so the UX is not breaking expect((wrapper.find('input').element as HTMLInputElement).value).toBe('Greece'); - // Only after the search value is blurred, the search value can be reset + // Still not supposed to change the search value + const menu = document.body.querySelector('div[role=menu]') as HTMLDivElement; + menu.focus(); + await nextTick(); + expect((wrapper.find('input').element as HTMLInputElement).value).toBe('Greece'); + + // Only after nothing is focused anymore, the search value can be reset + menu.blur(); (wrapper.find('input').element as HTMLInputElement).blur(); await nextTick(); expect((wrapper.find('input').element as HTMLInputElement).value).toBe(''); diff --git a/src/components/forms/auto-complete/RuiAutoComplete.vue b/src/components/forms/auto-complete/RuiAutoComplete.vue index 3747d4f..979cf67 100644 --- a/src/components/forms/auto-complete/RuiAutoComplete.vue +++ b/src/components/forms/auto-complete/RuiAutoComplete.vue @@ -106,8 +106,12 @@ const { const textInput = ref(); const activator = ref(); -const noDataContainer = ref(); const menuRef = ref(); +const menuWrapperRef = ref(); + +const { focused: activatorFocusedWithin } = useFocusWithin(activator); +const { focused: menuWrapperFocusedWithin } = useFocusWithin(menuWrapperRef); +const anyFocused = logicOr(activatorFocusedWithin, menuWrapperFocusedWithin); const multiple = computed(() => Array.isArray(props.value)); @@ -186,14 +190,14 @@ const value = computed<(T extends string ? T : Record)[]>({ }); if (multipleVal || filtered.length === 0) { - if (get(shouldApplyValueAsSearch) && !get(searchInputFocused)) + if (get(shouldApplyValueAsSearch) && !get(anyFocused)) updateInternalSearch(); return filtered; } else { const val = filtered[0]; - if (get(shouldApplyValueAsSearch) && !get(searchInputFocused)) + if (get(shouldApplyValueAsSearch) && !get(anyFocused)) updateInternalSearch(getText(val)); return [val]; @@ -210,7 +214,7 @@ const value = computed<(T extends string ? T : Record)[]>({ return filtered.push(val); }); - if (get(shouldApplyValueAsSearch) && !get(searchInputFocused)) { + if (get(shouldApplyValueAsSearch) && !get(anyFocused)) { if (filtered.length > 0) updateInternalSearch(filtered[0]); else @@ -380,11 +384,6 @@ function moveSelectedValueHighlight(event: KeyboardEvent, next: boolean) { } } -const { focused: activatorFocusedWithin } = useFocusWithin(activator); -const { focused: noDataContainerFocusedWithin } = useFocusWithin(noDataContainer); -const { focused: menuFocusedWithin } = useFocusWithin(containerProps.ref); -const anyFocused = logicOr(activatorFocusedWithin, noDataContainerFocusedWithin, menuFocusedWithin); - function textValueToProperValue(val: any): T { const keyAttr = props.keyAttr; if (!keyAttr) @@ -428,7 +427,8 @@ function onInputFocused() { if (get(shouldApplyValueAsSearch)) get(textInput)?.select(); - set(justOpened, true); + if (!get(isOpen)) + set(justOpened, true); } function clear() { @@ -523,7 +523,7 @@ function arrowClicked(event: any) { const renderedOptions = ref([]); const menuMinHeight: ComputedRef = computed(() => { - const renderedOptionsData = get(renderedOptions).slice(0, 5); + const renderedOptionsData = get(renderedOptions).slice(0, Math.min(5, get(renderedData).length)); return renderedOptionsData.reduce((currentValue, item: typeof RuiButton) => currentValue + item.$el.offsetHeight, 0); }); @@ -714,72 +714,73 @@ defineExpose({