feat(docsearch): add hitComponent and transformItems options
This commit is contained in:
parent
a86a36805d
commit
6ad18485fd
3 changed files with 43 additions and 22 deletions
|
|
@ -14,20 +14,23 @@ import {
|
|||
} from './types';
|
||||
import { createSearchClient, groupBy, noop } from './utils';
|
||||
import { createStoredSearches } from './stored-searches';
|
||||
import { Hit } from './Hit';
|
||||
import { SearchBox } from './SearchBox';
|
||||
import { ScreenState } from './ScreenState';
|
||||
import { Footer } from './Footer';
|
||||
|
||||
interface DocSearchProps
|
||||
extends Omit<
|
||||
PublicAutocompleteOptions<InternalDocSearchHit>,
|
||||
'onStateChange' | 'getSources'
|
||||
> {
|
||||
extends Pick<PublicAutocompleteOptions<InternalDocSearchHit>, 'navigator'> {
|
||||
appId?: string;
|
||||
apiKey: string;
|
||||
indexName: string;
|
||||
searchParameters: any;
|
||||
onClose(): void;
|
||||
searchParameters?: any;
|
||||
onClose?(): void;
|
||||
transformItems?(items: DocSearchHit[]): DocSearchHit[];
|
||||
hitComponent?(props: {
|
||||
hit: DocSearchHit;
|
||||
children: React.ReactNode;
|
||||
}): JSX.Element;
|
||||
}
|
||||
|
||||
export function DocSearch({
|
||||
|
|
@ -36,7 +39,9 @@ export function DocSearch({
|
|||
indexName,
|
||||
searchParameters,
|
||||
onClose = noop,
|
||||
...autocompleteProps
|
||||
transformItems = x => x,
|
||||
hitComponent = Hit,
|
||||
navigator,
|
||||
}: DocSearchProps) {
|
||||
const [state, setState] = React.useState<
|
||||
AutocompleteState<InternalDocSearchHit>
|
||||
|
|
@ -107,7 +112,7 @@ export function DocSearch({
|
|||
initialState: {
|
||||
query: initialQuery,
|
||||
},
|
||||
...autocompleteProps,
|
||||
navigator,
|
||||
onStateChange({ state }) {
|
||||
setState(state as any);
|
||||
},
|
||||
|
|
@ -191,17 +196,7 @@ export function DocSearch({
|
|||
throw error;
|
||||
})
|
||||
.then((hits: DocSearchHit[]) => {
|
||||
const formattedHits = hits.map(hit => {
|
||||
const url = new URL(hit.url);
|
||||
return {
|
||||
...hit,
|
||||
url: hit.url
|
||||
// @TODO: temporary convenience for development.
|
||||
.replace(url.origin, '')
|
||||
.replace('#__docusaurus', ''),
|
||||
};
|
||||
});
|
||||
const sources = groupBy(formattedHits, hit => hit.hierarchy.lvl0);
|
||||
const sources = groupBy(hits, hit => hit.hierarchy.lvl0);
|
||||
|
||||
// We store the `lvl0`s to display them as search suggestions
|
||||
// in the “no results“ screen.
|
||||
|
|
@ -224,6 +219,7 @@ export function DocSearch({
|
|||
return Object.values(
|
||||
groupBy(items, item => item.hierarchy.lvl1)
|
||||
)
|
||||
.map(transformItems)
|
||||
.map(hits =>
|
||||
hits.map(item => {
|
||||
return {
|
||||
|
|
@ -256,6 +252,8 @@ export function DocSearch({
|
|||
favoriteSearches,
|
||||
saveRecentSearch,
|
||||
initialQuery,
|
||||
navigator,
|
||||
transformItems,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
@ -338,6 +336,7 @@ export function DocSearch({
|
|||
<ScreenState
|
||||
{...autocomplete}
|
||||
state={state}
|
||||
hitComponent={hitComponent}
|
||||
recentSearches={recentSearches}
|
||||
favoriteSearches={favoriteSearches}
|
||||
onItemClick={item => {
|
||||
|
|
|
|||
12
src/Hit.tsx
Normal file
12
src/Hit.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
|
||||
import { DocSearchHit } from './types';
|
||||
|
||||
interface HitProps {
|
||||
hit: DocSearchHit;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function Hit({ hit, children }: HitProps) {
|
||||
return <a href={hit.url}>{children}</a>;
|
||||
}
|
||||
|
|
@ -4,7 +4,11 @@ import {
|
|||
AutocompleteState,
|
||||
} from '@francoischalifour/autocomplete-core';
|
||||
|
||||
import { StoredDocSearchHit, InternalDocSearchHit } from './types';
|
||||
import {
|
||||
DocSearchHit,
|
||||
InternalDocSearchHit,
|
||||
StoredDocSearchHit,
|
||||
} from './types';
|
||||
import { Snippet } from './Snippet';
|
||||
|
||||
interface ResultsProps<TItem>
|
||||
|
|
@ -19,6 +23,10 @@ interface ResultsProps<TItem>
|
|||
renderIcon(props: { item: TItem; index: number }): React.ReactNode;
|
||||
renderAction(props: { item: TItem }): React.ReactNode;
|
||||
onItemClick(item: TItem): void;
|
||||
hitComponent(props: {
|
||||
hit: DocSearchHit;
|
||||
children: React.ReactNode;
|
||||
}): JSX.Element;
|
||||
}
|
||||
|
||||
export function Results<TItem extends StoredDocSearchHit>(
|
||||
|
|
@ -28,6 +36,8 @@ export function Results<TItem extends StoredDocSearchHit>(
|
|||
return null;
|
||||
}
|
||||
|
||||
const Hit = props.hitComponent;
|
||||
|
||||
return (
|
||||
<section className="DocSearch-Hits">
|
||||
<div className="DocSearch-Hit-source">{props.title}</div>
|
||||
|
|
@ -52,7 +62,7 @@ export function Results<TItem extends StoredDocSearchHit>(
|
|||
},
|
||||
})}
|
||||
>
|
||||
<a href={item.url}>
|
||||
<Hit hit={item}>
|
||||
<div className="DocSearch-Hit-Container">
|
||||
{props.renderIcon({ item, index })}
|
||||
|
||||
|
|
@ -110,7 +120,7 @@ export function Results<TItem extends StoredDocSearchHit>(
|
|||
|
||||
{props.renderAction({ item })}
|
||||
</div>
|
||||
</a>
|
||||
</Hit>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
Loading…
Reference in a new issue