Skip to content

Commit

Permalink
feat(Assistant): Add possiblity to navigate with arrow keys in Search…
Browse files Browse the repository at this point in the history
…Result
  • Loading branch information
JF-Cozy committed Nov 4, 2024
1 parent 3465e7f commit 4de3268
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/assistant/ResultMenu/ResultMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ResultMenuContent from './ResultMenuContent'

import styles from './styles.styl'

const ResultMenu = ({ anchorRef, onClick }) => {
const ResultMenu = ({ anchorRef, listRef, onClick }) => {
return (
<Popper
style={{
Expand All @@ -20,7 +20,7 @@ const ResultMenu = ({ anchorRef, onClick }) => {
>
<Paper className={styles['resultMenu']} square>
<div className={styles['resultMenu-inner']}>
<ResultMenuContent onClick={onClick} />
<ResultMenuContent ref={listRef} onClick={onClick} />
</div>
</Paper>
</Popper>
Expand Down
20 changes: 14 additions & 6 deletions src/assistant/ResultMenu/ResultMenuContent.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { forwardRef } from 'react'

import flag from 'cozy-flags'
import List from 'cozy-ui/transpiled/react/List'
Expand All @@ -15,7 +15,7 @@ import { useSearch } from '../Search/SearchProvider'
import ResultMenuItem from './ResultMenuItem'

const SearchResult = () => {
const { isLoading, results, searchValue } = useSearch()
const { isLoading, results, selectedIndex, searchValue } = useSearch()

if (isLoading && !results?.length)
return (
Expand All @@ -34,19 +34,24 @@ const SearchResult = () => {
secondaryText={result.secondary}
query={searchValue}
highlightQuery="true"
selected={
flag('cozy.assistant.enabled')
? selectedIndex === idx + 1
: selectedIndex === idx
}
onClick={result.onClick}
/>
))
}

const ResultMenuContent = ({ onClick }) => {
const ResultMenuContent = forwardRef(({ onClick }, ref) => {
const { t } = useI18n()
const { isMobile } = useBreakpoints()
const { searchValue } = useSearch()
const { searchValue, selectedIndex } = useSearch()
const { dataProxyServicesAvailable } = useDataProxy()

return (
<List>
<List ref={ref}>
{flag('cozy.assistant.enabled') && (
<ResultMenuItem
icon={
Expand All @@ -57,12 +62,15 @@ const ResultMenuContent = ({ onClick }) => {
primaryText={searchValue}
query={searchValue}
secondaryText={t('assistant.search.result')}
selected={selectedIndex === 0}
onClick={onClick}
/>
)}
{dataProxyServicesAvailable && <SearchResult />}
</List>
)
}
})

ResultMenuContent.displayName = 'ResultMenuContent'

export default ResultMenuContent
3 changes: 2 additions & 1 deletion src/assistant/ResultMenu/ResultMenuItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const ResultMenuItem = ({
icon,
primaryText,
secondaryText,
selected,
onClick,
query,
highlightQuery = false
Expand All @@ -37,7 +38,7 @@ const ResultMenuItem = ({
)

return (
<ListItem button size="small" onClick={onClick}>
<ListItem button size="small" selected={selected} onClick={onClick}>
<ListItemIcon>{iconComponent}</ListItemIcon>
<ListItemText primary={primary} secondary={secondary} />
</ListItem>
Expand Down
3 changes: 2 additions & 1 deletion src/assistant/Search/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import SearchBarDesktop from './SearchBarDesktop'
const SearchBar = () => {
const { isMobile } = useBreakpoints()
const [inputValue, setInputValue] = useState('')
const { clearSearch, delayedSetSearchValue } = useSearch()
const { clearSearch, setSelectedIndex, delayedSetSearchValue } = useSearch()

const handleClear = () => {
setInputValue('')
clearSearch()
}

const handleChange = ev => {
setSelectedIndex(0)
delayedSetSearchValue(ev.target.value)
setInputValue(ev.target.value)
}
Expand Down
45 changes: 41 additions & 4 deletions src/assistant/Search/SearchBarDesktop.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import styles from './styles.styl'

const SearchBarDesktop = ({ value, onClear, onChange }) => {
const { t } = useI18n()
const { searchValue } = useSearch()
const { searchValue, results, selectedIndex, setSelectedIndex } = useSearch()
const { onAssistantExecute } = useAssistant()
const navigate = useNavigate()
const searchRef = useRef()
const listRef = useRef()

const handleClick = () => {
if (!flag('cozy.assistant.enabled')) return
Expand All @@ -37,9 +38,41 @@ const SearchBarDesktop = ({ value, onClear, onChange }) => {
}

const handleKeyDown = ev => {
const listElementCount = listRef.current?.childElementCount

if (ev.key === 'ArrowDown') {
ev.preventDefault()

if (selectedIndex === listElementCount - 1) {
setSelectedIndex(0)
} else {
setSelectedIndex(v => v + 1)
}
}

if (ev.key === 'ArrowUp') {
ev.preventDefault()

if (selectedIndex === 0) {
setSelectedIndex(listElementCount - 1)
} else {
setSelectedIndex(v => v - 1)
}
}

if (ev.key === 'Escape') {
ev.preventDefault()
onClear()
}

if (ev.key === 'Enter') {
ev.preventDefault() // prevent form submit
if (value !== '') handleClick()
ev.preventDefault()
if (selectedIndex) {
const onClickFn = results?.[selectedIndex - 1]?.onClick || handleClick
onClickFn()
} else if (value !== '') {
handleClick()
}
}
}

Expand All @@ -61,7 +94,11 @@ const SearchBarDesktop = ({ value, onClear, onChange }) => {
onChange={onChange}
/>
{searchValue && (
<ResultMenu anchorRef={searchRef} onClick={handleClick} />
<ResultMenu
listRef={listRef}
anchorRef={searchRef}
onClick={handleClick}
/>
)}
</span>
</ClickAwayListener>
Expand Down
17 changes: 15 additions & 2 deletions src/assistant/Search/SearchProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ export const useSearch = () => {

const SearchProvider = ({ children }) => {
const [searchValue, setSearchValue] = useState('')
const [selectedIndex, setSelectedIndex] = useState()
const { isLoading, results } = useFetchResult(searchValue)

const delayedSetSearchValue = useMemo(
() => debounce(setSearchValue, 250),
[setSearchValue]
)

const clearSearch = useCallback(() => setSearchValue(''), [])
const clearSearch = useCallback(() => {
setSearchValue('')
setSelectedIndex()
}, [])

const value = useMemo(
() => ({
Expand All @@ -32,9 +36,18 @@ const SearchProvider = ({ children }) => {
delayedSetSearchValue,
isLoading,
clearSearch,
selectedIndex,
setSelectedIndex,
results
}),
[searchValue, delayedSetSearchValue, isLoading, clearSearch, results]
[
searchValue,
delayedSetSearchValue,
isLoading,
clearSearch,
selectedIndex,
results
]
)

return (
Expand Down

0 comments on commit 4de3268

Please sign in to comment.