Skip to content

Commit

Permalink
feat(plugins): introduce Query Suggestions plugin (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
francoischalifour authored Nov 9, 2020
1 parent 86adc65 commit 7d19396
Show file tree
Hide file tree
Showing 24 changed files with 283 additions and 116 deletions.
12 changes: 8 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ aliases:
mkdir -p packages/autocomplete-shared/dist
mkdir -p packages/autocomplete-core/dist
mkdir -p packages/autocomplete-js/dist
mkdir -p packages/autocomplete-plugin-recent-searches/dist
mkdir -p packages/autocomplete-preset-algolia/dist
mkdir -p packages/autocomplete-plugin-recent-searches/dist
mkdir -p packages/autocomplete-plugin-query-suggestions/dist
cp -R /tmp/workspace/packages/autocomplete-shared/dist packages/autocomplete-shared
cp -R /tmp/workspace/packages/autocomplete-core/dist packages/autocomplete-core
cp -R /tmp/workspace/packages/autocomplete-js/dist packages/autocomplete-js
cp -R /tmp/workspace/packages/autocomplete-plugin-recent-searches/dist packages/autocomplete-plugin-recent-searches
cp -R /tmp/workspace/packages/autocomplete-preset-algolia/dist packages/autocomplete-preset-algolia
cp -R /tmp/workspace/packages/autocomplete-plugin-recent-searches/dist packages/autocomplete-plugin-recent-searches
cp -R /tmp/workspace/packages/autocomplete-plugin-query-suggestions/dist packages/autocomplete-plugin-query-suggestions
defaults: &defaults
working_directory: ~/autocomplete
Expand Down Expand Up @@ -66,14 +68,16 @@ jobs:
mkdir -p /tmp/workspace/packages/autocomplete-shared/dist
mkdir -p /tmp/workspace/packages/autocomplete-core/dist
mkdir -p /tmp/workspace/packages/autocomplete-js/dist
mkdir -p /tmp/workspace/packages/autocomplete-plugin-recent-searches/dist
mkdir -p /tmp/workspace/packages/autocomplete-preset-algolia/dist
mkdir -p /tmp/workspace/packages/autocomplete-plugin-recent-searches/dist
mkdir -p /tmp/workspace/packages/autocomplete-plugin-query-suggestions/dist
cp -R packages/autocomplete-shared/dist /tmp/workspace/packages/autocomplete-shared
cp -R packages/autocomplete-core/dist /tmp/workspace/packages/autocomplete-core
cp -R packages/autocomplete-js/dist /tmp/workspace/packages/autocomplete-js
cp -R packages/autocomplete-plugin-recent-searches/dist /tmp/workspace/packages/autocomplete-plugin-recent-searches
cp -R packages/autocomplete-preset-algolia/dist /tmp/workspace/packages/autocomplete-preset-algolia
cp -R packages/autocomplete-plugin-recent-searches/dist /tmp/workspace/packages/autocomplete-plugin-recent-searches
cp -R packages/autocomplete-plugin-query-suggestions/dist /tmp/workspace/packages/autocomplete-plugin-query-suggestions
- persist_to_workspace:
root: *workspace_root
paths:
Expand Down
4 changes: 4 additions & 0 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
},
{
"path": "packages/autocomplete-plugin-recent-searches/dist/umd/index.js",
"maxSize": "2.5 kB"
},
{
"path": "packages/autocomplete-plugin-query-suggestions/dist/umd/index.js",
"maxSize": "2.25 kB"
}
]
Expand Down
83 changes: 12 additions & 71 deletions examples/js/app.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,28 @@
import { Hit } from '@algolia/client-search';
import algoliasearch from 'algoliasearch/lite';
import {
autocomplete,
AutocompleteSource,
getAlgoliaHits,
reverseHighlightHit,
} from '@algolia/autocomplete-js';
import { autocomplete } from '@algolia/autocomplete-js';
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';

const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);

type QuerySuggestionHit = { query: string };

const recentSearches = createLocalStorageRecentSearchesPlugin({
key: 'recent',
limit: 3,
});

autocomplete<Hit<QuerySuggestionHit>>({
container: '#autocomplete',
debug: true,
openOnFocus: true,
// dropdownPlacement: 'start',
plugins: [recentSearches],
getSources({ query }) {
return getAlgoliaHits<QuerySuggestionHit>({
searchClient,
queries: [
{
indexName: 'instant_search_demo_query_suggestions',
query,
params: {
hitsPerPage: recentSearches.data.getAlgoliaQuerySuggestionsHitsPerPage(
10
),
facetFilters: [
...recentSearches.data.getAlgoliaQuerySuggestionsFacetFilters(),
],
},
},
],
}).then(([hits]) => {
return [
{
getItemInputValue({ item }) {
return item.query;
},
getItems() {
return hits;
},
templates: {
item({ item }) {
return `
<div class="aa-ItemContent">
<div class="aa-ItemSourceIcon">${searchIcon}</div>
<div class="aa-ItemTitle">
${reverseHighlightHit<Hit<QuerySuggestionHit>>({
hit: item,
attribute: 'query',
})}
</div>
</div>
`;
},
},
} as AutocompleteSource<Hit<QuerySuggestionHit>>,
];
});
const querySuggestions = createQuerySuggestionsPlugin({
searchClient,
indexName: 'instant_search_demo_query_suggestions',
getSearchParams() {
return recentSearches.data.getAlgoliaSearchParams();
},
});

const searchIcon = `
<svg width="20" height="20" viewBox="0 0 20 20">
<path
d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z"
stroke="currentColor"
fill="none"
fillRule="evenodd"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
`;
autocomplete({
container: '#autocomplete',
openOnFocus: true,
plugins: [recentSearches, querySuggestions],
});
2 changes: 1 addition & 1 deletion examples/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@algolia/autocomplete-js": "1.0.0-alpha.34",
"@algolia/autocomplete-plugin-recent-searches": "1.0.0-alpha.34",
"@algolia/client-search": "4.5.1",
"@algolia/autocomplete-plugin-query-suggestions": "1.0.0-alpha.34",
"algoliasearch": "4.5.1"
},
"devDependencies": {
Expand Down
10 changes: 3 additions & 7 deletions packages/autocomplete-core/src/getDefaultProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,10 @@ export function getDefaultProps<TItem>(
});
},
getSources(options) {
const getSourcesFromPlugins = plugins
.map((plugin) => plugin.getSources)
.filter((getSources) => getSources !== undefined);

return Promise.all(
[...getSourcesFromPlugins, props.getSources].map((getSources) =>
getNormalizedSources(getSources!, options)
)
[...plugins.map((plugin) => plugin.getSources), props.getSources]
.filter(Boolean)
.map((getSources) => getNormalizedSources(getSources!, options))
)
.then((nested) => flatten(nested))
.then((sources) =>
Expand Down
2 changes: 1 addition & 1 deletion packages/autocomplete-core/src/types/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export interface AutocompleteOptions<TItem> {
/**
* The sources to get the suggestions from.
*/
getSources(
getSources?(
params: GetSourcesParams<TItem>
): MaybePromise<Array<AutocompleteSource<TItem>>>;
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/autocomplete-core/src/types/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export type AutocompletePlugin<TItem, TData = unknown> = Partial<
* The subscribed properties are properties that are called when other sources
* are interacted with.
*/
subscribed: {
subscribed?: {
onSelect: AutocompleteSource<TItem>['onSelect'];
};
/**
* An extra plugin specific object to store variables and functions
*/
data: TData;
data?: TData;
};
16 changes: 10 additions & 6 deletions packages/autocomplete-core/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { MaybePromise } from '@algolia/autocomplete-shared';

import {
InternalAutocompleteOptions,
InternalAutocompleteSource,
AutocompleteState,
AutocompleteCollection,
AutocompleteOptions,
AutocompleteSource,
AutocompleteState,
GetSourcesParams,
InternalAutocompleteOptions,
InternalAutocompleteSource,
} from './types';

export const noop = () => {};
Expand Down Expand Up @@ -45,8 +47,10 @@ function normalizeSource<TItem>(
}

export function getNormalizedSources<TItem>(
getSources: AutocompleteOptions<TItem>['getSources'],
options
getSources: (
params: GetSourcesParams<TItem>
) => MaybePromise<Array<AutocompleteSource<TItem>>>,
options: GetSourcesParams<TItem>
): Promise<Array<InternalAutocompleteSource<TItem>>> {
return Promise.resolve(getSources(options)).then((sources) =>
Promise.all(
Expand Down
11 changes: 11 additions & 0 deletions packages/autocomplete-plugin-query-suggestions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# @algolia/autocomplete-plugin-query-suggestions

A plugin to add Query Suggestions to Algolia Autocomplete.

## Installation

```sh
yarn add @algolia/autocomplete-plugin-query-suggestions@alpha
# or
npm install @algolia/autocomplete-plugin-query-suggestions@alpha
```
45 changes: 45 additions & 0 deletions packages/autocomplete-plugin-query-suggestions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@algolia/autocomplete-plugin-query-suggestions",
"description": "A plugin to add query suggestions to Algolia Autocomplete.",
"version": "1.0.0-alpha.34",
"license": "MIT",
"homepage": "https://github.com/algolia/autocomplete.js",
"repository": "algolia/autocomplete.js",
"author": {
"name": "Algolia, Inc.",
"url": "https://www.algolia.com"
},
"source": "src/index.ts",
"types": "dist/esm/index.d.ts",
"module": "dist/esm/index.js",
"main": "dist/umd/index.js",
"umd:main": "dist/umd/index.js",
"unpkg": "dist/umd/index.js",
"jsdelivr": "dist/umd/index.js",
"sideEffects": false,
"files": [
"dist/"
],
"scripts": {
"build:clean": "rm -rf ./dist",
"build:esm": "babel src --root-mode upward --extensions '.ts,.tsx' --out-dir dist/esm --ignore '**/*/__tests__/'",
"build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/esm",
"build:umd": "rollup --config",
"build": "rm -rf ./dist && yarn build:umd && yarn build:esm && yarn build:types",
"on:change": "concurrently \"yarn build:esm\" \"yarn build:types\"",
"prepare": "yarn run build:esm",
"watch": "watch \"yarn on:change\" --ignoreDirectoryPattern \"/dist/\""
},
"dependencies": {
"@algolia/autocomplete-core": "1.0.0-alpha.34",
"@algolia/autocomplete-js": "1.0.0-alpha.34"
},
"devDependencies": {
"@algolia/client-search": "4.5.1",
"algoliasearch": "4.5.1"
},
"peerDependencies": {
"@algolia/client-search": "^4.5.1",
"algoliasearch": "^4.5.1"
}
}
16 changes: 16 additions & 0 deletions packages/autocomplete-plugin-query-suggestions/rollup.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { plugins } from '../../rollup.base.config';
import { getBundleBanner } from '../../scripts/getBundleBanner';

import pkg from './package.json';

export default {
input: 'src/index.ts',
output: {
file: 'dist/umd/index.js',
format: 'umd',
sourcemap: true,
name: pkg.name,
banner: getBundleBanner(pkg),
},
plugins,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { AutocompletePlugin } from '@algolia/autocomplete-core';
import { getAlgoliaHits, SourceTemplates } from '@algolia/autocomplete-js';
import { SearchOptions } from '@algolia/client-search';
import { SearchClient } from 'algoliasearch/lite';

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

export type CreateQuerySuggestionsPluginParams<
TItem extends QuerySuggestionsHit
> = {
searchClient: SearchClient;
indexName: string;
getSearchParams?(): SearchOptions;
getTemplates?(
params: GetTemplatesParams<TItem>
): SourceTemplates<TItem>['templates'];
};

export function createQuerySuggestionsPlugin<
TItem extends QuerySuggestionsHit
>({
searchClient,
indexName,
getSearchParams = () => ({}),
getTemplates = defaultGetTemplates,
}: CreateQuerySuggestionsPluginParams<TItem>): AutocompletePlugin<
TItem,
undefined
> {
return {
getSources({ query, setQuery, refresh }) {
return [
{
getItemInputValue({ item }) {
return item.query;
},
getItems() {
return getAlgoliaHits<TItem>({
searchClient,
queries: [
{
indexName,
query,
params: getSearchParams(),
},
],
});
},
templates: getTemplates({
onTapAhead(item) {
setQuery(item.query);
refresh();
},
}),
},
];
},
};
}
Loading

0 comments on commit 7d19396

Please sign in to comment.