feat: filtering comboboxes (#887)

This commit is contained in:
jamesread 2026-06-19 23:21:00 +01:00
parent 43eccdaf48
commit 97105a27c5
2 changed files with 18 additions and 23 deletions

View File

@ -2,6 +2,7 @@
<div class="choice-combobox" ref="rootRef"> <div class="choice-combobox" ref="rootRef">
<input <input
ref="searchInputRef" ref="searchInputRef"
:id="id"
type="text" type="text"
class="choice-combobox-input" class="choice-combobox-input"
role="combobox" role="combobox"
@ -11,21 +12,16 @@
:aria-activedescendant="activeDescendantId" :aria-activedescendant="activeDescendantId"
:placeholder="placeholderText" :placeholder="placeholderText"
:value="query" :value="query"
:required="required"
@focus="handleFocus" @focus="handleFocus"
@input="handleSearchInput" @input="handleSearchInput"
@keydown="handleKeydown" @keydown="handleKeydown"
@blur="handleBlur" @blur="handleBlur"
/> />
<input <input
:id="id"
:name="name" :name="name"
type="text" type="hidden"
class="choice-combobox-hidden-value"
tabindex="-1"
:value="modelValue" :value="modelValue"
:required="required"
readonly
aria-hidden="true"
/> />
<ul <ul
v-if="isOpen && filteredChoices.length > 0" v-if="isOpen && filteredChoices.length > 0"
@ -38,7 +34,7 @@
:id="`${listboxId}-option-${index}`" :id="`${listboxId}-option-${index}`"
:key="choice.value" :key="choice.value"
role="option" role="option"
:aria-selected="index === highlightedIndex" :aria-selected="choice.value === modelValue"
:class="{ :class="{
highlighted: index === highlightedIndex, highlighted: index === highlightedIndex,
selected: choice.value === modelValue selected: choice.value === modelValue
@ -193,15 +189,23 @@ function moveHighlight(delta) {
function handleKeydown(event) { function handleKeydown(event) {
if (event.key === 'ArrowDown') { if (event.key === 'ArrowDown') {
event.preventDefault() event.preventDefault()
const wasOpen = isOpen.value
openList() openList()
if (wasOpen) {
moveHighlight(1) moveHighlight(1)
}
return return
} }
if (event.key === 'ArrowUp') { if (event.key === 'ArrowUp') {
event.preventDefault() event.preventDefault()
const wasOpen = isOpen.value
openList() openList()
if (wasOpen) {
moveHighlight(-1) moveHighlight(-1)
} else if (filteredChoices.value.length > 0) {
highlightedIndex.value = filteredChoices.value.length - 1
}
return return
} }
@ -273,18 +277,6 @@ onBeforeUnmount(() => {
width: 100%; width: 100%;
} }
.choice-combobox-hidden-value {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.choice-combobox-list { .choice-combobox-list {
position: absolute; position: absolute;
z-index: 10; z-index: 10;

View File

@ -58,7 +58,10 @@ describe('config: multipleDropdowns', function () {
const firstInput = await comboboxes[0].findElement(By.css('.choice-combobox-input')) const firstInput = await comboboxes[0].findElement(By.css('.choice-combobox-input'))
await firstInput.click() await firstInput.click()
expect(await comboboxes[0].findElements(By.css('.choice-combobox-list li'))).to.have.length(2) await webdriver.wait(new Condition('wait for first combobox list', async () => {
const lists = await comboboxes[0].findElements(By.css('.choice-combobox-list li'))
return lists.length === 2
}), 2000)
await firstInput.sendKeys(Key.TAB) await firstInput.sendKeys(Key.TAB)