Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

10 changes: 0 additions & 10 deletions packages/react-instantsearch-core/src/hooks/useAutocomplete.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/react-instantsearch-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { default as version } from './version';
export * from './components/AutocompleteWrapper';
export * from './components/Configure';
export * from './components/DynamicWidgets';
export * from './components/Index';
Expand Down Expand Up @@ -31,7 +30,6 @@ export * from './connectors/useStats';
export * from './connectors/useToggleRefinement';
export * from './connectors/useTrendingItems';
export * from './connectors/useLookingSimilar';
export * from './hooks/useAutocomplete';
export * from './hooks/useConnector';
export * from './hooks/useInstantSearch';
export * from './lib/wrapPromiseWithState';
Expand Down
39 changes: 25 additions & 14 deletions packages/react-instantsearch/src/components/Autocomplete.tsx
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>> = {
Copy link
Copy Markdown
Contributor

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?

Copy link
Copy Markdown
Member Author

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

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} />} />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The 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();
});
});