Fix typeahead search logic when repeating a letter

Fixes #35

This ports 186a4cfcef
This commit is contained in:
Ryan Gossiaux
2022-01-21 17:06:51 -08:00
parent bc809ef590
commit 5e795d2d4f
4 changed files with 102 additions and 6 deletions

View File

@@ -139,14 +139,22 @@
searchQuery += value.toLowerCase(); searchQuery += value.toLowerCase();
let match = options.findIndex( let reorderedOptions =
activeOptionIndex !== null
? options
.slice(activeOptionIndex + 1)
.concat(options.slice(0, activeOptionIndex + 1))
: options;
let matchingOption = reorderedOptions.find(
(option) => (option) =>
!option.dataRef.disabled && !option.dataRef.disabled &&
option.dataRef.textValue.startsWith(searchQuery) option.dataRef.textValue.startsWith(searchQuery)
); );
if (match === -1 || match === activeOptionIndex) return; let matchIdx = matchingOption ? options.indexOf(matchingOption) : -1;
activeOptionIndex = match; if (matchIdx === -1 || matchIdx === activeOptionIndex) return;
activeOptionIndex = matchIdx;
}, },
clearSearch() { clearSearch() {
if (disabled) return; if (disabled) return;

View File

@@ -3125,6 +3125,46 @@ describe('Keyboard interactions', () => {
assertActiveListboxOption(options[1]) assertActiveListboxOption(options[1])
}) })
) )
it(
'should be possible to search for the next occurence',
suppressConsoleLogs(async () => {
render(svelte`
<Listbox value={undefined} onChange={console.log}>
<ListboxButton>Trigger</ListboxButton>
<ListboxOptions>
<ListboxOption value="a">alice</ListboxOption>
<ListboxOption value="b">bob</ListboxOption>
<ListboxOption value="c">charlie</ListboxOption>
<ListboxOption value="d">bob</ListboxOption>
</ListboxOptions>
</Listbox>
`)
// Open listbox
await click(getListboxButton())
let options = getListboxOptions()
// Search for bob
await type(word('b'))
// We should be on the first `bob`
assertActiveListboxOption(options[1])
// Search for bob again
await type(word('b'))
// We should be on the second `bob`
assertActiveListboxOption(options[3])
// Search for bob once again
await type(word('b'))
// We should be back on the first `bob`
assertActiveListboxOption(options[1])
})
)
}) })
}) })

View File

@@ -99,14 +99,22 @@
search(value: string) { search(value: string) {
searchQuery += value.toLowerCase(); searchQuery += value.toLowerCase();
let match = items.findIndex( let reorderedItems =
activeItemIndex !== null
? items
.slice(activeItemIndex + 1)
.concat(items.slice(0, activeItemIndex + 1))
: items;
let matchingItem = reorderedItems.find(
(item) => (item) =>
item.data.textValue.startsWith(searchQuery) && !item.data.disabled item.data.textValue.startsWith(searchQuery) && !item.data.disabled
); );
if (match === -1 || match === activeItemIndex) return; let matchIdx = matchingItem ? items.indexOf(matchingItem) : -1;
if (matchIdx === -1 || matchIdx === activeItemIndex) return;
activeItemIndex = match; activeItemIndex = matchIdx;
}, },
clearSearch() { clearSearch() {
searchQuery = ""; searchQuery = "";

View File

@@ -2682,6 +2682,46 @@ describe('Keyboard interactions', () => {
assertMenuLinkedWithMenuItem(items[1]) assertMenuLinkedWithMenuItem(items[1])
}) })
) )
it(
'should be possible to search for the next occurence',
suppressConsoleLogs(async () => {
render(svelte`
<Menu>
<MenuButton>Trigger</MenuButton>
<MenuItems>
<MenuItem as="a">alice</MenuItem>
<MenuItem as="a">bob</MenuItem>
<MenuItem as="a">charlie</MenuItem>
<MenuItem as="a">bob</MenuItem>
</MenuItems>
</Menu>
`)
// Open menu
await click(getMenuButton())
let items = getMenuItems()
// Search for bob
await type(word('b'))
// We should be on the first `bob`
assertMenuLinkedWithMenuItem(items[1])
// Search for bob again
await type(word('b'))
// We should be on the second `bob`
assertMenuLinkedWithMenuItem(items[3])
// Search for bob once again
await type(word('b'))
// We should be back on the first `bob`
assertMenuLinkedWithMenuItem(items[1])
})
)
}) })
}) })