Skip to content

Commit

Permalink
Fix unfocus issue.
Browse files Browse the repository at this point in the history
  • Loading branch information
robinjhuang committed Sep 5, 2024
1 parent 44bafe2 commit 35896c1
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 95 deletions.
122 changes: 38 additions & 84 deletions components/Search/Autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import '@algolia/autocomplete-theme-classic'
import type { SearchClient } from 'algoliasearch/lite'
import type { BaseItem } from '@algolia/autocomplete-core'
import type { AutocompleteOptions } from '@algolia/autocomplete-js'
Expand All @@ -13,7 +12,7 @@ import {
} from 'react'
import { createRoot, Root } from 'react-dom/client'

import { useSearchBox } from 'react-instantsearch'
import { usePagination, useSearchBox } from 'react-instantsearch'
import { autocomplete } from '@algolia/autocomplete-js'
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches'
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions'
Expand All @@ -24,6 +23,8 @@ import {
INSTANT_SEARCH_QUERY_SUGGESTIONS,
} from 'src/constants'

import '@algolia/autocomplete-theme-classic'

type AutocompleteProps = Partial<AutocompleteOptions<BaseItem>> & {
searchClient: SearchClient
className?: string
Expand All @@ -33,18 +34,19 @@ type SetInstantSearchUiStateOptions = {
query: string
}

export function Autocomplete({
export default function Autocomplete({
searchClient,
className,
...autocompleteProps
}: AutocompleteProps) {
const autocompleteContainer = useRef<HTMLDivElement>(null)
const panelRootRef = useRef<Root | null>(null)
const rootRef = useRef<HTMLElement | null>(null)
const inputRef = useRef<HTMLInputElement | null>(null)

const { query, refine: setQuery } = useSearchBox()

const { refine: setPage } = usePagination()

const [instantSearchUiState, setInstantSearchUiState] =
useState<SetInstantSearchUiStateOptions>({ query })
const debouncedSetInstantSearchUiState = debounce(
Expand All @@ -54,14 +56,9 @@ export function Autocomplete({

useEffect(() => {
setQuery(instantSearchUiState.query)
setPage(0)
}, [instantSearchUiState, setQuery])

const focusInput = () => {
if (inputRef.current) {
inputRef.current.focus()
}
}

const plugins = useMemo(() => {
const recentSearches = createLocalStorageRecentSearchesPlugin({
key: 'instantsearch',
Expand All @@ -71,7 +68,6 @@ export function Autocomplete({
...source,
onSelect({ item }) {
setInstantSearchUiState({ query: item.label })
focusInput()
},
}
},
Expand All @@ -90,43 +86,31 @@ export function Autocomplete({
...source,
sourceId: 'querySuggestionsPlugin',
onSelect({ item }) {
setInstantSearchUiState({ query: item.name })

if (inputRef.current) {
inputRef.current.value = item.name
setInstantSearchUiState({
query: item.query,
})
},
getItems(params) {
if (!params.state.query) {
return []
}

searchClient
.search([
{
indexName: INSTANT_SEARCH_INDEX_NAME,
query: item.name,
params: { hitsPerPage: 10 },
},
])
.then(() => {
recentSearches.data!.addItem({
id: item.name,
label: item.name,
})
focusInput()
})
.catch((err) => {
console.error('Search failed:', err)
})

debouncedSetInstantSearchUiState({ query: item.name })
return source.getItems(params)
},
templates: {
item({ item }) {
...source.templates,
header({ items }) {
if (items.length === 0) {
return <Fragment />
}

return (
<div className="aa-ItemWrapper">
<div className="aa-ItemContent">
<div className="aa-ItemTitle">
{item.name}
</div>
</div>
</div>
<Fragment>
<span className="aa-SourceHeaderTitle">
In other categories
</span>
<span className="aa-SourceHeaderLine" />
</Fragment>
)
},
},
Expand All @@ -135,47 +119,33 @@ export function Autocomplete({
})

return [recentSearches, querySuggestions]
}, [searchClient, debouncedSetInstantSearchUiState])
}, [])

useEffect(() => {
if (!autocompleteContainer.current) {
return
}

const autocompleteInstance = autocomplete({
...autocompleteProps,
container: autocompleteContainer.current,
initialState: { query },
insights: true,
plugins,
onReset() {
setInstantSearchUiState({
query: '',
})
},
onSubmit({ state }) {
setInstantSearchUiState({ query: state.query })
console.log('On Submit')
searchClient
.search([
{
indexName: INSTANT_SEARCH_INDEX_NAME,
query: state.query,
params: { hitsPerPage: 10 },
},
])
.then(() => {
focusInput()
})
.catch((err) => {
console.error('Search failed:', err)
})
},
onStateChange({ prevState, state }) {
if (prevState.query !== state.query) {
console.log('State changed')
debouncedSetInstantSearchUiState({ query: state.query })
}
},
renderer: {
createElement,
Fragment,
render: () => {},
},
renderer: { createElement, Fragment, render: () => {} },
render({ children }, root) {
if (!panelRootRef.current || rootRef.current !== root) {
rootRef.current = root
Expand All @@ -187,24 +157,8 @@ export function Autocomplete({
},
})

// Store a reference to the input element
inputRef.current =
autocompleteContainer.current.querySelector('.aa-Input')

return () => autocompleteInstance.destroy()
}, [
plugins,
searchClient,
autocompleteProps,
query,
debouncedSetInstantSearchUiState,
])

return (
<div className={className}>
<div ref={autocompleteContainer} />
</div>
)
}
}, [plugins])

export default Autocomplete
return <div className={className} ref={autocompleteContainer} />
}
3 changes: 0 additions & 3 deletions components/registry/Registry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@ type RegistryProps = {
const Registry: React.FC<RegistryProps> = ({}) => {
return (
<div className="relative mt-8 bg-gray-900 lg:mt-20">
{/* Header section */}
<GenericHeader
title="Welcome to the Registry"
subTitle="View nodes or sign in to create and publish your own"
buttonText="Get Started"
buttonLink="/nodes"
/>

{/* InstantSearch component for Algolia search */}
<div className="md:w-full w-full mt-5">
<InstantSearch
searchClient={searchClient}
Expand All @@ -47,7 +45,6 @@ const Registry: React.FC<RegistryProps> = ({}) => {
preserveSharedStateOnUnmount: true,
}}
>
{/* Autocomplete search bar */}
<header className="header">
<div className="header-wrapper wrapper">
<Autocomplete
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@
"build-storybook": "build-storybook"
},
"dependencies": {
"@algolia/autocomplete-core": "^1.17.2",
"@algolia/autocomplete-js": "^1.17.2",
"@algolia/autocomplete-plugin-query-suggestions": "^1.17.2",
"@algolia/autocomplete-core": "^1.17.4",
"@algolia/autocomplete-js": "^1.17.4",
"@algolia/autocomplete-plugin-query-suggestions": "1.17.4",
"@algolia/autocomplete-plugin-recent-searches": "^1.17.4",
"@algolia/autocomplete-theme-classic": "^1.17.2",
"@algolia/autocomplete-theme-classic": "1.17.4",
"@mdx-js/loader": "^3.0.1",
"@next/mdx": "12.3.1",
"@tanstack/react-query": "^5.17.19",
"@types/react-instantsearch": "^6.10.4",
"algoliasearch": "^4.24.0",
"autocomplete-shared": "link:@types/@algolia/autocomplete-shared",
"axios": "^1.6.5",
"downloadjs": "^1.4.7",
"firebase": "^10.11.1",
Expand Down
11 changes: 7 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 35896c1

Please sign in to comment.