-
Notifications
You must be signed in to change notification settings - Fork 550
feat(autocomplete): indices prop for React component #6703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,30 @@ | ||
| import React from 'react'; | ||
| import { | ||
| EXPERIMENTAL_AutocompleteWrapper as AutocompleteWrapper, | ||
| EXPERIMENTAL_useAutocomplete as useAutocomplete, | ||
| } from 'react-instantsearch-core'; | ||
| import { Index } from 'react-instantsearch-core'; | ||
|
|
||
| export function EXPERIMENTAL_Autocomplete() { | ||
| return ( | ||
| <AutocompleteWrapper> | ||
| <AutocompleteInner /> | ||
| </AutocompleteWrapper> | ||
| ); | ||
| } | ||
| import { Hits, SearchBox } from '../widgets'; | ||
|
|
||
| import type { BaseHit, Hit } from 'instantsearch.js'; | ||
|
|
||
| function AutocompleteInner() { | ||
| useAutocomplete(); | ||
| type IndexConfig<TItem extends Hit<BaseHit> = Hit<BaseHit>> = { | ||
| indexName: string; | ||
| getQuery?: (item: TItem) => string; | ||
| getURL?: (item: TItem) => string; | ||
| itemComponent: React.ComponentType<TItem> | React.ComponentType<any>; | ||
| }; | ||
|
|
||
| return null; | ||
| export type AutocompleteProps = { | ||
| indices: IndexConfig[]; | ||
| }; | ||
|
|
||
| export function EXPERIMENTAL_Autocomplete({ indices }: AutocompleteProps) { | ||
| return ( | ||
| <Index EXPERIMENTAL_isolated> | ||
| <SearchBox /> | ||
| {indices.map((index) => ( | ||
| <Index key={index.indexName} indexName={index.indexName}> | ||
| <Hits hitComponent={({ hit }) => <index.itemComponent {...hit} />} /> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't consider using hit instead of connectautocomplete. I guess pros are: no need to have a separate connector for showing the hits, cons would be counting the items and making sure they're in a single wrapper div may be a little more work (as we'd need something else than Hits for that. For this PR this works indeed.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just a placeholder for now, we'll probably just use hooks directly |
||
| </Index> | ||
| ))} | ||
| </Index> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /** | ||
| * @jest-environment jsdom | ||
| */ | ||
|
|
||
| import { | ||
| createMultiSearchResponse, | ||
| createSearchClient, | ||
| createSingleSearchResponse, | ||
| } from '@instantsearch/mocks'; | ||
| import { InstantSearchTestWrapper } from '@instantsearch/testutils'; | ||
| import { render, screen } from '@testing-library/react'; | ||
| import React from 'react'; | ||
|
|
||
| import { EXPERIMENTAL_Autocomplete } from '../Autocomplete'; | ||
|
|
||
| describe('Autocomplete', () => { | ||
| function createMockedSearchClient() { | ||
| return createSearchClient({ | ||
| // @ts-expect-error - doesn't properly handle multi index, expects all responses to be of the same type | ||
| search: jest.fn(() => | ||
| Promise.resolve( | ||
| createMultiSearchResponse( | ||
| createSingleSearchResponse({ | ||
| hits: [{ objectID: '1', name: 'Item 1' }], | ||
| }), | ||
| // @ts-expect-error - ignore second response type | ||
| createSingleSearchResponse({ | ||
| hits: [{ objectID: '2', query: 'hello' }], | ||
| }) | ||
| ) | ||
| ) | ||
| ), | ||
| }); | ||
| } | ||
|
|
||
| test('should render a searchbox and indices with hits', async () => { | ||
| const searchClient = createMockedSearchClient(); | ||
| render( | ||
| <InstantSearchTestWrapper searchClient={searchClient}> | ||
| <EXPERIMENTAL_Autocomplete | ||
| indices={[ | ||
| { | ||
| indexName: 'indexName', | ||
| itemComponent: (props: { name: string }) => props.name, | ||
| }, | ||
| { | ||
| indexName: 'indexName2', | ||
| itemComponent: (props: { query: string }) => props.query, | ||
| }, | ||
| ]} | ||
| /> | ||
| </InstantSearchTestWrapper> | ||
| ); | ||
|
|
||
| expect(await screen.findByText('Item 1')).toBeInTheDocument(); | ||
| expect(await screen.findByText('hello')).toBeInTheDocument(); | ||
| expect(screen.getByRole('searchbox')).toBeInTheDocument(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so if you'd have multiple different types of hits, this would be a union and you assert within the template?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be possible but they would have to declare indices somewhere else than inline, I don't think anyone would really care tbh, and we'd probably need some helper functions