Skip to content

Commit

Permalink
feat(plugin): add transformSource API
Browse files Browse the repository at this point in the history
This updates the plugins' API to allow complete source override, as opposed to only templates override.

## Why

Users might want to override the behavior of the original source (e.g., keep the panel open on select). This wasn't possible with the previous API, which only allow to modify the template.

## API

```tsx
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
  key: 'search',
  limit: 3,
  transformSource({ source, onRemove }) {
    return {
      ...source,
      getItemUrl({ item }) {
        return `https://google.com?q=${item.query}`;
      },
    };
  },
});
const querySuggestionsPlugin = createQuerySuggestionsPlugin({
  searchClient,
  indexName: 'instant_search_demo_query_suggestions',
  transformSource({ source, onTapAhead }) {
    return {
      ...source,
      onSelect({ setIsOpen }) {
        setIsOpen(true);
      },
      getItemUrl({ item }) {
        return `https://google.com?q=${item.query}`;
      },
      templates: {
        ...source.templates,
        item(params) {
          const { item } = params;
          return (
            <a
              href={`https://google.com?q=${item.query}`}
              className="aa-ItemLink"
            >
              {source.templates.item(params)}
            </a>
          );
        },
      },
    };
  },
});
```
  • Loading branch information
francoischalifour committed Feb 7, 2021
1 parent 9bc826e commit fbd9e72
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import {
AutocompletePlugin,
AutocompleteState,
} from '@algolia/autocomplete-core';
import { getAlgoliaHits, SourceTemplates } from '@algolia/autocomplete-js';
import { AutocompleteSource, getAlgoliaHits } from '@algolia/autocomplete-js';
import { SearchOptions } from '@algolia/client-search';
import { SearchClient } from 'algoliasearch/lite';

import {
getTemplates as defaultGetTemplates,
GetTemplatesParams,
} from './getTemplates';
import { getTemplates } from './getTemplates';
import { QuerySuggestionsHit } from './types';

export type CreateQuerySuggestionsPluginParams<
Expand All @@ -18,7 +15,10 @@ export type CreateQuerySuggestionsPluginParams<
searchClient: SearchClient;
indexName: string;
getSearchParams?(params: { state: AutocompleteState<TItem> }): SearchOptions;
getTemplates?(params: GetTemplatesParams<TItem>): SourceTemplates<TItem>;
transformSource?(params: {
source: AutocompleteSource<TItem>;
onTapAhead(item: TItem): void;
}): AutocompleteSource<TItem>;
};

export function createQuerySuggestionsPlugin<
Expand All @@ -27,38 +27,43 @@ export function createQuerySuggestionsPlugin<
searchClient,
indexName,
getSearchParams = () => ({}),
getTemplates = defaultGetTemplates,
transformSource = ({ source }) => source,
}: CreateQuerySuggestionsPluginParams<TItem>): AutocompletePlugin<
TItem,
undefined
> {
return {
getSources({ query, setQuery, refresh, state }) {
function onTapAhead(item: TItem) {
setQuery(item.query);
refresh();
}

const templates = getTemplates({ onTapAhead });

return [
{
sourceId: 'querySuggestionsPlugin',
getItemInputValue({ item }) {
return item.query;
},
getItems() {
return getAlgoliaHits<TItem>({
searchClient,
queries: [
{
indexName,
query,
params: getSearchParams({ state }),
},
],
});
},
templates: getTemplates({
onTapAhead(item) {
setQuery(item.query);
refresh();
transformSource({
source: {
sourceId: 'querySuggestionsPlugin',
getItemInputValue({ item }) {
return item.query;
},
getItems() {
return getAlgoliaHits<TItem>({
searchClient,
queries: [
{
indexName,
query,
params: getSearchParams({ state }),
},
],
});
},
}),
},
templates,
},
onTapAhead,
}),
];
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ export type CreateRecentSearchesLocalStorageOptions<

type LocalStorageRecentSearchesPluginOptions<
TItem extends RecentSearchesItem
> = Pick<CreateRecentSearchesPluginParams<TItem>, 'getTemplates'> &
> = Pick<CreateRecentSearchesPluginParams<TItem>, 'transformSource'> &
CreateRecentSearchesLocalStorageOptions<TItem>;

export function createLocalStorageRecentSearchesPlugin<
TItem extends RecentSearchesItem
>({
key,
limit = 5,
getTemplates,
transformSource,
search = defaultSearch,
}: LocalStorageRecentSearchesPluginOptions<TItem>): AutocompletePlugin<
TItem,
Expand All @@ -59,7 +59,7 @@ export function createLocalStorageRecentSearchesPlugin<
});

return createRecentSearchesPlugin({
getTemplates,
transformSource,
storage,
});
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import { AutocompletePlugin } from '@algolia/autocomplete-core';
import { SourceTemplates } from '@algolia/autocomplete-js';
import { MaybePromise, warn } from '@algolia/autocomplete-shared';
import { AutocompleteSource } from '@algolia/autocomplete-js';
import { createRef, MaybePromise, warn } from '@algolia/autocomplete-shared';
import { SearchOptions } from '@algolia/client-search';

import { createStore, RecentSearchesStorage } from './createStore';
import {
getTemplates as defaultGetTemplates,
GetTemplatesParams,
} from './getTemplates';
import { getTemplates } from './getTemplates';
import { RecentSearchesItem } from './types';

type Ref<TType> = {
current: TType;
};

export type RecentSearchesPluginData = {
getAlgoliaSearchParams(params?: SearchOptions): SearchOptions;
};
Expand All @@ -22,18 +15,21 @@ export type CreateRecentSearchesPluginParams<
TItem extends RecentSearchesItem
> = {
storage: RecentSearchesStorage<TItem>;
getTemplates?(params: GetTemplatesParams): SourceTemplates<TItem>;
transformSource?(params: {
source: AutocompleteSource<TItem>;
onRemove(id: string): void;
}): AutocompleteSource<TItem>;
};

export function createRecentSearchesPlugin<TItem extends RecentSearchesItem>({
storage,
getTemplates = defaultGetTemplates,
transformSource = ({ source }) => source,
}: CreateRecentSearchesPluginParams<TItem>): AutocompletePlugin<
TItem,
RecentSearchesPluginData
> {
const store = createStore<TItem>(storage);
const lastItemsRef: Ref<MaybePromise<TItem[]>> = { current: [] };
const store = createStore(storage);
const lastItemsRef = createRef<MaybePromise<TItem[]>>([]);

return {
subscribe({ onSelect }) {
Expand All @@ -44,7 +40,7 @@ export function createRecentSearchesPlugin<TItem extends RecentSearchesItem>({
store.add({
id: inputValue,
query: inputValue,
} as TItem);
} as any);
}
});
},
Expand All @@ -55,33 +51,38 @@ export function createRecentSearchesPlugin<TItem extends RecentSearchesItem>({
store.add({
id: query,
query,
} as TItem);
} as any);
}
},
getSources({ query, refresh }) {
lastItemsRef.current = store.getAll(query);

function onRemove(id: string) {
store.remove(id);
refresh();
}

const templates = getTemplates<any>({ onRemove });

return Promise.resolve(lastItemsRef.current).then((items) => {
if (items.length === 0) {
return [];
}

return [
{
sourceId: 'recentSearchesPlugin',
getItemInputValue({ item }) {
return item.query;
},
getItems() {
return items;
},
templates: getTemplates({
onRemove(id) {
store.remove(id);
refresh();
transformSource({
source: {
sourceId: 'recentSearchesPlugin',
getItemInputValue({ item }) {
return item.query;
},
}),
},
getItems() {
return items;
},
templates,
},
onRemove,
}),
];
});
},
Expand Down
52 changes: 52 additions & 0 deletions packages/website/docs/createLocalStorageRecentSearchesPlugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,58 @@ function search({ query, items, limit }) {
}
```

### `transformSource`

> `(params: { source: AutocompleteSource, onRemove: () => void })`
#### Example

Keeping the panel open on select:

```tsx
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
key: 'navbar',
transformSource({ source, onRemove }) {
return {
...source,
onSelect({ setIsOpen }) {
setIsOpen(true);
},
};
},
});
```

Opening a link:

```tsx
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
key: 'navbar',
transformSource({ source, onRemove }) {
return {
...source,
getItemUrl({ item }) {
return `https://google.com?q=${item.query}`;
},
templates: {
...source.templates,
item(params) {
const { item } = params;
return (
<a
className="aa-ItemLink"
href={`https://google.com?q=${item.query}`}
>
{source.templates.item(params)}
</a>
);
},
},
};
},
});
```

## Returns

### `data`
Expand Down
54 changes: 54 additions & 0 deletions packages/website/docs/createQuerySuggestionsPlugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,57 @@ import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query
### `getSearchParams`

> [`() => SearchParameters`](https://www.algolia.com/doc/api-reference/search-api-parameters/)
### `transformSource`

> `(params: { source: AutocompleteSource, onTapAhead: () => void })`
#### Example

Keeping the panel open on select:

```tsx
const querySuggestionsPlugin = createQuerySuggestionsPlugin({
searchClient,
indexName: 'instant_search_demo_query_suggestions',
transformSource({ source, onTapAhead }) {
return {
...source,
onSelect({ setIsOpen }) {
setIsOpen(true);
},
};
},
});
```

Opening a link:

```tsx
const querySuggestionsPlugin = createQuerySuggestionsPlugin({
searchClient,
indexName: 'instant_search_demo_query_suggestions',
transformSource({ source, onTapAhead }) {
return {
...source,
getItemUrl({ item }) {
return `https://google.com?q=${item.query}`;
},
templates: {
...source.templates,
item(params) {
const { item } = params;
return (
<a
className="aa-ItemLink"
href={`https://google.com?q=${item.query}`}
>
{source.templates.item(params)}
</a>
);
},
},
};
},
});
```
Loading

0 comments on commit fbd9e72

Please sign in to comment.