UNPKG

@nosto/autocomplete

Version:

Library designed to simplify the implementation of search autocomplete functionality

259 lines (253 loc) 6.53 kB
import { SearchQuery, InputSearchQuery, SearchResult, SearchOptions } 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 '@nosto/search-js/currencies'; /** * @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; }[]; } 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<State = DefaultState>(config: AutocompleteConfig<State>): AutocompleteInstance; /** * * @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[]>; }>; export { autocomplete, search }; export type { AutocompleteConfig, AutocompleteInstance, DefaultState, GoogleAnalyticsConfig, SearchAutocompleteOptions, Selector };