From 68d59c226e9fc505e3bd8292d004c9385f443b34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:42:09 +0000 Subject: [PATCH 1/3] Initial plan From 3aac9344a9fc2f2919f3acd7fbdc45ec46687899 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:47:55 +0000 Subject: [PATCH 2/3] Add Escape key handling to inline search functionality - Pressing Escape with text clears the search query - Pressing Escape with empty query closes the dropdown - Added comprehensive tests for Escape key behavior Co-authored-by: brc-dd <40380293+brc-dd@users.noreply.github.com> --- lib/components/SInputDropdown.vue | 18 +++- tests/components/SInputDropdown.spec.ts | 107 ++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/lib/components/SInputDropdown.vue b/lib/components/SInputDropdown.vue index dcaf29b2..5c7825b8 100644 --- a/lib/components/SInputDropdown.vue +++ b/lib/components/SInputDropdown.vue @@ -71,7 +71,7 @@ const inlineActiveIndex = ref(-1) const dropdownId = useId() -const { isOpen, open } = useFlyout(container) +const { isOpen, open, close } = useFlyout(container) const { inset, update: updatePosition } = useManualDropdownPosition(container, () => props.position) const isInlineSearch = computed(() => props.search === 'inline') @@ -256,6 +256,22 @@ function handleInlineKeydown(event: KeyboardEvent) { return } + if (event.key === 'Escape') { + if (inlineQuery.value) { + // Clear the search query if it exists + inlineQuery.value = '' + inlineActiveIndex.value = -1 + event.preventDefault() + event.stopPropagation() + } else { + // Close the dropdown if query is empty + close() + event.preventDefault() + event.stopPropagation() + } + return + } + if (event.key === 'ArrowDown') { event.preventDefault() event.stopPropagation() diff --git a/tests/components/SInputDropdown.spec.ts b/tests/components/SInputDropdown.spec.ts index 1cadc994..d0ef583b 100644 --- a/tests/components/SInputDropdown.spec.ts +++ b/tests/components/SInputDropdown.spec.ts @@ -128,4 +128,111 @@ describe('components/SInputDropdown', () => { expect(box.attributes('aria-activedescendant')).toBeUndefined() }) }) + + describe('Escape key handling for inline search', () => { + it('should clear search query when Escape is pressed with text', async () => { + const wrapper = mount(SInputDropdown, { + props: { + search: 'inline', + options: [ + { label: 'Option 1', value: 1 }, + { label: 'Option 2', value: 2 }, + { label: 'Option 3', value: 3 } + ], + modelValue: [] + } + }) + + // Open dropdown + await wrapper.find('.box').trigger('click') + await nextTick() + + const input = wrapper.find('.inline-input') + + // Type to create a search query + await input.setValue('Option') + await nextTick() + + // Verify query exists + expect((input.element as HTMLInputElement).value).toBe('Option') + + // Press Escape + await input.trigger('keydown', { key: 'Escape' }) + await nextTick() + + // Query should be cleared + expect((input.element as HTMLInputElement).value).toBe('') + + // Dropdown should still be open + const box = wrapper.find('.box') + expect(box.attributes('aria-expanded')).toBe('true') + }) + + it('should close dropdown when Escape is pressed with empty query', async () => { + const wrapper = mount(SInputDropdown, { + props: { + search: 'inline', + options: [ + { label: 'Option 1', value: 1 }, + { label: 'Option 2', value: 2 } + ], + modelValue: [] + } + }) + + // Open dropdown + await wrapper.find('.box').trigger('click') + await nextTick() + + const box = wrapper.find('.box') + expect(box.attributes('aria-expanded')).toBe('true') + + const input = wrapper.find('.inline-input') + + // Press Escape with empty query + await input.trigger('keydown', { key: 'Escape' }) + await nextTick() + + // Dropdown should be closed + expect(box.attributes('aria-expanded')).toBe('false') + }) + + it('should clear query then close dropdown on consecutive Escape presses', async () => { + const wrapper = mount(SInputDropdown, { + props: { + search: 'inline', + options: [ + { label: 'Option 1', value: 1 }, + { label: 'Option 2', value: 2 } + ], + modelValue: [] + } + }) + + // Open dropdown + await wrapper.find('.box').trigger('click') + await nextTick() + + const input = wrapper.find('.inline-input') + + // Type to create a search query + await input.setValue('Opt') + await nextTick() + + const box = wrapper.find('.box') + + // First Escape: clear query + await input.trigger('keydown', { key: 'Escape' }) + await nextTick() + + expect((input.element as HTMLInputElement).value).toBe('') + expect(box.attributes('aria-expanded')).toBe('true') + + // Second Escape: close dropdown + await input.trigger('keydown', { key: 'Escape' }) + await nextTick() + + expect(box.attributes('aria-expanded')).toBe('false') + }) + }) }) From 21e1967786e6c577de8b3de5cde60c53dcf008c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 02:49:33 +0000 Subject: [PATCH 3/3] Remove unnecessary comments from Escape key handler Co-authored-by: brc-dd <40380293+brc-dd@users.noreply.github.com> --- lib/components/SInputDropdown.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/components/SInputDropdown.vue b/lib/components/SInputDropdown.vue index 5c7825b8..8d69ab3b 100644 --- a/lib/components/SInputDropdown.vue +++ b/lib/components/SInputDropdown.vue @@ -258,13 +258,11 @@ function handleInlineKeydown(event: KeyboardEvent) { if (event.key === 'Escape') { if (inlineQuery.value) { - // Clear the search query if it exists inlineQuery.value = '' inlineActiveIndex.value = -1 event.preventDefault() event.stopPropagation() } else { - // Close the dropdown if query is empty close() event.preventDefault() event.stopPropagation()