Skip to content

Commit

Permalink
Improve search (#385)
Browse files Browse the repository at this point in the history
* make search case insensitive for the listbox

* make search case insensitive for the menu
  • Loading branch information
RobinMalfait committed Apr 20, 2021
1 parent fad851c commit 79a136f
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 4 deletions.
33 changes: 33 additions & 0 deletions packages/@headlessui-react/src/components/listbox/listbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,39 @@ describe('Keyboard interactions', () => {
assertActiveListboxOption(options[2])
})
)

it(
'should be possible to search for a word (case insensitive)',
suppressConsoleLogs(async () => {
render(
<Listbox value={undefined} onChange={console.log}>
<Listbox.Button>Trigger</Listbox.Button>
<Listbox.Options>
<Listbox.Option value="alice">alice</Listbox.Option>
<Listbox.Option value="bob">bob</Listbox.Option>
<Listbox.Option value="charlie">charlie</Listbox.Option>
</Listbox.Options>
</Listbox>
)

// Focus the button
getListboxButton()?.focus()

// Open listbox
await press(Keys.ArrowUp)

let options = getListboxOptions()

// We should be on the last option
assertActiveListboxOption(options[2])

// Search for bob in a different casing
await type(word('BO'))

// We should be on `bob`
assertActiveListboxOption(options[1])
})
)
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ let reducers: {
if (state.disabled) return state
if (state.listboxState === ListboxStates.Closed) return state

let searchQuery = state.searchQuery + action.value
let searchQuery = state.searchQuery + action.value.toLowerCase()
let match = state.options.findIndex(
option =>
!option.dataRef.current.disabled &&
Expand Down
32 changes: 32 additions & 0 deletions packages/@headlessui-react/src/components/menu/menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2408,6 +2408,38 @@ describe('Keyboard interactions', () => {
assertMenuLinkedWithMenuItem(items[2])
})
)
it(
'should be possible to search for a word (case insensitive)',
suppressConsoleLogs(async () => {
render(
<Menu>
<Menu.Button>Trigger</Menu.Button>
<Menu.Items>
<Menu.Item as="a">alice</Menu.Item>
<Menu.Item as="a">bob</Menu.Item>
<Menu.Item as="a">charlie</Menu.Item>
</Menu.Items>
</Menu>
)

// Focus the button
getMenuButton()?.focus()

// Open menu
await press(Keys.ArrowUp)

let items = getMenuItems()

// We should be on the last item
assertMenuLinkedWithMenuItem(items[2])

// Search for bob in a different casing
await type(word('BO'))

// We should be on `bob`
assertMenuLinkedWithMenuItem(items[1])
})
)
})
})

Expand Down
2 changes: 1 addition & 1 deletion packages/@headlessui-react/src/components/menu/menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ let reducers: {
return { ...state, searchQuery: '', activeItemIndex }
},
[ActionTypes.Search]: (state, action) => {
let searchQuery = state.searchQuery + action.value
let searchQuery = state.searchQuery + action.value.toLowerCase()
let match = state.items.findIndex(
item =>
item.dataRef.current.textValue?.startsWith(searchQuery) && !item.dataRef.current.disabled
Expand Down
36 changes: 36 additions & 0 deletions packages/@headlessui-vue/src/components/listbox/listbox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2965,6 +2965,42 @@ describe('Keyboard interactions', () => {
assertActiveListboxOption(options[2])
})
)

it(
'should be possible to search for a word (case insensitive)',
suppressConsoleLogs(async () => {
renderTemplate({
template: html`
<Listbox v-model="value">
<ListboxButton>Trigger</ListboxButton>
<ListboxOptions>
<ListboxOption value="alice">alice</ListboxOption>
<ListboxOption value="bob">bob</ListboxOption>
<ListboxOption value="charlie">charlie</ListboxOption>
</ListboxOptions>
</Listbox>
`,
setup: () => ({ value: ref(null) }),
})

// Focus the button
getListboxButton()?.focus()

// Open listbox
await press(Keys.ArrowUp)

let options = getListboxOptions()

// We should be on the last option
assertActiveListboxOption(options[2])

// Search for bob in a different casing
await type(word('BO'))

// We should be on `bob`
assertActiveListboxOption(options[1])
})
)
})
})

Expand Down
2 changes: 1 addition & 1 deletion packages/@headlessui-vue/src/components/listbox/listbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export let Listbox = defineComponent({
if (disabled) return
if (listboxState.value === ListboxStates.Closed) return

searchQuery.value += value
searchQuery.value += value.toLowerCase()

let match = options.value.findIndex(
option =>
Expand Down
30 changes: 30 additions & 0 deletions packages/@headlessui-vue/src/components/menu/menu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2454,6 +2454,36 @@ describe('Keyboard interactions', () => {
// We should still be on the last item
assertMenuLinkedWithMenuItem(items[2])
})

it('should be possible to search for a word (case insensitive)', async () => {
renderTemplate(jsx`
<Menu>
<MenuButton>Trigger</MenuButton>
<MenuItems>
<MenuItem as="a">alice</MenuItem>
<MenuItem as="a">bob</MenuItem>
<MenuItem as="a">charlie</MenuItem>
</MenuItems>
</Menu>
`)

// Focus the button
getMenuButton()?.focus()

// Open menu
await press(Keys.ArrowUp)

let items = getMenuItems()

// We should be on the last item
assertMenuLinkedWithMenuItem(items[2])

// Search for bob in a different casing
await type(word('BO'))

// We should be on `bob`
assertMenuLinkedWithMenuItem(items[1])
})
})
})

Expand Down
2 changes: 1 addition & 1 deletion packages/@headlessui-vue/src/components/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export let Menu = defineComponent({
activeItemIndex.value = nextActiveItemIndex
},
search(value: string) {
searchQuery.value += value
searchQuery.value += value.toLowerCase()

let match = items.value.findIndex(
item => item.dataRef.textValue.startsWith(searchQuery.value) && !item.dataRef.disabled
Expand Down

0 comments on commit 79a136f

Please sign in to comment.