From acd8700d8e9cb3104306755644442bb4f36ab148 Mon Sep 17 00:00:00 2001 From: Bogdan Dolin Date: Tue, 30 Apr 2024 21:56:47 +0700 Subject: [PATCH 1/2] feat(autocomplete): hideOnOptionSelect --- api-generator/components/autocomplete.js | 6 +++ components/lib/autocomplete/AutoComplete.d.ts | 5 ++ .../lib/autocomplete/AutoComplete.spec.js | 49 ++++++++++++++++++- components/lib/autocomplete/AutoComplete.vue | 8 ++- .../lib/autocomplete/BaseAutoComplete.vue | 4 ++ doc/common/apidoc/index.json | 8 +++ 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/api-generator/components/autocomplete.js b/api-generator/components/autocomplete.js index 1e1720043a..73498e2798 100644 --- a/api-generator/components/autocomplete.js +++ b/api-generator/components/autocomplete.js @@ -221,6 +221,12 @@ const AutoCompleteProps = [ default: 'false', description: 'When enabled, the focused option is selected.' }, + { + name: 'hideOnOptionSelect', + type: 'boolean', + default: 'true', + description: 'Whether to hide the overlay when an option is selected.' + }, { name: 'searchLocale', type: 'string', diff --git a/components/lib/autocomplete/AutoComplete.d.ts b/components/lib/autocomplete/AutoComplete.d.ts index 9db080eaa3..945cee187a 100755 --- a/components/lib/autocomplete/AutoComplete.d.ts +++ b/components/lib/autocomplete/AutoComplete.d.ts @@ -457,6 +457,11 @@ export interface AutoCompleteProps { * @defaultValue false */ selectOnFocus?: boolean | undefined; + /** + * Whether to hide the overlay when an option is selected. + * @defaultValue true + */ + hideOnOptionSelect?: boolean | undefined; /** * When enabled, the focus is placed on the hovered option. * @defaultValue true diff --git a/components/lib/autocomplete/AutoComplete.spec.js b/components/lib/autocomplete/AutoComplete.spec.js index ab8e2e1c7c..1eade05832 100644 --- a/components/lib/autocomplete/AutoComplete.spec.js +++ b/components/lib/autocomplete/AutoComplete.spec.js @@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'; import PrimeVue from 'primevue/config'; import { nextTick } from 'vue'; import AutoComplete from './AutoComplete.vue'; +import { describe } from 'vitest'; describe('AutoComplete.vue', () => { let wrapper; @@ -85,7 +86,7 @@ describe('AutoComplete.vue', () => { }); }); - it('multiple', () => { + describe('multiple', () => { it('should have correct custom icon', async () => { wrapper.setProps({ multiple: true, @@ -99,5 +100,51 @@ describe('AutoComplete.vue', () => { expect(tokenIcon.classes()).toContain('pi-discord'); }); }); + + it('should hide overlay when hideOnOptionSelect is true', async () => { + await wrapper.setProps({ + hideOnOptionSelect: true, + }); + + const input = await wrapper.find('input'); + + await input.setValue('b'); + + // @NOTE: Without this delay, the test fails. vm.$nextTick() doesn't help. + await new Promise((resolve) => setTimeout(resolve, 300)); + + await wrapper.setProps({ + suggestions: [{ name: 'Bahrain', code: 'BH' }] + }); + + await wrapper.find('.p-autocomplete-item').trigger('click'); + + await new Promise((resolve) => setTimeout(resolve, 5)); + + expect(wrapper.find('.p-autocomplete-panel').exists()).toBe(false); + }); + + it('should keep overlay open when hideOnOptionSelect is false', async () => { + await wrapper.setProps({ + hideOnOptionSelect: false, + }); + + const input = await wrapper.find('input'); + + await input.setValue('b'); + + // @NOTE: Without this delay, the test fails. vm.$nextTick() doesn't help. + await new Promise((resolve) => setTimeout(resolve, 300)); + + await wrapper.setProps({ + suggestions: [{ name: 'Bahrain', code: 'BH' }] + }); + + await wrapper.find('.p-autocomplete-item').trigger('click'); + + await new Promise((resolve) => setTimeout(resolve, 5)); + + expect(wrapper.find('.p-autocomplete-panel').exists()).toBe(true); + }); }); }); diff --git a/components/lib/autocomplete/AutoComplete.vue b/components/lib/autocomplete/AutoComplete.vue index 680b4ad19a..814badee1b 100755 --- a/components/lib/autocomplete/AutoComplete.vue +++ b/components/lib/autocomplete/AutoComplete.vue @@ -515,7 +515,9 @@ export default { this.$emit('item-select', { originalEvent: event, value: option }); - isHide && this.hide(true); + if (this.hideOnOptionSelect) { + isHide && this.hide(true); + } }, onOptionMouseMove(event, index) { if (this.focusOnHover) { @@ -623,7 +625,9 @@ export default { this.onOptionSelect(event, this.visibleOptions[this.focusedOptionIndex]); } - this.hide(); + if (this.hideOnOptionSelect) { + this.hide(); + } } }, onEscapeKey(event) { diff --git a/components/lib/autocomplete/BaseAutoComplete.vue b/components/lib/autocomplete/BaseAutoComplete.vue index 1a36decb25..9a8890ec98 100644 --- a/components/lib/autocomplete/BaseAutoComplete.vue +++ b/components/lib/autocomplete/BaseAutoComplete.vue @@ -141,6 +141,10 @@ export default { type: Boolean, default: false }, + hideOnOptionSelect: { + type: Boolean, + default: true + }, focusOnHover: { type: Boolean, default: true diff --git a/doc/common/apidoc/index.json b/doc/common/apidoc/index.json index 8d735733dc..732326b942 100644 --- a/doc/common/apidoc/index.json +++ b/doc/common/apidoc/index.json @@ -3820,6 +3820,14 @@ "default": "false", "description": "When enabled, the focused option is selected." }, + { + "name": "hideOnOptionSelect", + "optional": true, + "readonly": false, + "type": "boolean", + "default": "true", + "description": "Whether to hide the overlay when an option is selected." + }, { "name": "focusOnHover", "optional": true, From 260577582c01efadd9b96c6ebb283fd647ac3f14 Mon Sep 17 00:00:00 2001 From: Bogdan Dolin Date: Tue, 30 Apr 2024 22:02:54 +0700 Subject: [PATCH 2/2] extract hideOnOptionSelect into a separate describe --- components/lib/autocomplete/AutoComplete.spec.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/lib/autocomplete/AutoComplete.spec.js b/components/lib/autocomplete/AutoComplete.spec.js index 1eade05832..c1259ab167 100644 --- a/components/lib/autocomplete/AutoComplete.spec.js +++ b/components/lib/autocomplete/AutoComplete.spec.js @@ -86,7 +86,7 @@ describe('AutoComplete.vue', () => { }); }); - describe('multiple', () => { + it('multiple', () => { it('should have correct custom icon', async () => { wrapper.setProps({ multiple: true, @@ -100,10 +100,12 @@ describe('AutoComplete.vue', () => { expect(tokenIcon.classes()).toContain('pi-discord'); }); }); + }); + describe('hideOnOptionSelect', () => { it('should hide overlay when hideOnOptionSelect is true', async () => { await wrapper.setProps({ - hideOnOptionSelect: true, + hideOnOptionSelect: true }); const input = await wrapper.find('input'); @@ -126,7 +128,7 @@ describe('AutoComplete.vue', () => { it('should keep overlay open when hideOnOptionSelect is false', async () => { await wrapper.setProps({ - hideOnOptionSelect: false, + hideOnOptionSelect: false }); const input = await wrapper.find('input');