Fix typeahead search logic when repeating a letter
Fixes #35
This ports 186a4cfcef
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
40
src/lib/components/listbox/listbox.test.ts
vendored
40
src/lib/components/listbox/listbox.test.ts
vendored
@@ -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])
|
||||||
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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 = "";
|
||||||
|
|||||||
40
src/lib/components/menu/menu.test.ts
vendored
40
src/lib/components/menu/menu.test.ts
vendored
@@ -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])
|
||||||
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user