@nosto/autocomplete
Version:
Library designed to simplify the implementation of search autocomplete functionality
353 lines (344 loc) • 12.1 kB
TypeScript
import { SearchOptions, SearchQuery, InputSearchQuery, SearchResult } from '@nosto/nosto-js/client';
import * as _nosto_search_js from '@nosto/search-js';
import { HitDecorator, SearchOptions as SearchOptions$1 } from '@nosto/search-js';
export { priceDecorator } from '/search-js/currencies';
type AutocompleteInstance = {
/**
* Open the dropdown.
*/
open(): void;
/**
* Close the dropdown.
*/
close(): void;
/**
* Destroy the autocomplete instance.
*/
destroy(): void;
};
type SearchAutocompleteOptions = Pick<SearchOptions, "isKeyword" | "redirect">;
/**
* @param config Autocomplete configuration.
* @returns Autocomplete instance.
* @group Autocomplete
* @category Core
* @example
* ```js
* import { autocomplete } from '@nosto/autocomplete';
*
* // Basic usage
* autocomplete({
* inputSelector: '#search',
* dropdownSelector: '#dropdown',
* render: (container, state) => {
* container.innerHTML = `
* <div>
* <h1>${state.query}</h1>
* <ul>
* ${state.response.products
* .map((product) => `<li>${product.name}</li>`)
* .join('')}
* </ul>
* </div>
* `;
* },
* fetch: {
* products: {
* fields: ['name', 'url', 'imageUrl', 'price', 'listPrice', 'brand'],
* size: 5
* },
* keywords: {
* size: 5,
* fields: ['keyword', '_highlight.keyword'],
* highlight: {
* preTag: `<strong>`,
* postTag: '</strong>'
* }
* }
* }
* });
*
* // Liquid template.
* import { autocomplete, fromRemoteLiquidTemplate, fromLiquidTemplate, defaultLiquidTemplate } from '@nosto/autocomplete/liquid';
*
* autocomplete({
* inputSelector: '#search',
* dropdownSelector: '#dropdown',
* render: fromRemoteLiquidTemplate('autocomplete.liquid'),
* // Or:
* render: window.nostoAutocomplete.fromLiquidTemplate(defaultLiquidTemplate),
* ...
* });
*
* // Mustache template.
* import { autocomplete, fromRemoteMustacheTemplate, fromMustacheTemplate, defaultMustacheTemplate } from '@nosto/autocomplete/mustache';
*
* autocomplete({
* inputSelector: '#search',
* dropdownSelector: '#dropdown',
* render: fromRemoteMustacheTemplate('autocomplete.mustache'),
* // Or:
* render: fromMustacheTemplate(defaultMustacheTemplate),
* ...
* });
*
* // React example.
* import { autocomplete, Autocomplete } from '@nosto/autocomplete/react';
* import ReactDOM from 'react-dom';
*
* let reactRoot;
*
* autocomplete({
* inputSelector: '#search',
* dropdownSelector: '#dropdown',
* render: function (container, state) {
* if (!reactRoot) {
* reactRoot = ReactDOM.createRoot(container);
* }
* reactRoot.render(<Autocomplete {...state} />);
* },
* ...
* });
* ```
*/
declare function autocomplete$1<State = DefaultState>(config: AutocompleteConfig<State>): AutocompleteInstance;
/**
* @group Autocomplete
* @category Core
*/
interface GoogleAnalyticsConfig {
/**
* Path of search page
* @default "/search"
*/
serpPath?: string;
/**
* Search query url parameter name
* @default "query"
*/
queryParamName?: string;
/**
* Enable Google Analytics
* @default true
*/
enabled?: boolean;
}
type Selector = string | Element;
/**
* @group Autocomplete
* @category Core
*/
interface AutocompleteConfig<State> {
/**
* The input element to attach the autocomplete to
*/
inputSelector: Selector;
/**
* The dropdown element to attach the autocomplete to
*/
dropdownSelector: Selector | ((input: HTMLInputElement) => Selector);
/**
* The function to use to render the dropdown
*/
render: (container: HTMLElement, state: State) => void | PromiseLike<void>;
/**
* Minimum length of the query before searching
*/
minQueryLength?: number;
/**
* The function to use to fetch the search state
*/
fetch: SearchQuery | ((input: string) => PromiseLike<State>);
/**
* The function to use to submit the search
*/
submit?: (query: string, config: AutocompleteConfig<State>, options?: SearchAutocompleteOptions) => void;
/**
* Enable history
*/
historyEnabled?: boolean;
/**
* Max number of history items to show
*/
historySize?: number;
/**
* Enable Nosto Analytics
*/
nostoAnalytics?: boolean;
/**
* Google Analytics configuration. Set to `false` to disable.
*/
googleAnalytics?: GoogleAnalyticsConfig | boolean;
/**
* Decorate each search hit before rendering
*
* @example
* ```ts
* import { priceDecorator } from "@nosto/autocomplete"
*
* autocomplete({
* hitDecorators: [
* priceDecorator({ defaultCurrency: "USD" })
* ]
* })
* ```
*/
hitDecorators?: HitDecorator[];
/**
* Whether to submit the form natively or not
*/
nativeSubmit?: boolean;
/**
* A function to call when the user clicks on a search hit to use custom routing
* @example
* ```ts
* autocomplete({
* routingHandler: (url) => {
* location.href = url
* }
* })
* ```
*/
routingHandler?: (url: string) => void;
}
/**
* @group Autocomplete
* @category Core
*/
interface DefaultState {
/**
* The current search query object.
*/
query?: InputSearchQuery;
/**
* The current search response.
*/
response?: SearchResult;
/**
* The history items.
*/
history?: {
item: string;
}[];
}
var autocomplete = "<div class=\"ns-autocomplete-results\">\n {{#response.keywords.hits.length}}\n <div class=\"ns-autocomplete-keywords\">\n <div class=\"ns-autocomplete-header\">\n Keywords\n </div>\n {{#response.keywords.hits}}\n <div class=\"ns-autocomplete-keyword\" data-ns-hit=\"{{toJson}}\" data-testid=\"keyword\">\n {{#_highlight.keyword}}\n <span>{{{.}}}</span>\n {{/_highlight.keyword}}\n {{^_highlight.keyword}}\n <span>{{keyword}}</span>\n {{/_highlight.keyword}}\n </div>\n {{/response.keywords.hits}}\n </div>\n {{/response.keywords.hits.length}}\n\n {{#response.products.hits.length}}\n <div class=\"ns-autocomplete-products\">\n <div class=\"ns-autocomplete-header\">\n Products\n </div>\n {{#response.products.hits}}\n <a class=\"ns-autocomplete-product\" href=\"{{url}}\" data-ns-hit=\"{{toJson}}\" data-testid=\"product\">\n <img\n class=\"ns-autocomplete-product-image\"\n src=\"{{#imageUrl}}{{ imageUrl }}{{/imageUrl}}{{^imageUrl}}{{ imagePlaceholder }}{{/imageUrl}}\"\n alt=\"{{name}}\"\n width=\"60\"\n height=\"40\"\n />\n <div class=\"ns-autocomplete-product-info\">\n {{#brand}}\n <div class=\"ns-autocomplete-product-brand\">\n {{.}}\n </div>\n {{/brand}}\n <div class=\"ns-autocomplete-product-name\">\n {{name}}\n </div>\n <div>\n <span>\n {{price}}€\n </span>\n {{#showListPrice}}\n <span class=\"ns-autocomplete-product-list-price\">\n {{listPrice}}€\n </span>\n {{/showListPrice}}\n </div>\n </div>\n </a>\n {{/response.products.hits}}\n </div>\n {{/response.products.hits.length}}\n\n {{#history.length}}\n <div class=\"ns-autocomplete-history\">\n <div class=\"ns-autocomplete-header\">\n Recently searched\n </div>\n {{#history}}\n <div class=\"ns-autocomplete-history-item\" data-ns-hit=\"{{toJson}}\" data-testid=\"history\">\n {{item}}\n <a href=\"#\" class=\"ns-autocomplete-history-item-remove\" data-ns-remove-history=\"{{item}}\">\n ✕\n </a>\n </div>\n {{/history}}\n </div>\n <div class=\"ns-autocomplete-history-clear\">\n <button type=\"button\" class=\"ns-autocomplete-button\" data-ns-remove-history=\"all\">\n Clear history\n </button>\n </div>\n {{/history.length}}\n\n {{#response.keywords.hits.length}}{{#response.products.hits.length}}\n <div class=\"ns-autocomplete-submit\">\n <button type=\"submit\" class=\"ns-autocomplete-button\">\n See all search results\n </button>\n </div>\n {{/response.products.hits.length}}{{/response.keywords.hits.length}}\n</div>\n";
type Options = {
/**
* Mustache helpers to extend template functionality.
*/
helpers?: object;
};
/**
* Render a Mustache template into a container
*
* @param template Mustache template
* @param options Options object.
* @returns Render function
* @group Autocomplete
* @category Mustache
/**
* @example
* ```js
* import { fromMustacheTemplate } from "@nosto/autocomplete/mustache";
*
* const render = fromMustacheTemplate(`
* <div>
* <h1>{{title}}</h1>
* <ul>
* {{#products}}
* <li>{{name}}</li>
* {{/products}}
* </ul>
* </div>
* `, {
* helpers: {
* toJson: function () {
* return JSON.stringify(this)
* }});
*
* render(document.getElementById("container"), {
* title: "My Title",
* products: [
* { name: "Product 1" },
* { name: "Product 2" },
* { name: "Product 3" }
* ]
* });
* ```
*/
declare function fromMustacheTemplate<State extends object = DefaultState>(template: string, options?: Options): (container: HTMLElement, state: State) => Promise<void>;
/**
*
* @param query Query object.
* @param options Options object.
* @returns Promise of search response.
* @group Autocomplete
* @category Core
* @example
* ```js
* import { search } from "@nosto/autocomplete"
*
* search({
* query: "shoes",
* products: {
* fields: ["name", "price"],
* facets: ["brand", "category"],
* size: 10,
* from: 0,
* }
* }).then((state) => {
* console.log(state.response)
* })
* ```
*/
declare function search(query: SearchQuery, options?: SearchOptions$1): Promise<{
query: SearchQuery;
response: _nosto_search_js.DecoratedResult<readonly _nosto_search_js.HitDecorator[]>;
}>;
/**
* Nosto Autocomplete Web Component using Mustache templates.
*
* This component integrates the Nosto Autocomplete functionality with Mustache templating.
* It fetches the configuration from a script tag, compiles the Mustache template,
* and initializes the autocomplete with the compiled template as the render function.
* If a custom template isn't passed, the component will use the default Liquid template.
*
* @example
* ```html
* <nosto-autocomplete>
* <form>
* <input type="text" id="input" />
* <div id="results"></div>
* </form>
* <script autocomplete-config type="application/json">
* {
* "inputSelector": "#input",
* "dropdownSelector": "#results",
* "fetch": {
* "products": {
* "fields": ["name", "url", "imageUrl", "price", "listPrice", "brand"],
* "size": 5
* },
* "keywords": {
* "size": 5,
* "fields": ["keyword", "_highlight.keyword"]
* }
* }
* }
* </script>
* <script type="text/x-mustache-template" autocomplete-template>
* <h1>{{query}}</h1>
* <ul>
* {{#products}}
* <li>{{name}}</li>
* {{/products}}
* </ul>
* </script>
* </nosto-autocomplete>
* ```
*/
declare class NostoAutocomplete extends HTMLElement {
connectedCallback(): Promise<AutocompleteInstance>;
}
export { NostoAutocomplete, autocomplete$1 as autocomplete, autocomplete as defaultMustacheTemplate, fromMustacheTemplate, search };
export type { AutocompleteConfig, AutocompleteInstance, DefaultState, GoogleAnalyticsConfig, Options };